]> git.ozlabs.org Git - ppp.git/commitdiff
ipv6cp: Add support for ipv6cp-use-remotenumber option
authorPali Rohár <pali@kernel.org>
Sat, 31 Jul 2021 15:09:08 +0000 (17:09 +0200)
committerPali Rohár <pali@kernel.org>
Tue, 21 Dec 2021 14:43:56 +0000 (15:43 +0100)
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 <pali@kernel.org>
pppd/ipv6cp.c
pppd/ipv6cp.h
pppd/pppd.8

index decaa6705e6cf335e7271fd55d3a08712bb87736..130819dc6f5256c9e5316e51d0f681f613862f50 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <unistd.h>
 #include <netdb.h>
 #include <sys/param.h>
@@ -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));
index 5e1db6ba510f65d6eb6dae0bb130de5927c0cadc..3ce9df422eb53f3afd542c80fc7c04723b335ccc 100644 (file)
@@ -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 */
index 229bab5520b2716be68ae396d6f6f5f9a5a7a963..1f2b8598954ccd8ea45cf615be8829f48b48b59f 100644 (file)
@@ -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 <local>,<remote>\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