1

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.

Roshin Raphel
  • 2,612
  • 4
  • 22
  • 40
  • 1
    when you ping other IP/url then it sends request directly to other IP/ulr and there is no reason to send to your local IP. – furas Aug 01 '20 at 12:44
  • 1
    as I know tools to capture packets need library [pcap](https://en.wikipedia.org/wiki/Pcap) (`packet capture`). I have to also run code as `root` (using `sudo`) on Linux Mint (based on Ubuntu 18.04). I used `0.0.0.0` to listening on all my network cards (`LAN`, `WiFi`) and I got some result. – furas Aug 01 '20 at 12:57
  • @furas Thank you for the comment, I got the solution because of the you told you got it working. And I analyzed why it was working in some cases, which led me to the answer. – Roshin Raphel Aug 01 '20 at 15:58

1 Answers1

1

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)
Roshin Raphel
  • 2,612
  • 4
  • 22
  • 40