I'm trying to write a small "firewall" using python, scapy and netfilter queue that also handles fragmented packets with no known order of arrival. So i thought of keeping the packets in a dictionary sorted by the IP header ID value and each entry is a list of tuples - The packet offset and the netfilter queue packet object itself (So when the verdict is decided i can either drop or accept). The problem im encountering is after appending a new packet to the list in the dictionary, it looks like the payload of the packet is appended to all of the other packets as well. I've looked it up and i think it got something to do with immutability but couldn't fine any good solution\explanation . I'm new to python and would really hope some guidance. Code:
def update_fragmented_lists(scapy_packet, pkt):
current_dict = pkt_dict[scapy_packet[IP].id]
if len(current_dict) < 4:
current_dict.append((scapy_packet[IP].frag, pkt))
else:
for frag, waiting_pkt in current_dict:
waiting_pkt.drop()
del(pkt_dict[scapy_packet[IP].id])
def reconstruct_packet(packet_id):
curr_dict = pkt_dict[packet_id]
curr_dict = sorted(curr_dict, key=get_key)
print(curr_dict)
if IP(curr_dict[-1][1].get_payload()).flags == 1:
return None
last_off = 0
http_req = ""
for (offset, pkt) in curr_dict:
scapy_packet = IP(pkt.get_payload())
if offset*8 == last_off:
http_req += scapy_packet[Raw].load
last_off += len(scapy_packet[Raw].load)
else:
http_req = None
break
return http_req
def handle_packet(pkt):
scapy_packet = IP(pkt.get_payload())
packet_id = scapy_packet[IP].id
if (scapy_packet[IP].flags == 1) or (scapy_packet[IP].flags == 0 and scapy_packet[IP].frag != 0):
update_fragmented_lists(scapy_packet, pkt)
http_req = reconstruct_packet(packet_id)
if http_req is not None:
if check_forbidden_suffix(http_req):
for offset, fragmented_pkt in pkt_dict[packet_id]:
fragmented_pkt.accept()
else:
for offset, fragmented_pkt in pkt_dict[packet_id]:
fragmented_pkt.drop()
pkt_dict = defaultdict(list)
nfqueue = NetfilterQueue()
nfqueue.bind(1, handle_packet)
try:
nfqueue.run()
except KeyboardInterrupt:
os.system('iptables -F')
os.system('iptables -X')
Any help would be really appreciated!