networkd: RFC compliant autonomous prefix handling#5636
networkd: RFC compliant autonomous prefix handling#5636poettering merged 1 commit intosystemd:masterfrom
Conversation
|
No, I think this is still wrong. If I understand section 5.5.3.e correctly, an incoming advertisement with preferred lifetime and valid lifetime as zero for a prefix that is already known should:
|
|
Yes, the router sends the first RA after reconnect with: |
|
This bug can be used as a denial-of-service attack. Only this RA is needed to force the network interface of all systemd-networkd nodes in the local network to go into the fail state and then looses all ipv4/6 addresses after they expire. |
|
I have created a simple test suite to validate the correct behavior using My implementation does work as expected. |
src/network/networkd-ndisc.c
Outdated
|
|
||
| /* see RFC4862 section 5.5.3.e */ | ||
| r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address); | ||
| if(r > 0){ |
There was a problem hiding this comment.
See CODING_STYLE: space before ( and after ).
This patch uses 4ch indentation, instead of 8ch, but it is updated in the second patch. It seems that they should be squashed together.
src/network/networkd-ndisc.c
Outdated
|
|
||
| static void ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) { | ||
| _cleanup_address_free_ Address *address = NULL; | ||
| Address *existing_address = NULL; |
src/network/networkd-ndisc.c
Outdated
| else if(existing_address->cinfo.ifa_valid <= NDISC_PREFIX_LFT_MIN) | ||
| address->cinfo.ifa_valid = existing_address->cinfo.ifa_valid; | ||
| else | ||
| address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; |
There was a problem hiding this comment.
So this first branch of the outer if follows the RFC word for word. Looks good.
src/network/networkd-ndisc.c
Outdated
|
|
||
| #define NDISC_DNSSL_MAX 64U | ||
| #define NDISC_RDNSS_MAX 64U | ||
| #define NDISC_PREFIX_LFT_MIN 7200 |
There was a problem hiding this comment.
Please add U like in other constants.
| else if(lifetime_remaining <= NDISC_PREFIX_LFT_MIN) | ||
| address->cinfo.ifa_valid = lifetime_remaining; | ||
| else | ||
| address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; |
There was a problem hiding this comment.
I made a comment here, but it seems github lost it: this follows the RFC very closely, should be correct.
| r = address_get(link, address->family, &address->in_addr, address->prefixlen, &existing_address); | ||
| if(r > 0){ | ||
| if(lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > existing_address->cinfo.ifa_valid) | ||
| address->cinfo.ifa_valid = lifetime_valid; |
There was a problem hiding this comment.
This one is clear and from the RFC. ACK.
src/network/networkd-ndisc.c
Outdated
| if(lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > existing_address->cinfo.ifa_valid) | ||
| address->cinfo.ifa_valid = lifetime_valid; | ||
| else if(existing_address->cinfo.ifa_valid <= NDISC_PREFIX_LFT_MIN) | ||
| address->cinfo.ifa_valid = existing_address->cinfo.ifa_valid; |
There was a problem hiding this comment.
ACK. We don't have secured Router Advertisments so the bottom half of section 5.5.3, part e), 2nd bullet does not apply.
src/network/networkd-ndisc.c
Outdated
| else if(existing_address->cinfo.ifa_valid <= NDISC_PREFIX_LFT_MIN) | ||
| address->cinfo.ifa_valid = existing_address->cinfo.ifa_valid; | ||
| else | ||
| address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; |
src/network/networkd-ndisc.c
Outdated
| else | ||
| address->cinfo.ifa_valid = NDISC_PREFIX_LFT_MIN; | ||
| }else if(lifetime_valid > 0) | ||
| address->cinfo.ifa_valid = lifetime_valid; |
There was a problem hiding this comment.
This happens when r = address_get() < 0, right? Shouldn't this also check if lifetime_valid > NDISC_PREFIX_LFT_MIN like above?
There was a problem hiding this comment.
I thought about this too, and in the end that seems to be the same as bullet 1, i.e. having the address invalidated because remaining lifetime is <= 0. In that case this assignment would be correct. Let's see what @hendrikw01 says.
Thanks for the review!
There was a problem hiding this comment.
lifetime_valid doesn´t need to be 2 hours or longer. That means the router can add a prefix/address with a lifetime of 30 secs and renew it every 10 secs. This behavior is totally fine but a bogus RA can´t force it to invalidate faster. If we got new prefix (address_get() < 0) we can´t decide if this is a legit Prefix or not, so the only option is to assume it is, and if it is the router updates the prefix before it gets invalid.
|
Now, I think I have all issues covered. From my side, it can be merged. |
|
I think you're supposed to squash your fixups, not just push more commits. |
Previously, `lifetime_valid` of a Router Advertisement was not handled the way RFC4862 has specified. In particular: Sections 5.5.3.d and 5.5.3.e
|
Sorry, first time for me to squash something in git. |
Previously,
lifetime_validof a Router Advertisement was not handled the way RFC4862 has specified.In particular: Sections 5.5.3.d and 5.5.3.e
This pull request fixes: #3879 and #5638