Page MenuHomeFreeBSD

Introduce net.inet6.icmp6.reply_from_interface and net.inet6.icmp6.reply_src sysctls
Needs ReviewPublic

Authored by neel_neelc.org on Jun 7 2020, 11:06 PM.

Details

Reviewers
ae
melifaro
bz
Group Reviewers
manpages
Summary

Introduce net.inet6.icmp6.reply_from_interface and net.inet6.icmp6.reply_src sysctls, which is equivalent to IPv4's net.inet.icmp.reply_from_interface and "net.inet.icmp.reply_src respectively.

Submitted by: Neel Chauhan <neel AT neelc DOT org>
PR: https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=246748

Test Plan

Set up an IPv6 router with multiple interfaces (can be loopback), and set net.inet6.icmp6.reply_from_interface and net.inet6.icmp6.reply_src. You should see the interface the packet went through or specified interface respectively.

Diff Detail

Repository
rS FreeBSD src repository
Lint
Lint Skipped
Unit
Unit Tests Skipped

Event Timeline

neel_neelc.org created this revision.Jun 7 2020, 11:06 PM
neel_neelc.org requested review of this revision.Jun 7 2020, 11:06 PM
neel_neelc.org retitled this revision from Introduce net.inet6.icmp6.reply_from_interface and \"net.inet.icmp.reply_src" sysctls to Introduce net.inet6.icmp6.reply_from_interface and net.inet6.icmp6.reply_src sysctls.Jun 7 2020, 11:09 PM
neel_neelc.org edited the summary of this revision. (Show Details)
neel_neelc.org edited the test plan for this revision. (Show Details)
neel_neelc.org added reviewers: ae, melifaro, bz.
neel_neelc.org added a subscriber: network.

I have tested this, and it "sort of" works.

I have the kernel generate the ICMPv6 packets by means of a pf rule:

block return-icmp6 ( admin-unr ) in quick on em2 inet6

(em2 is the interface where my probe packets are coming in)

and I can see the outgoing packets change source address according to the sysctl, but the "reply_from_interface=1" packets never arrive, as they are sent with hlim=0

This is with "net.inet6.icmp6.reply_from_interface=1", correct source address (em2), but "hlim=0":

11:09:28.488074 00:50:56:9c:ba:fc > 00:c1:64:63:f3:94, ethertype IPv6 (0x86dd), length 122: (hlim 0, next-header ICMPv6 (58) payload length: 68) 2001:67c:158c:20a::139 > 2001:608:0:736::18: [icmp6 sum ok] ICMP6, destination unreachable, unreachable prohibited 2001:608:4:99::1

changing to "net.inet6.icmp6.reply_from_interface=0" -> source address changes to em0 (this is the "normal" result, default route points out em0), but hlim = 64
11:09:33.527294 00:50:56:9c:ba:fc > 00:c1:64:63:f3:94, ethertype IPv6 (0x86dd), length 122: (hlim 64, next-header ICMPv6 (58) payload length: 68) 2001:608:3:3022::177 > 2001:608:0:736::18: [icmp6 sum ok] ICMP6, destination unreachable, unreachable prohibited 2001:608:4:99::1

For testing "net.inet6.icmp6.reply_src" I created a "lo2" interface with 2001:db8::c0:ff:ee/128 on it, and sent probe packets:
11:15:48.953556 00:50:56:9c:ba:fc > 00:c1:64:63:f3:94, ethertype IPv6 (0x86dd), length 122: (hlim 0, next-header ICMPv6 (58) payload length: 68) 2001:db8::c0:ff:ee > 2001:608:0:736::18: [icmp6 sum ok] ICMP6, destination unreachable, unreachable prohibited 2001:608:4:99::1

so, source address is right, but hlim=0 again.

If I read the function right, hlim is always 0 when hitting the "if (srcp == NULL) {" clause, and in the "no icmp6 sysctl" clause, hlim is set by in6_selectsrc_addr(), calling

if (hlim != NULL)
        *hlim = in6_selecthlim(NULL, retifp);

so maybe that's sufficient to add to the two new clauses?

hlim = in6_selecthlim(NULL, ifp);

Good catch! Try this patch with the added "hlim = in6_selecthlim(NULL, ifp);".

Try this now.

Mmmmh. I have patched my kernel, and hlim is set up correctly now (64), and I can nicely see the packets go out:

17:39:28.026301 IP6 (hlim 64, next-header ICMPv6 (58) payload length: 68) 2001:67c:158c:20a::139 > 2001:608:0:736::18: [icmp6 sum ok] ICMP6, destination unreachable,  unreachable prohibited 2001:608:4:99::1

This actually turned up a new issue.

On my first tests, I had manually configured "em2 inet6 ...", there was no config at bootup, and after ifconfig, the link-local address come *second*

