Skip to content

Conversation

miri64
Copy link
Member

@miri64 miri64 commented Feb 19, 2018

Contribution description

When implementing ICMPv6 for GNRC I also added build and send functions for ICMPv6 error messages, but I never actually used them while implementing IPv6. Reviewing that sub-module I found it quite buggy:

  • Packets in receive order were assumed in send order
  • Packets were sent out without an IP header attached
  • Packets were just sent to the PID of the IP thread instead of searching the registry
  • etc.

This PR fixes those issues. Additionally a call of the send functions is added were appropriate, so GNRC is now able to correctly (but optionally) report to a sender what went wrong. To prevent further degeneration of that module, I activated it for gnrc_networking (but also some tests might be nice, which is why I set the WIP label, though the tests can also come as a follow-up IMHO).

Testing procedures

I tested this using examples/gnrc_networking and scapy. If you get problems receiving you might need to merge #10356 first. The tests are required to be executed in order as commands previously executed in other tests might be a precondition:

  1. Compile and start gnrc_networking (make sure gnrc_icmpv6_error is included; should be automatically as per this PR) for native
    make -C examples/gnrc_networking all term
  2. Get the link-local IPv6 address and hardware address of the native instance:
    > ifconfig
    Iface  6  HWaddr: 36:54:72:4F:8B:1F 
              MTU:1500  HL:64  RTR  
              RTR_ADV  
              Source address length: 6
              Link type: wired
              inet6 addr: fe80::3454:72ff:fe4f:8b1f  scope: local  VAL
              inet6 group: ff02::2
              inet6 group: ff02::1
              inet6 group: ff02::1:ff4f:8b1f
              inet6 group: ff02::1a
              
              Statistics for Layer 2
                RX packets 32  bytes 6964
                TX packets 28 (Multicast: 6)  bytes 6980
                TX succeeded 28 errors 0
              Statistics for IPv6
                RX packets 32  bytes 6516
                TX packets 28 (Multicast: 6)  bytes 6588
                TX succeeded 28 errors 0
    
  3. Get the link-local IPv6 address of your TAP interface/bridge
  4. Start scapy with root privileges (required to send ethernet frames)
  5. Set some variables:
    DST_ADDR = "<native link-local IPv6 address>"
    DST_HWADDR = "<native hardware address>"
    SRC_ADDR = "<TAP interface link-local IPv6 address>"
  6. Test UDP "port unreachable" error:
    1. Port not registered:
      scapy:
      p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst=DST_ADDR, src=SRC_ADDR) / UDP(),
                iface="tapbr0")
      assert(ICMPv6DestUnreach in p)
      assert(p[ICMPv6DestUnreach].code == 4) # Port unreachable
    2. Port registered:
      RIOT:
      udp server start 1337
      scapy:
      p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst=DST_ADDR, src=SRC_ADDR) / UDP(dport=1337),
                iface="tapbr0", timeout=1)
      assert(p == None)
  7. Check if large packets are carried correctly:
    # 1452 = 1500 (Ethernet payload length) - 40 (IPv6 header size) - 8 (UDP header size)
    p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst=DST_ADDR, src=SRC_ADDR) / UDP() / (1452 * "x"),
                   iface="tapbr0")
    assert(ICMPv6DestUnreach in p)
    assert(p[ICMPv6DestUnreach].code == 4) # Port unreachable
    assert(len(p[Raw]) < 1452)
  8. Test "address unreachable" (local address):
    p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst="fe80::1", src=SRC_ADDR) / UDP(), iface="tapbr0", timeout=1)
    assert(ICMPv6DestUnreach in p)
    assert(p[ICMPv6DestUnreach].code == 3) # Address unreachable
  9. Test "beyond scope of source address":
    p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst="affe::1", src=SRC_ADDR) / UDP(), iface="tapbr0", timeout=1)
    assert(ICMPv6DestUnreach in p)
    assert(p[ICMPv6DestUnreach].code == 2) # Beyond scope of source address
  10. Test "erroneous header field encountered":
    p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst=DST_ADDR, src=SRC_ADDR, plen=20) / UDP(),
                   iface="tapbr0")
    assert(ICMPv6ParamProblem in p)
    assert(p[ICMPv6ParamProblem].code == 0) # erroneous header field encountered
    assert(p[ICMPv6ParamProblem].ptr == 4)  # IPv6 length field
  11. Test "No route to destination"
    Linux: Configure route to native instance and set a global source address:
    sudo ip a a beef::1 dev tapbr0
    sudo ip r a affe::/64 via "<native link-local IPv6 address>" dev tapbr0
    RIOT: Configure route back to Linux:
    nib route add 6 beef::/64 "<TAP interface link-local IPv6 address>"
    
    scapy:
    p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst="affe::1", src="beef::1") / UDP(), iface="tapbr0")
    assert(ICMPv6DestUnreach in p)
    assert(p[ICMPv6DestUnreach].code == 0) # No route to destination
  12. Test "Address unreachable" (neighboring node):
    RIOT: Configure route to bogus neighbor:
    nib route add 6 affe::/64 fe80::1
    
    scapy:
    sendp(Ether(dst=DST_HWADDR) / IPv6(dst="affe::1", src="beef::1") / UDP(), iface="tapbr0")
    # srp1 would not return, for some reason
    # just check with wireshark or a second `scapy` instance using
    ps = sniff(iface="tapbr0", count=20)
    p = [p for p in ps if ICMPv6DestUnreach in p]
    assert(len(p) == 1)
    assert(p[0][ICMPv6DestUnreach].code == 3) # Address unreachable
  13. Test "Hop limit exceeded in transit"
    p = srp1(Ether(dst=DST_HWADDR) / IPv6(dst="affe::1", src="beef::1", hlim=1) / UDP(), iface="tapbr0")
    assert(ICMPv6TimeExceeded in p)
    assert(p[ICMPv6TimeExceeded].code == 0) # Hop limit exceeded in transit

