bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */
bool noremoteip = 0; /* Let him have no IP address */
+unsigned dfl_route_metric = 0; /* metric of the default route to set over the PPP link */
+
ip_up_hook_fn *ip_up_hook = NULL;
ip_down_hook_fn *ip_down_hook = NULL;
ip_choose_hook_fn *ip_choose_hook = NULL;
static int setdnsaddr (char **);
static int setwinsaddr (char **);
static int setnetmask (char **);
+static int replacedefaultroute_nonfunctional();
+
int setipaddr (char *, char **, int);
static void printipaddr (struct option *, void (*)(void *, char *,...),void *);
"disable defaultroute option", OPT_ALIAS | OPT_A2CLR,
&ipcp_wantoptions[0].default_route },
+ { "defaultroute-metric", o_int, &dfl_route_metric,
+ "Metric to use for the default route (Linux only; default 0)",
+ OPT_PRIV|OPT_LLIMIT|OPT_INITONLY, NULL, 0, -1 },
+
#ifdef __linux__
- { "replacedefaultroute", o_bool,
- &ipcp_wantoptions[0].replace_default_route,
- "Replace default route", OPT_PRIV | 1
- },
- { "noreplacedefaultroute", o_bool,
- &ipcp_wantoptions[0].replace_default_route,
- "Do not replace default route", 0 },
+ { "replacedefaultroute", o_special_noarg,
+ &replacedefaultroute_nonfunctional,
+ "Removed option to replace default route", OPT_PRIV
+ },
+ { "noreplacedefaultroute", o_special_noarg,
+ &replacedefaultroute_nonfunctional,
+ "Removed option to not replace default route", 0 },
#endif
+
{ "proxyarp", o_bool, &ipcp_wantoptions[0].proxy_arp,
"Add proxy ARP entry", OPT_ENABLE|1, &ipcp_allowoptions[0].proxy_arp },
{ "noproxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp,
ip_active_pkt
};
-static void ipcp_clear_addrs (int, u_int32_t, u_int32_t, bool);
+static void ipcp_clear_addrs (int, u_int32_t, u_int32_t);
static void ipcp_script (char *, int); /* Run an up/down script */
static void ipcp_script_done (void *);
return 0;
if (!doit)
return 1;
-
+
/*
* If colon first character, then no local addr.
*/
*colon = ':';
prio_local = option_priority;
}
-
+
/*
* If colon last character, then no remote addr.
*/
return (1);
}
+static int
+replacedefaultroute_nonfunctional()
+{
+ ppp_option_error("replacedefaultroute and noreplacedefaultroute route options no longer have any effect.");
+ ppp_option_error("Please refer to the man page for defaultroute and defaultroute-metric.");
+ return 1;
+}
+
int
parse_dotted_ip(char *p, u_int32_t *vp)
{
ADDCIWINS(CI_MS_WINS1, go->req_wins1, go->winsaddr[0]);
ADDCIWINS(CI_MS_WINS2, go->req_wins2, go->winsaddr[1]);
-
+
*lenp -= len;
}
* Reset all his options.
*/
BZERO(ho, sizeof(*ho));
-
+
/*
* Process all his options.
*/
wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */
break;
}
-
+
ho->neg_addr = 1;
ho->hisaddr = ciaddr1;
break;
orc = CONFNAK;
}
break;
-
+
case CI_COMPRESSTYPE:
if (!ao->neg_vj ||
(cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {
ho->vj_protocol = cishort;
if (cilen == CILEN_VJ) {
GETCHAR(maxslotindex, p);
- if (maxslotindex > ao->maxslotindex) {
+ if (maxslotindex > ao->maxslotindex) {
orc = CONFNAK;
if (!reject_if_disagree){
DECPTR(1, p);
if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE))
return 0;
if (wo->default_route)
- if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr,
- wo->replace_default_route))
+ if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr))
default_route_set[u] = 1;
if (wo->proxy_arp)
if (sifproxyarp(u, wo->hisaddr))
*/
if (demand) {
if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) {
- ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr,
- wo->replace_default_route);
+ ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr);
if (go->ouraddr != wo->ouraddr) {
warn("Local IP address changed to %I", go->ouraddr);
ppp_script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0);
}
/* assign a default route through the interface if required */
- if (ipcp_wantoptions[f->unit].default_route)
- if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr,
- wo->replace_default_route))
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
default_route_set[f->unit] = 1;
/* Make a proxy ARP entry if requested. */
sifnpmode(f->unit, PPP_IP, NPMODE_PASS);
/* assign a default route through the interface if required */
- if (ipcp_wantoptions[f->unit].default_route)
- if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr,
- wo->replace_default_route))
+ if (ipcp_wantoptions[f->unit].default_route)
+ if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr))
default_route_set[f->unit] = 1;
/* Make a proxy ARP entry if requested. */
sifnpmode(f->unit, PPP_IP, NPMODE_DROP);
sifdown(f->unit);
ipcp_clear_addrs(f->unit, ipcp_gotoptions[f->unit].ouraddr,
- ipcp_hisoptions[f->unit].hisaddr, 0);
+ ipcp_hisoptions[f->unit].hisaddr);
}
/* Execute the ip-down script */
* proxy arp entries, etc.
*/
static void
-ipcp_clear_addrs(int unit, u_int32_t ouraddr, u_int32_t hisaddr, bool replacedefaultroute)
+ipcp_clear_addrs(int unit, u_int32_t ouraddr, u_int32_t hisaddr)
{
if (proxy_arp_set[unit]) {
cifproxyarp(unit, hisaddr);
proxy_arp_set[unit] = 0;
}
- /* If replacedefaultroute, sifdefaultroute will be called soon
- * with replacedefaultroute set and that will overwrite the current
- * default route. This is the case only when doing demand, otherwise
- * during demand, this cifdefaultroute would restore the old default
- * route which is not what we want in this case. In the non-demand
- * case, we'll delete the default route and restore the old if there
- * is one saved by an sifdefaultroute with replacedefaultroute.
- */
- if (!replacedefaultroute && default_route_set[unit]) {
+ if (default_route_set[unit]) {
cifdefaultroute(unit, ouraddr, hisaddr);
default_route_set[unit] = 0;
}
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 struct rtentry old_def_rt; /* Old default route */
-static int default_rt_repl_rest; /* replace and restore old default rt */
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 */
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);
extern u_char inpacket_buf[]; /* borrowed from main.c */
-extern int dfl_route_metric;
+extern unsigned dfl_route_metric;
+extern unsigned dfl_route6_metric;
/*
* SET_SA_FAMILY - set the sa_family field of a struct sockaddr,
return 1;
}
-/********************************************************************
- *
- * defaultroute_exists - determine if there is a default route
- * with the given metric (or negative for any)
- */
-
-static int defaultroute_exists (struct rtentry *rt, int metric)
-{
- int result = 0;
-
- if (!open_route_table())
- return 0;
-
- while (read_route_table(rt) != 0) {
- if ((rt->rt_flags & RTF_UP) == 0)
- continue;
-
- if (kernel_version > KVERSION(2,1,0) && SIN_ADDR(rt->rt_genmask) != 0)
- continue;
- if (SIN_ADDR(rt->rt_dst) == 0L && (metric < 0
- || rt->rt_metric == metric)) {
- result = 1;
- break;
- }
- }
-
- close_route_table();
- return result;
-}
-
/*
* have_route_to - determine if the system has any route to
* a given IP address. `addr' is in network byte order.
}
/********************************************************************
+ * route_netlink
*
- * sifdefaultroute - 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.
+ * Try using netlink to add/remove routes.
*/
-
-int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway, bool replace)
+static
+int _route_netlink(const char* op_fam, int operation, int family, unsigned metric)
{
- struct rtentry rt, tmp_rt;
- struct rtentry *del_rt = NULL;
+ struct {
+ struct nlmsghdr nlh;
+ struct rtmsg rtmsg;
+ struct {
+ struct rtattr rta;
+ unsigned ind;
+ } oif;
+ struct {
+ struct rtattr rta;
+ unsigned val;
+ } metric;
+ } nlreq;
+ int resp;
- if (default_rt_repl_rest) {
- /* We have already replaced the original defaultroute, if we
- * are called again, we will delete the current default route
- * and set the new default route in this function.
- * - this is normally only the case the doing demand: */
- if (defaultroute_exists(&tmp_rt, -1))
- del_rt = &tmp_rt;
- } else if (!replace) {
- /*
- * We don't want to replace an existing route.
- * We may however add our route along an existing route with a different
- * metric.
- */
- if (defaultroute_exists(&rt, dfl_route_metric) && strcmp(rt.rt_dev, ifname) != 0) {
- if (rt.rt_flags & RTF_GATEWAY)
- error("not replacing existing default route via %I with metric %d",
- SIN_ADDR(rt.rt_gateway), dfl_route_metric);
- else
- error("not replacing existing default route through %s with metric %d",
- rt.rt_dev, dfl_route_metric);
- return 0;
- }
- } else if (defaultroute_exists(&old_def_rt, -1 ) &&
- strcmp( old_def_rt.rt_dev, ifname) != 0) {
- /*
- * We want to replace an existing route and did not replace an existing
- * default route yet, let's check if we should save and replace an
- * existing default route:
- */
- u_int32_t old_gateway = SIN_ADDR(old_def_rt.rt_gateway);
+ memset(&nlreq, 0, sizeof(nlreq));
- if (old_gateway != gateway) {
- if (!replace) {
- error("not replacing default route to %s [%I]",
- old_def_rt.rt_dev, old_gateway);
- return 0;
- } else {
- /* we need to copy rt_dev because we need it permanent too: */
- char * tmp_dev = malloc(strlen(old_def_rt.rt_dev)+1);
- strcpy(tmp_dev, old_def_rt.rt_dev);
- old_def_rt.rt_dev = tmp_dev;
-
- notice("replacing old default route to %s [%I]",
- old_def_rt.rt_dev, old_gateway);
- default_rt_repl_rest = 1;
- del_rt = &old_def_rt;
- }
- }
- }
+ nlreq.nlh.nlmsg_len = sizeof(nlreq);
+ nlreq.nlh.nlmsg_type = operation;
+ nlreq.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE;
+ if (operation == RTM_NEWROUTE)
+ nlreq.nlh.nlmsg_flags |= NLM_F_APPEND;
+
+ nlreq.rtmsg.rtm_family = family;
+ nlreq.rtmsg.rtm_table = RT_TABLE_MAIN;
+ nlreq.rtmsg.rtm_protocol = RTPROT_BOOT;
+ nlreq.rtmsg.rtm_scope = RT_SCOPE_LINK;
+ nlreq.rtmsg.rtm_type = RTN_UNICAST;
+
+ nlreq.oif.rta.rta_len = sizeof(nlreq.oif);
+ nlreq.oif.rta.rta_type = RTA_OIF;
+ nlreq.oif.ind = if_nametoindex(ifname);
+
+ nlreq.metric.rta.rta_len = sizeof(nlreq.metric);
+ nlreq.metric.rta.rta_type = RTA_PRIORITY;
+ nlreq.metric.val = metric;
+
+ resp = rtnetlink_msg(op_fam, NULL, &nlreq, sizeof(nlreq), NULL, NULL, 0);
+ if (resp == 0)
+ return 1; /* success */
+
+ error("Unable to %s %s default route: %s", operation == RTM_NEWROUTE ? "add" : "remove",
+ family == AF_INET ? "IPv4" : "IPv6",
+ resp < 0 ? strerror(-resp) : "Netlink error");
+ return 0;
+}
+#define route_netlink(operation, family, metric) _route_netlink(#operation "/" #family, operation, family, metric)
+
+/********************************************************************
+ *
+ * sifdefaultroute - assign a default route through the address given.
+ */
+int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
+{
+ /* try appending using netlink first */
+ if (route_netlink(RTM_NEWROUTE, AF_INET, dfl_route_metric))
+ return 1;
+
+ /* ok, that failed, let's see if we can use ioctl */
+ struct rtentry rt;
memset (&rt, 0, sizeof (rt));
SET_SA_FAMILY (rt.rt_dst, AF_INET);
error("default route ioctl(SIOCADDRT): %m");
return 0;
}
- if (default_rt_repl_rest && del_rt)
- if (ioctl(sock_fd, SIOCDELRT, del_rt) < 0) {
- if ( ! ok_error ( errno ))
- error("del old default route ioctl(SIOCDELRT): %m(%d)", errno);
- return 0;
- }
have_default_route = 1;
return 1;
int cifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway)
{
+ /* try removing using netlink first */
+ if (route_netlink(RTM_DELROUTE, AF_INET, dfl_route_metric))
+ return 1;
+
+ /* ok, that failed, let's see if we can use ioctl */
struct rtentry rt;
have_default_route = 0;
return 0;
}
}
- if (default_rt_repl_rest) {
- notice("restoring old default route to %s [%I]",
- old_def_rt.rt_dev, SIN_ADDR(old_def_rt.rt_gateway));
- if (ioctl(sock_fd, SIOCADDRT, &old_def_rt) < 0) {
- if ( ! ok_error ( errno ))
- error("restore default route ioctl(SIOCADDRT): %m(%d)", errno);
- return 0;
- }
- default_rt_repl_rest = 0;
- }
return 1;
}
#ifdef PPP_WITH_IPV6CP
-/*
- * /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];
+ /* try appending using netlink first */
+ if (route_netlink(RTM_NEWROUTE, AF_INET6, dfl_route6_metric))
+ return 1;
- 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;
- }
+ /* ok, that failed, let's see if we can use ioctl */
+ struct in6_rtmsg rt;
memset (&rt, 0, sizeof (rt));
int cif6defaultroute (int unit, eui64_t ouraddr, eui64_t gateway)
{
+ /* try removing using netlink first */
+ if (route_netlink(RTM_DELROUTE, AF_INET6, dfl_route6_metric))
+ return 1;
+
+ /* ok, that failed, let's see if we can use ioctl */
struct in6_rtmsg rt;
have_default_route6 = 0;