Unable to send ICMP packets from a raw socket in Python
Asked Answered
M

0

7

I have a raw Python socket initialized like so:

mySocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
mySocket.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

My problem is that I can't send any packet from the socket where the protocol field in my IP header is specified as '1' (ICMP). If this field is anything else it'll work just fine, including '17' (UDP) for example. I don't get any errors, the packet just doesn't display in Wireshark, and I can't receive it on my server.

I'm generating the IP header like so:

def getIPHeader(src, dst, proto):
    version = 4
    IHL = 5
    DSCP = 0
    ECN = 0
    totalLength = 40
    identification = 333
    flags = 0
    fragmentOffset = 0
    timeToLive = 128
    protocol = proto
    headerChecksum = 0
    sourceIP = socket.inet_aton(src)
    destIP = socket.inet_aton(dst)
    options = 0

    version_IHL = (version << 4) | IHL
    DSCP_ECN = (DSCP << 2) | ECN
    flags_fragmentOffset = (flags << 13) | fragmentOffset

    # The '!' ensures all arguments are converted to network byte order
    header = struct.pack("!BBHHHBBH4s4s", version_IHL, DSCP_ECN, totalLength, identification, flags_fragmentOffset, timeToLive, protocol, headerChecksum, sourceIP, destIP)
    return header

And sending like so:

icmpHeader = struct.pack("!bbHHh", 8, 0, 0, 666, 0)
packet = getIPHeader("192.168.2.15", "8.8.8.8", 1) + icmpHeader
mySocket.sendto(packet, ("8.8.8.8", 0))

Sending with UDP protocol set works (obviously malformed):

icmpHeader = struct.pack("!bbHHh", 8, 0, 0, 666, 0)
packet = getIPHeader("192.168.2.15", "8.8.8.8", 17) + icmpHeader
mySocket.sendto(packet, ("8.8.8.8", 0))

The worst part is if I send a ping from the command line, then copy the exact hex from Wireshark of the IP and ICMP data into my code, it STILL doesn't work, like so:

packet = b'\x45\x00\x00\x3c\x24\xad\x00\x00\x80\x01\x43\x4d\xc0\xa8\x02\x0f\x08\x08\x08\x08\x08\x00\x4d\x44\x00\x01\x00\x17\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x61\x62\x63\x64\x65\x66\x67\x68\x69'
mySocket.sendto(packet, ("8.8.8.8", 0))

However, as before, if I change the 10th byte of the hard coded data to '\x11' (17 decimal, UDP), I can then see it in Wireshark (obviously with a malformed UDP section as the rest of the packet is ICMP).

I'm running Windows 10, Python 3.4.1, and my firewall is off. Any ideas?

UPDATE: I've tried this on two different computers, a Windows 8 and a Windows 10 machine, both worked, so it's something to do with my computer, the plot thickens...

Manslayer answered 16/8, 2015 at 14:6 Comment(10)
Have you tried a different port than zero? The port is not relevant for icmp. But 0 is reserved and maybe the cause of the issue.Bullard
I've just tried a variety of non zero ports, still not working. Thanks for the suggestion.Manslayer
Otherwise have a look at the python-ping package which is a pure ping implementation with python raw sockets.Bullard
Unfortunately he's not including his own IP headers. When I let the kernel create the IP header, i.e. setting IP_HDRINCL to 0, mine works too. Which could suggest a problem with my IP header, yet I've compared it to known good packets and it's the same, even when I try to send packets directly copied from Wireshark it doesn't work (as shown above), very strange.Manslayer
Can you try to open your socket with socket.IPPROTO_ICMP instead of RAW.Bullard
That still doesn't work while I'm using my own IP headerManslayer
Have you considered using the python package scapy found here: secdev.org/projects/scapy I've had much better luck using this for low level protocol and packet manipulation.Sisley
I've used Scapy for other projects on Windows and it worked great, however I intentionally didn't want to use it for this project. I actually ported the whole thing to linux instead (not that much modification was required) shortly after I asked this question and the whole problem was solved, it worked beautifullyManslayer
do you see at least an ARP request being sent from your machine in wireshark?Pretermit
Stupid question: are you running this as administrator mode?Sitar

© 2022 - 2024 — McMap. All rights reserved.