Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much

Simple Construction of a RAW TCP/IP Packet.

by cleen (Pilgrim)
on Jun 11, 2000 at 08:00 UTC ( #17576=CUFP: print w/replies, xml ) Need Help??

I wrote this a long while back just to learn the basic structs of programming with tcp/ip. Yes its very simple but this base struct has provided me with the core of alot of really cool things. (Thanks to tcp/ip Illustrated vol. 2 of course :). All this code does is construct the headers, and send a packet from a specifed source host and source port, to a specified destination host and port. Doesnt even rand the inicial sequence number...heheh. But hopefully this will be of use to someone other to myself! Just an FYI, if this looks all wierd, uhh, Im having a biotch of a time pasting this code...
#!/usr/local/bin/perl # Dont make fun of my path use Socket; $src_host = $ARGV[0]; # The source IP/Hostname $src_port = $ARGV[1]; # The Source Port $dst_host = $ARGV[2]; # The Destination IP/Hostname $dst_port = $ARGV[3]; # The Destination Port. if(!defined $src_host or !defined $src_port or !defined $dst_host or +!defined $dst_port) { print "Usage: $0 <source host> <source port> <dest host> <dest port +>\n"; exit; } else { main(); } sub main { my $src_host = (gethostbyname($src_host))[4]; my $dst_host = (gethostbyname($dst_host))[4]; socket(RAW, AF_INET, SOCK_RAW, 255) || die $!; setsockopt(RAW, 0, 1, 1); my ($packet) = makeheaders($src_host, $src_port, $dst_host, $dst_port +); my ($destination) = pack('Sna4x8', AF_INET, $dst_port, $dst_host); send(RAW,$packet,0,$destination); } sub makeheaders { local($src_host,$src_port,$dst_host,$dst_port) = @_; my $zero_cksum = 0; # Lets construct the TCP half my $tcp_proto = 6; my ($tcp_len) = 20; my $syn = 13456; my $ack = 0; my $tcp_headerlen = "5"; my $tcp_reserved = 0; my $tcp_head_reserved = $tcp_headerlen . $tcp_reserved; my $tcp_urg = 0; # Flag bits my $tcp_ack = 0; # eh no my $tcp_psh = 0; # eh no my $tcp_rst = 0; # eh no my $tcp_syn = 1; # yeah lets make a connexion! :) my $tcp_fin = 0; my $null = 0; my $tcp_win = 124; my $tcp_urg_ptr = 0; my $tcp_all = $null . $null . $tcp_urg . $tcp_ack . $tcp_psh . $tcp_rst . $tcp_syn . $tcp_fin ; # In order to calculate the TCP checksum we have # to create a fake tcp header, hence why we did # all this stuff :) Stevens called it psuedo headers :) my ($tcp_pseudo) = pack('a4a4CCnnnNNH2B8nvn', $tcp_len,$src_port,$dst_port,$syn,$ack, $tcp_head_reserved,$tcp_all,$tcp_win,$null,$tcp_urg_ptr); my ($tcp_checksum) = &checksum($tcp_pseudo); # Now lets construct the IP packet my $ip_ver = 4; my $ip_len = 5; my $ip_ver_len = $ip_ver . $ip_len; my $ip_tos = 00; my ($ip_tot_len) = $tcp_len + 20; my $ip_frag_id = 19245; my $ip_frag_flag = "010"; my $ip_frag_oset = "0000000000000"; my $ip_fl_fr = $ip_frag_flag . $ip_frag_oset; my $ip_ttl = 30; # Lets pack this baby and ship it on out! my ($pkt) = pack('H2H2nnB16C2na4a4nnNNH2B8nvn', $ip_ver_len,$ip_tos,$ip_tot_len,$ip_frag_id, $ip_fl_fr,$ip_ttl,$tcp_proto,$zero_cksum,$src_host, $dst_host,$src_port,$dst_port,$syn,$ack,$tcp_head_reserved, $tcp_all,$tcp_win,$tcp_checksum,$tcp_urg_ptr); return $pkt; } sub checksum { # This of course is a blatent rip from _the_ GOD, # W. Richard Stevens. my ($msg) = @_; my ($len_msg,$num_short,$short,$chk); $len_msg = length($msg); $num_short = $len_msg / 2; $chk = 0; foreach $short (unpack("S$num_short", $msg)) { $chk += $short; } $chk += unpack("C", substr($msg, $len_msg - 1, 1)) if $len_msg % 2; $chk = ($chk >> 16) + ($chk & 0xffff); return(~(($chk >> 16) + $chk) & 0xffff); }

Replies are listed 'Best First'.
RE: Simple Construction of a RAW TCP/IP Packet.
by JanneVee (Friar) on Jun 12, 2000 at 17:56 UTC
    This is an interesting insight to a TCP/IP packet... And actually I consider this example simpler than the C examples.
      The fact is, perl is the bomb, I havnt really been given a good example why C is so much better then perl, Ive heard people say it, but never been given a REASONABLE example, they claim efficiency, less process time, bah, in either case, if the programmer doesnt know what they are doing they are going to be in-efficient. Reality: Perl can be faster, and more efficient then C if it is written properly.

      on a side note, I am in the process of writing more raw socket examples for perl monks, IE constructing ICMP packets (what I am currently working on), to even constructing multicast packets...Its really fun to do, really it is :)

        I'm just waiting to see and excited to see the end result of that. Crazy idea: a traceroute perlscript!
        you really do a great job. i'm looking forward to some work for same thing. can i communicate with you by email? Thanks my name: haijun nation: China

      I am sending a packets from client machine to server machine. I have 4 dynamic fields i.e. source IP address ,Source Port , Destination IP address and Destination Port All four fields are calling from file. It means every times generating new IP packets which have different IP addresses and Ports. Question is that, For example If I want to send the 100,000 packets per second for the duration of 10 seconds.So my total send packets is 1 Million. But they are sending not more than 26 thousands. I am using one variable DIM...for suppose I change this field like that $dim=1; instead of $dim= scalar(@lines); then it is perfectly work and send 1 Million Packets(but everytime same packets which is not my requirement). Itz means my program can generate 1 Million packets. I want to generate the different packets .Please help me where I am lacking???

      #! /usr/bin/perl -s use Net::RawSock; use NetPacket::IP; use NetPacket::TCP; use Time::HiRes qw(usleep gettimeofday tv_interval); use feature qw/say/; use Benchmark; if(!defined $n or !defined $secs ) { print "Usage: ./ -n=<number of packets/sec> -secs=< +number of seconds> \n"; exit; } print "\nCreating Packets ...."; open (FILE, '/home/tahir/Downloads/packet_generator.txt'); chomp (@lines = (<FILE>)); close(FILE); ## Create IP my $ip_obj = NetPacket::IP->decode(''); ## Init IP $ip_obj->{ver} = 4; $ip_obj->{hlen} = 5; $ip_obj->{tos} = 0; $ip_obj->{id} = 0x1d1d; $ip_obj->{ttl} = 0x5a; $ip_obj->{flags} = 2; $ip_obj->{len} = 84; ## Create TCP my $tcp_obj = NetPacket::TCP->decode(''); ## Init TCP $tcp_obj->{hlen} = 5; $tcp_obj->{winsize} = 0x8e30; $tcp_obj->{seqnum} = 0xFFFF; $tcp_obj->{acknum} = 0xCCCC; $tcp_obj->{flags} = SYN; $tcp_obj->{data} =ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmn; ## Assemble $ip_obj->{proto} = 6; $ip_obj->{data} = $tcp_obj->encode($ip_obj); $num =0; for ($num = 0; $num<=@lines; $num++) { $line=$lines[$num]; #for every line in the lines #build packet my($sip, $sport, $dip, $dport) = split(/\s+/, $line); + $ip_obj->{src_ip} = $sip; $tcp_obj->{src_port} = $sport; $ip_obj->{dest_ip} = $dip; $tcp_obj->{dest_port} = $dport; #print ": $sip\t"; #print ": $sport\t"; #print " : $dip\t"; #print ": $dport\n"; ## Create RAW @packets[$num] = $ip_obj->encode; #say $lines[$j]; #add packet to a vector of packets #end for #Now we have an array of packets } #you want n pkt/sec for 10 seconds, so #you want n/1000 pkt per 1/1000 sec $num=0; $count = 0; $pkts_per_ms = $n / 1000; $start = time(); #[Time::HiRes::gettimeofday]; $dim= scalar(@lines); # $TEST=$packets[0]; while ( ((time()-$start)<($secs)) || ($count < ($n*$secs))) { $before = [Time::HiRes::gettimeofday]; for ($i=$pkts_per_ms;$i>0;$i--) { $num=($num+1)% $dim ; #if now packets is the array of packets,you will send Net::RawSock::write_ip($packets[$num]); # Net::RawSock::write_ip($TEST); } while (tv_interval($before)<0.001) { #print tv_interval($before), " "; } $count = $count + $pkts_per_ms; } print "TIME: ", time()-$start, "\n"; #print "You took ", tv_interval($start), " seconds for sending $co +unt packets.\n"; print "You took ", time() - $start, " seconds for sending $count p +ackets.\n";
