Как правильно распаковать разъем RAW на Win10 с помощью Python? - PullRequest
0 голосов
/ 23 июня 2018

У меня есть рабочий код для Linux, но в Windows я получил неожиданный результат. Код:

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()

Я взял это как пример

Итак, в Linux я получаю ожидаемые данные

127.0.1.1 Протокол заголовка: 2048 Распакованный протокол: 8 Версия: 4 Длина заголовка IP: 5 TTL: 64 Протокол: 17 Адрес источника: 127.0.0.1 Адрес назначения: 127.0.0.53 Протокол заголовка: 2048 Распакован протокол: 8 версия: 4 IP-заголовок длина: 5 TTL: 64 протокол: 17 Адрес источника: 127.0.0.1 Адрес назначения: 127.0.0.53 Заголовок протокол: 2048 распакованный протокол: 8 версия: 4 длина заголовка IP: 5 TTL: 64 Протокол: 17 Адрес источника: 127.0.0.53 Адрес назначения : 127.0.0.1 Протокол заголовка: 2048 Распакованный протокол: 8 Версия: 4 IP Длина заголовка: 5 TTL: 64 Протокол: 17 Адрес источника: 127.0.0.53 Адрес назначения: 127.0.0.1 Протокол заголовка: 2048 Распакован протокол: 8 Версия: 4 Длина заголовка IP: 5 TTL: 64 Протокол: 6 Адрес источника: 10.0.2.15 Адрес назначения: 5.196.61.211

Но в Windows все поля неверны

10.0.2.15

Протокол заголовка: 2560 Распакованный протокол: 10 Версия: 0 IP-заголовок Продолжительность: 2 TTL: 8 Протокол: 70 Адрес источника: 183.96.34.40 Адрес назначения: 36.2.80.16 Протокол заголовка: 2560 Распакован протокол: 10 версия: 0 длина заголовка IP: 2 TTL: 8 протокол: 70 Адрес источника: 183.96.34.40 Адрес назначения: 36.2.80.16 Заголовок протокол: 2560 распакованный протокол: 10 версия: 0 длина заголовка IP: 2 TTL: 8 Протокол: 70 Адрес источника: 183.96.34.40 Пункт назначения Адрес: 36.3.80.16 Протокол заголовка: 2560 Распакованный протокол: 10 Версия: 0 Длина заголовка IP: 2 TTL: 8 Протокол: 70 Адрес источника : 183.96.34.40 Адрес назначения: 36.3.80.16 Протокол заголовка: 2560 Распакованный протокол: 10 Версия: 0 Длина заголовка IP: 2 TTL: 8 Протокол: 70 Адрес источника: 183.96.34.40 Адрес назначения: 36.3.80.17

Как я могу получить правильные данные?

PS. Я знаю про pypcap, scapy и другие, но мне нужен анализатор необработанных данных без сторонних библиотек. Если это возможно, конечно.

PPS. Я посмотрел здесь все похожие темы, но решение до сих пор не найдено

Многие, спасибо

1 Ответ

0 голосов
/ 23 июня 2018

В Linux вы используете SOCK_RAW с AF_PACKET для прослушивания на уровне 2, что означает, что вы сначала получаете информацию уровня 2 (ethernet), а затем информацию уровня 3 (IP).В Windows вы используете AF_INET для прослушивания на уровне 3, что означает, что вы не получаете никакой информации уровня 2.Тем не менее, ваш код принимает информацию уровня 2 (ethernet) в обоих случаях.
Способ исправить это, таким образом, пропустить обработку любой информации ethernet в Windows, поскольку ее не будет, и сразу начать с заголовка IP.

...