def test__write(self): ts = int(time.time()) expected_time = datetime.fromtimestamp(ts) pkt_sender_mac = '01:02:03:04:05:06' pkt_sender_ip = '192.168.0.1' pkt_target_ip = '192.168.0.2' pkt_target_mac = '00:00:00:00:00:00' eth_src = '02:03:04:05:06:07' eth_dst = 'ff:ff:ff:ff:ff:ff' arp_packet = make_arp_packet(pkt_sender_ip, pkt_sender_mac, pkt_target_ip, pkt_target_mac) arp = ARP(arp_packet, time=ts, src_mac=hex_str_to_bytes(eth_src), dst_mac=hex_str_to_bytes(eth_dst), vid=100) out = io.StringIO() arp.write(out) expected_output = dedent("""\ ARP observed at {expected_time}: 802.1q VLAN ID (VID): 100 (0x064) Ethernet source: {eth_src} Ethernet destination: {eth_dst} Hardware type: 0x0001 Protocol type: 0x0800 Hardware address length: 6 Protocol address length: 4 Operation: 1 (request) Sender hardware address: {pkt_sender_mac} Sender protocol address: {pkt_sender_ip} Target hardware address: {pkt_target_mac} Target protocol address: {pkt_target_ip} """) self.assertThat(out.getvalue().strip(), Equals(expected_output.format(**locals()).strip()))
class ETHERTYPE: """Enumeration to represent ethertypes that MAAS needs to understand.""" IPV4 = hex_str_to_bytes("0800") IPV6 = hex_str_to_bytes("86dd") ARP = hex_str_to_bytes("0806") VLAN = hex_str_to_bytes("8100")
def make_ipv6_packet( payload_length=None, version=None, payload=None, protocol=0x11, truncated=False, ): """Construct an IPv6 packet using the specified parameters.""" if payload is None: payload = b"" if payload_length is None: payload_length = len(payload) if version is None: version = 6 version__traffic_class__flow_label = (version << 28).to_bytes(4, "big") ipv6_packet = ( # Version, traffic class, flow label version__traffic_class__flow_label + # Total length in bytes payload_length.to_bytes(2, "big") + # Next header (default is UDP) protocol.to_bytes(1, "big") + # Hop limit (TTL) hex_str_to_bytes("00") + # Source address hex_str_to_bytes("00000000000000000000000000000000") + # Destination address hex_str_to_bytes("00000000000000000000000000000000")) assert len(ipv6_packet) == 40, "Length was %d" % len(ipv6_packet) if truncated: return ipv6_packet[:19] ipv6_packet = ipv6_packet + payload return ipv6_packet
def make_udp_packet( total_length=None, payload=None, truncated_header=False, truncated_payload=False, ): """Construct an IPv4 packet using the specified parameters. If the specified `vid` is not None, it is interpreted as an integer VID, and the appropriate Ethertype fields are adjusted. """ if payload is None: payload = b"" if total_length is None: total_length = 8 + len(payload) udp_packet = ( # Source port hex_str_to_bytes("0000") + # Destination port hex_str_to_bytes("0000") + # UDP header length + payload length total_length.to_bytes(2, "big") + # Checksum hex_str_to_bytes("0000")) assert len(udp_packet) == 8, "Length was %d" % len(udp_packet) if truncated_header: return udp_packet[:7] udp_packet = udp_packet + payload if truncated_payload: return udp_packet[:-1] return udp_packet
def test__parses_non_vlan(self): src_mac = factory.make_mac_address() dst_mac = factory.make_mac_address() ethertype = ETHERTYPE.ARP payload = factory.make_bytes(48) eth = Ethernet( make_ethernet_packet(dst_mac=dst_mac, src_mac=src_mac, ethertype=ethertype, payload=payload)) self.assertThat(eth.dst_mac, Equals(hex_str_to_bytes(dst_mac))) self.assertThat(eth.src_mac, Equals(hex_str_to_bytes(src_mac))) self.assertThat(eth.ethertype, Equals(ethertype)) self.assertThat(eth.payload, Equals(payload)) self.assertThat(eth.is_valid(), Equals(True))
def test__properties(self): pkt_sender_mac = '01:02:03:04:05:06' pkt_sender_ip = '192.168.0.1' pkt_target_ip = '192.168.0.2' pkt_target_mac = '00:00:00:00:00:00' eth_src = '02:03:04:05:06:07' eth_dst = 'ff:ff:ff:ff:ff:ff' arp_packet = make_arp_packet(pkt_sender_ip, pkt_sender_mac, pkt_target_ip, pkt_target_mac) arp = ARP(arp_packet, src_mac=hex_str_to_bytes(eth_src), dst_mac=hex_str_to_bytes(eth_dst)) self.assertThat(arp.source_eui, Equals(EUI(pkt_sender_mac))) self.assertThat(arp.target_eui, Equals(EUI(pkt_target_mac))) self.assertThat(arp.source_ip, Equals(IPAddress(pkt_sender_ip))) self.assertThat(arp.target_ip, Equals(IPAddress(pkt_target_ip)))
def test__properties(self): pkt_sender_mac = "01:02:03:04:05:06" pkt_sender_ip = "192.168.0.1" pkt_target_ip = "192.168.0.2" pkt_target_mac = "00:00:00:00:00:00" eth_src = "02:03:04:05:06:07" eth_dst = "ff:ff:ff:ff:ff:ff" arp_packet = make_arp_packet(pkt_sender_ip, pkt_sender_mac, pkt_target_ip, pkt_target_mac) arp = ARP( arp_packet, src_mac=hex_str_to_bytes(eth_src), dst_mac=hex_str_to_bytes(eth_dst), ) self.assertThat(arp.source_eui, Equals(EUI(pkt_sender_mac))) self.assertThat(arp.target_eui, Equals(EUI(pkt_target_mac))) self.assertThat(arp.source_ip, Equals(IPAddress(pkt_sender_ip))) self.assertThat(arp.target_ip, Equals(IPAddress(pkt_target_ip)))
def make_ipv4_packet( total_length=None, version=None, ihl=None, payload=None, truncated=False ): """Construct an IPv4 packet using the specified parameters.""" if payload is None: payload = b"" if total_length is None: total_length = 20 + len(payload) if version is None: version = 4 if ihl is None: ihl = 5 version__ihl = ((version << 4) | ihl).to_bytes(1, "big") ipv4_packet = ( # Version, IHL version__ihl + # TOS hex_str_to_bytes("00") + # Total length in bytes total_length.to_bytes(2, "big") + # Identification hex_str_to_bytes("0000") + # Flags, fragment offset hex_str_to_bytes("0000") + # TTL hex_str_to_bytes("00") + # Protocol (just make it UDP for now) hex_str_to_bytes("11") + # Header checksum hex_str_to_bytes("0000") + # Source address hex_str_to_bytes("00000000") + # Destination address hex_str_to_bytes("00000000") # No options. ) assert len(ipv4_packet) == 20, "Length was %d" % len(ipv4_packet) if truncated: return ipv4_packet[:19] ipv4_packet = ipv4_packet + payload return ipv4_packet
def make_ethernet_packet(dst_mac='ff:ff:ff:ff:ff:ff', src_mac='01:02:03:04:05:06', ethertype=ETHERTYPE.ARP, vid=None, payload=b''): """Construct an Ethernet packet using the specified values. If the specified `vid` is not None, it is interpreted as an integer VID, and the appropriate Ethertype fields are adjusted. """ # Basic Ethernet header is (destination, source, ethertype) ethernet_packet = ( hex_str_to_bytes(dst_mac) + hex_str_to_bytes(src_mac) + # If a VID is defined, use the 802.1q Ethertype instead... (hex_str_to_bytes('8100') if vid is not None else ethertype)) if vid is not None: ethernet_packet = ( ethernet_packet + bytes.fromhex("%04x" % vid) + # ... and place the payload Ethertype in the 802.1q header. ethertype) ethernet_packet = ethernet_packet + payload return ethernet_packet
def make_arp_packet(sender_ip, sender_mac, target_ip, target_mac='00:00:00:00:00:00', op=ARP_OPERATION.REQUEST, hardware_type='0x0001', protocol='0x0800', hardware_length='0x06', protocol_length='0x04'): # Concatenate a byte string with the specified values. # For ARP format, see: https://tools.ietf.org/html/rfc826 arp_packet = (hex_str_to_bytes(hardware_type) + hex_str_to_bytes(protocol) + hex_str_to_bytes(hardware_length) + hex_str_to_bytes(protocol_length) + ARP_OPERATION(op) + hex_str_to_bytes(sender_mac) + ipv4_to_bytes(sender_ip) + hex_str_to_bytes(target_mac) + ipv4_to_bytes(target_ip)) return arp_packet
class ETHERTYPE: """Enumeration to represent ethertypes that MAAS needs to understand.""" IPV4 = hex_str_to_bytes('0800') IPV6 = hex_str_to_bytes('86dd') ARP = hex_str_to_bytes('0806') VLAN = hex_str_to_bytes('8100')