def test_ipv6_ext_frag_send_full_pktbuf(child, s, iface, ll_dst): length = pktbuf_size(child) # remove some slack for meta-data and header and 1 addition fragment header length -= (len(IPv6() / IPv6ExtHdrFragment() / UDP()) + (len(IPv6() / IPv6ExtHdrFragment())) + 96) port = s.getsockname()[1] # trigger neighbor discovery so it doesn't fill the packet buffer udp_send(child, ll_dst, port, 1) data, _ = s.recvfrom(1) last_nd = time.time() count = 0 while True: if (time.time() - last_nd) > 5: # trigger neighbor discovery so it doesn't fill the packet buffer udp_send(child, ll_dst, port, 1) data, _ = s.recvfrom(1) last_nd = time.time() udp_send(child, ll_dst, port, length) count += 1 try: data, _ = s.recvfrom(length) except socket.timeout: # 8 is the alignment unit of the packet buffer # and 20 the size of a packet snip, so take next multiple of 8 to # 28 length -= 24 else: break finally: pktbuf_empty(child) assert (count > 1)
def assertFragmented(packet, pcap, count=1, size=None, reassemble_to=None): assertHasLayer(IPv6ExtHdrFragment, packet, "expected packet to have a IPv6 Fragment Extension header") assertEqual(0x00, packet[IPv6ExtHdrFragment].offset, "expected packet to be the first fragment") fragments = pcap.filter(lambda p: p.haslayer(IPv6ExtHdrFragment) and p[ IPv6ExtHdrFragment].id == packet[IPv6ExtHdrFragment].id) assertGreaterThanOrEqualTo( count, len(fragments), "expected to receive at least %d fragments, got %d" % (count, len(fragments))) assertEqual( 1, len(filter(lambda p: p[IPv6ExtHdrFragment].m == False, fragments)), "expected a single fragment to have the More Fragments flag set to False" ) if not size == None: for fragment in fragments: assertLessThanOrEqualTo( size, len(fragment), "expected all fragments to be no larger than %d octets, got one of %d" % (size, len(fragment))) if not reassemble_to == None: reassembled_size = len(packet) - len(IPv6ExtHdrFragment()) for fragment in fragments: if fragment[IPv6ExtHdrFragment].offset != 0x00: reassembled_size += len(fragment[IPv6ExtHdrFragment].payload) assertEqual( reassemble_to, reassembled_size, "expected fragments to reassemble to %d, got %d" % (reassemble_to, reassembled_size))
def test_empty_mixed2_w_rt_hdr_registered(child, iface, hw_dst, ll_dst, ll_src): # Register to routing header register_protnum(child, EXT_HDR_NH[IPv6ExtHdrRouting]) # Try sending a packet with a number of extension headers in not recommended # (but legal) order sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / IPv6ExtHdrHopByHop() / IPv6ExtHdrRouting() / IPv6ExtHdrDestOpt() / IPv6ExtHdrFragment() / UDP() / "\x01\x02", iface=iface, verbose=0) # Routing header with payload child.expect(r"~~ SNIP 0 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len = int(child.match.group(1)) # NH = IPv6ExtHdrDestOpt, len = 0x00, routing type = 0, segments left = 0 # NH = IPv6ExtHdrFragment, len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000000 {:02X} 00 00 00 00 00 00 00 " r"{:02X} 00 01 04 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrDestOpt], EXT_HDR_NH[IPv6ExtHdrFragment])) # NH = 17 (UDP), reserved = 0x00, fragment offset = 0, res = 0, M = 0 child.expect(r"00000010 11 00 00 00 00 00 00 00") # Hop-by-hop-option child.expect(r"~~ SNIP 1 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len += int(child.match.group(1)) # NH = IPv6ExtHdrRouting, len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000000 {:02X} 00 01 04 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrRouting])) # IPv6 header child.expect(r"~~ SNIP 2 - size:\s+40 byte, type: NETTYPE_IPV6 \(\d+\)") child.expect_exact(r"length: {} next header: {}".format( ipv6_payload_len, EXT_HDR_NH[IPv6ExtHdrHopByHop])) child.expect_exact(r"destination address: {}".format(ll_dst)) pktbuf_empty(child) unregister(child)
def test_reass_offset_too_large(child, iface, hw_dst, ll_dst, ll_src): size = pktbuf_size(child) sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / IPv6ExtHdrFragment(offset=((size * 2) // 8)) / "x" * 128, iface=iface, verbose=0) pktbuf_empty(child)
def test_ipv6_ext_frag_fwd_too_big(child, s, iface, ll_dst): mock_id, mtu, dst_mac = _fwd_setup(child, ll_dst, "beef::1", "affe::1") assert(get_host_mtu(iface) > mtu) payload_fit = get_host_mtu(iface) - len(IPv6() / IPv6ExtHdrFragment() / UDP()) pkt = srp1(Ether(dst=dst_mac) / IPv6(src="beef::1", dst="affe::1") / IPv6ExtHdrFragment(m=True, id=0x477384a9) / UDP(sport=1337, dport=1337) / ("x" * payload_fit), timeout=2, verbose=0, iface=iface) # packet should not be fragmented further but an ICMPv6 error should be # returned instead assert(pkt is not None) assert(ICMPv6PacketTooBig in pkt) assert(IPv6ExtHdrFragment in pkt) assert(pkt[IPv6ExtHdrFragment].id == 0x477384a9) _fwd_teardown(child, mock_id)
def test_empty_fragment_header_wo_register(child, iface, hw_dst, ll_dst, ll_src): # Try sending an empty fragment header sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / IPv6ExtHdrFragment() / UDP(), iface=iface, verbose=0) pktbuf_empty(child)
def pad(packet, n, include_header=False, fragment=True): """ Adds n bytes of padding to packet. If include_header is set to True, n defines the total length of the resultant packet. """ if include_header: n -= len(packet) if fragment and packet.haslayer(IPv6ExtHdrFragment): n += len(IPv6ExtHdrFragment()) return packet / Raw(load=n * 'A')
def test_ipv6_ext_frag_fwd_success(child, s, iface, ll_dst): mtu, dst_mac = _fwd_setup(child, ll_dst, "beef::1", "affe::1") payload_fit = mtu - len(IPv6() / IPv6ExtHdrFragment() / UDP()) pkt = Ether(dst=dst_mac) / IPv6(src="beef::1", dst="affe::1") / \ IPv6ExtHdrFragment(m=True, id=0x477384a9) / \ UDP(sport=1337, dport=1337) / ("x" * payload_fit) # fill missing fields pkt = Ether(raw(pkt)) sendp(pkt, verbose=0, iface=iface) # check hexdump of mock device ipv6 = pkt[IPv6] ipv6.hlim -= 1 # the packet will have passed a hop # segment packet as GNRC does segments = [bytes(ipv6)[:40], bytes(ipv6.payload)] for seg in segments: addr = 0 for i in range(0, len(seg), 16): bs = seg[i:i + 16] exp_str = ("{:08X}" + (" {:02X}") * len(bs)).format(addr, *bs) child.expect_exact(exp_str) addr += 16 _fwd_teardown(child)
def test_ipv6_ext_frag_send_last_fragment_filled(child, s, iface, ll_dst): # every fragment has an IPv6 header and a fragmentation header so subtract # them mtu = get_host_mtu(iface) - len(IPv6() / IPv6ExtHdrFragment()) # first fragment has UDP header (so subtract it) and is rounded down to # the nearest multiple of 8 length = (mtu - len(UDP())) & 0xfff8 # second fragment fills the whole available MTU length += mtu port = s.getsockname()[1] udp_send(child, ll_dst, port, length) data, _ = s.recvfrom(length) assert len(data) == length pktbuf_empty(child)
def craft(hdr, fl): snd = [] rcv = {} for fl in range(fl, fl+nbrFlux): Utils.set_fl(hdr, fl) sip = 'fc00:2:0:1::1' # Adresses don't rlly matter dip = 'fc00:2:0:2::1' packets_snd = fragment6(IPv6(src=sip, dst=dip) / IPv6ExtHdrFragment() / ICMPv6EchoRequest(data='A'*300), 100) packets_snd = [pkt.__class__(str(hdr/pkt)) for pkt in packets_snd[:-1]] # remove last frag snd.extend(packets_snd) rcv = {} return (snd, rcv)
def test_empty_fragment_header_w_register(child, iface, hw_dst, ll_dst, ll_src): # Register to fragment header register_protnum(child, EXT_HDR_NH[IPv6ExtHdrFragment]) # Try sending an empty fragment header sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / IPv6ExtHdrFragment() / UDP() / "\x01\x02", iface=iface, verbose=0) child.expect(r"~~ SNIP 0 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len = int(child.match.group(1)) # NH = 17 (UDP), reserved = 0x00, fragment offset = 0, res = 0, M = 0 child.expect(r"00000000 11 00 00 00 00 00 00 00") child.expect(r"~~ SNIP 1 - size:\s+40 byte, type: NETTYPE_IPV6 \(\d+\)") child.expect_exact(r"length: {} next header: {}".format( ipv6_payload_len, EXT_HDR_NH[IPv6ExtHdrFragment])) child.expect_exact(r"destination address: {}".format(ll_dst)) pktbuf_empty(child) unregister(child)
def craft(hdr, fl): snd = [] rcv = {} for fl in range(fl, fl+nbrFlux): Utils.set_fl(hdr, fl) sip = 'fc00:2:0:1::1' # Adresses don't rlly matter dip = 'fc00:2:0:2::1' packets_snd = fragment6(IPv6(src=sip, dst=dip) / IPv6ExtHdrFragment() / ICMPv6EchoRequest(data='A'*300), 100) packets_snd = [pkt.__class__(str(hdr/pkt)) for pkt in packets_snd] packet_excepted = pkt.__class__(str(hdr/IPv6(src=sip, dst=dip) / ICMPv6EchoRequest(data='A'*300))) snd.extend(packets_snd) random.shuffle(snd) # shuffle rcv[fl] = [packet_excepted] return (snd, rcv)
def test_empty_mixed1_w_dest_opt_registered(child, iface, hw_dst, ll_dst, ll_src): # Register to destination-option header register_protnum(child, EXT_HDR_NH[IPv6ExtHdrDestOpt]) # Try sending a packet with a number of extension headers in recommended # order: https://tools.ietf.org/html/rfc8200#section-4.1 sendp(Ether(dst=hw_dst) / IPv6(dst=ll_dst, src=ll_src) / IPv6ExtHdrHopByHop() / IPv6ExtHdrDestOpt() / IPv6ExtHdrRouting() / IPv6ExtHdrFragment() / IPv6ExtHdrDestOpt() / UDP() / "\x01\x02", iface=iface, verbose=0) # IPv6ExtHdrDestOpt is two times in the packet so pktdump will it print two # times # 1st print parsed up to the first IPv6ExtHdrDestOpt # Destination option 1 with payload child.expect(r"~~ SNIP 0 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len = int(child.match.group(1)) # NH = IPv6ExtHdrRouting, len = 0x00, PadN option (0x01) of length 0x04 # NH = IPv6ExtHdrFragment, len = 0x00, routing type = 0, segments left = 0 child.expect(r"00000000 {:02X} 00 01 04 00 00 00 00 " r"{:02X} 00 00 00 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrRouting], EXT_HDR_NH[IPv6ExtHdrFragment])) # NH = IPv6ExtHdrDestOpt, reserved = 0x00, fragment offset = 0, res = 0, M = 0 # NH = 17 (UDP), len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000010 {:02X} 00 00 00 00 00 00 00 " r"11 00 01 04 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrDestOpt])) # Hop-by-hop option child.expect(r"~~ SNIP 1 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len += int(child.match.group(1)) # NH = IPv6ExtHdrDestOpt, len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000000 {:02X} 00 01 04 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrDestOpt])) # IPv6 header child.expect(r"~~ SNIP 2 - size:\s+40 byte, type: NETTYPE_IPV6 \(\d+\)") child.expect_exact(r"length: {} next header: {}".format( ipv6_payload_len, EXT_HDR_NH[IPv6ExtHdrHopByHop])) child.expect_exact(r"destination address: {}".format(ll_dst)) # 2nd print parsed up to the second IPv6ExtHdrHopByHop # Destination option 2 with payload child.expect(r"~~ SNIP 0 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len = int(child.match.group(1)) # NH = 17 (UDP), len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000000 11 00 01 04 00 00 00 00") # Fragment header child.expect(r"~~ SNIP 1 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len += int(child.match.group(1)) # NH = IPv6ExtHdrDestOpt, reserved = 0x00, fragment offset = 0, res = 0, M = 0 child.expect(r"00000000 {:02X} 00 00 00 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrDestOpt])) # Routing header child.expect(r"~~ SNIP 2 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len += int(child.match.group(1)) # NH = IPv6ExtHdrFragment, len = 0x00, routing type = 0, segments left = 0 child.expect(r"00000000 {:02X} 00 00 00 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrFragment])) # Destination option 1 child.expect(r"~~ SNIP 3 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len += int(child.match.group(1)) # NH = IPv6ExtHdrRouting, len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000000 {:02X} 00 01 04 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrRouting])) # Hop-by-hop option child.expect(r"~~ SNIP 4 - size:\s+(\d+) byte, type: NETTYPE_\w+ \(\d+\)") ipv6_payload_len += int(child.match.group(1)) # NH = IPv6ExtHdrDestOpt, len = 0x00, PadN option (0x01) of length 0x04 child.expect(r"00000000 {:02X} 00 01 04 00 00 00 00".format( EXT_HDR_NH[IPv6ExtHdrDestOpt])) # IPv6 header child.expect(r"~~ SNIP 5 - size:\s+40 byte, type: NETTYPE_IPV6 \(\d+\)") child.expect_exact(r"length: {} next header: {}".format( ipv6_payload_len, EXT_HDR_NH[IPv6ExtHdrHopByHop])) child.expect_exact(r"destination address: {}".format(ll_dst)) pktbuf_empty(child) unregister(child)