Roshin Raphel
Roshin Raphel

Reputation: 2709

ICMP packet sniffing not receiving any data (Black Hat Python Book)

I came across this code snippet from the book, Black hat Python, Chapter 3. The Network: Raw Sockets and Sniffing :

import socket
import os

host = "x.x.x.x"        # Host to listen on

# Create a raw socket and bind it to the public interface
if os.name == "nt":
    socket_protocol = socket.IPPROTO_IP
else:
    socket_protocol = socket.IPPROTO_ICMP
    
sniffer = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)     # We want the IP headers included in the capture
# if we're using Windows, we need to send an IOCTL
# to set up promiscuous mode
if os.name == "nt":
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
print(sniffer.recvfrom(65565))      # Read in a single packet

# If we're using Windows, turn off promiscuous mode
if os.name == "nt":
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

And when I do ping google.com the above code is supposed to capture the first ping packet, but instead waits for the packet indefinitely in the line print(sniffer.recvfrom(65565)).

I tried with host as my machine's local ip and with localhost, and tried changing the buffer size as seen in a similar question. But it did not good.

I works when I set host = "" and do ping 127.0.0.1, but not when I ping other urls.

Can somebody please tell me what is wrong?

I am using Python 3.8.2 and Ubuntu 18.04.

Upvotes: 1

Views: 512

Answers (1)

Roshin Raphel
Roshin Raphel

Reputation: 2709

The issue is not actually with the code, it is a compatibility issue, pinging the more modern servers are done by IPv6, while the code picks only IPv4 ICMP packets. An easy solution will be to restrict the ping to IPv4 by :

ping -4 google.com

The sniffer for IPv6 only requires small changes form the IPv4 version, it is as follows :

import socket
import os

host = ""       # Host to listen on

# Create a raw socket and bind it to the public interface
if os.name == "nt":
    socket_protocol = socket.IPPROTO_IPV6
else:
    socket_protocol = socket.IPPROTO_ICMPV6
    
sniffer = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket_protocol)
sniffer.bind((host, 0))
sniffer.setsockopt(socket.IPPROTO_IPV6, socket.IP_HDRINCL, 1)       # We want the IP headers included in the capture
# if we're using Windows, we need to send an IOCTL
# to set up promiscuous mode
if os.name == "nt":
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
print(sniffer.recvfrom(65565))      # Read in a single packet

# If we're using Windows, turn off promiscuous mode
if os.name == "nt":
    sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)

Upvotes: 1

Related Questions