求助:如何用Python实现无状态网络函数的数据包过滤与转发
嘿,你已经搞定了数据包捕获和合法性校验的核心部分,接下来要实现转发合法包、丢弃非法包的逻辑其实没那么复杂,我给你拆解下思路,再附上修改后的代码示例:
关键实现思路
1. 非法包的“丢弃”逻辑
其实你现在的代码已经天然实现了丢弃功能——当你用AF_PACKET类型的原始套接字捕获数据包后,默认不会把数据包传递给系统的上层协议栈,所以只要你不对非法包做任何转发操作,它就会直接被丢弃,不需要额外处理~
2. 合法包的转发实现
转发需要我们重新构造可发送的数据包,这里推荐数据链路层转发的方案(更贴合你当前的代码逻辑):
- 首先要获取当前监听网卡的MAC地址(作为转发包的源MAC)
- 找到目标IP对应的下一跳网关MAC(作为转发包的目的MAC)
- 修改原始数据包的以太网帧头,替换成新的源/目的MAC
- 创建一个发送用的原始套接字,把修改后的数据包发送出去
修改后的完整代码示例
import socket import sys from struct import unpack, pack from scapy.all import get_if_hwaddr, getmacbyip # 用scapy快速获取MAC,避免手动解析ARP # 初始化监听套接字 s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)) # 配置网络参数(根据你的实际环境修改) INTERFACE = "eth0" # 监听的网卡名称,比如eth0、wlan0 GATEWAY_IP = "192.168.0.1" # 网络网关IP # 获取网卡MAC和网关MAC iface_mac = get_if_hwaddr(INTERFACE) gateway_mac = getmacbyip(GATEWAY_IP) allowed_services = [80, 443] allowed_hosts = [f'192.168.0.{x}' for x in range(1, 11)] # 允许192.168.0.1-10 def forward_packet(original_packet, src_mac, dst_mac): # 拆解原始以太网帧头 eth_header = original_packet[:14] eth = unpack('!6s6sH', eth_header) eth_protocol = eth[2] # 构造新的以太网帧头:替换源MAC和目的MAC new_eth_header = pack('!6s6sH', bytes.fromhex(dst_mac.replace(':', '')), bytes.fromhex(src_mac.replace(':', '')), eth_protocol) # 拼接新帧头和原始数据包的负载部分 new_packet = new_eth_header + original_packet[14:] # 创建发送套接字并发送数据包 send_sock = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)) send_sock.bind((INTERFACE, 0)) send_sock.send(new_packet) send_sock.close() while True: try: packet = s.recvfrom(65565)[0] eth_length = 14 eth_header = packet[:eth_length] eth = unpack('!6s6sH', eth_header) eth_protocol = socket.ntohs(eth[2]) # 处理IP数据包(协议号8) if eth_protocol == 8: ip_header = packet[eth_length:20+eth_length] iph = unpack('!BBHHHBBH4s4s', ip_header) version_ihl = iph[0] ihl = version_ihl & 0xF iph_length = ihl * 4 protocol = iph[6] saddr = socket.inet_ntoa(iph[8]) daddr = socket.inet_ntoa(iph[9]) # 处理TCP数据包(协议号6) if protocol == 6: t = iph_length + eth_length tcp_header = packet[t:t+20] tcph = unpack('!HHLLBBHHH', tcp_header) sport = tcph[0] dport = tcph[1] # 判断数据包是否合法 is_valid = (daddr in allowed_hosts and dport in allowed_services) or \ (saddr in allowed_hosts and sport in allowed_services) if is_valid: print(f'Good TCP packet from {saddr} -> Forwarding') forward_packet(packet, iface_mac, gateway_mac) else: print(f'Bad Packet from {saddr} -> Dropping (Verify IP/Port)') print('---------------------------------------------------------------\n') except KeyboardInterrupt: print("\nStopping packet capture...") s.close() sys.exit(0)
注意事项
- 运行脚本需要root权限(执行
sudo python3 your_script.py),因为原始套接字需要系统级权限 - 依赖
scapy库,需要先安装:pip install scapy - 请务必根据你的实际网络环境修改
INTERFACE和GATEWAY_IP参数 - 如果不想依赖scapy,也可以自己实现ARP请求逻辑来获取网关MAC,只是会多写一些代码
内容的提问来源于stack exchange,提问作者João Barraca Filipe
相关产品推荐
相关产品推荐