Issues/PRs references

None

@miri64 miri64 added Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation Area: network Area: Networking GNRC labels Feb 19, 2018
@miri64 miri64 requested a review from bergzand February 19, 2018 09:04
@miri64
Copy link
Member Author

miri64 commented Feb 19, 2018

(for now I was mostly using scapy to test)

@tcschmidt
Copy link
Member

@bergzand this looks like a simple bug fix - can you take a look?

@bergzand
Copy link
Member

@bergzand this looks like a simple bug fix - can you take a look?

This is on my todo list and I will review it as soon as I have time. At the moment the +301 -149 lines changed is for me a bit too much to categorize it as a small bug fix and quickly review it.

@tcschmidt
Copy link
Member

Good. Seems important for RIOT to get such homework done - otherwise bugs accumulate ;)

@miri64
Copy link
Member Author

miri64 commented Oct 24, 2018

@bergzand do you have time now? I already accidentally opened a somewhat duplicate in #10225 and since error messages are also somewhat important for Extension Header handling, this should be tackled with the scope of that project (though it doesn't really belong into it).

@miri64 miri64 force-pushed the gnrc_icmpv6_error/enh/use-icmpv6-error branch from 3df8284 to a264cd6 Compare November 9, 2018 13:20
@miri64
Copy link
Member Author

miri64 commented Nov 9, 2018

Rebased and adapted for master (also did some extensive testing with scapy I will post in a minute).

@miri64
Copy link
Member Author

miri64 commented Nov 9, 2018

Updated testing procedures.

@miri64
Copy link
Member Author

miri64 commented Nov 9, 2018

I also was able to solicit a "Packet too big" error now. I used the gnrc_border_router on samr21-xpro for that (it needs the gnrc_icmpv6_error module to be included manually for now). Then I configured a route to a bogus neighbor to the WPAN interface:

nib route add 6 2001:db8::1/128 fe80::ab:cd

And injected a huge packet to that neighbor into the ethos TAP using scapy:

p = srp1(Ether() / IPv6(dst="2001:db8::1") / UDP(sport=1337, dport=1337) / (1452 * "x"), iface="tap0")
assert(ICMPv6PacketTooBig in p)

@miri64
Copy link
Member Author

miri64 commented Nov 9, 2018

