# -sam k (commport5@lucidx.com)

# not fully functional yet
# stay tuned for more (in a later version)

use Socket;

sub cease {
 ($tcpo, $ctcp, $nite, $headers) = ($offset_tcp, $_[2], 0);
 $packet_tcp->bset($ctcp, $tcpo);
 $proto = $packet_tcp->proto;
 ($vers,$ihl,$tos,$tot,$id,$frg,$ttl,$pro,$chc,$saddr,$daddr,$sport,$dport,$seq,$aseq,$dof,$res1,$res2,$urg,$ack,$psh,$rst,$syn,$fin,$win,$chk,$data) =
 $packet_tcp->get({ip=>['version','ihl','tos','tot_len','id','frag_off','ttl','protocol','check','saddr','daddr'],tcp=>[
 'source','dest','seq','ack_seq','doff','res1','res2','urg','ack','psh','rst','syn','fin','window','check','data']});
 $seq =~ s/^-//;
 $addlength = 0;
 $destip = $daddr;
 $destport = $dport;
 $sourceport = $sport;
 $sourceip = $saddr;
 length($sourceip) == 4 or $sourceip = gethostbyname($sourceip);
 length($destip) == 4 or $destip = gethostbyname($destip);
 $wproto = (getprotbyname("tcp"))[2];
 $tproto = (getprotbyname($proto))[2];
 if ($tproto == $wproto) {
  $proto_head = { };
  $ip_head = {
   -proto     => $tproto,
   -version   => "4",
   -IHL       => 5 + $addlength,
   -tos       => "00000000",
   -flags     => "000",
   -ident     => rand(30000) + 10000,
   -ttl       => 64,
   -source    => $sourceip,
   -dest      => $destip,
   -phead     => $proto_head
  };
  $proto_head->{-sport}    = $sourceport;
  $proto_head->{-dport}    = $destport;
  $proto_head->{-URG}      = 0;
  $proto_head->{-ACK}      = 0;
  $proto_head->{-PSH}      = 0;
  $proto_head->{-RST}      = 1;
  $proto_head->{-SYN}      = 0;
  $proto_head->{-FIN}      = 0;
  $proto_head->{-headlen}  = 5;
  $proto_head->{-sequence} = rand(2 ** 32);
  $proto_head->{-acknum}   = 0;
  $proto_head->{-window}   = 4096;
  $proto_head->{-urgent}   = 0;
  $proto_head->{-data}     = '';
 }
 &buildPacket($ip_head);
}

sub buildPacket {
 my $pr = shift;
 my $proto_packet;
 my $octets = 20 + length($pr->{-phead}{-data});
 my $pseudo_header = pack(
  'A4 A4 C C n',
  $pr->{-source},
  $pr->{-dest},
  0,
  6,
  $octets
 );
 my $flg_bits = pack(
  'H B8',
  $pr->{-phead}{-headlen},
  "00" .
  $pr->{-phead}{-URG} .
  $pr->{-phead}{-ACK} .
  $pr->{-phead}{-PSH} .
  $pr->{-phead}{-RST} .
  $pr->{-phead}{-SYN} .
  $pr->{-phead}{-FIN}
 );
 $proto_packet = pack(
  'n n l l A2 n n n',
  $pr->{-phead}{-sport},
  $pr->{-phead}{-dport},
  $pr->{-phead}{-sequence},
  $pr->{-phead}{-acknum},
  $flg_bits,
  $pr->{-phead}{-window},
  0,
  $pr->{-phead}{-urgent},
  $octets,
  0
 ) . $pr->{-phead}{-data};
 my $tmp_packet = $pseudo_header . $proto_packet;
 length($tmp_packet) % 2 and $tmp_packet .= chr(0);
 my $tcp_check = &calcChecksum($tmp_packet);
 substr($proto_packet,16,2) = $tcp_check;
 my $length = $pr->{-IHL} * 4 + length($proto_packet);
 my $identification = $pr->{-ident}++;
 my $allflags = $pr->{-flags} . "0" x 13;
 my $checksum = 0;
 my $ipheader = pack(
  'C B8 n n B16 C C n A4 A4',
  ($pr->{-version} << 4) | $pr->{-IHL},
  $pr->{-tos},
  $length,
  $identification,
  $allflags,
  $pr->{-ttl},
  $pr->{-proto},
  $checksum,
  $pr->{-source},
  $pr->{-dest},
 );
 my $newcheck = &calcChecksum($ipheader);
 substr($ipheader,10,2) = $newcheck;
 my $final_header = $ipheader . $proto_packet;
 $pr->{-constructed} = $final_header;
}

sub calcChecksum {
 my $msg = shift;
 my ($tot, $word, $tmp);
 while ($word = substr($msg,0,2)) {
  substr($msg,0,2) = '';
  $tot += unpack('n',$word);
 }
 my $back = pack('n',$tot % 65535);
 return(~$back);
}

sub sendPacket {
 my($pr, $type) = @_;
 my $flags = 0;
 socket(SOCK, AF_INET, SOCK_RAW, PROTO_RAW) or die "Error: $!";
 if ($pr->{-proto} == 1) {
  my $sendadd = pack(
   'S n A4 x8',
   AF_INET,
   0,
   $pr->{-dest}
  );
  send (SOCK, $pr->{-constructed}, 0, $sendadd) or die "Send Error: $!";
 } 
 else {
  setsockopt(SOCK, SOL_SOCKET, IP_HDRINCL, 1) or die "Cant set $!\n";
  my $sendadd = pack(
   'S n A4 x8',
   AF_INET,
   $pr->{-phead}{-dport},
   $pr->{-dest}
  );
  send (SOCK, $pr->{-constructed}, $flags, $sendadd) or die "Send Error: $!";
 }
}

sub binDebug {
 my $data = shift;
 my $counter = 1;
 print "Binary Octet Dump:\n";
 for (my $i = 0;$i < length($data);$i += 4) {
  print "$counter: " .
  join(' ',unpack('B8 B8 B8 B8',substr($data,$i,4))) . "\n";
  $counter++;
 }
}

sub hexDebug {
 my $data = shift;
 my $counter = 1;
 print "Hex Dump:\n";
 for (my $i = 0;$i < length($data);$i += 4) {
  print "$counter: " .
  join(' ',unpack('H2 H2 H2 H2',substr($data,$i,4))) . "\n";
  $counter++;
 }
}

1;
