Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICMPv6: Recognise ND option 38 (PREF64) #1109

Merged
merged 1 commit into from
Mar 19, 2025

Conversation

bonktree
Copy link
Contributor

@bonktree bonktree commented Dec 8, 2023

This option, defined in RFC 8781, allows a router administrator to pass NAT64 prefix information for the network to end hosts together with other routing and prefix information in the RA message, getting rid of the need for DNS64 service in the network.

As of today the option is widely supported by software routers, including radvd-project/radvd#179, BIRD and systemd/systemd#28565.

We implement the printer and test some valid and broken option contents.

@bonktree bonktree marked this pull request as ready for review December 8, 2023 20:36
@bonktree bonktree force-pushed the pr-print-pref64 branch 2 times, most recently from 9ac9e1a to 43c5b31 Compare March 2, 2025 16:22
@bonktree bonktree force-pushed the pr-print-pref64 branch 2 times, most recently from c8a01a4 to 10e75cb Compare March 13, 2025 08:16
This option, defined in RFC 8781, allows a router administrator to pass
NAT64 prefix information for the network to end hosts together with
other routing and prefix information in the RA message, getting rid
of the need for DNS64 service in the network.

As of today the option is widely supported by software routers,
including radvd, BIRD and systemd-networkd.

We implement the printer and test some valid and broken option contents.
Copy link
Contributor

@fenner fenner left a comment

Choose a reason for hiding this comment

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

Just for a data point of "can this decode the PREF64 attribute in some random network", I captured an RA packet on the ietf-ipv6-mostly network, which is advertising the default 6to4 in the PREF64 field, and it decoded as follows:

09:56:27.552274 IP6 (hlim 255, next-header ICMPv6 (58), payload length 144) fe80::1998:1 > ff02::1: [icmp6 sum ok] ICMP6, router advertisement, length 144
	hop limit 64, Flags [other stateful], pref high, router lifetime 9000s, reachable time 0ms, retrans timer 0ms
	  source link-address option (1), length 8 (1): 00:00:5e:00:02:c6
	  rdnss option (25), length 40 (5):  lifetime 9000s, addr: 2001:67c:370:229::9 addr: 2001:67c:370:229::10
	  prefix info option (3), length 32 (4): 2001:67c:370:1998::/64, Flags [onlink, auto], valid time 2592000s, pref. time 604800s
	  prefix info option (3), length 32 (4): 2001:67c:370:1998::/64, Flags [onlink, auto], valid time 2592000s, pref. time 604800s
	  pref64 option (38), length 16 (2): 64:ff9b::/96 (plc 0), lifetime 18000s

Comment on lines +1572 to +1573
get_pref64_len_repr(w),
w & 0x0007,
Copy link
Contributor

Choose a reason for hiding this comment

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

It feels a little odd to have the w & 0x0007 both inside get_pref64_len_repr() and in the ND_PRINT args. It might be more clear to use a temp variable, maybe named plc, and then pass that to both get_pref64_len_repr() and in the ND_PRINT arg list. Obviously this is pretty minor.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The arg of get_pref64_len_repr() is eventually used to index memory, so IMHO the mask should not be removed from get_pref64_len_repr() anyway; it should be local to the array member access. Otherwise, in the case where the compiler does not inline the call, we would not be far from introducing a gadget to read garbage memory; it would take a single human error. In my view, the resulting code would be harder to maintain.

A temporary variable declaration five screens away, only useful for opt 38, does not address the point above.

One way to reduce repetition would be to abstract "%s/%u (plc %u)" into its own function instead of get_pref64_len_repr():

static void
print_pref64(netdissect_options *ndo, const u_char *in6, size_t w)
{
	static const char *lengths[] = {
		"96", "64", "56", "48", "40", "32"
	};
	const char *plen;
	uint16_t plc = w & 0x0007;

	if (plc < 6)
		plen = lengths[plc];
	else
		plen = "??";
	ND_PRINT("%s/%s (plc %u)",
	         ip6addr_string(ndo, in6),
	         plen, plc);
}

..., and then use it in icmp6_opt_print(). Or, maybe, even print the lifetime in here.
The mask is local to the memory access, so it is hard to make a mistake. We do not have to write w & 0x0007 twice.
That might or might not be easier to read.

Copy link
Contributor

Choose a reason for hiding this comment

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

Sometimes the cure is worse than the disease. While the two masks jumped out at me as unusual, I don't think it's a blocker. Thanks for humoring me.

@fxlb fxlb merged commit 50fd84b into the-tcpdump-group:master Mar 19, 2025
20 checks passed
@fxlb
Copy link
Member

fxlb commented Mar 19, 2025

Thank you!

@bonktree bonktree deleted the pr-print-pref64 branch March 19, 2025 11:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants