Simple Construction of a RAW TCP/IP Packet

001#!/usr/local/bin/perl
002 
003use Socket;
004 
005$src_host = $ARGV[0]; # The source IP/Hostname
006$src_port = $ARGV[1]; # The Source Port
007$dst_host = $ARGV[2]; # The Destination IP/Hostname
008$dst_port = $ARGV[3]; # The Destination Port.
009 
010 if(!defined $src_host or !defined $src_port or !defined $dst_host or !defined $dst_port) {
011   print "Usage: $0 <source host> <source port> <dest host> <dest port>\n";
012   exit;
013 }
014 else {
015  main();
016 }
017  
018sub main {
019 my $src_host = (gethostbyname($src_host))[4];
020 my $dst_host = (gethostbyname($dst_host))[4];
021 
022 socket(RAW, AF_INET, SOCK_RAW, 255) || die $!;
023 setsockopt(RAW, 0, 1, 1);
024  
025 my ($packet) = makeheaders($src_host, $src_port, $dst_host, $dst_port);
026 my ($destination) = pack('Sna4x8', AF_INET, $dst_port, $dst_host);
027 send(RAW,$packet,0,$destination);
028}
029 
030sub makeheaders {
031 local($src_host,$src_port,$dst_host,$dst_port) = @_;
032 my $zero_cksum = 0;
033 # Lets construct the TCP half
034 my $tcp_proto          = 6;
035 my ($tcp_len)          = 20;
036 my $syn                = 13456;
037 my $ack                = 0;
038 my $tcp_headerlen      = "5";
039 my $tcp_reserved       = 0;
040 my $tcp_head_reserved  = $tcp_headerlen .
041                          $tcp_reserved;
042 my $tcp_urg            = 0; # Flag bits
043 my $tcp_ack            = 0; # eh no
044 my $tcp_psh            = 0; # eh no
045 my $tcp_rst            = 0; # eh no
046 my $tcp_syn            = 1; # yeah lets make a connexion! :)
047 my $tcp_fin            = 0;
048 my $null               = 0;
049 my $tcp_win            = 124;
050 my $tcp_urg_ptr        = 0;
051 my $tcp_all            = $null . $null .
052                          $tcp_urg . $tcp_ack .
053                          $tcp_psh . $tcp_rst .
054                          $tcp_syn . $tcp_fin ;
055 
056 # In order to calculate the TCP checksum we have
057 # to create a fake tcp header, hence why we did
058 # all this stuff :) Stevens called it psuedo headers :)
059 
060 my ($tcp_pseudo) = pack('a4a4CCnnnNNH2B8nvn',
061  $tcp_len,$src_port,$dst_port,$syn,$ack,
062  $tcp_head_reserved,$tcp_all,$tcp_win,$null,$tcp_urg_ptr);
063 
064 my ($tcp_checksum) = &checksum($tcp_pseudo);
065 
066 # Now lets construct the IP packet
067 my $ip_ver             = 4;
068 my $ip_len             = 5;
069 my $ip_ver_len         = $ip_ver . $ip_len;
070 my $ip_tos             = 00;
071 my ($ip_tot_len)       = $tcp_len + 20;
072 my $ip_frag_id         = 19245;
073 my $ip_frag_flag       = "010";
074 my $ip_frag_oset       = "0000000000000";
075 my $ip_fl_fr           = $ip_frag_flag . $ip_frag_oset;
076 my $ip_ttl             = 30;
077 
078 # Lets pack this baby and ship it on out!
079 my ($pkt) = pack('H2H2nnB16C2na4a4nnNNH2B8nvn',
080  $ip_ver_len,$ip_tos,$ip_tot_len,$ip_frag_id,
081  $ip_fl_fr,$ip_ttl,$tcp_proto,$zero_cksum,$src_host,
082  $dst_host,$src_port,$dst_port,$syn,$ack,$tcp_head_reserved,
083  $tcp_all,$tcp_win,$tcp_checksum,$tcp_urg_ptr);
084 
085 return $pkt;
086}
087 
088sub checksum {
089 # This of course is a blatent rip from _the_ GOD,
090 # W. Richard Stevens.
091   
092 my ($msg) = @_;
093 my ($len_msg,$num_short,$short,$chk);
094 $len_msg = length($msg);
095 $num_short = $len_msg / 2;
096 $chk = 0;
097 foreach $short (unpack("S$num_short", $msg)) {
098  $chk += $short;
099 }
100 $chk += unpack("C", substr($msg, $len_msg - 1, 1)) if $len_msg % 2;
101 $chk = ($chk >> 16) + ($chk & 0xffff);
102 return(~(($chk >> 16) + $chk) & 0xffff);
103}