BatchMcNulty has asked for the wisdom of the Perl Monks concerning the following question:

Hi Perlmonks!

This problem is driving me up the wall.

I'm trying to do some packet crafting to send TCP SYN packets so I can add half-open scanning to my UBERSCAN utility, and I've come up against the weirdest problem.

I can't seem to send crafted TCP packets (or any other kind of raw packets) of more than 12 bytes!

It's definitely not the SYN packet itsself - If you delete the trailing "t" from $synpacket this test program sends TESTTESTTEST (exactly 12 bytes) and my packet sniffer picks it up no problem, and it's definitely not a real TCP packet! I've also tried this on other IP protocols, such as UDP under raw sockets with the same results.

I add one single, solitary byte my packet sniffer sees nothing, and Perl responds with an error like "Operation not supported", yet netstat picks up on activity generated by it, and even sometimes claims there are bytes on the wire.

I'm definitely running it as root, the only thing that fixes it is sending a packet of less than 13 bytes. It's nuts!

12 bytes: No problem, happy times, will send ANYTHING, even a dummy packet.
13 bytes, FAIL, sadface, won't even send a perfectly crafted SYN packet.

ALso, I can't seem to switch off IP_HDRINCL. The kernel is adamant that it's going to build the IP header itsself, which is fine by me except for this little problem.

What's going on, guys? I've tried it on 2 computers, both running Ubuntu Linux, and they both responded the same way. Again, I've also tried it with different IP protocols, IE UDP, etc. Is it my OS, is it Perl, or have I made a really silly mistake?

Here's the code - you have to run it as root, with the destination address as a rider, like so:
sudo perl raw_sock_problem.pl 192.168.1.1

Please help!

Batch McNulty

#!/usr/bin/perl use Socket; my $dest_addr = @ARGV[0]; my $dest_port = 21332; my $source_ip_addr = "0.0.0.0"; # (ie, myself) #my $source_ip_addr = "192.168.1.7"; # Doesn't matter whether I use 0. +0.0.0 or my actual IP my $source_port = 21573; my $synpacket = "TESTTESTTESTt"; # Obviously this isn't a real SYN +packet # Delete the trailing lowe +r case "t" and it works fine... @source_addr_octets = split('\.', $source_ip_addr); @dest_addr_octets = split('\.', $dest_addr); my $mc_source_port = inet_aton($source_port); my $count = 0; $count = 0; undef $mc_dest_addr; until ($count == scalar(@dest_addr_octets)) { print "\n$count:$dest_addr_octets[$count]"; $mc_dest_addr .= inet_aton($dest_addr_octets[$count]); $count++; } $count = 0; $mc_destination = $dest_port; $mc_destination .= $mc_dest_addr; print "\n socketing..."; print "\n"; $sockfd = socket (SOCKET, AF_INET, SOCK_RAW, 6) or die "\n\n *** CAN'T + SOCKET! We root? Error:$! Sys:$@ *** \n \$source_port:$source_port \ +$dest_port:$dest_port\n"; #$sockfd = socket (SOCKET, AF_INET, SOCK_RAW, 17) or die "\n\n *** CAN +'T SOCKET! We root? Error:$! Sys:$@ *** \n \$source_port:$source_port + \$dest_port:$dest_port\n"; $|=1; my $broadcastAddr; my $custom_remote_host = inet_aton($dest_addr); print STDOUT "\n remote_host:$dest_addr. \t remote_port:$dest_port"; my $response = $broadcastAddr = sockaddr_in($dest_port, $custom_remote +_host); setsockopt(SOCKET, SOL_SOCKET, SO_SNDBUF, 16384) or die "\n\n *** Can +'t setsockopt on SO_SNDBUF! We root? Error:$! Sys:$@ *** \n\n"; $num_of_bytes = length($synpacket); $mc_destination = pack('Sna4x8', AF_INET, $dest_port, $dest_addr); my $server_port; my $machine_code_addr = sockaddr_in($server_port, INADDR_ANY); bind (SOCKET, $machine_code_addr) or die "\n\n Couldn't bind $machi +ne_code_addr. Error:$! \n\n"; # Program WILL NOT SEND anything longer than 12 bytes. # Try and you get an "Operation not supported" error! $num_of_bytes = length ($synpacket); print STDOUT "\n Packet to be sent:$synpacket"; print STDOUT "\n num_of_bytes:$num_of_bytes"; print STDOUT "\n"; print STDOUT "\n PRESS ENTER TO START!"; print STDOUT "\n"; my $nothing = <STDIN>; print STDOUT "\n"; for ($count == 0; $count < 35535; $count++) { $result = send( SOCKET, $synpacket, $num_of_bytes, $broadcastAddr +); #$result = syswrite(SOCKET, $synpacket, $num_of_bytes); # Gives + "Destination address required" error print STDOUT "\n count:$count ** Result:$result Error:$! Sys:$@ ** + "; } print STDOUT "\n"; print STDOUT " ***********************\n * FINAL COUNT: $count * \n ** +********************\n"; print STDOUT "\n Result (bytes sent):$result Error:$! System:$@"; print STDOUT "\n"; close (SOCKET); print "\n "; print "\n Socket closed."; print "\n"; die;

Replies are listed 'Best First'.
Re: Can't send more than 12 bytes on raw socket! (not including IP header)
by hippo (Archbishop) on Aug 10, 2018 at 16:58 UTC
    $result = send( SOCKET, $synpacket, $num_of_bytes, $broadcastAddr );

    perldoc -f send says

    send SOCKET,MSG,FLAGS,TO send SOCKET,MSG,FLAGS

    so your invocation appears to be incorrect. Replacing $num_of_bytes with 0 gives me a successful outcome, although I did clean up your code a little before running so let us know if you still have problems.

      Thank you so much! I don't know WHERE I got the idea that I had to put the number of bytes I was sending - all my manuals agree with you... I think it must be that recv works like that. Doh!

      I did have an inkling it was noob error of some kind, though. It was just so oddly persistent... now to see what happens when I send the real syn packet...

      Thank you from the bottom of my heart! :-)

Re: Can't send more than 12 bytes on raw socket! (not including IP header)
by ikegami (Patriarch) on Aug 10, 2018 at 23:30 UTC

    Perl functions are more or less thin wrappers for OS system calls. If you get an error you don't understand, consult the appropriate man page.

    EOPNOTSUPP
    Some bit in the flags argument is inappropriate for the socket type.

    This should have lead to check the value you were passing to the flags argument, which is clearly incorrect.