em2: flags=8963<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> metric 0 mtu 1500
        inet6 2001:67c:158c:20a::139 prefixlen 124
        inet6 fe80::250:56ff:fe9c:9ea%em2 prefixlen 64 scopeid 0x3

On the next rounds, I had put this into rc.conf ("ipv6_ifconfig_em2=..."), so addresses are configured at bootup. This leads to a different ordering on the addresses, with link-local address *first*:

em2: flags=8863<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
        inet6 fe80::250:56ff:fe9c:9ea%em2 prefixlen 64 scopeid 0x3
        inet6 2001:67c:158c:20a::139 prefixlen 124

and then it totally stops working. No packets are seen in "tcpdump -i em0" - which makes me assume that the code is now picking up the LLA, and something further down decides "nah, we must never send a packet to a global destination with a link-local source" and throws it away.

Whether or not "net.inet6.icmp6.reply_src=lo2" works depends on timing - if you bring it up with an IPv6 GUA ("ifconfig lo2 create inet6...") it works, if you let it configure the LLA first and then add the GUA, it doesn't.

So, the code also needs to check for "is this a source address with proper scope?", I'd say. Maybe in6_selectsrc_addr() can be used? It takes an optional "ifp" argument...

Yeah, the scopes. In the else{} statement we get and check the scopes, but not in the new ones I made. I moved in6_splitscope() earlier so my new statements can use it also.

Try this patch.

With that change, it now works both for the "reply_from_interface=1" and "reply_src=lo2" case for me, with LLAs present and "config at boot".

So from a pure functionality point of view "this works for me".

Whether or not this is the right style to do it, @bz will say :-)

Thansk!

May you be so kind as adding some lines into the man page, too?
Otherwise those are some more of the obscure sysctls, which are even not documented in the source code.

Sure, added the man pages.

markj added a subscriber: markj.Jun 24 2020, 4:33 PM
markj added inline comments.
share/man/man4/icmp6.4
257

This sentence appears incomplete.

sys/netinet6/icmp6.c
2155

Style: there should be no space after the cast. Ditto below.

2163

What if there is no match? Then srcp is left pointing to NULL and we will crash when dereferencing it below.

Sorry for the delay.

I have an updated patch here.

neel_neelc.org marked 2 inline comments as done.Jun 27 2020, 5:29 PM

Generally looks like a nice feature to have.
Would it be possible to add tests validating this behaviour?

sys/netinet6/icmp6.c
132

Would it be possible to name in in a bit more descriptive way?

2152–2188

Any chance this block can be moved to a separate function, to ease reading / testing?

0mp added a subscriber: 0mp.Jun 27 2020, 6:43 PM
0mp added inline comments.
share/man/man4/icmp6.4
249

This patch makes corrections to the man page and variable naming as mentioned by melifaro@ and 0mp@.

No tests are included, but a future revision will include them.

neel_neelc.org marked 3 inline comments as done.Jun 27 2020, 8:46 PM

Generally LGTM, I'd be happy to commit it once there are some tests.

sys/netinet6/icmp6.c
2152–2188

Still, I'm wondering if you can move everything under V_icmp6_replyif into a separate function.

Unfortunately, I was unable to get test cases working. For some reason ICMP does not work in Kyua VNET jails. This is also why the other IPv6 forward/redirect tests fail as well.

This could just be my dev box (AMD Ryzen-based HP "Omen" desktop) running 13-CURRENT.

My (failing test is here: https://gist.github.com/neelchauhan/e830f9cab71f79c81a258b8bdbc295d4

These sysctls do work, when testing via a bhyve VM.

Unfortunately, I was unable to get test cases working. For some reason ICMP does not work in Kyua VNET jails. This is also why the other IPv6 forward/redirect tests fail as well.

Do they fail on your setup?
Can you share the logs of failing forwarding/redirect tests?

This could just be my dev box (AMD Ryzen-based HP "Omen" desktop) running 13-CURRENT.

My (failing test is here: https://gist.github.com/neelchauhan/e830f9cab71f79c81a258b8bdbc295d4

Ipv6 stack on the interface does not become available immediatelt, as the LL addresses have to go through TENTATIVE state. Other tests typically include test&sleep cycle after address assignment to address it.

These sysctls do work, when testing via a bhyve VM.

neel_neelc.org added a comment.EditedJun 28 2020, 8:00 PM

The Kyua log of my failing test is here: https://gist.github.com/neelchauhan/9e1ea12e0872f097294dc1f162b1a513

The failing forward6 log is: https://gist.github.com/neelchauhan/5aa257ddc8957d82c1f0cd27d4337889

The failing redirect6 log is: https://gist.github.com/neelchauhan/dcb0f945db80f66ec70fe6ade5f88dfe

I believe the issue is I am using slaac on my dev box. I'll test after disabling it.

UPDATE: Even disabling slaac meant I can't run the tests, same error.

Sorry for the delay, but I got passing tests! This patch includes them.

It was just that my test logic was originally wrong (the one on the Gist).