X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fipcp.c;h=db31a2f202fbc2cf57299a4d2164e3b47ee42128;hp=d8f1933ba98ac8dd3542d819ab2016ea798570ac;hb=1fae28ce79350b03f0cf8a69ad06dd68637cd6b1;hpb=88890fc13f9b346db647c882b376926686177112 diff --git a/pppd/ipcp.c b/pppd/ipcp.c index d8f1933..db31a2f 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -18,7 +18,7 @@ */ #ifndef lint -static char rcsid[] = "$Id: ipcp.c,v 1.26 1996/07/01 01:13:53 paulus Exp $"; +static char rcsid[] = "$Id: ipcp.c,v 1.38 1999/03/12 06:07:17 paulus Exp $"; #endif /* @@ -33,9 +33,7 @@ static char rcsid[] = "$Id: ipcp.c,v 1.26 1996/07/01 01:13:53 paulus Exp $"; #include #include #include -#include -#include -#include +#include #include "pppd.h" #include "fsm.h" @@ -48,10 +46,13 @@ 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 */ +bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ + /* local vars */ static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ 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 */ /* * Callbacks for fsm code. (CI = Configuration Information) @@ -65,7 +66,6 @@ static int ipcp_rejci __P((fsm *, u_char *, int)); /* Peer rej'd our CI */ static int ipcp_reqci __P((fsm *, u_char *, int *, int)); /* Rcv CI */ static void ipcp_up __P((fsm *)); /* We're UP */ static void ipcp_down __P((fsm *)); /* We're DOWN */ -static void ipcp_script __P((fsm *, char *)); /* Run an up/down script */ static void ipcp_finished __P((fsm *)); /* Don't need lower layer */ fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ @@ -88,6 +88,71 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ "IPCP" /* String name of protocol */ }; +/* + * Command-line options. + */ +static int setvjslots __P((char **)); +static int setdnsaddr __P((char **)); +static int setwinsaddr __P((char **)); + +static option_t ipcp_option_list[] = { + { "noip", o_bool, &ipcp_protent.enabled_flag, + "Disable IP and IPCP" }, + { "-ip", o_bool, &ipcp_protent.enabled_flag, + "Disable IP and IPCP" }, + { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, + "Disable VJ compression", OPT_A2COPY, &ipcp_allowoptions[0].neg_vj }, + { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, + "Disable VJ compression", OPT_A2COPY, &ipcp_allowoptions[0].neg_vj }, + { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, + "Disable VJ connection-ID compression", OPT_A2COPY, + &ipcp_allowoptions[0].cflag }, + { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, + "Disable VJ connection-ID compression", OPT_A2COPY, + &ipcp_allowoptions[0].cflag }, + { "vj-max-slots", 1, setvjslots, + "Set maximum VJ header slots" }, + { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, + "Accept peer's address for us", 1 }, + { "ipcp-accept-remote", o_bool, &ipcp_wantoptions[0].accept_remote, + "Accept peer's address for it", 1 }, + { "ipparam", o_string, &ipparam, + "Set ip script parameter" }, + { "noipdefault", o_bool, &disable_defaultip, + "Don't use name for default IP adrs", 1 }, + { "ms-dns", 1, setdnsaddr, + "DNS address for the peer's use" }, + { "ms-wins", 1, setwinsaddr, + "Nameserver for SMB over TCP/IP for peer" }, + { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, + "Set timeout for IPCP" }, + { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, + "Set max #xmits for term-reqs" }, + { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, + "Set max #xmits for conf-reqs" }, + { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, + "Set max #conf-naks for IPCP" }, + { "defaultroute", o_bool, &ipcp_wantoptions[0].default_route, + "Add default route", OPT_ENABLE|1, &ipcp_allowoptions[0].default_route }, + { "nodefaultroute", o_bool, &ipcp_allowoptions[0].default_route, + "disable defaultroute option", OPT_A2COPY, + &ipcp_wantoptions[0].default_route }, + { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, + "disable defaultroute option", OPT_A2COPY, + &ipcp_wantoptions[0].default_route }, + { "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, + "disable proxyarp option", OPT_A2COPY, + &ipcp_wantoptions[0].proxy_arp }, + { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, + "disable proxyarp option", OPT_A2COPY, + &ipcp_wantoptions[0].proxy_arp }, + { "usepeerdns", o_bool, &usepeerdns, + "Ask peer for DNS address(es)" }, + { NULL } +}; + /* * Protocol entry points from main code. */ @@ -103,6 +168,7 @@ static int ipcp_printpkt __P((u_char *, int, static void ip_check_options __P((void)); static int ip_demand_conf __P((int)); static int ip_active_pkt __P((u_char *, int)); +static void create_resolv __P((u_int32_t, u_int32_t)); struct protent ipcp_protent = { PPP_IPCP, @@ -117,11 +183,16 @@ struct protent ipcp_protent = { NULL, 1, "IPCP", + ipcp_option_list, ip_check_options, ip_demand_conf, ip_active_pkt }; +static void ipcp_clear_addrs __P((int)); +static void ipcp_script __P((char *)); /* Run an up/down script */ +static void ipcp_script_done __P((void *)); + /* * Lengths of configuration options. */ @@ -135,6 +206,15 @@ struct protent ipcp_protent = { #define CODENAME(x) ((x) == CONFACK ? "ACK" : \ (x) == CONFNAK ? "NAK" : "REJ") +/* + * This state variable is used to ensure that we don't + * run an ipcp-up/down script while one is already running. + */ +static enum script_state { + s_down, + s_up, +} ipcp_script_state; +static pid_t ipcp_script_pid; /* * Make a string representation of a network IP address. @@ -155,6 +235,92 @@ u_int32_t ipaddr; return b; } +/* + * Option parsing. + */ + +/* + * setvjslots - set maximum number of connection slots for VJ compression + */ +static int +setvjslots(argv) + char **argv; +{ + int value; + + if (!int_option(*argv, &value)) + return 0; + if (value < 2 || value > 16) { + option_error("vj-max-slots value must be between 2 and 16"); + return 0; + } + ipcp_wantoptions [0].maxslotindex = + ipcp_allowoptions[0].maxslotindex = value - 1; + return 1; +} + +/* + * setdnsaddr - set the dns address(es) + */ +static int +setdnsaddr(argv) + char **argv; +{ + u_int32_t dns; + struct hostent *hp; + + dns = inet_addr(*argv); + if (dns == -1) { + if ((hp = gethostbyname(*argv)) == NULL) { + option_error("invalid address parameter '%s' for ms-dns option", + *argv); + return 0; + } + dns = *(u_int32_t *)hp->h_addr; + } + + /* if there is no primary then update it. */ + if (ipcp_allowoptions[0].dnsaddr[0] == 0) + ipcp_allowoptions[0].dnsaddr[0] = dns; + + /* always set the secondary address value to the same value. */ + ipcp_allowoptions[0].dnsaddr[1] = dns; + + return (1); +} + +/* + * setwinsaddr - set the wins address(es) + * This is primrarly used with the Samba package under UNIX or for pointing + * the caller to the existing WINS server on a Windows NT platform. + */ +static int +setwinsaddr(argv) + char **argv; +{ + u_int32_t wins; + struct hostent *hp; + + wins = inet_addr(*argv); + if (wins == -1) { + if ((hp = gethostbyname(*argv)) == NULL) { + option_error("invalid address parameter '%s' for ms-wins option", + *argv); + return 0; + } + wins = *(u_int32_t *)hp->h_addr; + } + + /* if there is no primary then update it. */ + if (ipcp_allowoptions[0].winsaddr[0] == 0) + ipcp_allowoptions[0].winsaddr[0] = wins; + + /* always set the secondary address value to the same value. */ + ipcp_allowoptions[0].winsaddr[1] = wins; + + return (1); +} + /* * ipcp_init - Initialize IPCP. @@ -181,6 +347,10 @@ ipcp_init(unit) wo->maxslotindex = MAX_STATES - 1; /* really max index */ wo->cflag = 1; + wo->req_dns1 = usepeerdns; /* Request DNS addresses from the peer */ + wo->req_dns2 = usepeerdns; + + /* max slots and slot-id compression are currently hardwired in */ /* ppp_if.c to 16 and 1, this needs to be changed (among other */ /* things) gmc */ @@ -272,6 +442,7 @@ ipcp_protrej(unit) /* * ipcp_resetci - Reset our CI. + * Called by fsm_sconfreq, Send Configure Request. */ static void ipcp_resetci(f) @@ -291,6 +462,7 @@ ipcp_resetci(f) /* * ipcp_cilen - Return length of our CI. + * Called by fsm_sconfreq, Send Configure Request. */ static int ipcp_cilen(f) @@ -302,6 +474,7 @@ ipcp_cilen(f) #define LENCIVJ(neg, old) (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) #define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) +#define LENCIDNS(neg) (neg ? (CILEN_ADDR) : 0) /* * First see if we want to change our options to the old @@ -328,12 +501,15 @@ ipcp_cilen(f) } return (LENCIADDR(go->neg_addr, go->old_addrs) + - LENCIVJ(go->neg_vj, go->old_vj)); + LENCIVJ(go->neg_vj, go->old_vj) + + LENCIDNS(go->req_dns1) + + LENCIDNS(go->req_dns2)) ; } /* * ipcp_addci - Add our desired CIs to a packet. + * Called by fsm_sconfreq, Send Configure Request. */ static void ipcp_addci(f, ucp, lenp) @@ -378,18 +554,37 @@ ipcp_addci(f, ucp, lenp) neg = 0; \ } +#define ADDCIDNS(opt, neg) \ + if (neg) { \ + int addrlen = CILEN_ADDR; \ + if (len >= addrlen) { \ + u_int32_t l; \ + PUTCHAR(opt, ucp); \ + PUTCHAR(addrlen, ucp); \ + l = ntohl(0); \ + PUTLONG(l, ucp); \ + len -= addrlen; \ + } else \ + neg = 0; \ + } + ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); + ADDCIDNS(CI_MS_DNS1, go->req_dns1); + + ADDCIDNS(CI_MS_DNS2, go->req_dns2); + *lenp -= len; } /* * ipcp_ackci - Ack our CIs. + * Called by fsm_rconfack, Receive Configure ACK. * * Returns: * 0 - Ack was bad. @@ -480,6 +675,7 @@ bad: * ipcp_nakci - Peer has sent a NAK for some of our CIs. * This should not modify any state if the Nak is bad * or if IPCP is in the OPENED state. + * Calback from fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. * * Returns: * 0 - Nak was bad. @@ -495,7 +691,7 @@ ipcp_nakci(f, p, len) u_char cimaxslotindex, cicflag; u_char citype, cilen, *next; u_short cishort; - u_int32_t ciaddr1, ciaddr2, l; + u_int32_t ciaddr1, ciaddr2, l, cidnsaddr; ipcp_options no; /* options we've seen Naks for */ ipcp_options try; /* options to request next time */ @@ -538,6 +734,22 @@ ipcp_nakci(f, p, len) code \ } +/* + * Peer returns DNS address in a NAK packet + */ +#define NAKCIDNS(opt, neg, code) \ + if (go->neg && \ + ((cilen = p[1]) == CILEN_ADDR) && \ + len >= cilen && \ + p[0] == opt) { \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cidnsaddr = 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. @@ -584,6 +796,18 @@ ipcp_nakci(f, p, len) } ); + NAKCIDNS(CI_MS_DNS1, req_dns1, + try.dnsaddr[0] = cidnsaddr; + IPCPDEBUG((LOG_INFO, "Received DNS address %s", ip_ntoa(cidnsaddr))); + try.req_dns1 = 0; + ); + + NAKCIDNS(CI_MS_DNS2, req_dns2, + try.dnsaddr[1] = cidnsaddr; + IPCPDEBUG((LOG_INFO, "Received DNS address %s", ip_ntoa(cidnsaddr))); + try.req_dns2 = 0; + ); + /* * There may be remaining CIs, if the peer is requesting negotiation * on an option that we didn't include in our request packet. @@ -605,7 +829,7 @@ ipcp_nakci(f, p, len) no.neg_vj = 1; break; case CI_ADDRS: - if (go->neg_addr && go->old_addrs || no.old_addrs + if ((go->neg_addr && go->old_addrs) || no.old_addrs || cilen != CILEN_ADDRS) goto bad; try.neg_addr = 1; @@ -656,6 +880,7 @@ bad: /* * ipcp_rejci - Reject some of our CIs. + * Callback from fsm_rconfnakrej. */ static int ipcp_rejci(f, p, len) @@ -720,12 +945,33 @@ ipcp_rejci(f, p, len) try.neg = 0; \ } +#define REJCIDNS(opt, neg, dnsaddr) \ + if (go->neg && \ + ((cilen = p[1]) == CI_MS_DNS1) && \ + len >= cilen && \ + p[0] == opt) { \ + u_int32_t l; \ + len -= cilen; \ + INCPTR(2, p); \ + GETLONG(l, p); \ + cilong = htonl(l); \ + /* Check rejected value. */ \ + if (cilong != dnsaddr) \ + goto bad; \ + try.neg = 0; \ + } + + REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, go->ouraddr, go->hisaddr); REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, go->maxslotindex, go->cflag); + REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); + + REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); + /* * If there are any remaining CIs, then this packet is bad. */ @@ -746,6 +992,7 @@ bad: /* * ipcp_reqci - Check the peer's requested CIs and send appropriate response. + * Callback from fsm_rconfreq, Receive Configure Request * * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified * appropriately. If reject_if_disagree is non-zero, doesn't return @@ -922,6 +1169,27 @@ ipcp_reqci(f, inp, len, reject_if_disagree) orc = CONFNAK; } break; + + case CI_MS_WINS1: + case CI_MS_WINS2: + /* Microsoft primary or secondary WINS request */ + d = citype == CI_MS_WINS2; + IPCPDEBUG((LOG_INFO, "ipcp: received WINS%d Request ", d+1)); + + /* If we do not have a DNS address then we cannot send it */ + if (ao->winsaddr[d] == 0 || + cilen != CILEN_ADDR) { /* Check CI length */ + orc = CONFREJ; /* Reject CI */ + break; + } + GETLONG(tl, p); + if (htonl(tl) != ao->winsaddr[d]) { + DECPTR(sizeof(u_int32_t), p); + tl = ntohl(ao->winsaddr[d]); + PUTLONG(tl, p); + orc = CONFNAK; + } + break; case CI_COMPRESSTYPE: IPCPDEBUG((LOG_INFO, "ipcp: received COMPRESSTYPE ")); @@ -1062,15 +1330,15 @@ ip_check_options() } if (demand && wo->hisaddr == 0) { - fprintf(stderr, "%s: remote IP address required for demand-dialling\n", - progname); + option_error("remote IP address required for demand-dialling\n"); exit(1); } +#if 0 if (demand && wo->accept_remote) { - fprintf(stderr, "%s: ipcp-accept-remote is incompatible with demand\n", - progname); + option_error("ipcp-accept-remote is incompatible with demand\n"); exit(1); } +#endif } @@ -1086,12 +1354,12 @@ ip_demand_conf(u) if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) return 0; - if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) - return 0; if (!sifup(u)) return 0; + if (!sifnpmode(u, PPP_IP, NPMODE_QUEUE)) + return 0; if (wo->default_route) - if (sifdefaultroute(u, wo->hisaddr)) + if (sifdefaultroute(u, wo->ouraddr, wo->hisaddr)) default_route_set[u] = 1; if (wo->proxy_arp) if (sifproxyarp(u, wo->hisaddr)) @@ -1137,6 +1405,17 @@ ipcp_up(f) ipcp_close(f->unit, "Could not determine local IP address"); return; } + script_setenv("IPLOCAL", ip_ntoa(go->ouraddr)); + script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr)); + + if (usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { + script_setenv("USEPEERDNS", "1"); + if (go->dnsaddr[0]) + script_setenv("DNS1", ip_ntoa(go->dnsaddr[0])); + if (go->dnsaddr[1]) + script_setenv("DNS2", ip_ntoa(go->dnsaddr[1])); + create_resolv(go->dnsaddr[0], go->dnsaddr[1]); + } /* * Check that the peer is allowed to use the IP address it wants. @@ -1158,26 +1437,57 @@ ipcp_up(f) */ if (demand) { if (go->ouraddr != wo->ouraddr || ho->hisaddr != wo->hisaddr) { - syslog(LOG_ERR, "Failed to negotiate desired IP addresses"); - ipcp_close(f->unit, "Wrong IP addresses"); - return; + if (go->ouraddr != wo->ouraddr) { + syslog(LOG_WARNING, "Local IP address changed to %s", + ip_ntoa(go->ouraddr)); + script_setenv("OLDIPLOCAL", ip_ntoa(wo->ouraddr)); + wo->ouraddr = go->ouraddr; + } else + script_unsetenv("OLDIPLOCAL"); + if (ho->hisaddr != wo->hisaddr) { + syslog(LOG_WARNING, "Remote IP address changed to %s", + ip_ntoa(ho->hisaddr)); + script_setenv("OLDIPREMOTE", ip_ntoa(wo->hisaddr)); + wo->hisaddr = ho->hisaddr; + } else + script_unsetenv("OLDIPREMOTE"); + ipcp_clear_addrs(f->unit); + + /* Set the interface to the new addresses */ + mask = GetMask(go->ouraddr); + if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { + IPCPDEBUG((LOG_WARNING, "sifaddr failed")); + ipcp_close(f->unit, "Interface configuration failed"); + return; + } + + /* assign a default route through the interface if required */ + 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. */ + if (ipcp_wantoptions[f->unit].proxy_arp) + if (sifproxyarp(f->unit, ho->hisaddr)) + proxy_arp_set[f->unit] = 1; + } demand_rexmit(PPP_IP); sifnpmode(f->unit, PPP_IP, NPMODE_PASS); - } -#ifndef _linux_ /* Linux destroys routes when the device goes down. */ - else /* always use the code which adds the routes. */ -#endif - { + + } else { /* * Set IP addresses and (if specified) netmask. */ mask = GetMask(go->ouraddr); + +#if !(defined(SVR4) && (defined(SNI) || defined(__USLC__))) if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { IPCPDEBUG((LOG_WARNING, "sifaddr failed")); ipcp_close(f->unit, "Interface configuration failed"); return; } +#endif /* bring the interface up for IP */ if (!sifup(f->unit)) { @@ -1185,11 +1495,19 @@ ipcp_up(f) ipcp_close(f->unit, "Interface configuration failed"); return; } + +#if (defined(SVR4) && (defined(SNI) || defined(__USLC__))) + if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask)) { + IPCPDEBUG((LOG_WARNING, "sifaddr failed")); + ipcp_close(f->unit, "Interface configuration failed"); + return; + } +#endif 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, ho->hisaddr)) + if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) default_route_set[f->unit] = 1; /* Make a proxy ARP entry if requested. */ @@ -1199,14 +1517,18 @@ ipcp_up(f) syslog(LOG_NOTICE, "local IP address %s", ip_ntoa(go->ouraddr)); syslog(LOG_NOTICE, "remote IP address %s", ip_ntoa(ho->hisaddr)); + syslog(LOG_NOTICE, "primary DNS address %s", ip_ntoa(go->dnsaddr[0])); + syslog(LOG_NOTICE, "secondary DNS address %s", ip_ntoa(go->dnsaddr[1])); } /* * Execute the ip-up script, like this: * /etc/ppp/ip-up interface tty speed local-IP remote-IP */ - ipcp_script(f, _PATH_IPUP); - + if (ipcp_script_state == s_down && ipcp_script_pid == 0) { + ipcp_script_state = s_up; + ipcp_script(_PATH_IPUP); + } } @@ -1220,10 +1542,9 @@ static void ipcp_down(f) fsm *f; { - u_int32_t ouraddr, hisaddr; - - np_down(f->unit, PPP_IP); IPCPDEBUG((LOG_INFO, "ipcp: down")); + np_down(f->unit, PPP_IP); + sifvjcomp(f->unit, 0, 0, 0); /* * If we are doing dial-on-demand, set the interface @@ -1231,24 +1552,40 @@ ipcp_down(f) */ if (demand) { sifnpmode(f->unit, PPP_IP, NPMODE_QUEUE); - } else { - ouraddr = ipcp_gotoptions[f->unit].ouraddr; - hisaddr = ipcp_hisoptions[f->unit].hisaddr; - if (proxy_arp_set[f->unit]) { - cifproxyarp(f->unit, hisaddr); - proxy_arp_set[f->unit] = 0; - } - if (default_route_set[f->unit]) { - cifdefaultroute(f->unit, hisaddr); - default_route_set[f->unit] = 0; - } sifdown(f->unit); - cifaddr(f->unit, ouraddr, hisaddr); + ipcp_clear_addrs(f->unit); } /* Execute the ip-down script */ - ipcp_script(f, _PATH_IPDOWN); + if (ipcp_script_state == s_up && ipcp_script_pid == 0) { + ipcp_script_state = s_down; + ipcp_script(_PATH_IPDOWN); + } +} + + +/* + * ipcp_clear_addrs() - clear the interface addresses, routes, + * proxy arp entries, etc. + */ +static void +ipcp_clear_addrs(unit) + int unit; +{ + u_int32_t ouraddr, hisaddr; + + ouraddr = ipcp_gotoptions[unit].ouraddr; + hisaddr = ipcp_hisoptions[unit].hisaddr; + if (proxy_arp_set[unit]) { + cifproxyarp(unit, hisaddr); + proxy_arp_set[unit] = 0; + } + if (default_route_set[unit]) { + cifdefaultroute(unit, ouraddr, hisaddr); + default_route_set[unit] = 0; + } + cifaddr(unit, ouraddr, hisaddr); } @@ -1263,21 +1600,46 @@ ipcp_finished(f) } +/* + * ipcp_script_done - called when the ip-up or ip-down script + * has finished. + */ +static void +ipcp_script_done(arg) + void *arg; +{ + ipcp_script_pid = 0; + switch (ipcp_script_state) { + case s_up: + if (ipcp_fsm[0].state != OPENED) { + ipcp_script_state = s_down; + ipcp_script(_PATH_IPDOWN); + } + break; + case s_down: + if (ipcp_fsm[0].state == OPENED) { + ipcp_script_state = s_up; + ipcp_script(_PATH_IPUP); + } + break; + } +} + + /* * ipcp_script - Execute a script with arguments * interface-name tty-name speed local-IP remote-IP. */ static void -ipcp_script(f, script) - fsm *f; +ipcp_script(script) char *script; { char strspeed[32], strlocal[32], strremote[32]; char *argv[8]; - sprintf(strspeed, "%d", baud_rate); - strcpy(strlocal, ip_ntoa(ipcp_gotoptions[f->unit].ouraddr)); - strcpy(strremote, ip_ntoa(ipcp_hisoptions[f->unit].hisaddr)); + slprintf(strspeed, sizeof(strspeed), "%d", baud_rate); + slprintf(strlocal, sizeof(strlocal), "%I", ipcp_gotoptions[0].ouraddr); + slprintf(strremote, sizeof(strremote), "%I", ipcp_hisoptions[0].hisaddr); argv[0] = script; argv[1] = ifname; @@ -1287,7 +1649,34 @@ ipcp_script(f, script) argv[5] = strremote; argv[6] = ipparam; argv[7] = NULL; - run_program(script, argv, 0); + ipcp_script_pid = run_program(script, argv, 0, ipcp_script_done, NULL); +} + +/* + * create_resolv - create the replacement resolv.conf file + */ +static void +create_resolv(peerdns1, peerdns2) + u_int32_t peerdns1, peerdns2; +{ + FILE *f; + + f = fopen(_PATH_RESOLV, "w"); + if (f == NULL) { + syslog(LOG_ERR, "Failed to create %s: %m", _PATH_RESOLV); + return; + } + + if (peerdns1) + fprintf(f, "nameserver %s\n", ip_ntoa(peerdns1)); + + if (peerdns2) + fprintf(f, "nameserver %s\n", ip_ntoa(peerdns2)); + + if (ferror(f)) + syslog(LOG_ERR, "Write failed to %s: %m", _PATH_RESOLV); + + fclose(f); } /* @@ -1346,9 +1735,9 @@ ipcp_printpkt(p, plen, printer, arg) if (olen == CILEN_ADDRS) { p += 2; GETLONG(cilong, p); - printer(arg, "addrs %s", ip_ntoa(htonl(cilong))); + printer(arg, "addrs %I", htonl(cilong)); GETLONG(cilong, p); - printer(arg, " %s", ip_ntoa(htonl(cilong))); + printer(arg, " %I", htonl(cilong)); } break; case CI_COMPRESSTYPE: @@ -1372,9 +1761,21 @@ ipcp_printpkt(p, plen, printer, arg) if (olen == CILEN_ADDR) { p += 2; GETLONG(cilong, p); - printer(arg, "addr %s", ip_ntoa(htonl(cilong))); + printer(arg, "addr %I", htonl(cilong)); } break; + case CI_MS_DNS1: + case CI_MS_DNS2: + p += 2; + GETLONG(cilong, p); + printer(arg, "ms-dns %I", htonl(cilong)); + break; + case CI_MS_WINS1: + case CI_MS_WINS2: + p += 2; + GETLONG(cilong, p); + printer(arg, "ms-wins %I", htonl(cilong)); + break; } while (p < optend) { GETCHAR(code, p); @@ -1409,31 +1810,45 @@ ipcp_printpkt(p, plen, printer, arg) * We don't bring the link up for IP fragments or for TCP FIN packets * with no data. */ -#ifndef IP_OFFMASK +#define IP_HDRLEN 20 /* bytes */ #define IP_OFFMASK 0x1fff -#endif +#define IPPROTO_TCP 6 +#define TCP_HDRLEN 20 +#define TH_FIN 0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define net_short(x) (((x)[0] << 8) + (x)[1]) +#define get_iphl(x) (((unsigned char *)(x))[0] & 0xF) +#define get_ipoff(x) net_short((unsigned char *)(x) + 6) +#define get_ipproto(x) (((unsigned char *)(x))[9]) +#define get_tcpoff(x) (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) static int ip_active_pkt(pkt, len) u_char *pkt; int len; { - struct ip *ip; - struct tcphdr *tcp; + u_char *tcp; int hlen; - if (len < sizeof(struct ip) + PPP_HDRLEN) + len -= PPP_HDRLEN; + pkt += PPP_HDRLEN; + if (len < IP_HDRLEN) return 0; - ip = (struct ip *) (pkt + PPP_HDRLEN); - if ((ntohs(ip->ip_off) & IP_OFFMASK) != 0) + if ((get_ipoff(pkt) & IP_OFFMASK) != 0) return 0; - if (ip->ip_p != IPPROTO_TCP) + if (get_ipproto(pkt) != IPPROTO_TCP) return 1; - hlen = ip->ip_hl * 4; - if (len < hlen + sizeof(struct tcphdr) + PPP_HDRLEN) + hlen = get_iphl(pkt) * 4; + if (len < hlen + TCP_HDRLEN) return 0; - tcp = (struct tcphdr *) (pkt + PPP_HDRLEN + hlen); - if ((tcp->th_flags & TH_FIN) != 0 && hlen + tcp->th_off * 4 == len) + tcp = pkt + hlen; + if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) return 0; return 1; }