title: Python Sniffing from Black Hat Python book
body: <pre><code>import socket
  import os
  import struct
  import sys
  from ctypes import *
  
  # host to listen on
  host   = sys.argv[1]
  
  class IP(Structure):
  
      _fields_ = [
          ("ihl",           c_ubyte, 4),
          ("version",       c_ubyte, 4),
          ("tos",           c_ubyte),
          ("len",           c_ushort),
          ("id",            c_ushort),
          ("offset",        c_ushort),
          ("ttl",           c_ubyte),
          ("protocol_num",  c_ubyte),
          ("sum",           c_ushort),
          ("src",           c_ulong),
          ("dst",           c_ulong)
      ]
  
      def __new__(self, socket_buffer=None):
          return self.from_buffer_copy(socket_buffer)    
  
      def __init__(self, socket_buffer=None):
  
          # map protocol constants to their names
          self.protocol_map = {1:"ICMP", 6:"TCP", 17:"UDP"}
  
          # human readable IP addresses
          self.src_address = socket.inet_ntoa(struct.pack("&lt;L",self.src))
          self.dst_address = socket.inet_ntoa(struct.pack("&lt;L",self.dst))
  
          # human readable protocol
          try:
              self.protocol = self.protocol_map[self.protocol_num]
          except:
              self.protocol = str(self.protocol_num)
  
  # 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))
  
  # we want the IP headers included in the capture
  sniffer.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
  
  # if we're on Windows we need to send some ioctls
  # to setup promiscuous mode
  if os.name == "nt":
      sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
  
  try:
      while True:
  
          # read in a single packet
          raw_buffer = sniffer.recvfrom(65565)[0]
  
          # create an IP header from the first 20 bytes of the buffer
          ip_header = IP(raw_buffer[0:20])
  
          print "Protocol: %s %s -&gt; %s" % (ip_header.protocol, ip_header.src_address, ip_header.dst_address)
  
  except KeyboardInterrupt:
      # if we're on Windows turn off promiscuous mode
      if os.name == "nt":
          sniffer.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
  </code></pre>
  
  <p>This is code from the book Black Hat Python. This code is supposed to sniff with raw sockets and display information from the IP header. It works fine for me on Windows (using Windows 8.1 64bit). When I attempt to run this on linux (Kali linux 1.1.0-amd64) I get the following error</p>
  
  <pre><code>ValueError: Buffer size too small (20 instead of at least 32 bytes)
  </code></pre>
  
  <p>To get around that I added 12 spaces to the buffer like this</p>
  
  <pre><code>ip_header = IP(raw_buffer[0:20]+' '*12)
  </code></pre>
  
  <p>When I do that I get the following error</p>
  
  <pre><code>struct.error: 'L' format requires 0 &lt;= number &lt;= 4294967295
  </code></pre>
  
  <p>This occurs on the line</p>
  
  <pre><code>self.src_address = socket.inet_ntoa(struct.pack("&lt;L",self.src))
  </code></pre>
  
  <p>I have tried changing the symbol before the L to > and ! and I tried it with just L all of them give me the same issue. I also tried wrapping self.src in ntohs like so</p>
  
  <pre><code>self.src_address = socket.inet_ntoa(struct.pack("&lt;L",socket.ntohs(self.src)))
  </code></pre>
  
  <p>I'm thinking this has something to do with endianness but I'm not sure. Any help would be greatly appreciated.</p>
  
  <p>NOTE: On windows you have to run as an administrator and on linux you have to run as a superuser because of the raw sockets. If you run this on linux open up another terminal and ping www.google.com so you can generate some ICMP packets for it to capture.</p>
  
  <p>EDIT: I have also tried reversing the buffer with </p>
  
  <pre><code>ip_header = IP(raw_buffer[0:20][::-1]+' '*12)
  </code></pre>
  
  <p>EDIT 2: I did try both 65535 and 65534 on the below line before doing any of the other items I listed here. </p>
  
  <pre><code>raw_buffer = sniffer.recvfrom(65565)[0]
  </code></pre>
  
  <p>EDIT 3: This worked on an ubuntu machine running python 2.7.6 and my kali distro was 2.7.3 so I decided to get the latest version of python on my kali box which happens to be 2.7.9. Still no luck.</p>
  
  <p>I placed the following code to the <strong>new</strong> function in my structure to view the buffer size</p>
  
  <pre><code>print sizeof(self)
  </code></pre>
  
  <p>On my Ubuntu and windows machines it was 20 however on my kali machine it was 32</p>