We should put these tests somewhere btw. I'd say release specs, as soon as this is merged and the current release is out.

@miri64
Copy link
Member Author

miri64 commented Nov 9, 2018

(Note to self Packet too big just as before, but with a socket_zep interface on native:

sudo ip a a beef::1/64 dev tapbr0
sudo ip r a affe::/64 via "<native link-local IPv6 address>" dev tapbr0
GNRC_NETIF_NUMOF=2 USEMODULE=socket_zep TERMFLAGS="-z [::]:17755 tap0" \
    make -C examples/gnrc_networking clean all term
nib route add 7 beef::/64 "<TAP interface link-local IPv6 address>"
nib route add 8 affe::/64 fe80::1
p = srp1(Ether(dst=DST_HWADDR) / IPv6(src="beef::1", dst="affe::1") / UDP() / (1452 * "x"), iface="tapbr0")
assert(ICMPv6PacketTooBig in p)
assert(p[ICMPv6PacketTooBig].code == 0)
assert(p[ICMPv6PacketTooBig].mtu < 1500)

@miri64 miri64 added the CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR label Nov 9, 2018
@miri64 miri64 force-pushed the gnrc_icmpv6_error/enh/use-icmpv6-error branch from a264cd6 to fbd7714 Compare November 13, 2018 10:33
@miri64
Copy link
Member Author

miri64 commented Nov 13, 2018

Rebased to current master to include fixes from #10356.

miri64 added a commit to miri64/RIOT that referenced this pull request Nov 13, 2018
miri64 added a commit to miri64/RIOT that referenced this pull request Nov 13, 2018
@miri64 miri64 mentioned this pull request Nov 13, 2018
3 tasks
@miri64 miri64 force-pushed the gnrc_icmpv6_error/enh/use-icmpv6-error branch from fbd7714 to 626eaf9 Compare November 14, 2018 15:46
@miri64
Copy link
Member Author

miri64 commented Nov 14, 2018

As discussed offline I split the huge monolitic commit up in several smaller ones to trace my steps

miri64 added a commit to miri64/RIOT that referenced this pull request Nov 14, 2018
@miri64 miri64 force-pushed the gnrc_icmpv6_error/enh/use-icmpv6-error branch from 1aa55b6 to 897e688 Compare November 16, 2018 16:39
@miri64
Copy link
Member Author

miri64 commented Nov 16, 2018

Squashed

@bergzand
Copy link
Member

Enabling USEMODULE += gnrc_icmpv6_error adds 720B of additional flash usage on a samr21-xpro on the gnrc_networking example.

Copy link
Member

@bergzand bergzand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK

Tested with the testing instructions. All responses look good to me, nothing out of the ordinary, responses are properly truncated when copying the full frame would exceed the MTU.

@bergzand
Copy link
Member

For the record, I have no issues with the relative large amount of commits :)

@miri64
Copy link
Member Author

miri64 commented Nov 16, 2018

Enabling USEMODULE += gnrc_icmpv6_error adds 720B of additional flash usage on a samr21-xpro on the gnrc_networking example.

For the record, I have no issues with the relative large amount of commits :)

Given that it adds (optional) functionality I think that is acceptable.

@miri64 miri64 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Nov 16, 2018
@bergzand
Copy link
Member

Given that it adds (optional) functionality I think that is acceptable.

Agreed, I've always understood that the examples should showcase the functionality and I'd say that this one is good to have enabled by default.

@miri64 miri64 added CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR and removed CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR labels Nov 16, 2018
@miri64 miri64 merged commit 3b1a7d0 into RIOT-OS:master Nov 16, 2018
@miri64 miri64 deleted the gnrc_icmpv6_error/enh/use-icmpv6-error branch November 16, 2018 19:12
@aabadie aabadie added this to the Release 2019.01 milestone Dec 2, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: network Area: Networking CI: ready for build If set, CI server will compile all applications for all available boards for the labeled PR Process: API change Integration Process: PR contains or issue proposes an API change. Should be handled with care. Type: bug The issue reports a bug / The PR fixes a bug (including spelling errors) Type: enhancement The issue suggests enhanceable parts / The PR enhances parts of the codebase / documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants