class ICMPPacket: def __init__(self, wan_int, packet): self.packet = packet self.wan_int = wan_int self.Checksum = Checksums() def Create(self): self.AssignValues() self.CreateICMP() self.AssembleICMP() self.CreateIPv4() self.AssembleIPv4() self.ip_chk = self.Checksum.IPv4(self.ipv4_header) self.icmp_chk = self.Checksum.ICMP(self.icmp_header + self.icmp_payload) def AssignValues(self): self.l2pro = 0x0800 Int = Interface() self.smac = Int.MAC(self.wan_int) self.dmac = self.packet.src_mac self.src_ip = Int.IP(self.wan_int) self.dst_ip = self.packet.src_ip self.icmp_payload = self.packet.ipv4_header + self.packet.udp_header def AssembleEthernet(self): self.ethernet_header = struct.pack( '!6s6sH', binascii.unhexlify(self.dmac.replace(":", "")), binascii.unhexlify(self.smac.replace(":", "")), self.l2pro) def CreateIPv4(self): ip_ver = 4 ip_vhl = 5 self.ip_ver = (ip_ver << 4) + ip_vhl ip_dsc = 0 ip_ecn = 0 self.ip_dfc = (ip_dsc << 2) + ip_ecn self.ip_tol = 20 + len( self.icmp_payload + self.icmp_header) # +8 for original udp header self.ip_idf = 0 ip_rsv = 0 ip_dtf = 0 ip_mrf = 0 ip_frag_offset = 0 self.ip_flg = (ip_rsv << 7) + (ip_dtf << 6) + (ip_mrf << 5) + ( ip_frag_offset) self.ip_ttl = 255 self.ip_proto = ICMP self.ip_chk = 0 self.ip_saddr = inet_aton(self.src_ip) self.ip_daddr = inet_aton(self.dst_ip) def AssembleIPv4(self): self.ipv4_header = struct.pack('!BBHHHBB', self.ip_ver, self.ip_dfc, self.ip_tol, self.ip_idf, self.ip_flg, self.ip_ttl, self.ip_proto) self.ipv4_header += struct.pack('<H', self.ip_chk) self.ipv4_header += struct.pack('!4s4s', self.ip_saddr, self.ip_daddr) def CreateICMP(self): self.icmp_type = 3 self.icmp_code = 3 self.icmp_chk = 0 self.icmp_id = 1 self.icmp_seq = 0 self.padding = 0 def AssembleICMP(self): self.icmp_header = struct.pack('!2B', self.icmp_type, self.icmp_code) self.icmp_header += struct.pack('<H', self.icmp_chk) self.icmp_header += struct.pack( '!2H', self.icmp_id, self.icmp_seq, )
class TCPPacket: def __init__(self, wan_int, packet): self.packet = packet self.wan_int = wan_int self.Checksum = Checksums() def Create(self): self.AssignValues() self.CreateIPv4() self.CreateTCP() self.AssembleIPv4() self.AssembleTCP() self.ipv4_checksum = self.Checksum.IPv4(self.ipv4_header) self.tcp_checksum = self.PseudoHeader() def AssignValues(self): self.l2pro = 0x0800 Int = Interface() self.smac = Int.MAC(self.wan_int) self.dmac = self.packet.src_mac self.src_ip = Int.IP(self.wan_int) self.dst_ip = self.packet.src_ip self.src_port = self.packet.dst_port self.dst_port = self.packet.src_port self.sport = struct.pack('!H', self.src_port) # print(self.packet.seq_number) self.ack_number = self.packet.seq_number + 1 ## -- L2 - Ethernet Section ---- ## def AssembleEthernet(self): self.ethernet_header = struct.pack( '!6s6sH', binascii.unhexlify(self.dmac.replace(':', '')), binascii.unhexlify(self.smac.replace(':', '')), self.l2pro) ## -- L3 - IP Section ---- ## def CreateIPv4(self): ip_ver = 4 ip_vhl = 5 self.ip_ver = (ip_ver << 4) + ip_vhl ip_dsc = 0 ip_ecn = 0 self.ip_dfc = (ip_dsc << 2) + ip_ecn self.ip_tol = 20 + 20 # ---- [ Total Length] self.ip_idf = 1 # ---- [ Identification ] ip_rsv = 0 # ---- [ Flags ] ip_dtf = 0 ip_mrf = 0 ip_frag_offset = 0 self.ip_flg = (ip_rsv << 7) + (ip_dtf << 6) + (ip_mrf << 5) + ( ip_frag_offset) self.ip_ttl = 255 # ---- [ Total Length ] self.ip_proto = TCP # ---- [ Protocol ] self.ipv4_checksum = 0 # ---- [ Check Sum ] self.ip_saddr = inet_aton(self.src_ip) # ---- [ Source Address ] self.ip_daddr = inet_aton(self.dst_ip) # ---- [ Destination Address ] def AssembleIPv4(self): self.ipv4_header = struct.pack( '!2B3H2B', self.ip_ver, # IP Version self.ip_dfc, # Differentiate Service Field self.ip_tol, # Total Length self.ip_idf, # Identification self.ip_flg, # Flags self.ip_ttl, # Time to leave self.ip_proto # protocol ) self.ipv4_header += struct.pack( '<H', self.ipv4_checksum # Checksum ) self.ipv4_header += struct.pack( '!4s4s', self.ip_saddr, # Source IP self.ip_daddr # Destination IP ) ## -- L4 - UDP Section ---- ## def CreateTCP(self): self.tcp_seq = 0 self.tcp_ack_seq = self.ack_number self.tcp_hdr_len = 80 tcp_urg = 0 tcp_ack = 1 tcp_psh = 0 tcp_rst = 1 tcp_syn = 0 tcp_fin = 0 tcp_doff = 5 self.tcp_offset_res = (tcp_doff << 4) + 0 self.tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + ( tcp_psh << 3) + (tcp_ack << 4) + (tcp_urg << 5) self.tcp_wdw = htons(0) self.tcp_checksum = 0 self.tcp_urg_ptr = 0 self.padding = b'\x00' * 12 def AssembleTCP(self): self.tcp_header = struct.pack('!2H2L2B3H', self.src_port, self.dst_port, self.tcp_seq, self.tcp_ack_seq, self.tcp_offset_res, self.tcp_flags, self.tcp_wdw, self.tcp_checksum, self.tcp_urg_ptr) def PseudoHeader(self): pseudo_header = b'' pseudo_header += inet_aton(self.src_ip) pseudo_header += inet_aton(self.dst_ip) pseudo_header += struct.pack('!2BH', 0, 6, 54) pseudo_header += self.sport + self.tcp_header[ 2:16] + b'\x00\x00' + self.tcp_header[18:] tcp_checksum = self.Checksum.TCP(pseudo_header) return tcp_checksum
class Packet: def __init__(self, response_ip, query_type): self.response_ip = response_ip self.query_type = query_type self.response_code = 0 self.answer_count = 0 self.dns_payload = b'' self.Checksum = Checksums() def CreateHeaders(self): self.CreateDNS() self.CreateUDP() self.CreateIPv4() self.AssembleIPv4() self.ip_chk = self.Checksum.IPv4(self.ipv4_header) def Assemble(self): self.AssembleEthernet() self.AssembleIPv4() self.AssembleUDP() self.AssembleDNS() dns_response = self.ethernet_header + self.ipv4_header + self.udp_header dns_response += self.dns_header + self.dns_payload return dns_response def BuildPayload(self): self.BuildQuery() # if AAAA record will set response code to refuse and not give an answer if (self.query_type == AAAA_RECORD): self.response_code = 5 # if local dns record returns none due to error, will inform client of error elif (not self.response_ip): self.response_code = 2 print('SERVER FAILURE') # standard query response from remote server or for local dns record else: self.answer_count = 1 self.BuildQueryResponse() def SplitPacket(self, packet): self.dst_mac = packet.src_mac self.src_mac = packet.dst_mac self.src_ip = packet.dst_ip self.dst_ip = packet.src_ip self.src_port = DNS_PORT self.dst_port = packet.src_port self.dns_id = packet.dns_id self.qname = packet.request self.l2pro = 0x0800 def AssembleEthernet(self): self.ethernet_header = struct.pack( '!6s6sH', binascii.unhexlify(self.dst_mac.replace(':', '')), binascii.unhexlify(self.src_mac.replace(':', '')), self.l2pro) def CreateIPv4(self): ip_ver = 4 ip_vhl = 5 self.ip_ver = (ip_ver << 4) + ip_vhl ip_dsc = 0 ip_ecn = 0 self.ip_dfc = (ip_dsc << 2) + ip_ecn self.ip_tol = 20 + self.udp_length self.ip_idf = 0 ip_rsv = 0 ip_dtf = 0 ip_mrf = 0 ip_frag_offset = 0 self.ip_flg = (ip_rsv << 7) + (ip_dtf << 6) + (ip_mrf << 5) + ( ip_frag_offset) self.ip_ttl = 255 self.ip_proto = IPPROTO_UDP self.ip_chk = 0 self.ip_saddr = inet_aton(self.src_ip) self.ip_daddr = inet_aton(self.dst_ip) def AssembleIPv4(self): self.ipv4_header = struct.pack('!2B3H2B', self.ip_ver, self.ip_dfc, self.ip_tol, self.ip_idf, self.ip_flg, self.ip_ttl, self.ip_proto) self.ipv4_header += struct.pack('<H', self.ip_chk) self.ipv4_header += struct.pack('!4s4s', self.ip_saddr, self.ip_daddr) def CreateUDP(self): self.udp_length = self.dns_length + 8 self.udp_chk = 0 def AssembleUDP(self): self.udp_header = struct.pack('!4H', self.src_port, self.dst_port, self.udp_length, self.udp_chk) def CreateDNS(self): self.id = self.dns_id self.qr = 1 self.opcode = 0 self.aa = 0 self.tc = 0 self.rd = 1 self.ra = 1 self.z = 0 self.rcode = self.response_code self.qdcount = 1 self.ancount = self.answer_count self.nscount = 0 self.arcount = 0 self.dns_length = 12 + len(self.dns_payload) def AssembleDNS(self): self.p1 = (self.qr << 7) | (self.opcode << 3) | (self.aa << 2) | ( self.tc << 1) | (self.rd << 0) self.p2 = (self.ra << 7) | (self.z << 4) | (self.rcode << 0) self.dns_header = struct.pack('!H2B4H', self.id, self.p1, self.p2, self.qdcount, self.ancount, self.nscount, self.arcount) def BuildQuery(self): self.qclass = 1 split_url = self.qname.split('.') for part in split_url: self.dns_payload += struct.pack('B', len(part)) for char in part: self.dns_payload += struct.pack('B', ord(char)) self.dns_payload += b'\x00' self.dns_payload += struct.pack('!2H', self.query_type, self.qclass) def BuildQueryResponse(self): # assigning vars self.rrname = b'\xc0\x0c' self.type = self.query_type self.rclass = 1 self.ttl = 300 self.rdlen = 4 self.rdata = inet_aton(self.response_ip) #packing vars self.dns_payload += struct.pack('!2s2HLH4s', self.rrname, self.type, self.rclass, self.ttl, self.rdlen, self.rdata)
class Packet: def __init__(self, response_ip, packet): self.response_ip = response_ip self.packet = packet self.Checksum = Checksums() self.dns_payload = b'' def Start(self): self.SplitPacket() self.CreateQueryResponse() self.CreateDNS() self.CreateUDP() self.CreateIPv4() self.AssembleIPv4() self.ip_chk = self.Checksum.IPv4(self.ipv4_header) def SplitPacket(self): self.smac = self.packet.smac self.dmac = self.packet.dmac self.dst_ip = self.packet.src self.src_ip = self.packet.dst self.src_port = DNS self.dst_port = self.packet.sport self.dnsID = self.packet.dnsID self.url = self.packet.qname.lower() self.l2pro = 0x0800 def AssembleEthernet(self): self.ethernet_header = struct.pack( '!6s6sH', binascii.unhexlify(self.smac.replace(":", "")), binascii.unhexlify(self.dmac.replace(":", "")), self.l2pro) def CreateIPv4(self): ip_ver = 4 ip_vhl = 5 self.ip_ver = (ip_ver << 4) + ip_vhl ip_dsc = 0 ip_ecn = 0 self.ip_dfc = (ip_dsc << 2) + ip_ecn self.ip_tol = 20 + self.udp_len self.ip_idf = 0 ip_rsv = 0 ip_dtf = 0 ip_mrf = 0 ip_frag_offset = 0 self.ip_flg = (ip_rsv << 7) + (ip_dtf << 6) + (ip_mrf << 5) + ( ip_frag_offset) self.ip_ttl = 255 self.ip_proto = IPPROTO_UDP self.ip_chk = 0 self.ip_saddr = inet_aton(self.src_ip) self.ip_daddr = inet_aton(self.dst_ip) def AssembleIPv4(self): self.ipv4_header = struct.pack('!2B3H2B', self.ip_ver, self.ip_dfc, self.ip_tol, self.ip_idf, self.ip_flg, self.ip_ttl, self.ip_proto) self.ipv4_header += struct.pack('<H', self.ip_chk) self.ipv4_header += struct.pack('!4s4s', self.ip_saddr, self.ip_daddr) def CreateUDP(self): self.udp_sport = DNS self.udp_dport = self.dst_port self.udp_len = self.dnsL + 8 + 6 self.udp_chk = 0 def AssembleUDP(self): self.udp_header = struct.pack('!4H', self.udp_sport, self.udp_dport, self.udp_len, self.udp_chk) def CreateDNS(self): self.id = self.dnsID self.qr = 1 self.opcode = 0 self.aa = 0 self.tc = 0 self.rd = 1 self.ra = 1 self.z = 0 self.ad = 0 self.cd = 0 self.rcode = 0 self.qdcount = 1 self.ancount = 1 self.nscount = 0 self.arcount = 0 self.dnsL = self.dnsRL + 12 def AssembleDNS(self): self.p1 = (self.qr << 7) | (self.opcode << 3) | (self.aa << 2) | ( self.tc << 1) | (self.rd << 0) self.p2 = (self.ra << 7) | (self.z << 6) | (self.ad << 5) | ( self.cd << 4) | (self.rcode << 0) self.dns_header = struct.pack('!H2B4H', self.id, self.p1, self.p2, self.qdcount, self.ancount, self.nscount, self.arcount) def CreateQueryResponse(self): self.qname = self.url self.qtype = 1 self.qclass = 1 self.rrname = b'\xc0\x0c' self.type = 1 self.rclass = 1 self.ttl = 300 self.rdlen = 4 self.rdata = inet_aton(self.response_ip) self.urlTTL = len(self.url) * 2 self.dnsRL = self.urlTTL + 14 + 2 def AssembleQueryResponse(self): split_url = self.url.split('.') for part in split_url: self.dns_payload += struct.pack('B', len(part)) for char in part: self.dns_payload += struct.pack('B', ord(char)) self.dns_payload += b'\x00' self.dns_payload += struct.pack('!2H', self.qtype, self.qclass) self.dns_payload += self.dns_payload self.dns_payload += struct.pack('!LH4s', self.ttl, self.rdlen, self.rdata)
class PacketManipulation: def __init__(self, packet_headers, net_info, data, connection, from_server): self.Checksum = Checksums() self.packet_headers = packet_headers self.dst_mac, self.wan_subnet = net_info self.data = data self.connection = connection self.from_server = from_server self.tcp_header_length = 0 self.dst_ip = None self.nat_port = None self.payload = b'' if (from_server): self.src_mac = connection['LAN']['MAC'] self.src_ip = connection['Server']['IP'] self.dst_ip = connection['Client']['IP'] self.client_port = connection['Client']['Port'] self.client_port = struct.pack('!H', connection['Client']['Port']) else: self.src_mac = connection['NAT']['MAC'] self.src_ip = connection['NAT']['IP'] self.nat_port = connection['NAT']['Port'] self.nat_port = struct.pack('!H', self.nat_port) self.dst_ip = self.packet_headers.dst self.dst_port = self.data[36:38] def Start(self): self.CheckDestination() self.TCP() self.PsuedoHeader() self.RebuildHeaders() def CheckDestination(self): if (self.dst_ip in self.wan_subnet): Int = Interface() dst_mac = Int.IPtoMAC(self.dst_ip) if (not dst_mac): run(f'ping {self.dst_ip} -c 1', shell=True) self.dst_mac = Int.IPtoMAC(self.dst_ip) else: self.dst_mac = dst_mac ''' Parsing TCP information like sequence and acknowledgement number amd calculated tcp header length to be used by other classes for offset/proper indexing of packet contents. Returning all relevant information back to HeaderParse Start method to be redistributed to other classes based on need ''' def TCP(self): bit_values = [32, 16, 8, 4] tcp = self.data[34:94] tmp_length = bin(tcp[12])[2:6] for i, bit in enumerate(tmp_length): if (bit == '1'): self.tcp_header_length += bit_values[i] self.tcp_header = self.data[34:34 + self.tcp_header_length] self.tcp_length = len(self.data) - 34 if (len(self.data) > 34 + self.tcp_header_length): self.payload = self.data[34 + self.tcp_header_length:] def PsuedoHeader(self): psuedo_header = b'' psuedo_header += inet_aton(self.src_ip) psuedo_header += inet_aton(self.dst_ip) psuedo_header += struct.pack('!2BH', 0, 6, self.tcp_length) if (self.from_server): psuedo_header += self.tcp_header[ 0:2] + self.client_port + self.tcp_header[ 4:16] + b'\x00\x00' + self.tcp_header[18:] else: psuedo_header += self.nat_port + self.tcp_header[ 2:16] + b'\x00\x00' + self.tcp_header[18:] psuedo_packet = psuedo_header + self.payload tcp_checksum = self.Checksum.TCP(psuedo_packet) self.tcp_checksum = struct.pack('<H', tcp_checksum) def RebuildHeaders(self): ethernet_header = self.RebuildEthernet() ip_header = self.RebuildIP() tcp_header = self.RebuildTCP() self.send_data = ethernet_header + ip_header + tcp_header + self.payload def RebuildEthernet(self): eth_header = struct.pack( '!6s6s', binascii.unhexlify(self.dst_mac.replace(':', '')), binascii.unhexlify(self.src_mac.replace(':', ''))) eth_header += self.packet_headers.eth_proto return eth_header def RebuildIP(self): ipv4_header = b'' ipv4_header += self.packet_headers.ipv4H[:10] ipv4_header += b'\x00\x00' ipv4_header += inet_aton(self.src_ip) ipv4_header += inet_aton(self.dst_ip) if (len(self.packet_headers.ipv4H) > 20): ipv4_header += self.packet_headers.ipv4H[20:] ipv4_checksum = self.Checksum.IPv4(ipv4_header) ipv4_checksum = struct.pack('<H', ipv4_checksum) ipv4_header = ipv4_header[:10] + ipv4_checksum + ipv4_header[12:] return ipv4_header def RebuildTCP(self): if (self.from_server): tcp_header = self.tcp_header[:2] + self.client_port + self.tcp_header[ 4:16] + self.tcp_checksum + b'\x00\x00' else: tcp_header = self.nat_port + self.tcp_header[ 2:16] + self.tcp_checksum + b'\x00\x00' if (self.tcp_header_length > 20): tcp_header += self.tcp_header[20:self.tcp_header_length] return tcp_header
class CreatePacket: def __init__(self, connection, to_server=False): self.connection = connection self.to_server = to_server self.Checksum = Checksums() def Create(self): self.AssignValues() self.CreateIPv4() self.CreateTCP() self.AssembleIPv4() self.AssembleTCP() self.ipv4_checksum = self.Checksum.IPv4(self.ipv4_header) self.tcp_checksum = self.PseudoHeader() def AssignValues(self): self.l2pro = 0x0800 self.nat_port = struct.pack('!H', self.connection['NAT']['Port']) self.client_port = struct.pack('!H', self.connection['Client']['Port']) if (self.to_server): self.smac = self.connection['NAT']['MAC'] self.src_ip = self.connection['NAT']['IP'] self.sport = self.connection['NAT']['Port'] self.dmac = self.connection['DFG']['MAC'] self.dst_ip = self.connection['Server']['IP'] self.dport = self.connection['Server']['Port'] else: self.smac = self.connection['LAN']['MAC'] self.src_ip = self.connection['Server']['IP'] self.sport = self.connection['Server']['Port'] self.dmac = self.connection['Client']['MAC'] self.dst_ip = self.connection['Client']['IP'] self.dport = self.connection['Client']['Port'] ## -- L2 - Ethernet Section ---- ## def AssembleEthernet(self): self.ethernet_header = struct.pack('!6s6sH' , binascii.unhexlify(self.dmac.replace(":","")), binascii.unhexlify(self.smac.replace(":","")), self.l2pro) ## -- L3 - IP Section ---- ## def CreateIPv4(self): ip_ver = 4 ip_vhl = 5 self.ip_ver = (ip_ver << 4 ) + ip_vhl ip_dsc = 0 ip_ecn = 0 self.ip_dfc = (ip_dsc << 2 ) + ip_ecn self.ip_tol = 20 + 20 # ---- [ Total Length] self.ip_idf = 1 # ---- [ Identification ] ip_rsv = 0 # ---- [ Flags ] ip_dtf = 0 ip_mrf = 0 ip_frag_offset = 0 self.ip_flg = (ip_rsv << 7) + (ip_dtf << 6) + (ip_mrf << 5) + (ip_frag_offset) self.ip_ttl = 255 # ---- [ Total Length ] self.ip_proto = IPPROTO_TCP # ---- [ Protocol ] self.ipv4_checksum = 0 # ---- [ Check Sum ] self.ip_saddr = inet_aton(self.src_ip) # ---- [ Source Address ] self.ip_daddr = inet_aton(self.dst_ip) # ---- [ Destination Address ] def AssembleIPv4(self): self.ipv4_header = struct.pack('!2B3H2B' , self.ip_ver, # IP Version self.ip_dfc, # Differentiate Service Field self.ip_tol, # Total Length self.ip_idf, # Identification self.ip_flg, # Flags self.ip_ttl, # Time to leave self.ip_proto # protocol ) self.ipv4_header += struct.pack('<H' , self.ipv4_checksum # Checksum ) self.ipv4_header += struct.pack('!4s4s' , self.ip_saddr, # Source IP self.ip_daddr # Destination IP ) ## -- L4 - UDP Section ---- ## def CreateTCP(self): self.tcp_seq = 696969 self.tcp_ack_seq = 0 self.tcp_hdr_len = 80 tcp_urg = 0 tcp_ack = 0 tcp_psh = 0 tcp_rst = 1 tcp_syn = 0 tcp_fin = 0 tcp_doff = 5 self.tcp_offset_res = (tcp_doff << 4) + 0 self.tcp_flags = tcp_fin + (tcp_syn << 1) + (tcp_rst << 2) + (tcp_psh << 3) + (tcp_ack << 4) + (tcp_urg << 5) self.tcp_wdw = htons(5840) self.tcp_checksum = 0 self.tcp_urg_ptr = 0 self.padding = b'\x00'*12 def AssembleTCP(self): self.tcp_header = struct.pack('!2H2L2B3H', self.sport, self.dport, self.tcp_seq, self.tcp_ack_seq, self.tcp_offset_res, self.tcp_flags, self.tcp_wdw, self.tcp_checksum, self.tcp_urg_ptr ) def PseudoHeader(self): pseudo_header = b'' pseudo_header += inet_aton(self.src_ip) pseudo_header += inet_aton(self.dst_ip) pseudo_header += struct.pack('!2BH', 0, 6, 54) if (self.to_server): pseudo_header += self.nat_port + self.tcp_header[2:16] + b'\x00\x00' + self.tcp_header[18:] else: pseudo_header += self.tcp_header[0:2] + self.client_port + self.tcp_header[4:16] + b'\x00\x00' + self.tcp_header[18:] pseudo_packet = pseudo_header tcp_checksum = self.Checksum.TCP(pseudo_packet) return tcp_checksum