Reputation: 81
I'm trying to use raw sockets in Python to send UDP packets to a host and then get the ICMP response back for the packet -- basically reimplementing traceroute.
I've managed to correctly construct my IP and UDP headers and send the packet. I can see it in Wireshark. I also see the ICMP response in Wireshark telling me that the TTL exceeded.
I have the following code:
me = gethostbyname(gethostname())
my_socket = socket(AF_INET, SOCK_RAW)
my_socket.setsockopt(IPPROTO_IP, IP_HDRINCL, 1)
my_socket.bind((me, 0))
hostname = 'www.google.com'
hostip = gethostbyname(hostname)
packet = create_packet(hostname)
send_socket.sendto(packet, (hostip , 0))
Then after the packet is sent I call another function to listen for incoming packets which includes this snippet:
while True:
ready = select.select([my_socket], [], [], time_left)
if ready[0] == []:
print "timeout"
time_now = time.time()
rec_packet, addr = my_socket.recvfrom(5120)
unpacked_ip = unpack('!BBHHHBBH4s4s', rec_packet[0:20]) #0-20 is IP header
prot = unpacked_ip[6] #gives the protocol id
if prot == 1:
#this is ICMP , let's do things
I'm able to successfully unpack the IP header and check the protocol, but it is always either 6 or 17 (TCP or UDP). I never get the IP packet containing the ICMP payload even though it appears in Wireshark.
I've tried comparing the ICMP packet in Wireshark to other packets in Wireshark that my program does see and the IP headers are pretty much identical. I don't know what is wrong.
Thanks for the help
Upvotes: 4
Views: 6320
Reputation: 5993
Judging from this answer, it looks like you need to pass the IPPROTO_ICMP
option in when you create your socket.
You can do this like:
my_socket = socket.socket(socket.AF_INET,socket.SOCK_RAW,socket.IPPROTO_ICMP)
Upvotes: 1