RE: Simple Construction of a RAW TCP/IP Packet.
by brick (Sexton) on Jun 14, 2000 at 05:04 UTC
    I wonder if this could be combined with some of the portscanner bits that have been posted then you could make an adjustable packet size autoscanning sort of thing to create signatures for a log munger-- something that looked for that kind of traffic and then noted it? Hrmmmm. Kind of building a tool to build a tool, but... -brick.
      Definatly, and I have done a simple port scanner with this, with options found much like in the Nmap scanner, IE fin scans (set your fin bit to 1 in the code, and the syn bit to 0) and look for ACK/RST for closed ports. Having the ability to construct the headers the way you want has infinate uses, at least in my mind.
      Hey, have you finished that raw icmp paper? I'm coding, and I can't any thing that gives me the info on the type, code, chksum, identifier and seq # and how to pack them, icmp style. I def. want to check that out. You did a great job on the last one. Anyways, let me know. thanks!
Re: Simple Construction of a RAW TCP/IP Packet.
by Anonymous Monk on Jun 13, 2010 at 10:47 UTC
    Thanks for this piece of code - it wonderful. However, I noticed that it appears that the tcp checksum calculation is not correct. I made tcp captures and tcpdump report the checksum is incorrect for TCP. I could not get any server to answer SYN-ACK to this SYN packet (tried with standard sshd and httpd), which confirms that the checksum is wrong. I am doing the research right now and trying to rewrite the checksum part.
    Cheers, Alex
      Alex- Did you manage to get anywhere with the re-write?
Re: Simple Construction of a RAW TCP/IP Packet.
by Anonymous Monk on Dec 28, 2012 at 05:59 UTC

    Just to share, the code above working properly after updating TCP checksum generation parameter to:

    my ($tcp_pseudo) = pack('a4a4CCnnnNNH2B8nvn', $src_host,$dst_host,0,$tcp_proto,$tcp_len, $src_port,$dst_port,$syn,$ack, $tcp_head_reserved,$tcp_all,$tcp_win,$null,$tcp_urg_ptr);
      Hello, I am trying to use this code to send TCP/IP packet but looks like it is not compiling correctly...the protocol field in IP header is 255 (same as one mentioned in socket(RAW,.....). Has anyone run into this issue?
Re: Simple Construction of a RAW TCP/IP Packet.
by Anonymous Monk on Mar 14, 2015 at 19:35 UTC

    Please note that the checksum subroutine given in the OP is insidiously buggy for odd length arguments (which is never the case here). Since $num_short calculation is missing int(), the unpack template ends in ".5", which in turn inserts an erroneous element to the loop.

    Anyone reading this thread is probably better served by searching for newer and more mature examples.

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: CUFP [id://17576]
Approved by root
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (13)
As of 2017-07-24 09:48 GMT
Find Nodes?
    Voting Booth?
    I came, I saw, I ...

    Results (350 votes). Check out past polls.