Parse three hex IPv4 headers into named fields, print what a filter would read from each, and compute the first-fragment payload as Total Length minus four times IHL — flagging any below a 20-byte minimum.
Parse three hex IPv4 headers into named fields, print what a filter would read from each, and compute the first-fragment payload as Total Length minus four times IHL — flagging any below a 20-byte minimum.
Answer
FIELDS = ( ('Version', 4), ('IHL', 4), ('DSCP/ECN', 8), ('Total Length', 16), ('Identification', 16), ('Flags', 3), ('Fragment Offset', 13), ('TTL', 8), ('Protocol', 8), ('Header Checksum', 16), ('Source Address', 32), ('Destination Address', 32), ) MIN_FIRST_FRAGMENT = 20 # bytes: a TCP header with no options def parse(hexs): bits = bin(int(hexs, 16))[2:].zfill(len(hexs) * 4) out, at = {}, 0 for name, w in FIELDS: out[name] = int(bits[at:at + w], 2) at += w return out def dotted(n): return '.'.join(str((n >> s) & 255) for s in (24, 16, 8, 0)) HEADERS = ( ('A', '450005dc1c462000400600 00c0a80738cb007109'), ('B', '450000241c472000400600 00c0a80738cb007109'), ('C', '4600002c1c482000400600 00c0a80738cb00710901010100'), ) print('header bits', sum(w for _, w in FIELDS), '=', sum(w for _, w in FIELDS) // 8, 'bytes') for label, spaced in HEADERS: h = parse(spaced.replace(' ', '')) hdr = 4 * h['IHL'] payload = h['Total Length'] - hdr print(label, dotted(h['Source Address']), '->', dotted(h['Destination Address']), 'proto', h['Protocol'], 'ihl', h['IHL'], 'total', h['Total Length'], 'payload', payload, 'ACCEPT' if payload >= MIN_FIRST_FRAGMENT else 'REJECT')
EXT - RFC 791 section 3.1 (Internet Header Format)