From 1c43c26d5c87df722141ad6a37f068968a9a6b5b Mon Sep 17 00:00:00 2001 From: Denys Fedoryshchenko Date: Sun, 12 Jul 2026 23:11:39 +0300 Subject: ipv6cp: fix byte order of default interface-id values The default fixed interface-ids conf_intf_id_val=1 and conf_peer_intf_id_val=2 were plain host-order integers, while every consumer (build_ip6_addr(), ifcfg.c, nd.c, dhcpv6.c) treats intf_id as an opaque 8-byte value in network byte order and copies it verbatim into the low 64 bits of the IPv6 address. parse_intfid() also produces network byte order, so only the built-in defaults were affected. On little-endian hosts this produced fe80::100:0:0:0 (and ::200:0:0:0 for the peer) instead of the intended fe80::1 / ::2 whenever ipv6-intf-id / ipv6-peer-intf-id were not set in the config. Store the defaults with htobe64() so the resulting addresses are ::1 and ::2 regardless of host endianness. The assignment is done in init() because htobe64() is not a constant expression on all libcs. Note: on little-endian deployments this changes the server link-local address from fe80::100:0:0:0 to fe80::1 when ipv6-intf-id is unset. --- accel-pppd/ppp/ipv6cp_opt_intfid.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/accel-pppd/ppp/ipv6cp_opt_intfid.c b/accel-pppd/ppp/ipv6cp_opt_intfid.c index fff74160..cb33f024 100644 --- a/accel-pppd/ppp/ipv6cp_opt_intfid.c +++ b/accel-pppd/ppp/ipv6cp_opt_intfid.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -25,9 +26,16 @@ static int conf_check_exists; static int conf_intf_id = INTF_ID_FIXED; -static uint64_t conf_intf_id_val = 1; +/* Fixed intf-id values are stored in network byte order: the rest of + * the code (build_ip6_addr(), ifcfg.c, nd.c, ...) copies them into the + * low 8 bytes of the IPv6 address as-is, and parse_intfid() already + * produces network byte order. The old host-order defaults (1 and 2) + * therefore yielded ::100:0:0:0 / ::200:0:0:0 instead of ::1 / ::2 on + * little-endian hosts. Defaults are assigned in init() because + * htobe64() is not a constant expression on all libcs (e.g. musl). */ +static uint64_t conf_intf_id_val; static int conf_peer_intf_id = INTF_ID_FIXED; -static uint64_t conf_peer_intf_id_val = 2; +static uint64_t conf_peer_intf_id_val; static int conf_accept_peer_intf_id; static struct ipv6cp_option_t *ipaddr_init(struct ppp_ipv6cp_t *ipv6cp); @@ -354,6 +362,11 @@ static void load_config(void) static void init() { + /* network byte order, so the resulting addresses are ::1 and ::2 + * regardless of host endianness */ + conf_intf_id_val = htobe64(1); + conf_peer_intf_id_val = htobe64(2); + if (sock6_fd < 0) return; -- cgit v1.2.3 From efa4cea1beec1fa758ac94f350dfa7bdfa6d472f Mon Sep 17 00:00:00 2001 From: Denys Fedoryshchenko Date: Sun, 12 Jul 2026 23:12:03 +0300 Subject: ipdb: fix undefined shift in build_ip6_addr() host-bits mask For prefix lengths 65..127 the mask for the host bits was built with (1 << (128 - prefix_len)) - 1 using a plain int literal, which is undefined behavior for shift counts of 31 and above, i.e. for any prefix length from 65 to 97. Use a 64-bit constant for the shift. --- accel-pppd/ipdb.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/accel-pppd/ipdb.c b/accel-pppd/ipdb.c index dd8c61c9..8fc08063 100644 --- a/accel-pppd/ipdb.c +++ b/accel-pppd/ipdb.c @@ -83,7 +83,10 @@ void __export build_ip6_addr(struct ipv6db_addr_t *a, uint64_t intf_id, struct i if (a->prefix_len <= 64) *(uint64_t *)(addr->s6_addr + 8) = intf_id; else - *(uint64_t *)(addr->s6_addr + 8) |= intf_id & htobe64((1 << (128 - a->prefix_len)) - 1); + /* prefix_len 65..127 means a shift of up to 63 bits: a plain + * int literal 1 is undefined behavior for shifts >= 31, so the + * host bits mask must be built from a 64-bit constant */ + *(uint64_t *)(addr->s6_addr + 8) |= intf_id & htobe64((UINT64_C(1) << (128 - a->prefix_len)) - 1); } -- cgit v1.2.3