Skip to content

Commit

Permalink
pppd: Add defaultroute6 and related options
Browse files Browse the repository at this point in the history
Which behave like IPv4's defaultroute etc.

Signed-off-by: Samuel Thibault <samuel.thibault@ens-lyon.org>
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
  • Loading branch information
sthibaul authored and paulusmack committed Oct 19, 2019
1 parent 66ce4ba commit 388597e
Show file tree
Hide file tree
Showing 6 changed files with 310 additions and 0 deletions.
26 changes: 26 additions & 0 deletions pppd/ipv6cp.c
Expand Up @@ -177,6 +177,7 @@ ipv6cp_options ipv6cp_hisoptions[NUM_PPP]; /* Options that we ack'd */
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;

/* Hook for a plugin to know when IPv6 protocol has come up */
Expand Down Expand Up @@ -245,6 +246,15 @@ static option_t ipv6cp_option_list[] = {
{ "ipv6cp-accept-local", o_bool, &ipv6cp_allowoptions[0].accept_local,
"Accept peer's interface identifier for us", 1 },

{ "defaultroute6", o_bool, &ipv6cp_wantoptions[0].default_route,
"Add default IPv6 route", OPT_ENABLE|1, &ipv6cp_allowoptions[0].default_route },
{ "nodefaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route,
"disable defaultroute6 option", OPT_A2CLR,
&ipv6cp_wantoptions[0].default_route },
{ "-defaultroute6", o_bool, &ipv6cp_allowoptions[0].default_route,
"disable defaultroute6 option", OPT_ALIAS | OPT_A2CLR,
&ipv6cp_wantoptions[0].default_route },

{ "ipv6cp-use-ipaddr", o_bool, &ipv6cp_allowoptions[0].use_ip,
"Use (default) IPv4 address as interface identifier", 1 },

Expand Down Expand Up @@ -443,6 +453,10 @@ ipv6cp_init(unit)
wo->vj_protocol = IPV6CP_COMP;
#endif

/*
* XXX This controls whether the user may use the defaultroute option.
*/
ao->default_route = 1;
}


Expand Down Expand Up @@ -1151,6 +1165,9 @@ ipv6_demand_conf(u)
#endif
if (!sifnpmode(u, PPP_IPV6, NPMODE_QUEUE))
return 0;
if (wo->default_route)
if (sif6defaultroute(u, wo->ourid, wo->hisid))
default_route_set[u] = 1;

notice("ipv6_demand_conf");
notice("local LL address %s", llv6_ntoa(wo->ourid));
Expand Down Expand Up @@ -1230,6 +1247,10 @@ ipv6cp_up(f)
return;
}

/* assign a default route through the interface if required */
if (ipv6cp_wantoptions[f->unit].default_route)
if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
default_route_set[f->unit] = 1;
}
demand_rexmit(PPP_IPV6);
sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);
Expand All @@ -1251,6 +1272,11 @@ ipv6cp_up(f)
}
sifnpmode(f->unit, PPP_IPV6, NPMODE_PASS);

/* assign a default route through the interface if required */
if (ipv6cp_wantoptions[f->unit].default_route)
if (sif6defaultroute(f->unit, go->ourid, ho->hisid))
default_route_set[f->unit] = 1;

notice("local LL address %s", llv6_ntoa(go->ourid));
notice("remote LL address %s", llv6_ntoa(ho->hisid));
}
Expand Down
1 change: 1 addition & 0 deletions pppd/ipv6cp.h
Expand Up @@ -150,6 +150,7 @@
typedef struct ipv6cp_options {
int neg_ifaceid; /* Negotiate interface identifier? */
int req_ifaceid; /* Ask peer to send interface identifier? */
int default_route; /* Assign default route through interface? */
int accept_local; /* accept peer's value for iface id? */
int opt_local; /* ourtoken set by option */
int opt_remote; /* histoken set by option */
Expand Down
11 changes: 11 additions & 0 deletions pppd/pppd.8
Expand Up @@ -127,6 +127,12 @@ is no other default route with the same metric. With the default
value of -1, the route is only added if there is no default route at
all.
.TP
.B defaultroute6
Add a default IPv6 route to the system routing tables, using the peer as
the gateway, when IPv6CP negotiation is successfully completed.
This entry is removed when the PPP connection is broken. This option
is privileged if the \fInodefaultroute6\fR option has been specified.
.TP
.B disconnect \fIscript
Execute the command specified by \fIscript\fR, by passing it to a
shell, after
Expand Down Expand Up @@ -743,6 +749,11 @@ Disable the \fIdefaultroute\fR option. The system administrator who
wishes to prevent users from creating default routes with pppd
can do so by placing this option in the /etc/ppp/options file.
.TP
.B nodefaultroute6
Disable the \fIdefaultroute6\fR option. The system administrator who
wishes to prevent users from adding a default route with pppd
can do so by placing this option in the /etc/ppp/options file.
.TP
.B nodeflate
Disables Deflate compression; pppd will not request or agree to
compress packets using the Deflate scheme.
Expand Down
6 changes: 6 additions & 0 deletions pppd/pppd.h
Expand Up @@ -683,6 +683,12 @@ int sifdefaultroute __P((int, u_int32_t, u_int32_t));
/* Create default route through i/f */
int cifdefaultroute __P((int, u_int32_t, u_int32_t));
/* Delete default route through i/f */
#ifdef INET6
int sif6defaultroute __P((int, eui64_t, eui64_t));
/* Create default IPv6 route through i/f */
int cif6defaultroute __P((int, eui64_t, eui64_t));
/* Delete default IPv6 route through i/f */
#endif
int sifproxyarp __P((int, u_int32_t));
/* Add proxy ARP entry for peer */
int cifproxyarp __P((int, u_int32_t));
Expand Down
199 changes: 199 additions & 0 deletions pppd/sys-linux.c
Expand Up @@ -163,6 +163,7 @@ struct in6_ifreq {
eui64_copy(eui64, sin6.s6_addr32[2]); \
} while (0)

static const eui64_t nulleui64;
#endif /* INET6 */

/* We can get an EIO error on an ioctl if the modem has hung up */
Expand Down Expand Up @@ -207,6 +208,7 @@ static unsigned char inbuf[512]; /* buffer for chars read from loopback */
static int if_is_up; /* Interface has been marked up */
static int if6_is_up; /* Interface has been marked up for IPv6, to help differentiate */
static int have_default_route; /* Gateway for default route added */
static int have_default_route6; /* Gateway for default IPv6 route added */
static u_int32_t proxy_arp_addr; /* Addr for proxy arp entry added */
static char proxy_arp_dev[16]; /* Device for proxy arp entry */
static u_int32_t our_old_addr; /* for detecting address changes */
Expand Down Expand Up @@ -234,6 +236,7 @@ static void close_route_table (void);
static int open_route_table (void);
static int read_route_table (struct rtentry *rt);
static int defaultroute_exists (struct rtentry *rt, int metric);
static int defaultroute6_exists (struct in6_rtmsg *rt, int metric);
static int get_ether_addr (u_int32_t ipaddr, struct sockaddr *hwaddr,
char *name, int namelen);
static void decode_version (char *buf, int *version, int *mod, int *patch);
Expand Down Expand Up @@ -350,6 +353,10 @@ void sys_cleanup(void)
*/
if (have_default_route)
cifdefaultroute(0, 0, 0);
#ifdef INET6
if (have_default_route6)
cif6defaultroute(0, nulleui64, nulleui64);
#endif

if (has_proxy_arp)
cifproxyarp(0, proxy_arp_addr);
Expand Down Expand Up @@ -1710,6 +1717,198 @@ int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
return 1;
}

#ifdef INET6
/*
* /proc/net/ipv6_route parsing stuff.
*/
static int route_dest_plen_col;
static int open_route6_table (void);
static int read_route6_table (struct in6_rtmsg *rt);

/********************************************************************
*
* open_route6_table - open the interface to the route table
*/
static int open_route6_table (void)
{
char *path;

close_route_table();

path = path_to_procfs("/net/ipv6_route");
route_fd = fopen (path, "r");
if (route_fd == NULL) {
error("can't open routing table %s: %m", path);
return 0;
}

/* default to usual columns */
route_dest_col = 0;
route_dest_plen_col = 1;
route_gw_col = 4;
route_metric_col = 5;
route_flags_col = 8;
route_dev_col = 9;
route_num_cols = 10;

return 1;
}

/********************************************************************
*
* read_route6_table - read the next entry from the route table
*/

static void hex_to_in6_addr(struct in6_addr *addr, const char *s)
{
char hex8[9];
unsigned i;
uint32_t v;

hex8[8] = 0;
for (i = 0; i < 4; i++) {
memcpy(hex8, s + 8*i, 8);
v = strtoul(hex8, NULL, 16);
addr->s6_addr32[i] = v;
}
}

