X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fipcp.c;h=0dc251e503d725f4bec5f7f81953fafcc0f04168;hb=4a54e34cf5629f9fed61f0b7d69ee3ba4d874bc6;hp=7357ac8ea546323f3ba178db99f0e77639beef3f;hpb=61821b9b6106a1e834ce14783a0b03b8c5301328;p=ppp.git diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 7357ac8..0dc251e 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -40,6 +40,10 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + /* * TODO: */ @@ -89,6 +93,7 @@ struct notifier *ip_down_notifier = NULL; static int default_route_set[NUM_PPP]; /* Have set up a default route */ static int proxy_arp_set[NUM_PPP]; /* Have created proxy arp entry */ static bool usepeerdns; /* Ask peer for DNS addrs */ +static bool usepeerwins; /* Ask peer for WINS addrs */ static int ipcp_is_up; /* have called np_up() */ static int ipcp_is_open; /* haven't called np_finished() */ static bool ask_for_local; /* request our address from peer */ @@ -196,6 +201,15 @@ 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", OPT_PRIV | 1 + }, + { "noreplacedefaultroute", o_bool, + &ipcp_wantoptions[0].replace_default_route, + "Do 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, @@ -208,6 +222,9 @@ static option_t ipcp_option_list[] = { { "usepeerdns", o_bool, &usepeerdns, "Ask peer for DNS address(es)", 1 }, + { "usepeerwins", o_bool, &usepeerwins, + "Ask peer for WINS address(es)", 1 }, + { "netmask", o_special, (void *)setnetmask, "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, @@ -269,7 +286,7 @@ struct protent ipcp_protent = { ip_active_pkt }; -static void ipcp_clear_addrs (int, u_int32_t, u_int32_t); +static void ipcp_clear_addrs (int, u_int32_t, u_int32_t, bool); static void ipcp_script (char *, int); /* Run an up/down script */ static void ipcp_script_done (void *); @@ -669,14 +686,17 @@ ipcp_resetci(fsm *f) ipcp_options *go = &ipcp_gotoptions[f->unit]; ipcp_options *ao = &ipcp_allowoptions[f->unit]; - wo->req_addr = (wo->neg_addr || wo->old_addrs) && - (ao->neg_addr || ao->old_addrs); + wo->req_addr = ((wo->neg_addr || wo->old_addrs) && + (ao->neg_addr || ao->old_addrs)) || + (wo->hisaddr && !wo->accept_remote); if (wo->ouraddr == 0) wo->accept_local = 1; if (wo->hisaddr == 0) wo->accept_remote = 1; wo->req_dns1 = usepeerdns; /* Request DNS addresses from the peer */ wo->req_dns2 = usepeerdns; + wo->req_wins1 = usepeerwins; /* Request WINS addresses from the peer */ + wo->req_wins2 = usepeerwins; *go = *wo; if (!ask_for_local) go->ouraddr = 0; @@ -728,8 +748,8 @@ ipcp_cilen(fsm *f) LENCIADDR(go->neg_addr) + LENCIDNS(go->req_dns1) + LENCIDNS(go->req_dns2) + - LENCIWINS(go->winsaddr[0]) + - LENCIWINS(go->winsaddr[1])) ; + LENCIWINS(go->req_wins1) + + LENCIWINS(go->req_wins2)) ; } @@ -800,8 +820,8 @@ ipcp_addci(fsm *f, u_char *ucp, int *lenp) neg = 0; \ } -#define ADDCIWINS(opt, addr) \ - if (addr) { \ +#define ADDCIWINS(opt, neg, addr) \ + if (neg) { \ if (len >= CILEN_ADDR) { \ u_int32_t l; \ PUTCHAR(opt, ucp); \ @@ -810,7 +830,7 @@ ipcp_addci(fsm *f, u_char *ucp, int *lenp) PUTLONG(l, ucp); \ len -= CILEN_ADDR; \ } else \ - addr = 0; \ + neg = 0; \ } ADDCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, go->ouraddr, @@ -825,9 +845,9 @@ ipcp_addci(fsm *f, u_char *ucp, int *lenp) ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); - ADDCIWINS(CI_MS_WINS1, go->winsaddr[0]); + ADDCIWINS(CI_MS_WINS1, go->req_wins1, go->winsaddr[0]); - ADDCIWINS(CI_MS_WINS2, go->winsaddr[1]); + ADDCIWINS(CI_MS_WINS2, go->req_wins2, go->winsaddr[1]); *lenp -= len; } @@ -929,8 +949,8 @@ ipcp_ackci(fsm *f, u_char *p, int len) goto bad; \ } -#define ACKCIWINS(opt, addr) \ - if (addr) { \ +#define ACKCIWINS(opt, neg, addr) \ + if (neg) { \ u_int32_t l; \ if ((len -= CILEN_ADDR) < 0) \ goto bad; \ @@ -956,9 +976,9 @@ ipcp_ackci(fsm *f, u_char *p, int len) ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); - ACKCIWINS(CI_MS_WINS1, go->winsaddr[0]); + ACKCIWINS(CI_MS_WINS1, go->req_wins1, go->winsaddr[0]); - ACKCIWINS(CI_MS_WINS2, go->winsaddr[1]); + ACKCIWINS(CI_MS_WINS2, go->req_wins2, go->winsaddr[1]); /* * If there are any remaining CIs, then this packet is bad. @@ -985,11 +1005,12 @@ bad: static int ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) { + ipcp_options *wo = &ipcp_wantoptions[f->unit]; ipcp_options *go = &ipcp_gotoptions[f->unit]; u_char cimaxslotindex, cicflag; u_char citype, cilen, *next; u_short cishort; - u_int32_t ciaddr1, ciaddr2, l, cidnsaddr; + u_int32_t ciaddr1, ciaddr2, l, cidnsaddr, ciwinsaddr; ipcp_options no; /* options we've seen Naks for */ ipcp_options try; /* options to request next time */ @@ -1054,6 +1075,19 @@ ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) code \ } +#define NAKCIWINS(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + ciwinsaddr = htonl(l); \ + no.neg = 1; \ + code \ + } + /* * Accept the peer's idea of {our,his} address, if different * from our idea, only if the accept_{local,remote} flag is set. @@ -1130,6 +1164,22 @@ ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) } ); + NAKCIWINS(CI_MS_WINS1, req_wins1, + if (treat_as_reject) { + try.req_wins1 = 0; + } else { + try.winsaddr[0] = ciwinsaddr; + } + ); + + NAKCIWINS(CI_MS_WINS2, req_wins2, + if (treat_as_reject) { + try.req_wins2 = 0; + } else { + try.winsaddr[1] = ciwinsaddr; + } + ); + /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. @@ -1160,7 +1210,7 @@ ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) GETLONG(l, p); ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) - try.ouraddr = ciaddr1; + try.ouraddr = wo->old_addrs ? ciaddr1 : 0; GETLONG(l, p); ciaddr2 = htonl(l); if (ciaddr2 && go->accept_remote) @@ -1175,7 +1225,7 @@ ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) ciaddr1 = htonl(l); if (ciaddr1 && go->accept_local) try.ouraddr = ciaddr1; - if (try.ouraddr != 0) + if (try.ouraddr != 0 && wo->neg_addr) try.neg_addr = 1; no.neg_addr = 1; break; @@ -1196,13 +1246,20 @@ ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) no.req_dns2 = 1; break; case CI_MS_WINS1: + if (go->req_wins1 || no.req_wins1 || cilen != CILEN_ADDR) + goto bad; + GETLONG(l, p); + try.winsaddr[0] = htonl(l); + try.req_wins1 = 1; + no.req_wins1 = 1; + break; case CI_MS_WINS2: - if (cilen != CILEN_ADDR) + if (go->req_wins2 || no.req_wins2 || cilen != CILEN_ADDR) goto bad; GETLONG(l, p); - ciaddr1 = htonl(l); - if (ciaddr1) - try.winsaddr[citype == CI_MS_WINS2] = ciaddr1; + try.winsaddr[1] = htonl(l); + try.req_wins2 = 1; + no.req_wins2 = 1; break; } p = next; @@ -1222,7 +1279,6 @@ bad: return 0; } - /* * ipcp_rejci - Reject some of our CIs. * Callback from fsm_rconfnakrej. @@ -1317,8 +1373,8 @@ ipcp_rejci(fsm *f, u_char *p, int len) try.neg = 0; \ } -#define REJCIWINS(opt, addr) \ - if (addr && \ +#define REJCIWINS(opt, neg, addr) \ + if (go->neg && \ ((cilen = p[1]) == CILEN_ADDR) && \ len >= cilen && \ p[0] == opt) { \ @@ -1330,7 +1386,7 @@ ipcp_rejci(fsm *f, u_char *p, int len) /* Check rejected value. */ \ if (cilong != addr) \ goto bad; \ - try.winsaddr[opt == CI_MS_WINS2] = 0; \ + try.neg = 0; \ } REJCIADDRS(CI_ADDRS, !go->neg_addr && go->old_addrs, @@ -1345,9 +1401,9 @@ ipcp_rejci(fsm *f, u_char *p, int len) REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); - REJCIWINS(CI_MS_WINS1, go->winsaddr[0]); + REJCIWINS(CI_MS_WINS1, req_wins1, go->winsaddr[0]); - REJCIWINS(CI_MS_WINS2, go->winsaddr[1]); + REJCIWINS(CI_MS_WINS2, req_wins2, go->winsaddr[1]); /* * If there are any remaining CIs, then this packet is bad. @@ -1461,7 +1517,7 @@ ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) if (ciaddr2 != wo->ouraddr) { if (ciaddr2 == 0 || !wo->accept_local) { orc = CONFNAK; - if (!reject_if_disagree) { + if (!reject_if_disagree && wo->old_addrs) { DECPTR(sizeof(u_int32_t), p); tl = ntohl(wo->ouraddr); PUTLONG(tl, p); @@ -1537,7 +1593,7 @@ ipcp_reqci(fsm *f, u_char *inp, int *len, int reject_if_disagree) /* Microsoft primary or secondary WINS request */ d = citype == CI_MS_WINS2; - /* If we do not have a DNS address then we cannot send it */ + /* If we do not have a WINS address then we cannot send it */ if (ao->winsaddr[d] == 0 || cilen != CILEN_ADDR) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ @@ -1638,7 +1694,8 @@ endswitch: * option safely. */ if (rc != CONFREJ && !ho->neg_addr && !ho->old_addrs && - wo->req_addr && !reject_if_disagree && !noremoteip) { + wo->req_addr && !reject_if_disagree && + ((wo->hisaddr && !wo->accept_remote) || !noremoteip)) { if (rc == CONFACK) { rc = CONFNAK; ucp = inp; /* reset pointer */ @@ -1716,7 +1773,8 @@ ip_demand_conf(int u) if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) return 0; if (wo->default_route) - if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr)) + if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr, + wo->replace_default_route)) default_route_set[u] = 1; if (wo->proxy_arp) if (sifproxyarp(u, wo->hisaddr)) @@ -1749,6 +1807,12 @@ ipcp_up(fsm *f) /* * We must have a non-zero IP address for both ends of the link. */ + + if (wo->hisaddr && !wo->accept_remote && (!(ho->neg_addr || ho->old_addrs) || ho->hisaddr != wo->hisaddr)) { + error("Peer refused to agree to his IP address"); + ipcp_close(f->unit, "Refused his IP address"); + return; + } if (!ho->neg_addr && !ho->old_addrs) ho->hisaddr = wo->hisaddr; @@ -1785,6 +1849,13 @@ ipcp_up(fsm *f) create_resolv(go->dnsaddr[0], go->dnsaddr[1]); } + if (go->winsaddr[0]) + script_setenv("WINS1", ip_ntoa(go->winsaddr[0]), 0); + if (go->winsaddr[1]) + script_setenv("WINS2", ip_ntoa(go->winsaddr[1]), 0); + if (usepeerwins && (go->winsaddr[0] || go->winsaddr[1])) + script_setenv("USEPEERWINS", "1", 0); + /* * Check that the peer is allowed to use the IP address it wants. */ @@ -1804,16 +1875,18 @@ ipcp_up(fsm *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); wo->ouraddr = go->ouraddr; } else script_unsetenv("OLDIPLOCAL"); - if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { + if (ho->hisaddr != wo->hisaddr) { warn("Remote IP address changed to %I", ho->hisaddr); - script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); + if (wo->hisaddr != 0) + script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); wo->hisaddr = ho->hisaddr; } else script_unsetenv("OLDIPREMOTE"); @@ -1829,7 +1902,8 @@ ipcp_up(fsm *f) /* assign a default route through the interface if required */ if (ipcp_wantoptions[f->unit].default_route) - if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) + if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr, + wo->replace_default_route)) default_route_set[f->unit] = 1; /* Make a proxy ARP entry if requested. */ @@ -1888,7 +1962,8 @@ ipcp_up(fsm *f) /* assign a default route through the interface if required */ if (ipcp_wantoptions[f->unit].default_route) - if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) + if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr, + wo->replace_default_route)) default_route_set[f->unit] = 1; /* Make a proxy ARP entry if requested. */ @@ -1922,7 +1997,7 @@ ipcp_up(fsm *f) */ if (ipcp_script_state == s_down && ipcp_script_pid == 0) { ipcp_script_state = s_up; - ipcp_script(_PATH_IPUP, 0); + ipcp_script(path_ipup, 0); } } @@ -1965,13 +2040,13 @@ ipcp_down(fsm *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 */ if (ipcp_script_state == s_up && ipcp_script_pid == 0) { ipcp_script_state = s_down; - ipcp_script(_PATH_IPDOWN, 0); + ipcp_script(path_ipdown, 0); } } @@ -1981,13 +2056,21 @@ ipcp_down(fsm *f) * proxy arp entries, etc. */ static void -ipcp_clear_addrs(int unit, u_int32_t ouraddr, u_int32_t hisaddr) +ipcp_clear_addrs(int unit, u_int32_t ouraddr, u_int32_t hisaddr, bool replacedefaultroute) { if (proxy_arp_set[unit]) { cifproxyarp(unit, hisaddr); proxy_arp_set[unit] = 0; } - if (default_route_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]) { cifdefaultroute(unit, ouraddr, hisaddr); default_route_set[unit] = 0; } @@ -2020,13 +2103,13 @@ ipcp_script_done(void *arg) case s_up: if (ipcp_fsm[0].state != OPENED) { ipcp_script_state = s_down; - ipcp_script(_PATH_IPDOWN, 0); + ipcp_script(path_ipdown, 0); } break; case s_down: if (ipcp_fsm[0].state == OPENED) { ipcp_script_state = s_up; - ipcp_script(_PATH_IPUP, 0); + ipcp_script(path_ipup, 0); } break; }