Raw socket packet sniffer in Python 3.6 on Windows

11,562

Solution 1

The hint is that all your Destination Mac addresses start with 0x45. That's the first byte of the IP header. So your code is getting all the IP packets, but not the MAC header for those frames.

Solution 2

Ok thanks to selbi i understand the problem, thank you very much
But to catch Ethernet header with Python in windows you have to use:

1. PyPCap

2. Dpkt

  • To install dpkt just open cmd as admin and type:

    py -2 -m pip install dpkt

Here references of Python Docs

3. Python 2.7

But you need to install Python 3.4> to get pip

And finally that's the code:

#!/usr/bin/env python

import getopt, sys
import dpkt, pcap
import socket
import struct
import binascii
import textwrap

def main():
    # Get host
    host = socket.gethostbyname(socket.gethostname())
    print('IP: {}'.format(host))

    name = None            
    pc = pcap.pcap(name)
    decode = { pcap.DLT_LOOP:dpkt.loopback.Loopback,
               pcap.DLT_NULL:dpkt.loopback.Loopback,
               pcap.DLT_EN10MB:dpkt.ethernet.Ethernet }[pc.datalink()]
    try:
        print 'listening on %s: %s' % (pc.name, pc.filter)
        for ts, pkt in pc:
            pkt = str(decode(pkt))
            dest_mac, src_mac, eth_proto, data = ethernet_frame(pkt)

            print '\nEthernet Frame:'
            print "Destination MAC: {}".format(dest_mac)
            print "Source: {}".format(src_mac)
            print "Protocol: {}".format(eth_proto)
    except KeyboardInterrupt:
        nrecv, ndrop, nifdrop = pc.stats()
        print '\n%d packets received by filter' % nrecv
        print '%d packets dropped by kernel' % ndrop

# Unpack ethernet frame
def ethernet_frame(data):
    dest_mac, src_mac, proto = struct.unpack('!6s6s2s', data[:14])
    return binascii.hexlify(dest_mac), binascii.hexlify(src_mac), binascii.hexlify(proto), data[14:]

if __name__ == '__main__':
    main()

Output:

Ethernet Frame:
Destination MAC: 5404a6f2740c <- My NIC MAC
Source: 6459f81dc690
Protocol: 0800 <- Right protocol

Ethernet Frame:
Destination MAC: 6459f81dc690
Source: 5404a6f2740c
Protocol: 0800

Ethernet Frame:
Destination MAC: 5404a6f2740c
Source: 6459f81dc690
Protocol: 0800

I hope you enjoy thanks again selbie

(Sorry i can't put more links cause of my reputation)

Share:
11,562
Alessandro Lodi
Author by

Alessandro Lodi

"Information: the negative reciprocal value of probability" - Claude Shannon

Updated on June 14, 2022

Comments

  • Alessandro Lodi
    Alessandro Lodi almost 2 years

    I am trying to sniff packets but i am getting strange output and i don't understand the reason..
    So that's my code please help me
    (I'm using Python 3.6 on Windows 8.1)

    Code:

    import socket
    import struct
    import binascii
    import textwrap
    
    def main():
        # Get host
        host = socket.gethostbyname(socket.gethostname())
        print('IP: {}'.format(host))
    
        # Create a raw socket and bind it
        conn = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
        conn.bind((host, 0))
    
        # Include IP headers
        conn.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
        # Enable promiscuous mode
        conn.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
    
        while True:
            # Recive data
            raw_data, addr = conn.recvfrom(65536)
    
            # Unpack data
            dest_mac, src_mac, eth_proto, data = ethernet_frame(raw_data)
    
            print('\nEthernet Frame:')
            print("Destination MAC: {}".format(dest_mac))
            print("Source MAC: {}".format(src_mac))
            print("Protocol: {}".format(eth_proto))
    
    # Unpack ethernet frame
    def ethernet_frame(data):
        dest_mac, src_mac, proto = struct.unpack('!6s6s2s', data[:14])
        return get_mac_addr(dest_mac), get_mac_addr(src_mac), get_protocol(proto), data[14:]
    
    # Return formatted MAC address AA:BB:CC:DD:EE:FF
    def get_mac_addr(bytes_addr):
        bytes_str = map('{:02x}'.format, bytes_addr)
        mac_address = ':'.join(bytes_str).upper()
        return mac_address
    
    # Return formatted protocol ABCD
    def get_protocol(bytes_proto):
        bytes_str = map('{:02x}'.format, bytes_proto)
        protocol = ''.join(bytes_str).upper()
        return protocol
    
    main()
    

    From this code i get this output:

    IP: 192.168.1.12

    Ethernet Frame:
    Destination MAC: 45:00:00:43:00:00
    Source MAC: 40:00:2C:11:48:D3
    Protocol: 4266

    Ethernet Frame:
    Destination MAC: 45:00:00:42:11:E7
    Source MAC: 00:00:80:11:00:00
    Protocol: C0A8

    Ethernet Frame:
    Destination MAC: 45:00:00:33:04:D6
    Source MAC: 00:00:80:11:00:00
    Protocol: C0A8

    .
    .
    .

    According to EtherType list this protocols don't exist and analysing my traffic with Wireshark i am sure that this MACs don't exist in my LAN

    So I'm definitely doing something wrong but I do not understand what
    Thanks in advance

  • Alessandro Lodi
    Alessandro Lodi over 7 years
    But how can i get MAC header? (i am new with Python)
  • Saurav Seth
    Saurav Seth over 7 years
    Instead of opening an AF_INET socket, open an AF_PACKET socket. opensourceforu.com/2015/03/a-guide-to-using-raw-sockets
  • krish
    krish over 3 years
    I have tried the above same packet sniffer code. it was not working on my windows 10.
  • Alessandro Lodi
    Alessandro Lodi over 3 years
    @krish the question is old.. I will try to fix it as soon as possible. Which errors do you get?
  • krish
    krish over 3 years
    The total Ethernet frame is mismatched. it has not given proper source mac and des mac