mirror of
https://github.com/langhuihui/monibuca.git
synced 2025-09-26 23:05:55 +08:00
gifix: replay cap script
This commit is contained in:
@@ -8,6 +8,7 @@ import random
|
||||
import threading
|
||||
import queue
|
||||
import socket
|
||||
import heapq
|
||||
|
||||
class PacketReplayer:
|
||||
def __init__(self, pcap_file, target_ip, target_port):
|
||||
@@ -18,31 +19,27 @@ class PacketReplayer:
|
||||
self.response_queue = queue.Queue()
|
||||
self.stop_reading = threading.Event()
|
||||
self.socket = None
|
||||
self.next_seq = None # 下一个期望的序列号
|
||||
self.pending_packets = [] # 使用优先队列存储待发送的包
|
||||
self.seen_packets = set() # 用于去重
|
||||
self.initial_seq = None # 初始序列号
|
||||
self.initial_ack = None # 初始确认号
|
||||
self.client_ip = None # 客户端IP
|
||||
self.client_port = None # 客户端端口
|
||||
self.first_data_packet = True # 标记是否是第一个数据包
|
||||
self.total_packets_sent = 0 # 发送的数据包数量
|
||||
self.total_bytes_sent = 0 # 发送的总字节数
|
||||
|
||||
def establish_tcp_connection(self, src_port):
|
||||
"""建立TCP连接"""
|
||||
print(f"正在建立TCP连接 {self.target_ip}:{self.target_port}...")
|
||||
try:
|
||||
# 创建socket对象
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
# 绑定源端口(如果指定了端口)
|
||||
if src_port > 0:
|
||||
try:
|
||||
self.socket.bind(('0.0.0.0', src_port))
|
||||
except socket.error as e:
|
||||
print(f"指定端口 {src_port} 被占用,将使用随机端口")
|
||||
self.socket.bind(('0.0.0.0', 0)) # 使用随机可用端口
|
||||
else:
|
||||
self.socket.bind(('0.0.0.0', 0)) # 使用随机可用端口
|
||||
|
||||
# 获取实际使用的端口
|
||||
# 不绑定源端口,让系统自动分配
|
||||
self.socket.settimeout(5)
|
||||
self.socket.connect((self.target_ip, self.target_port))
|
||||
actual_port = self.socket.getsockname()[1]
|
||||
print(f"使用本地端口: {actual_port}")
|
||||
|
||||
# 设置超时
|
||||
self.socket.settimeout(5)
|
||||
# 连接目标
|
||||
self.socket.connect((self.target_ip, self.target_port))
|
||||
print("TCP连接已建立")
|
||||
return True
|
||||
except Exception as e:
|
||||
@@ -57,11 +54,9 @@ class PacketReplayer:
|
||||
if IP not in packet:
|
||||
return
|
||||
|
||||
# 检查源IP
|
||||
if src_ip and packet[IP].src != src_ip:
|
||||
return
|
||||
|
||||
# 检查协议和源端口
|
||||
if protocol == 'tcp' and TCP in packet:
|
||||
if src_port and packet[TCP].sport != src_port:
|
||||
return
|
||||
@@ -72,7 +67,7 @@ class PacketReplayer:
|
||||
return
|
||||
conn_id = (packet[IP].src, packet[UDP].sport)
|
||||
self.connections[conn_id].append(packet)
|
||||
elif not protocol: # 如果没有指定协议,则包含所有IP包
|
||||
elif not protocol:
|
||||
if TCP in packet:
|
||||
if src_port and packet[TCP].sport != src_port:
|
||||
return
|
||||
@@ -84,11 +79,97 @@ class PacketReplayer:
|
||||
conn_id = (packet[IP].src, packet[UDP].sport)
|
||||
self.connections[conn_id].append(packet)
|
||||
|
||||
def send_packet(self, packet, packet_count):
|
||||
"""发送单个数据包,处理序列号"""
|
||||
if TCP not in packet or IP not in packet:
|
||||
return True
|
||||
|
||||
try:
|
||||
# 检查是否是发送到目标端口的包
|
||||
if packet[TCP].dport == self.target_port:
|
||||
# 记录客户端信息
|
||||
if self.client_ip is None:
|
||||
self.client_ip = packet[IP].src
|
||||
self.client_port = packet[TCP].sport
|
||||
print(f"识别到客户端: {self.client_ip}:{self.client_port}")
|
||||
|
||||
# 获取TCP序列号和确认号
|
||||
seq = packet[TCP].seq
|
||||
ack = packet[TCP].ack
|
||||
flags = packet[TCP].flags
|
||||
|
||||
# 打印数据包信息
|
||||
print(f"[序号:{packet_count}] 处理数据包: src={packet[IP].src}:{packet[TCP].sport} -> dst={packet[IP].dst}:{packet[TCP].dport}, seq={seq}, ack={ack}, flags={flags}")
|
||||
|
||||
# 发送当前包
|
||||
if Raw in packet:
|
||||
# 如果是第一个数据包,记录初始序列号
|
||||
if self.first_data_packet:
|
||||
self.initial_seq = seq
|
||||
self.next_seq = seq
|
||||
self.first_data_packet = False
|
||||
print(f"第一个数据包,初始序列号: {seq}")
|
||||
|
||||
# 如果是重传包,跳过
|
||||
if seq in self.seen_packets:
|
||||
print(f"跳过重传包,序列号: {seq}")
|
||||
return True
|
||||
|
||||
# 如果序列号大于期望的序列号,将包放入待发送队列
|
||||
if seq > self.next_seq:
|
||||
print(f"包乱序,放入队列,序列号: {seq}, 期望序列号: {self.next_seq}")
|
||||
heapq.heappush(self.pending_packets, (seq, packet))
|
||||
return True
|
||||
|
||||
payload = packet[Raw].load
|
||||
print(f"准备发送数据包,负载大小: {len(payload)} 字节")
|
||||
self.socket.send(payload)
|
||||
self.seen_packets.add(seq)
|
||||
old_seq = self.next_seq
|
||||
self.next_seq = self.next_seq + len(payload)
|
||||
print(f"更新序列号: {old_seq} -> {self.next_seq}")
|
||||
|
||||
# 更新统计信息
|
||||
self.total_packets_sent += 1
|
||||
self.total_bytes_sent += len(payload)
|
||||
|
||||
# 检查并发送待发送队列中的包
|
||||
while self.pending_packets and self.pending_packets[0][0] == self.next_seq:
|
||||
_, next_packet = heapq.heappop(self.pending_packets)
|
||||
if Raw in next_packet:
|
||||
next_payload = next_packet[Raw].load
|
||||
print(f"发送队列中的包,负载大小: {len(next_payload)} 字节")
|
||||
self.socket.send(next_payload)
|
||||
self.seen_packets.add(self.next_seq)
|
||||
old_seq = self.next_seq
|
||||
self.next_seq += len(next_payload)
|
||||
print(f"更新序列号: {old_seq} -> {self.next_seq}")
|
||||
|
||||
# 更新统计信息
|
||||
self.total_packets_sent += 1
|
||||
self.total_bytes_sent += len(next_payload)
|
||||
|
||||
packet_time = time.strftime("%H:%M:%S", time.localtime(float(packet.time)))
|
||||
print(f"[{packet_time}] [序号:{packet_count}] 已发送数据包 (序列号: {seq}, 负载大小: {len(payload)} 字节)")
|
||||
else:
|
||||
# 对于控制包,只记录到已处理集合
|
||||
if flags & 0x02: # SYN
|
||||
print(f"[序号:{packet_count}] 处理SYN包")
|
||||
elif flags & 0x10: # ACK
|
||||
print(f"[序号:{packet_count}] 处理ACK包")
|
||||
else:
|
||||
print(f"[序号:{packet_count}] 跳过无负载包")
|
||||
else:
|
||||
print(f"[序号:{packet_count}] 跳过非目标端口的包: src={packet[IP].src}:{packet[TCP].sport} -> dst={packet[IP].dst}:{packet[TCP].dport}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"发送数据包 {packet_count} 时出错: {e}")
|
||||
return False
|
||||
|
||||
def response_reader(self, src_port):
|
||||
"""持续读取服务器响应的线程函数"""
|
||||
while not self.stop_reading.is_set() and self.socket:
|
||||
try:
|
||||
# 使用socket接收数据
|
||||
data = self.socket.recv(4096)
|
||||
if data:
|
||||
self.response_queue.put(data)
|
||||
@@ -106,23 +187,19 @@ class PacketReplayer:
|
||||
print(f"开始读取并重放数据包到 {self.target_ip}:{self.target_port}")
|
||||
|
||||
try:
|
||||
# 使用PcapReader逐包读取
|
||||
reader = PcapReader(self.pcap_file)
|
||||
packet_count = 0
|
||||
connection_established = False
|
||||
|
||||
# 读取并处理数据包
|
||||
for packet in reader:
|
||||
packet_count += 1
|
||||
|
||||
if IP not in packet:
|
||||
continue
|
||||
|
||||
# 检查源IP
|
||||
if src_ip and packet[IP].src != src_ip:
|
||||
continue
|
||||
|
||||
# 检查协议和源端口
|
||||
current_src_port = None
|
||||
if protocol == 'tcp' and TCP in packet:
|
||||
if src_port and packet[TCP].sport != src_port:
|
||||
@@ -132,7 +209,7 @@ class PacketReplayer:
|
||||
if src_port and packet[UDP].sport != src_port:
|
||||
continue
|
||||
current_src_port = packet[UDP].sport
|
||||
elif not protocol: # 如果没有指定协议,则包含所有IP包
|
||||
elif not protocol:
|
||||
if TCP in packet:
|
||||
if src_port and packet[TCP].sport != src_port:
|
||||
continue
|
||||
@@ -146,37 +223,32 @@ class PacketReplayer:
|
||||
else:
|
||||
continue
|
||||
|
||||
# 找到第一个符合条件的包,建立连接
|
||||
if not connection_established:
|
||||
if not self.establish_tcp_connection(current_src_port):
|
||||
print("无法建立连接,退出")
|
||||
return
|
||||
# 启动响应读取线程
|
||||
self.stop_reading.clear()
|
||||
reader_thread = threading.Thread(target=self.response_reader, args=(current_src_port,))
|
||||
reader_thread.daemon = True
|
||||
reader_thread.start()
|
||||
connection_established = True
|
||||
|
||||
# 发送当前数据包
|
||||
try:
|
||||
if Raw in packet:
|
||||
self.socket.send(packet[Raw].load)
|
||||
packet_time = time.strftime("%H:%M:%S", time.localtime(float(packet.time)))
|
||||
print(f"[{packet_time}] [序号:{packet_count}] 已发送数据包 (负载大小: {len(packet[Raw].load)} 字节)")
|
||||
if delay > 0:
|
||||
time.sleep(delay)
|
||||
except Exception as e:
|
||||
print(f"发送数据包 {packet_count} 时出错: {e}")
|
||||
sys.exit(1) # 发送失败直接退出进程
|
||||
if not self.send_packet(packet, packet_count):
|
||||
print("发送数据包失败,退出")
|
||||
return
|
||||
|
||||
if delay > 0:
|
||||
time.sleep(delay)
|
||||
|
||||
print(f"\n统计信息:")
|
||||
print(f"总共处理了 {packet_count} 个数据包")
|
||||
print(f"成功发送了 {self.total_packets_sent} 个数据包")
|
||||
print(f"总共发送了 {self.total_bytes_sent} 字节数据")
|
||||
|
||||
except Exception as e:
|
||||
print(f"处理数据包时出错: {e}")
|
||||
sys.exit(1) # 其他错误也直接退出进程
|
||||
sys.exit(1)
|
||||
finally:
|
||||
# 关闭连接和停止读取线程
|
||||
self.stop_reading.set()
|
||||
if self.socket:
|
||||
self.socket.close()
|
||||
|
Reference in New Issue
Block a user