计算机网络学习实战篇——实现网络嗅探工具

实现功能

在计算机里捕获IP协议报文、UDP协议报文、TCP协议报文,并分析报文里的关键信息。

流程

在这里插入图片描述

搭建服务基本框架

基于操作系统的线程池实现。
链接:操作系统学习实战篇——实现支持异步任务的线程池

在这里插入图片描述

网卡的工作模式
在这里插入图片描述
本文将网卡设置成混杂模式

server.py

# -*- encoding=utf-8 -*-

import socket
import json
from 计算机操作系统.pool import ThreadPool as tp
from 计算机操作系统.task import AsyncTask


class ProcessTask(AsyncTask):
    def __init__(self,packet,*args,**kwargs):
        self.packet = packet
        AsyncTask(func=self.process,*args,**kwargs)
        pass

    def process(self):
        pass


class Server:
    def __init__(self):
        # 工作协议类型、套接字类型、工作具体的协议
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
        # 套接字绑定到具体端口
        # 自己的主机IP,在终端通过 ipconfig 命令查看
        self.ip = '192.168.1.105'
        self.port = 8888
        self.sock.bind((self.ip, self.port))

        # 混杂模式
        self.sock.ioctl(socket.SIO_RCVALL,socket.RCVALL_ON)
        # 定义线程池,线程数量10个
        self.pool = tp(10)
        self.pool.start()

    def loop_server(self):
        while True:
            # 1. 接收
            packet, addr = self.sock.recv(65535)
            # 2. 生成Task
            task = ProcessTask(packet)
            # 3. 提交
            self.pool.put(task)
            # 4. 获取结果
            result = task.get_result()
            result = json.dumps(
                result,
                indent=4
            )
            print(result)


if __name__=='__main__':
    server = Server()
    server.loop_server()

Python操作字节序列

字节序:
在这里插入图片描述大端字节序:高位字节在前,低位字节在后
小端字节序:低位字节在前,高位字节在后

由于计算机电路先处理低位字节效率比较高,主机的CPU处理时会按照小端字节序处理,但是呈现出来是大端字节序的形式。
而人类习惯读写大端字节序,所以网络中使用的是大端字节序。

在这里插入图片描述在这里插入图片描述
struct_demo.py

# -*- encoding=utf-8 -*-

import struct

# 八个字节
bin_str = b'ABCD1234'
print(bin_str)

# B 一个字节转换为一个整数
# >表示大端字节序
result = struct.unpack('>BBBBBBBB', bin_str)
print(result)

# H 两个字节转换为一个整数
result = struct.unpack('>HHHH', bin_str)
print(result)

# L 四个字节转换为一个整数
result = struct.unpack('>LL', bin_str)
print(result)

# 八个ASCII码的字符
result = struct.unpack('>8s', bin_str)
print(result)

result = struct.unpack('>BBHL', bin_str)
print(result)

实现IP报文解析器

在这里插入图片描述

parser.py (net包下)

# -*- encoding=utf-8 -*-
import struct
import socket


class IPParser:

    IP_HEADER_LENGTH = 20

    @classmethod
    def parser_ip_header(cls, ip_header):
        '''
        IP报文格式
        1. 4位IP-version 4位IP头长度 8位服务类型 16位总长度
        2.16位标识符 3位标记符 13位片偏移
        3. 8位TTL 8位协议 16位IP头部校验和
        4.32位源IP地址
        5.32位目的IP地址
        '''
        # 第一行
        line1 = struct.unpack('>BBH', ip_header[:4])
        ip_version = line1[0] >> 4
        iph_length = line1[0] & 15 * 4
        pkt_length = line1[2]
        # 第三行
        line3 = struct.unpack('>BBH', ip_header[8:12])
        TTL = line3[0]
        # 1表示ICMP协议,6表示TCP协议,17表示UDP协议
        protocol = line3[1]
        iph_checksum = line3[2]
        # 第四行
        line4 = struct.unpack('>4s', ip_header[12:16])
        src_ip = socket.inet_ntoa(line4[0])
        # 第五行
        line5 = struct.unpack('>4s', ip_header[16:20])
        dst_ip = socket.inet_ntoa(line5[0])
        return {
    
    
            'ip_version': ip_version,
            'iph_length': iph_length,
            'packet_length': pkt_length,
            'TTL': TTL,
            'protocol': protocol,
            'iph_checksum': iph_checksum,
            'src_ip': src_ip,
            'dst_ip': dst_ip
        }

    @classmethod
    def parser(cls, packet):
        ip_header = packet[:20]
        return cls.parser_ip_header(ip_header)

server.py里ProcessTask类修改:

class ProcessTask(AsyncTask):
    def __init__(self,packet,*args,**kwargs):
        self.packet = packet
        # AsyncTask(func=self.process,*args,**kwargs)
        super(ProcessTask,self).__init__(func=self.process,*args,**kwargs)

    def process(self):
        ip_header = IPParser.parser(self.packet)
        return ip_header

实现UDP报文解析器

在这里插入图片描述

parser.py(trans包下)

# -*- encoding=utf-8 -*-
import struct


class TransParser:
    # 定义IP头部偏移
    IP_HEADER_OFFSET = 20
    UDP_HEADER_LENGTH = 8


