#!/usr/bin/perl

use Net::RawIP qw(:pcap);
system("clear");
$SIG{INT} = \&quit;

my ($ip,$seq_nr,$count);

$my_ip = "123.123.123.123";	# change value
$count = 0;
$|=1;

$dev='eth0';
$ip_addr=${ifaddrlist()}{$dev};

$packet_tcp=new Net::RawIP({tcp=>{}});
$filt_tcp="ip proto \\tcp";
$pcap_tcp=$packet_tcp->pcapinit($dev,$filt_tcp,1500,60);
$offset_tcp = linkoffset($pcap_tcp);


if (fork){ loop $pcap_tcp,-1,\&check_tcp,\@packet_tcp;} 


sub check_tcp{
	
	my $time = timem();
	$packet_tcp->bset($_[2],$offset_tcp);
	$proto=$packet_tcp->proto;
	
	my ($saddr,$daddr,$sport,$dport,$seq,$ack_seq,$urg,$ack,$psh,$rst,$syn,$fin,$data)= $packet_tcp->get({ip=>['saddr','daddr'],tcp=>['source','dest','seq','ack_seq','urg','ack','psh','rst','syn','fin','data']});
	
	if ($sport == "22" ) {
 		# vorerst ssh ignorieren
	} elsif ( $dport == "22" ) {
	} else {
		
		$seq =~ s/-//g;
		
		
		if ($syn){	# & !$ack) {	
			
			print "PACKET: $seq "; 
	
			if ($urg) {print "URG "};
			if ($ack) {print "ACK "};
			if ($psh) {print "PSH "};
			if ($rst) {print "RST "};
			if ($syn) {print "SYN "};
			if ($fin) {print "FIN "};	
		
		
			if ($saddr > $daddr) {
				
				print "\t",ip2name($saddr), ":$sport \t -> \t",ip2name($daddr),":$dport \n";
				
				push(@ips, ip2name($daddr) . "#$seq");
				
			} else {
				
				print "\t",ip2name($daddr), ":$dport \t <- \t",ip2name($saddr),":$sport \n";
				
				# ATTACKER_IP - SEQ - ATTACK_PORT - MY_PORT
				push(@content, ip2name($saddr) . "#$seq#$sport#$dport");
				
			
				if ($#content >= "120"){
					foreach $entry(@content){
						($ip,$seq_nr,$attacker_port,$my_port) = split('#', $entry);
						if ($ip == ip2name($saddr) ){
							$count++;
						}
						if ($count >= "100"){
							print "INCOMING SYNFLOOD DETECTED!\n";
							$attacker = $ip;
							
							foreach $bad (@content) {
								($ipX,$seq_nrX,$attacker_portX,$my_portX) = split('#', $bad);
								if ($ipX == $attacker){
									print "KILLING BAD CONNECTION ATTEMPT!\n";
									
									# send FIN to abort connection
									my $new_packet= new Net::RawIP;
									$new_packet->set({
										ip=>{	saddr=>$my_ip,
											daddr=>$attacker
											},
										tcp=>{
											source=>$my_port,
											dest=>$attacker_portX,
											fin=>"1",
											seq=>$seq_nrX
										}
										});
									$new_packet->send;
								}
							}	
						}
					}
				$count = 0;	
				@content = ();
				}
				
			}
		}
	
	}
}

sub ip2name {
my $addr = shift;
(gethostbyaddr(pack("N",$addr),AF_INET))[0] || ip2dot($addr);
}

sub ip2dot {
sprintf("%u.%u.%u.%u",unpack "C4", pack "N1", shift);
}

sub quit {
	exit(0);
}