]> git.ozlabs.org Git - ppp.git/commitdiff
ipv6cp: Add support for ipv6cp-noremote option
authorPali Rohár <pali@kernel.org>
Fri, 26 Feb 2021 13:47:59 +0000 (14:47 +0100)
committerPali Rohár <pali@kernel.org>
Tue, 21 Dec 2021 14:43:56 +0000 (15:43 +0100)
With this option pppd is allowed to operate without having an IPv6 link
local address for the peer, like noremoteip option for IPv4.

This option is only available under Linux, like noremoteip option.

Signed-off-by: Pali Rohár <pali@kernel.org>
pppd/ipv6cp.c
pppd/pppd.8
pppd/sys-linux.c

index cef1e389d0e117a0da012a56c7e7f003d0455e11..6059c764ca49745220c0a3ad8a39631a37f45aaa 100644 (file)
@@ -179,6 +179,7 @@ int no_ifaceid_neg = 0;
 /* local vars */
 static int default_route_set[NUM_PPP];         /* Have set up a default route */
 static int ipv6cp_is_up;
+static bool ipv6cp_noremote;
 
 /* Hook for a plugin to know when IPv6 protocol has come up */
 void (*ipv6_up_hook)(void) = NULL;
@@ -263,6 +264,11 @@ static option_t ipv6cp_option_list[] = {
     { "ipv6cp-use-persistent", o_bool, &ipv6cp_wantoptions[0].use_persistent,
       "Use uniquely-available persistent value for link local address", 1 },
 
+#ifdef __linux__
+    { "ipv6cp-noremote", o_bool, &ipv6cp_noremote,
+      "Allow peer to have no interface identifier", 1 },
+#endif
+
     { "ipv6cp-restart", o_int, &ipv6cp_fsm[0].timeouttime,
       "Set timeout for IPv6CP", OPT_PRIO },
     { "ipv6cp-max-terminate", o_int, &ipv6cp_fsm[0].maxtermtransmits,
@@ -1170,7 +1176,7 @@ ipv6_demand_conf(int u)
 {
     ipv6cp_options *wo = &ipv6cp_wantoptions[u];
 
-    if (eui64_iszero(wo->hisid)) {
+    if (eui64_iszero(wo->hisid) && !ipv6cp_noremote) {
        /* make up an arbitrary identifier for the peer */
        eui64_magic_nz(wo->hisid);
     }
@@ -1194,7 +1200,8 @@ ipv6_demand_conf(int u)
            default_route_set[u] = 1;
 
     notice("local  LL address %s", llv6_ntoa(wo->ourid));
-    notice("remote LL address %s", llv6_ntoa(wo->hisid));
+    if (!eui64_iszero(wo->hisid))
+       notice("remote LL address %s", llv6_ntoa(wo->hisid));
 
     return 1;
 }
@@ -1227,7 +1234,7 @@ ipv6cp_up(fsm *f)
        ho->hisid = wo->hisid;
 
     if(!no_ifaceid_neg) {
-       if (eui64_iszero(ho->hisid)) {
+       if (eui64_iszero(ho->hisid) && !ipv6cp_noremote) {
            error("Could not determine remote LL address");
            ipv6cp_close(f->unit, "Could not determine remote LL address");
            return;
@@ -1244,7 +1251,8 @@ ipv6cp_up(fsm *f)
        }
     }
     script_setenv("LLLOCAL", llv6_ntoa(go->ourid), 0);
-    script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
+    if (!eui64_iszero(ho->hisid))
+        script_setenv("LLREMOTE", llv6_ntoa(ho->hisid), 0);
 
 #ifdef IPV6CP_COMP
     /* set tcp compression */
@@ -1306,7 +1314,8 @@ ipv6cp_up(fsm *f)
                default_route_set[f->unit] = 1;
 
        notice("local  LL address %s", llv6_ntoa(go->ourid));
-       notice("remote LL address %s", llv6_ntoa(ho->hisid));
+       if (!eui64_iszero(ho->hisid))
+           notice("remote LL address %s", llv6_ntoa(ho->hisid));
     }
 
     np_up(f->unit, PPP_IPV6);
index b31594ac3be8b97b5b67cacd02ae55328a37ccbf..f70e05389c29ff89ae0635d8d8d80c66bdbfb997 100644 (file)
@@ -536,6 +536,19 @@ With this option, pppd will accept the peer's idea of its (remote)
 IPv6 interface identifier, even if the remote IPv6 interface
 identifier was specified in an option.
 .TP
+.B ipv6cp\-noremote
+Allow pppd to operate without having an IPv6 link local address for the peer.
+This option is only available under Linux.  Normally, pppd will request the
+peer's IPv6 interface identifier (used for composing IPv6 link local address),
+and if the peer does not supply it, pppd will generate one for the peer.
+With this option, if the peer does not supply its IPv6 interface identifier,
+pppd will not ask the peer for it, and will not set the destination IPv6
+link local address of the ppp interface.  In this situation, the ppp interface
+can be used for routing by creating device routes, but the peer itself cannot
+be addressed directly for IPv6 traffic until the peer starts announcing ICMPv6
+Router Advertisement or ICMPv6 Neighbor Advertisement packets.  Note that IPv6
+router must announce ICMPv6 Router Advertisement packets.
+.TP
 .B ipv6cp\-max\-configure \fIn
 Set the maximum number of IPv6CP configure-request transmissions to
 \fIn\fR (default 10).
index 1e00366ba2914f5c1fba36fabd98e17edecaef72..49abe2c599e630b3c47eeccedef57242781fd589 100644 (file)
@@ -2941,7 +2941,19 @@ static int sif6addr_rtnetlink(unsigned int iface, eui64_t our_eui64, eui64_t his
     IN6_LLADDR_FROM_EUI64(nlreq.addrs[0].addr, our_eui64);
     nlreq.addrs[1].rta.rta_len = sizeof(nlreq.addrs[1]);
     nlreq.addrs[1].rta.rta_type = IFA_ADDRESS;
-    IN6_LLADDR_FROM_EUI64(nlreq.addrs[1].addr, his_eui64);
+
+    /*
+     * To set only local address, older kernel expects that local address is
+     * in IFA_ADDRESS field (not IFA_LOCAL). New kernels with support for peer
+     * address, ignore IFA_ADDRESS if is same as IFA_LOCAL. So for backward
+     * compatibility when setting only local address, set it via both IFA_LOCAL
+     * and IFA_ADDRESS fields. Same logic is implemented in 'ip address' command
+     * from iproute2 project.
+     */
+    if (!eui64_iszero(his_eui64))
+        IN6_LLADDR_FROM_EUI64(nlreq.addrs[1].addr, his_eui64);
+    else
+        IN6_LLADDR_FROM_EUI64(nlreq.addrs[1].addr, our_eui64);
 
     memset(&nladdr, 0, sizeof(nladdr));
     nladdr.nl_family = AF_NETLINK;
@@ -3059,7 +3071,9 @@ int sif6addr (int unit, eui64_t our_eui64, eui64_t his_eui64)
             error("sif6addr: ioctl(SIOCSIFADDR): %m (line %d)", __LINE__);
             return 0;
         }
+    }
 
+    if (!ret && !eui64_iszero(his_eui64)) {
         /*
          * Linux kernel does not provide AF_INET6 ioctl SIOCSIFDSTADDR for
          * setting remote peer host address, so set only route to remote host.