15
votes

to understand the network concepts a bit better and to improve my python skills I am trying to implement a packet sniffer with python. I have just started to learn python, so the code could be optimized of course ;)

I have implemented an packet sniffer which unpacks the ethernet frame and the arp header. I want to make it with raw sockets because I want to understand every byte within those headers, so please no scapy help :)

The problem is, that I won´t get any arp reply packet. It´s always opcode 1 and I

Here is my source code:

import socket
import struct
import binascii

rawSocket = socket.socket(socket.PF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))

while True:

    packet = rawSocket.recvfrom(2048)

    ethernet_header = packet[0][0:14]
    ethernet_detailed = struct.unpack("!6s6s2s", ethernet_header)

    arp_header = packet[0][14:42]
    arp_detailed = struct.unpack("2s2s1s1s2s6s4s6s4s", arp_header)

    print "****************_ETHERNET_FRAME_****************"
    print "Dest MAC:        ", binascii.hexlify(ethernet_detailed[0])
    print "Source MAC:      ", binascii.hexlify(ethernet_detailed[1])
    print "Type:            ", binascii.hexlify(ethernet_detailed[2])
    print "************************************************"
    print "******************_ARP_HEADER_******************"
    print "Hardware type:   ", binascii.hexlify(arp_detailed[0])
    print "Protocol type:   ", binascii.hexlify(arp_detailed[1])
    print "Hardware size:   ", binascii.hexlify(arp_detailed[2])
    print "Protocol size:   ", binascii.hexlify(arp_detailed[3])
    print "Opcode:          ", binascii.hexlify(arp_detailed[4])
    print "Source MAC:      ", binascii.hexlify(arp_detailed[5])
    print "Source IP:       ", socket.inet_ntoa(arp_detailed[6])
    print "Dest MAC:        ", binascii.hexlify(arp_detailed[7])
    print "Dest IP:         ", socket.inet_ntoa(arp_detailed[8])
    print "*************************************************\n"

could someone please explain me why I am getting no response packets just these?

OUTPUT:

****************_ETHERNET_FRAME_****************
Dest MAC:         ffffffffffff
Source MAC:       0012bfc87243
Type:             0806
************************************************
******************_ARP_HEADER_******************
Hardware type:    0001
Protocol type:    0800
Hardware size:    06
Protocol size:    04
Opcode:           0001
Source MAC:       0012bfc87243
Source IP:        192.168.2.1
Dest MAC:         000000000000
Dest IP:          192.168.2.226
*************************************************

Thanks so far! :)

1
I don't think it's the ARP opcode per se. Your recvfrom() seems to only able to capture inbound packets, not outbound ones. In this case, the opcode 2 (ARP reply) goes outbound, and it's not captured.Santa
If you run your script and have your machine send an ARP ping, instead, you'll only see the opcode 2 (ARP reply) and none of the original outbound ping.Santa

1 Answers

16
votes

I think you need to specify socket protocol number 0x0003 to sniff everything, and then filter out non-ARP packets after the fact. This worked for me:

import socket
import struct
import binascii

rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0003))

while True:

    packet = rawSocket.recvfrom(2048)

    ethernet_header = packet[0][0:14]
    ethernet_detailed = struct.unpack("!6s6s2s", ethernet_header)

    arp_header = packet[0][14:42]
    arp_detailed = struct.unpack("2s2s1s1s2s6s4s6s4s", arp_header)

    # skip non-ARP packets
    ethertype = ethernet_detailed[2]
    if ethertype != '\x08\x06':
        continue

    print "****************_ETHERNET_FRAME_****************"
    print "Dest MAC:        ", binascii.hexlify(ethernet_detailed[0])
    print "Source MAC:      ", binascii.hexlify(ethernet_detailed[1])
    print "Type:            ", binascii.hexlify(ethertype)
    print "************************************************"
    print "******************_ARP_HEADER_******************"
    print "Hardware type:   ", binascii.hexlify(arp_detailed[0])
    print "Protocol type:   ", binascii.hexlify(arp_detailed[1])
    print "Hardware size:   ", binascii.hexlify(arp_detailed[2])
    print "Protocol size:   ", binascii.hexlify(arp_detailed[3])
    print "Opcode:          ", binascii.hexlify(arp_detailed[4])
    print "Source MAC:      ", binascii.hexlify(arp_detailed[5])
    print "Source IP:       ", socket.inet_ntoa(arp_detailed[6])
    print "Dest MAC:        ", binascii.hexlify(arp_detailed[7])
    print "Dest IP:         ", socket.inet_ntoa(arp_detailed[8])
    print "*************************************************\n"

Sample output using arpping broadcast from the same host and its reply:

****************_ETHERNET_FRAME_****************
Dest MAC:         ffffffffffff
Source MAC:       000c29eb37bf
Type:             0806
************************************************
******************_ARP_HEADER_******************
Hardware type:    0001
Protocol type:    0800
Hardware size:    06
Protocol size:    04
Opcode:           0001
Source MAC:       000c29eb37bf
Source IP:        192.168.16.133
Dest MAC:         ffffffffffff
Dest IP:          192.168.16.2
*************************************************

****************_ETHERNET_FRAME_****************
Dest MAC:         000c29eb37bf
Source MAC:       005056f37861
Type:             0806
************************************************
******************_ARP_HEADER_******************
Hardware type:    0001
Protocol type:    0800
Hardware size:    06
Protocol size:    04
Opcode:           0002
Source MAC:       005056f37861
Source IP:        192.168.16.2
Dest MAC:         000c29eb37bf
Dest IP:          192.168.16.133
*************************************************