From 1e79371ec6feb288d4f72b1380332009cfa3dc0f Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Fri, 26 Feb 2021 14:47:59 +0100 Subject: [PATCH] ipv6cp: Add support for ipv6cp-noremote option MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- pppd/ipv6cp.c | 19 ++++++++++++++----- pppd/pppd.8 | 13 +++++++++++++ pppd/sys-linux.c | 16 +++++++++++++++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/pppd/ipv6cp.c b/pppd/ipv6cp.c index cef1e38..6059c76 100644 --- a/pppd/ipv6cp.c +++ b/pppd/ipv6cp.c @@ -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); diff --git a/pppd/pppd.8 b/pppd/pppd.8 index b31594a..f70e053 100644 --- a/pppd/pppd.8 +++ b/pppd/pppd.8 @@ -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). diff --git a/pppd/sys-linux.c b/pppd/sys-linux.c index 1e00366..49abe2c 100644 --- a/pppd/sys-linux.c +++ b/pppd/sys-linux.c @@ -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. -- 2.39.2