#!/usr/bin/env python3 # NOTE: as explained in 3d, I was working on this when something was wrong with # the network, and as a result, didn't get the point of this exercise. # This code does *not* work. I am quite confident I could get it to work, but # don't have the time to redo everything. import socket import struct import math mac_1 = b'\x00\x0f\xc9\x0c\xee\xed' mac_2 = b'\x00\x0f\xc9\x0c\xf7\x93' def parse_tcp(packet): header_length = packet[12] * 4 header = packet[:14] # We don't care about the variable length options data = packet[header_length:] src_port, dst_port, seqn, ackn, flags = struct.unpack("!HHIIxB", header) return src_port, dst_port, seqn, ackn, flags, data def parse_udp(packet): header_length = 8 header = packet[:header_length] data = packet[header_length:] src_port, dst_port, data_len, checksum = struct.unpack("!HHHH", header) return src_port, dst_port, data_len, data, checksum def parse_ip(packet): header_length_in_bytes = (packet[0] & 0x0f) * 4 header = packet[:20] data = packet[header_length_in_bytes:] length, protocol, src, dst = struct.unpack("!xxHxxxxxBxx4s4s", header) header = {'length': length, 'protocol': protocol, 'source': src, 'destination': dst} return header_length_in_bytes, header, data def format_ip(addr): return '.'.join('%d'%i for i in addr) def parse_eth(packet): if (packet[13:14] == b'\x81\x00'): dst, src, typecode = struct.unpack("!6s6sxxxx2s", packet[:18]) data = packet[18:] else: dst, src, typecode = struct.unpack("!6s6s2s", packet[:14]) data = packet[14:] return dst, src, typecode, data def format_mac(addr): return ':'.join('%02x'%i for i in addr) def main(): s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.ntohs(0x0003)) while True: raw, address = s.recvfrom(2 ** 16 - 1) eth_dst, eth_src, eth_type, eth_data = parse_eth(raw) if eth_type == b'\x08\x00': # IP print("ETH: {} --> {} ({})".format( format_mac(eth_dst), format_mac(eth_src), eth_type)) ip_header_len, ip_header, ip_payload = parse_ip(eth_data) print("IP: {} --> {} ({:04x})".format( format_ip(ip_header['source']), format_ip(ip_header['destination']), ip_header['protocol'])) if ip_header['protocol'] == 0x11: # UDP src_port, dst_port, _, udp_data, _ = parse_udp(ip_payload) print("UDP: :{} --> :{}".format( src_port, dst_port)) elif ip_header['protocol'] == 0x06: # TCP src_port, dst_port, seqn, ackn, flags, tcp_data = parse_tcp( ip_payload) print("TCP: :{} --> :{} / SEQ:{} ACK:{} ({:#02x})".format( src_port, dst_port, seqn, ackn, flags)) if eth_src == mac_1: eth_dst = mac_2 s.sendto(eth_dst + eth_src + eth_type + eth_data, ip_header['destination']) print("Forwarded to {}".format(mac_2)) elif eth_src == mac_2: eth_dst = mac_1 s.sendto(eth_dst + eth_src + eth_type + eth_data, ip_header['destination']) print("Forwarded to {}".format(mac_1)) print() if __name__ == "__main__": main()