From 189bad1c0baeb4fd65ff566d2723b5bc95205a65 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Sat, 31 Jul 2021 17:09:08 +0200 Subject: [PATCH] ipv6cp: Add support for ipv6cp-use-remotenumber option MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This new option cause that pppd would use "remotenumber" option value for negotiating IPv6 remote interface identifier. It is expected that "remotenumber" option in this case is set either to MAC address, IPv4 address, IPv6 address or telephone number (with or without plus sign) of remote peer system. This option is useful for PPPoE connections to generate stable and predicable IPv6 remote interface identifier as "remotenumber" is set by pppoe.so plugin to MAC address of remote ethernet peer. Similarly dial-up connections set "remotenumber" to telephone number of the remote system and VPN-based ppp plugins set "remotenumber" to address of remote peer (in case VPN connection is based on IPv4 transport protocol then address is set to IPv4, if based on IPv6 then remotenumber is IPv6 address). Having stable IPv6 interface identifiers in ipv6cp is really important. Signed-off-by: Pali Rohár --- pppd/ipv6cp.c | 78 +++++++++++++++++++++++++++++++++++++++++---------- pppd/ipv6cp.h | 1 + pppd/pppd.8 | 9 ++++-- 3 files changed, 70 insertions(+), 18 deletions(-) diff --git a/pppd/ipv6cp.c b/pppd/ipv6cp.c index decaa67..130819d 100644 --- a/pppd/ipv6cp.c +++ b/pppd/ipv6cp.c @@ -153,6 +153,7 @@ #include #include #include +#include #include #include #include @@ -259,10 +260,11 @@ static option_t ipv6cp_option_list[] = { &ipv6cp_wantoptions[0].default_route }, { "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip, - "Use (default) IPv4 address as interface identifier", 1 }, - + "Use (default) IPv4 addresses for both local and remote interface identifiers", 1 }, { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent, - "Use uniquely-available persistent value for link local address", 1 }, + "Use uniquely-available persistent value for local interface identifier", 1 }, + { "ipv6cp-use-remotenumber", o_bool, &ipv6cp_wantoptions[0].use_remotenumber, + "Use remotenumber value for remote interface identifier", 1 }, #ifdef __linux__ { "ipv6cp-noremote", o_bool, &ipv6cp_noremote, @@ -1082,6 +1084,23 @@ endswitch: } +/* + * eui48_to_eui64 - Convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1] + */ +static void +eui48_to_eui64(eui64_t *p_eui64, const u_char addr[6]) +{ + p_eui64->e8[0] = addr[0] | 0x02; + p_eui64->e8[1] = addr[1]; + p_eui64->e8[2] = addr[2]; + p_eui64->e8[3] = 0xFF; + p_eui64->e8[4] = 0xFE; + p_eui64->e8[5] = addr[3]; + p_eui64->e8[6] = addr[4]; + p_eui64->e8[7] = addr[5]; +} + + /* * ether_to_eui64 - Convert 48-bit Ethernet address into 64-bit EUI * @@ -1101,18 +1120,7 @@ ether_to_eui64(eui64_t *p_eui64) return 0; } - /* - * And convert the EUI-48 into EUI-64, per RFC 2472 [sec 4.1] - */ - p_eui64->e8[0] = addr[0] | 0x02; - p_eui64->e8[1] = addr[1]; - p_eui64->e8[2] = addr[2]; - p_eui64->e8[3] = 0xFF; - p_eui64->e8[4] = 0xFE; - p_eui64->e8[5] = addr[3]; - p_eui64->e8[6] = addr[4]; - p_eui64->e8[7] = addr[5]; - + eui48_to_eui64(p_eui64, addr); return 1; } @@ -1149,6 +1157,46 @@ ipv6_check_options(void) } } + if (!wo->opt_remote && wo->use_remotenumber && *remote_number) { + /* remote number can be either MAC address, IPv4 address, IPv6 address or telephone number */ + struct in_addr addr; + struct in6_addr addr6; + unsigned long long tel; + unsigned char mac[6]; + const char *str; + char *endptr; + if (sscanf(remote_number, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", + &mac[0], &mac[1], &mac[2], + &mac[3], &mac[4], &mac[5]) == 6) { + eui48_to_eui64(&wo->hisid, mac); + } else if (inet_pton(AF_INET, remote_number, &addr) == 1) { + eui64_setlo32(wo->hisid, ntohl(addr.s_addr)); + } else if (inet_pton(AF_INET6, remote_number, &addr6) == 1) { + /* use low 64 bits of IPv6 address for interface identifier */ + wo->hisid.e8[0] = addr6.s6_addr[8]; + wo->hisid.e8[1] = addr6.s6_addr[9]; + wo->hisid.e8[2] = addr6.s6_addr[10]; + wo->hisid.e8[3] = addr6.s6_addr[11]; + wo->hisid.e8[4] = addr6.s6_addr[12]; + wo->hisid.e8[5] = addr6.s6_addr[13]; + wo->hisid.e8[6] = addr6.s6_addr[14]; + wo->hisid.e8[7] = addr6.s6_addr[15]; + } else { + str = remote_number; + /* telephone number may start with leading '+' sign, so skip it */ + if (str[0] == '+') + str++; + errno = 0; + tel = strtoull(str, &endptr, 10); + if (!errno && *str && !*endptr && tel) { + wo->hisid.e32[0] = htonl(tel >> 32); + wo->hisid.e32[1] = htonl(tel & 0xFFFFFFFF); + } + } + if (!eui64_iszero(wo->hisid)) + wo->opt_remote = 1; + } + if (!wo->opt_local) { /* init interface identifier */ if (wo->use_ip && eui64_iszero(wo->ourid)) { eui64_setlo32(wo->ourid, ntohl(ipcp_wantoptions[0].ouraddr)); diff --git a/pppd/ipv6cp.h b/pppd/ipv6cp.h index 5e1db6b..3ce9df4 100644 --- a/pppd/ipv6cp.h +++ b/pppd/ipv6cp.h @@ -156,6 +156,7 @@ typedef struct ipv6cp_options { int opt_remote; /* histoken set by option */ int use_ip; /* use IP as interface identifier */ int use_persistent; /* use uniquely persistent value for address */ + int use_remotenumber; /* use remote number value for address */ int neg_vj; /* Van Jacobson Compression? */ u_short vj_protocol; /* protocol value to use in VJ option */ eui64_t ourid, hisid; /* Interface identifiers */ diff --git a/pppd/pppd.8 b/pppd/pppd.8 index 229bab5..1f2b859 100644 --- a/pppd/pppd.8 +++ b/pppd/pppd.8 @@ -212,11 +212,14 @@ Set the local and/or remote 64-bit interface identifier. Either one may be omitted. The identifier must be specified in standard ASCII notation of IPv6 addresses (e.g. ::dead:beef). If the \fIipv6cp\-use\-ipaddr\fR -option is given, the local identifier is the local IPv4 address (see above). +option is given, the local identifier is the local IPv4 address and the +remote identifier is the remote IPv4 address (see above). +If the \fIipv6cp-use-remotenumber\fR option is given, the remote identifier +is set to the value from \fIremotenumber\fR option. On systems which supports a unique persistent id, such as EUI\-48 derived from the Ethernet MAC address, \fIipv6cp\-use\-persistent\fR option can be -used to replace the \fIipv6 ,\fR option. Otherwise the -identifier is randomized. +used to set local identifier. Otherwise both local and remote identifiers +are randomized. .TP .B active\-filter \fIfilter\-expression Specifies a packet filter to be applied to data packets to determine -- 2.39.2