static int read_route6_table(struct in6_rtmsg *rt)
{
char *cols[ROUTE_MAX_COLS], *p;
int col;

memset (rt, '\0', sizeof (struct in6_rtmsg));

if (fgets (route_buffer, sizeof (route_buffer), route_fd) == (char *) 0)
return 0;

p = route_buffer;
for (col = 0; col < route_num_cols; ++col) {
cols[col] = strtok(p, route_delims);
if (cols[col] == NULL)
return 0; /* didn't get enough columns */
p = NULL;
}

hex_to_in6_addr(&rt->rtmsg_dst, cols[route_dest_col]);
rt->rtmsg_dst_len = strtoul(cols[route_dest_plen_col], NULL, 16);
hex_to_in6_addr(&rt->rtmsg_gateway, cols[route_gw_col]);

rt->rtmsg_metric = strtoul(cols[route_metric_col], NULL, 16);
rt->rtmsg_flags = strtoul(cols[route_flags_col], NULL, 16);
rt->rtmsg_ifindex = if_nametoindex(cols[route_dev_col]);

return 1;
}

/********************************************************************
*
* defaultroute6_exists - determine if there is a default route
*/

static int defaultroute6_exists (struct in6_rtmsg *rt, int metric)
{
int result = 0;

if (!open_route6_table())
return 0;

while (read_route6_table(rt) != 0) {
if ((rt->rtmsg_flags & RTF_UP) == 0)
continue;

if (rt->rtmsg_dst_len != 0)
continue;
if (rt->rtmsg_dst.s6_addr32[0] == 0L
&& rt->rtmsg_dst.s6_addr32[1] == 0L
&& rt->rtmsg_dst.s6_addr32[2] == 0L
&& rt->rtmsg_dst.s6_addr32[3] == 0L
&& (metric < 0 || rt->rtmsg_metric == metric)) {
result = 1;
break;
}
}

close_route_table();
return result;
}

/********************************************************************
*
* sif6defaultroute - assign a default route through the address given.
*
* If the global default_rt_repl_rest flag is set, then this function
* already replaced the original system defaultroute with some other
* route and it should just replace the current defaultroute with
* another one, without saving the current route. Use: demand mode,
* when pppd sets first a defaultroute it it's temporary ppp0 addresses
* and then changes the temporary addresses to the addresses for the real
* ppp connection when it has come up.
*/

int sif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
{
struct in6_rtmsg rt;
char buf[IF_NAMESIZE];

if (defaultroute6_exists(&rt, dfl_route_metric) &&
rt.rtmsg_ifindex != if_nametoindex(ifname)) {
if (rt.rtmsg_flags & RTF_GATEWAY)
error("not replacing existing default route via gateway");
else
error("not replacing existing default route through %s",
if_indextoname(rt.rtmsg_ifindex, buf));
return 0;
}

memset (&rt, 0, sizeof (rt));

rt.rtmsg_ifindex = if_nametoindex(ifname);
rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
rt.rtmsg_dst_len = 0;

rt.rtmsg_flags = RTF_UP;
if (ioctl(sock6_fd, SIOCADDRT, &rt) < 0) {
if ( ! ok_error ( errno ))
error("default route ioctl(SIOCADDRT): %m");
return 0;
}

have_default_route6 = 1;
return 1;
}

/********************************************************************
*
* cif6defaultroute - delete a default route through the address given.
*/

int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
{
struct in6_rtmsg rt;

have_default_route6 = 0;

memset (&rt, '\0', sizeof (rt));

rt.rtmsg_ifindex = if_nametoindex(ifname);
rt.rtmsg_metric = dfl_route_metric + 1; /* +1 for binary compatibility */
rt.rtmsg_dst_len = 0;

rt.rtmsg_flags = RTF_UP;
if (ioctl(sock6_fd, SIOCDELRT, &rt) < 0 && errno != ESRCH) {
if (still_ppp()) {
if ( ! ok_error ( errno ))
error("default route ioctl(SIOCDELRT): %m");
return 0;
}
}

return 1;
}
#endif /* INET6 */

/********************************************************************
*
* sifproxyarp - Make a proxy ARP entry for the peer.
Expand Down

0 comments on commit 388597e

Please sign in to comment.