第二次作业

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/2023summer
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/2023summer/homework/12995
这个作业的目标 学习使用scapy进行数据包的构造,发送,接收 学习并使用count-min sketch算法

代码已上传到gitee
https://gitee.com/gebilaowang66/fzu/tree/master/lab/work-2

一.使用scapy工具实现数据包的构造、发送和接收
先在发送端(192.168.11.3)构造数据包,接收端为192.168.11.2
from scapy.all import *
//目标IP地址和端口
receiver_ip = "192.168.11.2" receiver_port = 12345
packet = IP(dst=receiver_ip)/UDP(dport=receiver_port)/Raw(load="FZU_laowang")
send(packet)

构造一个UDP数据包并发送

在接收端准备了两个接收工具,分别是scapy和wireshark

1)scapy

先写接收脚本

点击查看代码
from scapy.all import *
//监听的IP地址和端口
receiver_ip = "192.168.11.2"
receiver_port = 12345
//定义回调函数处理接收到的数据包
def packet_handler(packet):
    if packet.haslayer(Raw):
        data = packet[Raw].load.decode()
        print("Received data:", data)
sniff(iface= 'ens33',filter=f"udp and host {receiver_ip} and port {receiver_port}", prn=packet_handler)<details>

发送接收都成功了

2>wireshark


发送并成功接收

二.count-min sketch的使用
我的理解来说,CM-sketch算法就是优化的哈希表,在建立多张哈希表的前提下,使用多个哈希函数在这几张表中进行映射,取值时通过在这几张表中取出最小的值,因此最终结果只可能大或者刚好,不可能小。
这种数据结构的优点就在于占用的内存更少,使用的是固定大小的二维数组,在相同情况下,静态哈希表所占用的空间更大,就算进行动态扩容,时间成本还是要高
尝试用python来实现CM-sketch算法,是第一次用python写算法,与c和c++比语法差距大,最后的输出结果不够好,希望大家能够批评指正

1)首先,写出精确计算流频率的脚本,没有什么特别特殊的地方,就是数组遍历

点击查看代码
from collections import defaultdict
from scapy.all import rdpcap
def calculate_flow_frequency(dataset):
    flow_counter = defaultdict(int)
    for packet in dataset:
        if packet.haslayer("IP") and packet.haslayer("UDP"):
            src_ip = packet["IP"].src
            dst_ip = packet["IP"].dst
            flow_key = (src_ip, dst_ip)
            flow_counter[flow_key] += 1
    return flow_counter
pcap_file = "test2.pcap"
dataset = rdpcap(pcap_file)
flow_frequency = calculate_flow_frequency(dataset)
for src_ip, freq in flow_frequency.items():
    print(f"源IP: {src_ip}, 频率精确值: {freq}")

2)接下来实现CM-sketch

点击查看代码
import random
from collections import defaultdict
from scapy.all import rdpcap
class CountMinSketch:
    def __init__(self, width, depth):
        self.width = width
        self.depth = depth
        self.sketch = [[0] * width for _ in range(depth)]
    
    def update(self, flow_hash):
        for i in range(self.depth):
            hash_val = (flow_hash + i) % self.width
            self.sketch[i][hash_val] += 1
    
    def estimate(self, flow_hash):
        min_count = float('inf')
        for i in range(self.depth):
            hash_val = (flow_hash + i) % self.width
            min_count = min(min_count, self.sketch[i][hash_val])
        return min_count
def calculate_flow_frequency(dataset, width, depth):
    flow_counter = CountMinSketch(width, depth)
    for packet in dataset:
        if packet.haslayer("IP"):
            src_ip = packet.payload.src  # 获取源IP
            dst_ip = packet.payload.dst  # 获取目的IP
            flow_hash = hash((src_ip, dst_ip))  # 计算流的哈希值
            flow_counter.update(flow_hash)  # 更新Count-Min Sketch
    return flow_counter
pcap_file = "test2.pcap"
dataset = rdpcap(pcap_file)  # 使用rdpcap函数读取pcap文件
width = 1000  # Count-Min Sketch的宽度
depth = 5  # Count-Min Sketch的深度
flow_frequency = calculate_flow_frequency(dataset, width, depth)
for packet in dataset:
    if packet.haslayer("IP")and packet.haslayer("UDP"):
        src_ip = packet.payload.src  # 获取源IP
        dst_ip = packet.payload.dst  # 获取目的IP
        flow_hash = hash((src_ip, dst_ip))  # 计算流的哈希值
        flow_estimate = flow_frequency.estimate(flow_hash)  # 估计流的频率
        print(f"源IP: {src_ip}, 频率估计值: {flow_estimate}")
首先是定义的CM-sketch类,核心就是update与estimate方法,其中update方法就是在得到当前流哈希值后去更新各个哈希表中的当前流的频率,estimate方法就是在最终输出结果的时候取出最小的那一个 核心函数calculate_flow_frequency,其实就是对每一个流进行update操作

3)接下来在接收端准备一个recive.py

点击查看代码
from scapy.all import *
package=sniff(iface= 'ens33',count= 105)  # 扫描ens33网卡的数据包 这个网卡的问题困扰了我很久,总是抓不到包,就是因为没有指定网卡
wrpcap( "test2.pcap",package)  # 将抓取到的包保存为test.pcap文件

4)在发送端准备一个send.py

点击查看代码
from scapy.all import *
src_ip = "192.168.11.3"
dst_ip = "192.168.11.2"
receiver_port = 12345
for _ in range(20):
    pkt = IP(src=src_ip, dst=dst_ip)/UDP(dport=receiver_port) / Raw(load="wuhu")
    send(pkt)
for _ in range(80):
    pkt = IP(src=RandIP(), dst=dst_ip) /UDP(dport=receiver_port)/ Raw(load="qifei")
    send(pkt)

代码工作到此准备完毕,接下来开始测试:


发送接收成功,wireshark中检查没问题

接下来检查算法
先用循环来算出精确值

用CM-sketch算法算出估计值(我想在最后的for循环进行计算的时候加上一个if条件与一个哈希数组,映射已计算的IP地址,如果为真那就跳过该IP,应该能解决IP重复计算,但是结果192.168.11.3这个IP从20变成了1,所有IP都只计算了一次,寄,大🔥有更好的方法请踢我一脚)

接下来进行对比,发现有几个IP还是会有误差,但是不大

接下来测试一下算法,分别由1000,10000,100000个数据包来提升,比较计算时间,占用空间,计算差距

首先是1000组,设置CM-sketch宽度为500

可以看到 在样本量较少的情况下,内存占用与时间消耗区别并不明显

接下来是1W组,设置CM-sketch宽度为1000
占用内存与时间消耗差距开始体现


接下来是10W组,光是发包就发了小十分钟,还丢了一堆包,10W最后只收到3W左右,UDP是真拉🤣

此时的占用内存和时间消耗已经很明显了 CMK优势开始凸显


BUG总结:
在用scapy创建和接收数据包的时候,出现了用scapy发送没问题,但是只有wireshark能接收到数据包,用scapy的sniff方法接收不到数据包,刚开始考虑了防火墙的问题,但是想想应该不会只防了scapy不防wireshark,之后又考虑了端口问题,是否要将发送数据包的端口改为scapy在接收端的端口?尝试了一下之后还是失败,最后查资料发现原因是捕捉网卡的问题,要在sniff指定iface为ens33才能接收

第一问:在人生道路上,你有没有专长的技能获取的成功经验?
多做,多想,多找有经验的人请教,但更多还是靠自律

第二问:你有什么技能比大多数人(70%以上)更好?
可能是骑山地车?毕竟这玩意绝对没有70%的人骑🤣🤣🤣🤣

第三问:你是如何学习C语言的,与你的高超技能相比,C语言的学习有什么经验和教训?
我感觉c语言和骑车一样都是堆时间,刷熟练度,跟骑车比一下,c语言有更多的教程和经验,其中垃圾信息也很多,经验和教训就是要懂得取舍吧,总是不能把所有的东西都学完,但是起码遇到了知道这是个啥🤣🤣

posted @ 2023-08-02 20:52  隔壁老王fzu  阅读(407)  评论(0)    收藏  举报