#
# This code implements MAFIA's firewall functionality for the IGMP protocol
# This code is still in a rudimentary stage. You can easily extend it to 
# filter out IGMP packets. The necessary changes can be easily added to the function
# check_igmp given below. Feel free to contact me if you have any questions.  
#
# Contact: krishna@cs.ucsb.edu
# This code is GPL.
#
package ipq_example;
use strict;
$^W = 1;

use IPTables::IPv4::IPQueue qw(:constants);
use NetPacket::IP;

use constant TIMEOUT => 1_000_000 * 2;		# 2 seconds

sub check_igmp 
{
	my ($payload, $ip, $protono, $igmp);
	
	$payload = shift;

	#
	# IP Header
	#
	$ip = NetPacket::IP->decode($payload);
	$protono = $ip->{proto};

	if ($protono != 2) {
		return 1; # accept
	}	
	else {	
		$igmp = NetPacket::IGMP->decode($payload);
	print<<EOT;
[ IP Header ]
Version           : $igmp->{ver}
Msg type: $igmp->{type}
Group address: $igmp->{group_addr}

EOT
	}
}

sub main
{
	my $ret;
	my $queue = new IPTables::IPv4::IPQueue(copy_mode => IPQ_COPY_PACKET,
	                                        copy_range => 2048)
		or die IPTables::IPv4::IPQueue->errstr;

	while (1) {
		my $msg = $queue->get_message(TIMEOUT);
		if (!defined $msg) {
			next if IPTables::IPv4::IPQueue->errstr eq 'Timeout';
			die IPTables::IPv4::IPQueue->errstr;
		}
	
		$ret = check_igmp($msg->payload()) if $msg->data_len();
		if ($ret == 1) {
			# accept packet
			$queue->set_verdict($msg->packet_id, NF_ACCEPT);
		} else {
			# drop packet
			$queue->set_verdict($msg->packet_id, NF_DROP);
		}
	}
}

main();
