X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fipcp.c;h=776f06f0e9ee50349b5e28823fc1e697f774d2c7;hb=HEAD;hp=d95b69b910f2dd41277e16d7445f841d8b50f3c1;hpb=5cb32f1c7e8584994a2c887cb7a3d9823068d2ce;p=ppp.git diff --git a/pppd/ipcp.c b/pppd/ipcp.c index d95b69b..5d9ff11 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -40,9 +40,9 @@ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * TODO: - */ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif #include #include @@ -55,7 +55,8 @@ #include #include -#include "pppd.h" +#include "pppd-private.h" +#include "options.h" #include "fsm.h" #include "ipcp.h" #include "pathnames.h" @@ -67,19 +68,16 @@ ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ +char *ipparam = NULL; /* Extra parameter for ip up/down scripts */ u_int32_t netmask = 0; /* IP netmask to set on interface */ bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ bool noremoteip = 0; /* Let him have no IP address */ -/* Hook for a plugin to know when IP protocol has come up */ -void (*ip_up_hook)(void) = NULL; +ip_up_hook_fn *ip_up_hook = NULL; +ip_down_hook_fn *ip_down_hook = NULL; +ip_choose_hook_fn *ip_choose_hook = NULL; -/* Hook for a plugin to know when IP protocol has come down */ -void (*ip_down_hook)(void) = NULL; - -/* Hook for a plugin to choose the remote IP address */ -void (*ip_choose_hook)(u_int32_t *) = NULL; /* Notifiers for when IPCP goes up and down */ struct notifier *ip_up_notifier = NULL; @@ -89,6 +87,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 */ @@ -137,9 +136,9 @@ static int setdnsaddr (char **); static int setwinsaddr (char **); static int setnetmask (char **); int setipaddr (char *, char **, int); -static void printipaddr (option_t *, void (*)(void *, char *,...),void *); +static void printipaddr (struct option *, void (*)(void *, char *,...),void *); -static option_t ipcp_option_list[] = { +static struct option ipcp_option_list[] = { { "noip", o_bool, &ipcp_protent.enabled_flag, "Disable IP and IPCP" }, { "-ip", o_bool, &ipcp_protent.enabled_flag, @@ -217,6 +216,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 }, @@ -329,10 +331,10 @@ setvjslots(char **argv) { int value; - if (!int_option(*argv, &value)) + if (!ppp_int_option(*argv, &value)) return 0; if (value < 2 || value > 16) { - option_error("vj-max-slots value must be between 2 and 16"); + ppp_option_error("vj-max-slots value must be between 2 and 16"); return 0; } ipcp_wantoptions [0].maxslotindex = @@ -353,7 +355,7 @@ setdnsaddr(char **argv) dns = inet_addr(*argv); if (dns == (u_int32_t) -1) { if ((hp = gethostbyname(*argv)) == NULL) { - option_error("invalid address parameter '%s' for ms-dns option", + ppp_option_error("invalid address parameter '%s' for ms-dns option", *argv); return 0; } @@ -388,7 +390,7 @@ setwinsaddr(char **argv) wins = inet_addr(*argv); if (wins == (u_int32_t) -1) { if ((hp = gethostbyname(*argv)) == NULL) { - option_error("invalid address parameter '%s' for ms-wins option", + ppp_option_error("invalid address parameter '%s' for ms-wins option", *argv); return 0; } @@ -439,13 +441,13 @@ setipaddr(char *arg, char **argv, int doit) *colon = '\0'; if ((local = inet_addr(arg)) == (u_int32_t) -1) { if ((hp = gethostbyname(arg)) == NULL) { - option_error("unknown host: %s", arg); + ppp_option_error("unknown host: %s", arg); return 0; } local = *(u_int32_t *)hp->h_addr; } - if (bad_ip_adrs(local)) { - option_error("bad local IP address %s", ip_ntoa(local)); + if (ppp_bad_ip_addr(local)) { + ppp_option_error("bad local IP address %s", ip_ntoa(local)); return 0; } if (local != 0) @@ -460,15 +462,15 @@ setipaddr(char *arg, char **argv, int doit) if (*++colon != '\0' && option_priority >= prio_remote) { if ((remote = inet_addr(colon)) == (u_int32_t) -1) { if ((hp = gethostbyname(colon)) == NULL) { - option_error("unknown host: %s", colon); + ppp_option_error("unknown host: %s", colon); return 0; } remote = *(u_int32_t *)hp->h_addr; if (remote_name[0] == 0) strlcpy(remote_name, colon, sizeof(remote_name)); } - if (bad_ip_adrs(remote)) { - option_error("bad remote IP address %s", ip_ntoa(remote)); + if (ppp_bad_ip_addr(remote)) { + ppp_option_error("bad remote IP address %s", ip_ntoa(remote)); return 0; } if (remote != 0) @@ -480,7 +482,7 @@ setipaddr(char *arg, char **argv, int doit) } static void -printipaddr(option_t *opt, void (*printer) (void *, char *, ...), void *arg) +printipaddr(struct option *opt, void (*printer) (void *, char *, ...), void *arg) { ipcp_options *wo = &ipcp_wantoptions[0]; @@ -511,7 +513,7 @@ setnetmask(char **argv) mask = htonl(mask); if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { - option_error("invalid netmask value '%s'", *argv); + ppp_option_error("invalid netmask value '%s'", *argv); return 0; } @@ -552,6 +554,11 @@ parse_dotted_ip(char *p, u_int32_t *vp) return p - p0; } +const char *ppp_ipparam() +{ + return ipparam; +} + /* * ipcp_init - Initialize IPCP. @@ -678,14 +685,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; @@ -737,8 +747,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)) ; } @@ -809,8 +819,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); \ @@ -819,7 +829,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, @@ -834,9 +844,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; } @@ -938,8 +948,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; \ @@ -965,9 +975,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. @@ -999,7 +1009,7 @@ ipcp_nakci(fsm *f, u_char *p, int len, int treat_as_reject) 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 */ @@ -1064,6 +1074,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. @@ -1140,6 +1163,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. @@ -1206,13 +1245,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; @@ -1232,7 +1278,6 @@ bad: return 0; } - /* * ipcp_rejci - Reject some of our CIs. * Callback from fsm_rconfnakrej. @@ -1327,8 +1372,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) { \ @@ -1340,7 +1385,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, @@ -1355,9 +1400,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. @@ -1547,7 +1592,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 */ @@ -1648,7 +1693,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 */ @@ -1690,7 +1736,7 @@ ip_check_options(void) wo->accept_local = 1; /* don't insist on this default value */ if ((hp = gethostbyname(hostname)) != NULL) { local = *(u_int32_t *)hp->h_addr; - if (local != 0 && !bad_ip_adrs(local)) + if (local != 0 && !ppp_bad_ip_addr(local)) wo->ouraddr = local; } } @@ -1720,7 +1766,7 @@ ip_demand_conf(int u) } if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) return 0; - ipcp_script(_PATH_IPPREUP, 1); + ipcp_script(PPP_PATH_IPPREUP, 1); if (!sifup(u)) return 0; if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) @@ -1760,6 +1806,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; @@ -1779,23 +1831,30 @@ ipcp_up(fsm *f) warn("Could not determine remote IP address: defaulting to %I", ho->hisaddr); } - script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); + ppp_script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); if (ho->hisaddr != 0) - script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); + ppp_script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1); if (!go->req_dns1) go->dnsaddr[0] = 0; if (!go->req_dns2) go->dnsaddr[1] = 0; if (go->dnsaddr[0]) - script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); + ppp_script_setenv("DNS1", ip_ntoa(go->dnsaddr[0]), 0); if (go->dnsaddr[1]) - script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); + ppp_script_setenv("DNS2", ip_ntoa(go->dnsaddr[1]), 0); if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { - script_setenv("USEPEERDNS", "1", 0); + ppp_script_setenv("USEPEERDNS", "1", 0); create_resolv(go->dnsaddr[0], go->dnsaddr[1]); } + if (go->winsaddr[0]) + ppp_script_setenv("WINS1", ip_ntoa(go->winsaddr[0]), 0); + if (go->winsaddr[1]) + ppp_script_setenv("WINS2", ip_ntoa(go->winsaddr[1]), 0); + if (usepeerwins && (go->winsaddr[0] || go->winsaddr[1])) + ppp_script_setenv("USEPEERWINS", "1", 0); + /* * Check that the peer is allowed to use the IP address it wants. */ @@ -1819,16 +1878,17 @@ ipcp_up(fsm *f) 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); + ppp_script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr), 0); wo->ouraddr = go->ouraddr; } else - script_unsetenv("OLDIPLOCAL"); - if (ho->hisaddr != wo->hisaddr && wo->hisaddr != 0) { + ppp_script_unsetenv("OLDIPLOCAL"); + 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) + ppp_script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr), 0); wo->hisaddr = ho->hisaddr; } else - script_unsetenv("OLDIPREMOTE"); + ppp_script_unsetenv("OLDIPREMOTE"); /* Set the interface to the new addresses */ mask = GetMask(go->ouraddr); @@ -1872,7 +1932,7 @@ ipcp_up(fsm *f) ifindex = if_nametoindex(ifname); /* run the pre-up script, if any, and wait for it to finish */ - ipcp_script(_PATH_IPPREUP, 1); + ipcp_script(PPP_PATH_IPPREUP, 1); /* check if preup script renamed the interface */ if (!if_indextoname(ifindex, ifname)) { @@ -1955,7 +2015,7 @@ ipcp_down(fsm *f) * before the interface is marked down. */ /* XXX more correct: we must get the stats before running the notifiers, * at least for the radius plugin */ - update_link_stats(f->unit); + ppp_get_link_stats(NULL); notify(ip_down_notifier, 0); if (ip_down_hook) ip_down_hook(); @@ -2092,20 +2152,20 @@ create_resolv(u_int32_t peerdns1, u_int32_t peerdns2) { FILE *f; - f = fopen(_PATH_RESOLV, "w"); + f = fopen(PPP_PATH_RESOLV, "w"); if (f == NULL) { - error("Failed to create %s: %m", _PATH_RESOLV); + error("Failed to create %s: %m", PPP_PATH_RESOLV); return; } if (peerdns1) fprintf(f, "nameserver %s\n", ip_ntoa(peerdns1)); - if (peerdns2) + if (peerdns2 && peerdns2 != peerdns1) fprintf(f, "nameserver %s\n", ip_ntoa(peerdns2)); if (ferror(f)) - error("Write failed to %s: %m", _PATH_RESOLV); + error("Write failed to %s: %m", PPP_PATH_RESOLV); fclose(f); }