class UDPParser(TransParser):
    '''
    1. 16位源端口  16位目的端口
    2. 16位UDP长度  16位校验和
    '''
    @classmethod
    def parser_udp_header(cls, udp_header):
        udp_header = struct.unpack('>HHHH', udp_header)
        return{
    
    
            'src_port': udp_header[0],
            'dst_port': udp_header[1],
            'udp_length': udp_header[2],
            'udp_checksum': udp_header[3]
        }
        pass

    @classmethod
    def parser(cls, packet):
        udp_header = packet[cls.IP_HEADER_OFFSET:cls.IP_HEADER_OFFSET+cls.UDP_HEADER_LENGTH]
        return cls.parser_udp_header(udp_header)

修改server.py的ProcessTask类

class ProcessTask(AsyncTask):
    def __init__(self,packet,*args,**kwargs):
        self.packet = packet
        # AsyncTask(func=self.process,*args,**kwargs)
        super(ProcessTask,self).__init__(func=self.process,*args,**kwargs)

    def process(self):
        headers = {
    
    
            'network_header': None,
            'transport_header': None
        }
        ip_header = IPParser.parser(self.packet)
        headers['network_header'] = ip_header
        if ip_header['protocol'] == 17:
            udp_header = UDPParser.parser(self.packet)
            headers['transport_header'] = udp_header
        return headers

实现TCP报文解析器

在这里插入图片描述
修改parser.py(trans包下)

# -*- encoding=utf-8 -*-
import struct


class TransParser:
    # 定义IP头部偏移
    IP_HEADER_OFFSET = 20
    UDP_HEADER_LENGTH = 8
    TCP_HEADER_LENGTH = 20


def data2str(data):
    l = len(data)
    data = struct.unpack(l*'B',data)
    string = ''
    for ch in data:
        if ch >= 127 or ch < 32:
            string += '.'
        else:
            string += chr(ch)
    return string


class UDPParser(TransParser):
    '''
    1. 16位源端口  16位目的端口
    2. 16位UDP长度  16位校验和
    '''
    @classmethod
    def parser_udp_header(cls, udp_header):
        udp_header = struct.unpack('>HHHH', udp_header)
        return{
    
    
            'src_port': udp_header[0],
            'dst_port': udp_header[1],
            'udp_length': udp_header[2],
            'udp_checksum': udp_header[3]
        }
        pass

    @classmethod
    def parser(cls, packet):
        udp_header = packet[cls.IP_HEADER_OFFSET:cls.IP_HEADER_OFFSET+cls.UDP_HEADER_LENGTH]
        data = packet[cls.IP_HEADER_OFFSET+cls.UDP_HEADER_LENGTH:]
        result = cls.parser_udp_header(udp_header)
        data = data2str(data)
        result['data'] = data
        return result


class TCPParser(TransParser):
    '''
    1. 16位源端口  16位目的端口
    2. 序列号
    3. 确认号
    4. 4位数据偏移 6位保留字段 6位标志位 16位窗口大小
    5. 16位校验和 16位紧急指针
    '''
    @classmethod
    def parser_tcp_header(cls, tcp_header):
        line1 = struct.unpack('>HH', tcp_header[:4])
        src_port = line1[0]
        dst_port = line1[1]

        line2 = struct.unpack('>L', tcp_header[4:8])
        seq_num = line2[0]

        line3 = struct.unpack('>L', tcp_header[8:12])
        ack_num = line3[0]

        line4 = struct.unpack('>BBH', tcp_header[12:16])
        data_offset = line4[0] >> 4
        flags = line4[1] & int('00111111',2)
        FIN = flags & 1
        SYN = (flags >> 1) & 1
        RST = (flags >> 2) & 1
        PSH = (flags >> 3) & 1
        ACK = (flags >> 4) & 1
        URG = (flags >> 5) & 1
        win_size = line4[2]

        line5 = struct.unpack('>HH', tcp_header[16:20])
        checksum = line5[0]
        urg_point = line5[1]

        return{
    
    
            'src_port': src_port,
            'dst_port': dst_port,
            'seq_num': seq_num,
            'ack_num': ack_num,
            'data_offset': data_offset,
            'flag': {
    
    
                'FIN': FIN,
                'SYN': SYN,
                'RST': RST,
                'PSH': PSH,
                'ACK': ACK,
                'URG': URG
            },
            'win_size': win_size,
            'checksum': checksum,
            'urg_point': urg_point
        }

    @classmethod
    def parser(cls, packet):
        tcp_header = packet[cls.IP_HEADER_OFFSET:cls.IP_HEADER_OFFSET+cls.TCP_HEADER_LENGTH]
        data = packet[cls.IP_HEADER_OFFSET+cls.TCP_HEADER_LENGTH:]
        data = data2str(data)
        result = cls.parser_tcp_header(tcp_header)
        result['data'] = data
        return result

修改server.py的ProcessTask类

class ProcessTask(AsyncTask):
    def __init__(self,packet,*args,**kwargs):
        self.packet = packet
        # AsyncTask(func=self.process,*args,**kwargs)
        super(ProcessTask,self).__init__(func=self.process,*args,**kwargs)

    def process(self):
        headers = {
    
    
            'network_header': None,
            'transport_header': None
        }
        ip_header = IPParser.parser(self.packet)
        headers['network_header'] = ip_header
        if ip_header['protocol'] == 17:
            udp_header = UDPParser.parser(self.packet)
            headers['transport_header'] = udp_header
        elif ip_header['protocol'] == 6:
            tcp_header = TCPParser.parser(self.packet)
            headers['transport_header'] = tcp_header
        return headers

猜你喜欢

转载自blog.csdn.net/weixin_44776894/article/details/107619984
今日推荐