низкоуровневый анализатор пакетов с сокетом и питоном - PullRequest
0 голосов
/ 29 января 2019

Весь скрипт внизу.

Итак, я пытаюсь, как сказано в заголовке, создать анализатор пакетов LowLevel в python.Процесс создания необработанного сокета и захвата пакета, кажется, работает нормально.

Моя проблема: когда я пытаюсь перевести исходный и целевой IP-адреса в удобочитаемую форму, используя следующий код:

self.src_address = socket.inet_ntoa(struct.pack('<L', self.src))
self.dst_address = socket.inet_ntoa(struct.pack('<L', self.dst))

Я получаю следующую ошибку:

Traceback (most recent call last):
  File "ip_header.py", line 68, in <module>
    sniffer()
  File "ip_header.py", line 62, in sniffer
    header = IP(raw_buffer)
  File "ip_header.py", line 31, in __init__
    self.src_address = socket.inet_ntoa(struct.pack('<L', self.src))
struct.error: 'L' format requires 0 <= number <= 4294967295

Я знаю, что ошибка вызвана struct.pack('<L', self.src)
Поэтому я изменил формат с Long (L) на Long Long (Q).Затем я получаю еще одну ошибку, вызванную функцией socket.inet_ntoa().

OSError: packed IP wrong length for inet_ntoa

По сути, эта функция преобразует 32-разрядный упакованный адрес IPv4 (байтовоподобный объект длиной четыре байта).) к стандартному строковому представлению с точками в квадрате (например, «123.45.67.89»).

Без перевода IP-адресов src и dst в удобочитаемый формат, я получаю кучу бесполезных чисел (очевидно, эти цифры представляют IP-адрес)

procotol : ICMP, src : 2623909733031061696 -> dst : 6651666592092407870



ЗДЕСЬ ВЕСЬ СЦЕНАРИЙ

#!/usr/bin/env python3
import struct
import socket
from ctypes import * 

class IP(Structure):
    '''
    This class parse IP header
    '''
    # list of ip protocols

    # structre of ip header
    _fields_ = [
            ("ihl", c_ubyte, 4),    # Internet Header Length represent the number of 32bits words.
            ("version", c_ubyte, 4),    # ip version number ( 4 for ipv4 ) , size = 4 bits
            ("tos", c_ubyte),
            ("len", c_ushort),  # Total Size of ip packet not only the header (20 bytes < len < 65535), size = 2 bytes
            ("id", c_ushort),   
            ('offset', c_ushort),
            ('ttl', c_ubyte),   # Time To Live in seconds , size = 1 byte
            ('protocol_num', c_ubyte),  # Protocol Number , (1 : icmp, 6:tcp, 17:udp ...) , size = 1 byte
            ('sum', c_ushort),  # Header CheckSum, size = 2 bytes
            ("src", c_ulong),   # Source Address , size = 4 bytes
            ("dst", c_ulong)    # Destination Address , size = 4 bytes
    ]
    def __new__(self, socket_buffer=None):
        # create ctypes buffer from socket buffer
        return self.from_buffer_copy(socket_buffer)

    def __init__(self, socket_buffer=None):
        # human readable ip
        self.src_address = socket.inet_ntoa(struct.pack('<L', self.src))
        self.dst_address = socket.inet_ntoa(struct.pack('<L', self.dst))

        # get type of protocol
        if self.protocol_num == 1:
            self.protocol = 'ICMP'
        elif self.protocol_num == 6:
            self.protocol = 'TCP'
        elif self.protocol_num == 17:
            self.protocol = 'UDP'
        else :
            self.protocol = self.protocol_num

def sniffer():
    '''
    create raw socket , sniff packets , close socket
    '''

    # create socket
    socket_protocol = socket.IPPROTO_ICMP
    sniff = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket_protocol)

    # include ip header in the capture
    sniff.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

    # capture packet 
    try :
        while True:
            raw_buffer, addr = sniff.recvfrom(4096)

            # parse packet header
            header = IP(raw_buffer)
            print("procotol : {}, src : {} -> dst : {}".format(header.protocol, header.src_address, header.dst_address))
    except KeyboardInterrupt:
        sniff.close()

if __name__ == '__main__':
    sniffer()
...