简体   繁体   中英

How to properly unpack a RAW socket on Win10 using Python?

I have working code for Linux, but on Windows I got unexpected result. Code:

import socket
import sys
from struct import unpack
import platform


def main():
    local_ip = socket.gethostbyname(socket.gethostname())
    print local_ip
    try:
        if platform.system() == 'Linux':
            s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW,
                              socket.ntohs(0x0003))
        elif platform.system() == 'Windows':
            s = socket.socket(socket.AF_INET, socket.SOCK_RAW,
                              socket.IPPROTO_IP)
            s.bind((local_ip, 0))
            s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
            s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
        else:
            sys.exit()
    except socket.error as msg:
        print('Socket could not be created. Error Code : ' + str(
            msg[0]) + ' Message ' + msg[1])
        sys.exit()

    # receive a packet
    i = 0
    while i < 10:
        i += 1
        packet = s.recvfrom(65565)
        # packet string from tuple
        packet = packet[0]
        # parse ethernet header
        eth_length = 14
        eth_header = packet[:eth_length]
        eth = unpack('!6s6sH', eth_header)
        eth_protocol = socket.ntohs(eth[2])
        ip_header = packet[eth_length:20 + eth_length]
        # unpack header
        iph = unpack('!BBHHHBBH4s4s', ip_header)
        version_ihl = iph[0]
        version = version_ihl >> 4
        ihl = version_ihl & 0xF
        ttl = iph[5]
        protocol = iph[6]
        s_addr = socket.inet_ntoa(iph[8])
        d_addr = socket.inet_ntoa(iph[9])
        print 'Header protocol:', eth[2], 'Unpacked protocol:', eth_protocol
        print 'Version : ' + str(
            version) + ' IP Header Length : ' + str(
            ihl) + ' TTL : ' + str(
            ttl) + ' Protocol : ' + str(
            protocol) + ' Source Address : ' + str(
            s_addr) + ' Destination Address : ' + str(d_addr)


if __name__ == '__main__':
    main()

I took this as example

So, on Linux I'm getting expected data

127.0.1.1 Header protocol: 2048 Unpacked protocol: 8 Version : 4 IP Header Length : 5 TTL : 64 Protocol : 17 Source Address : 127.0.0.1 Destination Address : 127.0.0.53 Header protocol: 2048 Unpacked protocol: 8 Version : 4 IP Header Length : 5 TTL : 64 Protocol : 17 Source Address : 127.0.0.1 Destination Address : 127.0.0.53 Header protocol: 2048 Unpacked protocol: 8 Version : 4 IP Header Length : 5 TTL : 64 Protocol : 17 Source Address : 127.0.0.53 Destination Address : 127.0.0.1 Header protocol: 2048 Unpacked protocol: 8 Version : 4 IP Header Length : 5 TTL : 64 Protocol : 17 Source Address : 127.0.0.53 Destination Address : 127.0.0.1 Header protocol: 2048 Unpacked protocol: 8 Version : 4 IP Header Length : 5 TTL : 64 Protocol : 6 Source Address : 10.0.2.15 Destination Address : 5.196.61.211

But on Windows all fields are incorrect

10.0.2.15

Header protocol: 2560 Unpacked protocol: 10 Version : 0 IP Header Length : 2 TTL : 8 Protocol : 70 Source Address : 183.96.34.40 Destination Address : 36.2.80.16 Header protocol: 2560 Unpacked protocol: 10 Version : 0 IP Header Length : 2 TTL : 8 Protocol : 70 Source Address : 183.96.34.40 Destination Address : 36.2.80.16 Header protocol: 2560 Unpacked protocol: 10 Version : 0 IP Header Length : 2 TTL : 8 Protocol : 70 Source Address : 183.96.34.40 Destination Address : 36.3.80.16 Header protocol: 2560 Unpacked protocol: 10 Version : 0 IP Header Length : 2 TTL : 8 Protocol : 70 Source Address : 183.96.34.40 Destination Address : 36.3.80.16 Header protocol: 2560 Unpacked protocol: 10 Version : 0 IP Header Length : 2 TTL : 8 Protocol : 70 Source Address : 183.96.34.40 Destination Address : 36.3.80.17

How can I get the correct data?

PS. I know about pypcap, scapy and other, but I need raw data parser without any third-party libs. If it possible, of course.

PPS. I looked here all similar topics, but solution still not found

Many thnx

On Linux you are using SOCK_RAW with AF_PACKET to sniff at layer 2, which means that you first get the layer 2 information (ethernet) and then layer 3 information (IP). On Windows you are using AF_INET to sniff at layer 3 which means that you don't get any layer 2 information. Still, your code assumes layer 2 information (ethernet) in both cases.
A way to fix this would thus to skip handling any ethernet information on Windows since there will be none and start immediately with the IP header.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM