暑期第二次作业

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

1.使用scapy工具实现数据包的构造、发送和接收


首先在终端使用ipconfig命令分别找到发送方和接收方虚拟机的ip,接着就可以在发送方虚拟机尝试发送啦

代码如下:

from scapy.all import *
# 构造数据包
packet = IP(src="192.168.45.211", dst="192.168.45.148")/TCP(sport=1234, dport=80)/'dfihsihfhss'
# 发送数据包
send(packet)



之后在接收方虚拟机可接收到这一数据包,将它打印出来对照可以发现是我们刚刚发送的

代码如下:

from scapy.all import *
# 定义回调函数,处理接收到的数据包
def packet_callback(packet):
    # 打印接收到的数据包信息
    packet.show()
# 接收数据包
sniff(filter="src host 192.168.45.211 && dst port 80", prn=packet_callback,count=1)

2.利用count-min sketch,估计数据集中每个流的频率,并与准确值作比较


首先构造10000个源ip地址随机的数据包,并把目标ip地址统一设为"192.168.48.255",这里为了防止源ip地址范围太过大使得后面统计的频率几乎都是个位数,将随机产生的数字设置在252到255之间,循环

四次产生一个ip地址,之后将这10000个数据包发送

代码如下:

import random
from collections import Counter
from scapy.all import *

# 生成随机IP地址
def generate_random_ip():
    ip = ".".join(str(random.randint(252, 255)) for _ in range(4))
    return ip

# 构造数据包
def create_packet():
    packet = IP(src=generate_random_ip(), dst="192.168.48.255") / UDP() / Raw(load="zzz")
    return packet

# 生成10000个不同的数据包
data_set = []
for _ in range(10000):
    packet = create_packet()
    send(packet)


接下来写接收这些数据包再把它们保存为pcap格式的文件(计算精确频率的部分可以忽略因为接下来还会再写一遍,这边只是当时为了看看打印结果)

代码如下:

from scapy.all import *
from collections import Counter

# 回调函数处理接收到的数据包
def process_packet(packet):
    # 提取源IP地址
    source_ip = packet[IP].src
    # 计算IP地址的频率
    ip_frequency[source_ip] += 1

# 创建一个空的Counter对象用于计算IP频率
ip_frequency = Counter()

# 使用sniff函数获取数据包
packets = sniff(filter="udp and dst host 192.168.48.255", prn=process_packet,count=10000)

# 打印每个IP地址及其频率
for ip, frequency in ip_frequency.items():
    print(f"IP地址: {ip}, 频率: {frequency}")
# 将数据包保存为pcap格式的文件
wrpcap("packets.pcap", packets)


在Wireshark上打开这一文件的确可以看到10000个数据包,说明捕获成功啦



最后就是利用CountMinSketch来估算数据频率和与精确频率做对比了






这里宽度和深度的设置跟误差息息相关,一开始都是随便设置然后发现误差有点大,后来发现原来可以用公式自动计算。


调整误差容忍度即可改变误差,降到0.0001精确值和估算值就几乎一样了,如果要完全一样再降一点即可

代码如下:

import numpy as np
from scapy.all import *
from collections import Counter

class CountMinSketch:
    def __init__(self, width, depth):
        self.width = width
        self.depth = depth
        self.count_matrix = np.zeros((depth, width), dtype=int)  # 初始化计数矩阵
        self.hash_params = self.generate_hash_params()  

    # 生成哈希函数参数
    def generate_hash_params(self):
        hash_params = []
        # 对于每个哈希函数,生成两个随机数作为参数
        for _ in range(self.depth):
            a = np.random.randint(1, self.width)  # 随机选择一个a
            b = np.random.randint(1, self.width)  # 随机选择一个b
            hash_params.append((a, b))
        return hash_params

    # 获取哈希值
    def get_hash_values(self, item):
        hash_values = []
        # 对于每个哈希函数,计算哈希值
        for a, b in self.hash_params:
            hash_value = (a * hash(item) + b) % self.width  # 使用哈希函数计算哈希值
            hash_values.append(hash_value)
        return hash_values

    # 添加元素
    def add(self, item):
        hash_values = self.get_hash_values(item)
        # 对于每个哈希函数,将元素添加到相应的桶中
        for i in range(self.depth):
            bucket_index = hash_values[i]  # 计算桶的索引
            self.count_matrix[i][bucket_index] += 1  # 在对应的桶中增加计数

    # 估算元素的频率
    def estimate_frequency(self, item):
        hash_values = self.get_hash_values(item)
        min_count = np.inf
        # 对于每个哈希函数,查找最小的计数值
        for i in range(self.depth):
            bucket_index = hash_values[i]  # 计算桶的索引
            count = self.count_matrix[i][bucket_index]  # 获取桶中的计数值
            min_count = min(min_count, count)  # 更新最小计数值
        return min_count

# 创建Count-Min Sketch对象
num_packets = 100000  # 数据包数量
error_tolerance = 0.0001  # 误差容忍度

width = int(np.ceil(np.exp(1) / error_tolerance))  # 计算桶的数量
depth = int(np.ceil(np.log(1 / error_tolerance)))
cms = CountMinSketch(width, depth)  # 创建 Count-Min Sketch 对象

# 定义回调函数处理每个数据包
def process_packet(packet):
    if IP in packet:
        ip = packet[IP].src
        cms.add(ip)  # 将源IP地址添加到 Count-Min Sketch 中

# 使用sniff函数读取pcap文件并处理每个数据包
sniff(offline="packets.pcap", prn=process_packet, store=0)

# 获取所有不重复的源IP地址
unique_ips = set()
for packet in PcapReader("packets.pcap"):
    if IP in packet:
        unique_ips.add(packet[IP].src)

# 估算每个源IP地址的频率
frequency_estimates = {}
exact_frequencies = Counter([packet[IP].src for packet in PcapReader("packets.pcap") if IP in packet])
for ip in unique_ips:
    estimate_frequency = cms.estimate_frequency(ip)  # 从 Count-Min Sketch 中估算源IP地址的频率
    exact_frequency = exact_frequencies[ip]  # 实际的源IP地址频率
    frequency_estimates[ip] = estimate_frequency

# 打印每个源IP地址的频率估算结果
for ip, estimate_frequency in frequency_estimates.items():
    exact_frequency = exact_frequencies[ip]
    difference =  estimate_frequency - exact_frequency
    print("源IP地址: {}, 估算频率: {}, 精确频率: {}, 频率差: {}".format(ip, estimate_frequency, exact_frequency, difference))

3.生活区问答

第一问:在人生道路上,你有没有专长的技能获取的成功经验?
感觉大多数事情肯投入时间、精力基本上都可以达到不错的效果
第二问:你有什么技能比大多数人(70%以上)更好?
暂时没想到吧
第三问:你是如何学习C语言的,与你的高超技能相比,C语言的学习有什么经验和教训?
看看网课,然后做点题目;做的题太少,一道题都要打好久,应该要多做一点题,还有感觉不应该只停留在做题,应该学一点比较实用的东西

posted @ 2023-08-10 19:54  Xianhj  阅读(207)  评论(0)    收藏  举报