暑期第二次作业
| 这个作业属于哪个课程 | 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语言的学习有什么经验和教训?
看看网课,然后做点题目;做的题太少,一道题都要打好久,应该要多做一点题,还有感觉不应该只停留在做题,应该学一点比较实用的东西

浙公网安备 33010602011771号