| This patch comes from OpenEmbedded. |
| The original patch is from Debian / SuSE to implement replacedefaultroute |
| Rebased it to fit ppp-2.4.5. Dongxiao Xu <dongxiao.xu@intel.com> |
| |
| Upstream-Status: Inappropriate [debian/suse patches] |
| |
| Index: ppp-2.4.7/pppd/ipcp.c |
| =================================================================== |
| --- ppp-2.4.7.orig/pppd/ipcp.c |
| +++ ppp-2.4.7/pppd/ipcp.c |
| @@ -198,6 +198,16 @@ static option_t ipcp_option_list[] = { |
| "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, |
| &ipcp_wantoptions[0].default_route }, |
| |
| +#ifdef __linux__ |
| + { "replacedefaultroute", o_bool, |
| + &ipcp_wantoptions[0].replace_default_route, |
| + "Replace default route", 1 |
| + }, |
| + { "noreplacedefaultroute", o_bool, |
| + &ipcp_allowoptions[0].replace_default_route, |
| + "Never replace default route", OPT_A2COPY, |
| + &ipcp_wantoptions[0].replace_default_route }, |
| +#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, |
| @@ -271,7 +281,7 @@ struct protent ipcp_protent = { |
| ip_active_pkt |
| }; |
| |
| -static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t)); |
| +static void ipcp_clear_addrs __P((int, u_int32_t, u_int32_t, bool)); |
| static void ipcp_script __P((char *, int)); /* Run an up/down script */ |
| static void ipcp_script_done __P((void *)); |
| |
| @@ -1761,7 +1771,12 @@ ip_demand_conf(u) |
| if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) |
| return 0; |
| if (wo->default_route) |
| +#ifndef __linux__ |
| if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr)) |
| +#else |
| + if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr, |
| + wo->replace_default_route)) |
| +#endif |
| default_route_set[u] = 1; |
| if (wo->proxy_arp) |
| if (sifproxyarp(u, wo->hisaddr)) |
| @@ -1849,7 +1864,8 @@ ipcp_up(f) |
| */ |
| if (demand) { |
| if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { |
| - ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr); |
| + ipcp_clear_addrs(f->unit, wo->ouraddr, wo->hisaddr, |
| + wo->replace_default_route); |
| if (go->ouraddr != wo->ouraddr) { |
| warn("Local IP address changed to %I", go->ouraddr); |
| script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); |
| @@ -1874,7 +1890,12 @@ ipcp_up(f) |
| |
| /* assign a default route through the interface if required */ |
| if (ipcp_wantoptions[f->unit].default_route) |
| +#ifndef __linux__ |
| if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) |
| +#else |
| + if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr, |
| + wo->replace_default_route)) |
| +#endif |
| default_route_set[f->unit] = 1; |
| |
| /* Make a proxy ARP entry if requested. */ |
| @@ -1924,7 +1945,12 @@ ipcp_up(f) |
| |
| /* assign a default route through the interface if required */ |
| if (ipcp_wantoptions[f->unit].default_route) |
| +#ifndef __linux__ |
| if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) |
| +#else |
| + if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr, |
| + wo->replace_default_route)) |
| +#endif |
| default_route_set[f->unit] = 1; |
| |
| /* Make a proxy ARP entry if requested. */ |
| @@ -2002,7 +2028,7 @@ ipcp_down(f) |
| 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); |
| + ipcp_hisoptions[f->unit].hisaddr, 0); |
| } |
| |
| /* Execute the ip-down script */ |
| @@ -2018,12 +2044,21 @@ ipcp_down(f) |
| * proxy arp entries, etc. |
| */ |
| static void |
| -ipcp_clear_addrs(unit, ouraddr, hisaddr) |
| +ipcp_clear_addrs(unit, ouraddr, hisaddr, replacedefaultroute) |
| int unit; |
| u_int32_t ouraddr; /* local address */ |
| u_int32_t hisaddr; /* remote address */ |
| + bool replacedefaultroute; |
| { |
| - if (proxy_arp_set[unit]) { |
| + /* 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]) { |
| cifproxyarp(unit, hisaddr); |
| proxy_arp_set[unit] = 0; |
| } |
| Index: ppp-2.4.7/pppd/ipcp.h |
| =================================================================== |
| --- ppp-2.4.7.orig/pppd/ipcp.h |
| +++ ppp-2.4.7/pppd/ipcp.h |
| @@ -70,6 +70,7 @@ typedef struct ipcp_options { |
| bool old_addrs; /* Use old (IP-Addresses) option? */ |
| bool req_addr; /* Ask peer to send IP address? */ |
| bool default_route; /* Assign default route through interface? */ |
| + bool replace_default_route; /* Replace default route through interface? */ |
| bool proxy_arp; /* Make proxy ARP entry for peer? */ |
| bool neg_vj; /* Van Jacobson Compression? */ |
| bool old_vj; /* use old (short) form of VJ option? */ |
| Index: ppp-2.4.7/pppd/pppd.8 |
| =================================================================== |
| --- ppp-2.4.7.orig/pppd/pppd.8 |
| +++ ppp-2.4.7/pppd/pppd.8 |
| @@ -121,6 +121,13 @@ the gateway, when IPCP negotiation is su |
| This entry is removed when the PPP connection is broken. This option |
| is privileged if the \fInodefaultroute\fR option has been specified. |
| .TP |
| +.B replacedefaultroute |
| +This option is a flag to the defaultroute option. If defaultroute is |
| +set and this flag is also set, pppd replaces an existing default route |
| +with the new default route. |
| + |
| + |
| +.TP |
| .B disconnect \fIscript |
| Execute the command specified by \fIscript\fR, by passing it to a |
| shell, after |
| @@ -734,7 +741,12 @@ disable both forms of hardware flow cont |
| .TP |
| .B nodefaultroute |
| Disable the \fIdefaultroute\fR option. The system administrator who |
| -wishes to prevent users from creating default routes with pppd |
| +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 noreplacedefaultroute |
| +Disable the \fIreplacedefaultroute\fR option. The system administrator who |
| +wishes to prevent users from replacing a default route with pppd |
| can do so by placing this option in the /etc/ppp/options file. |
| .TP |
| .B nodeflate |
| Index: ppp-2.4.7/pppd/pppd.h |
| =================================================================== |
| --- ppp-2.4.7.orig/pppd/pppd.h |
| +++ ppp-2.4.7/pppd/pppd.h |
| @@ -665,7 +665,11 @@ int sif6addr __P((int, eui64_t, eui64_t |
| int cif6addr __P((int, eui64_t, eui64_t)); |
| /* Remove an IPv6 address from i/f */ |
| #endif |
| +#ifndef __linux__ |
| int sifdefaultroute __P((int, u_int32_t, u_int32_t)); |
| +#else |
| +int sifdefaultroute __P((int, u_int32_t, u_int32_t, bool replace_default_rt)); |
| +#endif |
| /* Create default route through i/f */ |
| int cifdefaultroute __P((int, u_int32_t, u_int32_t)); |
| /* Delete default route through i/f */ |
| Index: ppp-2.4.7/pppd/sys-linux.c |
| =================================================================== |
| --- ppp-2.4.7.orig/pppd/sys-linux.c |
| +++ ppp-2.4.7/pppd/sys-linux.c |
| @@ -207,6 +207,8 @@ static unsigned char inbuf[512]; /* buff |
| 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 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 */ |
| @@ -1545,6 +1547,9 @@ static int read_route_table(struct rtent |
| p = NULL; |
| } |
| |
| + SET_SA_FAMILY (rt->rt_dst, AF_INET); |
| + SET_SA_FAMILY (rt->rt_gateway, AF_INET); |
| + |
| SIN_ADDR(rt->rt_dst) = strtoul(cols[route_dest_col], NULL, 16); |
| SIN_ADDR(rt->rt_gateway) = strtoul(cols[route_gw_col], NULL, 16); |
| SIN_ADDR(rt->rt_genmask) = strtoul(cols[route_mask_col], NULL, 16); |
| @@ -1614,20 +1619,51 @@ int have_route_to(u_int32_t addr) |
| /******************************************************************** |
| * |
| * sifdefaultroute - assign a default route through the address given. |
| - */ |
| - |
| -int sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway) |
| -{ |
| - struct rtentry rt; |
| - |
| - if (defaultroute_exists(&rt) && strcmp(rt.rt_dev, ifname) != 0) { |
| - if (rt.rt_flags & RTF_GATEWAY) |
| - error("not replacing existing default route via %I", |
| - SIN_ADDR(rt.rt_gateway)); |
| - else |
| - error("not replacing existing default route through %s", |
| - rt.rt_dev); |
| - return 0; |
| + * |
| + * 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 sifdefaultroute (int unit, u_int32_t ouraddr, u_int32_t gateway, bool replace) |
| +{ |
| + struct rtentry rt, tmp_rt; |
| + struct rtentry *del_rt = NULL; |
| + |
| + if (default_rt_repl_rest) { |
| + /* We have already reclaced 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 )) |
| + del_rt = &tmp_rt; |
| + } else if ( defaultroute_exists( &old_def_rt ) && |
| + strcmp( old_def_rt.rt_dev, ifname ) != 0) { |
| + /* We did not yet replace an existing default route, let's |
| + * check if we should save and replace a default route: |
| + */ |
| + u_int32_t old_gateway = SIN_ADDR(old_def_rt.rt_gateway); |
| + 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; |
| + } |
| + } |
| } |
| |
| memset (&rt, 0, sizeof (rt)); |
| @@ -1646,6 +1682,12 @@ int sifdefaultroute (int unit, u_int32_t |
| 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; |
| @@ -1681,6 +1723,16 @@ int cifdefaultroute (int unit, u_int32_t |
| 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; |
| } |