X-Git-Url: https://git.ozlabs.org/?a=blobdiff_plain;f=pppd%2Fipcp.c;h=71db5dd39f8368622b8145a144c09c777a7cb166;hb=6c85691696e798a46158b459436a78fba3dcc46f;hp=484c00c4b988c9a49f58b6912d9cd55e12a2fd4d;hpb=5b7a245572fb88a6c0aa2e753c74040105571ceb;p=ppp.git diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 484c00c..71db5dd 100644 --- a/pppd/ipcp.c +++ b/pppd/ipcp.c @@ -17,7 +17,7 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ -#define RCSID "$Id: ipcp.c,v 1.54 2000/04/15 01:27:11 masputra Exp $" +#define RCSID "$Id: ipcp.c,v 1.56 2001/02/22 03:15:16 paulus Exp $" /* * TODO: @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -45,6 +46,8 @@ 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 */ +u_int32_t netmask = 0; /* IP netmask to set on interface */ + bool disable_defaultip = 0; /* Don't use hostname for default IP adrs */ /* Hook for a plugin to know when IP protocol has come up */ @@ -53,11 +56,15 @@ void (*ip_up_hook) __P((void)) = NULL; /* Hook for a plugin to know when IP protocol has come down */ void (*ip_down_hook) __P((void)) = NULL; +/* Hook for a plugin to choose the remote IP address */ +void (*ip_choose_hook) __P((u_int32_t *)) = NULL; + /* local vars */ 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 int ipcp_is_up; /* have called np_up() */ +static bool ask_for_local; /* request our address from peer */ /* * Callbacks for fsm code. (CI = Configuration Information) @@ -99,6 +106,8 @@ static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ static int setvjslots __P((char **)); static int setdnsaddr __P((char **)); static int setwinsaddr __P((char **)); +static int setnetmask __P((char **)); +static int setipaddr __P((char *, char **, int)); static option_t ipcp_option_list[] = { { "noip", o_bool, &ipcp_protent.enabled_flag, @@ -115,7 +124,7 @@ static option_t ipcp_option_list[] = { { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, "Disable VJ connection-ID compression", OPT_A2COPY, &ipcp_allowoptions[0].cflag }, - { "vj-max-slots", 1, (void *)setvjslots, + { "vj-max-slots", o_special, (void *)setvjslots, "Set maximum VJ header slots" }, { "ipcp-accept-local", o_bool, &ipcp_wantoptions[0].accept_local, "Accept peer's address for us", 1 }, @@ -155,6 +164,10 @@ static option_t ipcp_option_list[] = { &ipcp_wantoptions[0].proxy_arp }, { "usepeerdns", o_bool, &usepeerdns, "Ask peer for DNS address(es)", 1 }, + { "netmask", o_special, (void *)setnetmask, + "set netmask" }, + { "IP addresses", o_wild, (void *) &setipaddr, + "set local and remote IP addresses", OPT_NOARG | OPT_MULTIPART }, { NULL } }; @@ -321,6 +334,140 @@ setwinsaddr(argv) return (1); } +/* + * setipaddr - Set the IP address + * If doit is 0, the call is to check whether this option is + * potentially an IP address specification. + */ +static int +setipaddr(arg, argv, doit) + char *arg; + char **argv; + int doit; +{ + struct hostent *hp; + char *colon; + u_int32_t local, remote; + ipcp_options *wo = &ipcp_wantoptions[0]; + static int prio_local = 0, prio_remote = 0; + + /* + * IP address pair separated by ":". + */ + if ((colon = strchr(arg, ':')) == NULL) + return 0; + if (!doit) + return 1; + + /* + * If colon first character, then no local addr. + */ + if (colon != arg && option_priority >= prio_local) { + *colon = '\0'; + if ((local = inet_addr(arg)) == (u_int32_t) -1) { + if ((hp = gethostbyname(arg)) == NULL) { + 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)); + return 0; + } + if (local != 0) + wo->ouraddr = local; + *colon = ':'; + prio_local = option_priority; + } + + /* + * If colon last character, then no remote addr. + */ + 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); + 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)); + return 0; + } + if (remote != 0) + wo->hisaddr = remote; + prio_remote = option_priority; + } + + return 1; +} + +/* + * setnetmask - set the netmask to be used on the interface. + */ +static int +setnetmask(argv) + char **argv; +{ + u_int32_t mask; + int n; + char *p; + + /* + * Unfortunately, if we use inet_addr, we can't tell whether + * a result of all 1s is an error or a valid 255.255.255.255. + */ + p = *argv; + n = parse_dotted_ip(p, &mask); + + mask = htonl(mask); + + if (n == 0 || p[n] != 0 || (netmask & ~mask) != 0) { + option_error("invalid netmask value '%s'", *argv); + return 0; + } + + netmask = mask; + return (1); +} + +int +parse_dotted_ip(p, vp) + char *p; + u_int32_t *vp; +{ + int n; + u_int32_t v, b; + char *endp, *p0 = p; + + v = 0; + for (n = 3;; --n) { + b = strtoul(p, &endp, 0); + if (endp == p) + return 0; + if (b > 255) { + if (n < 3) + return 0; + /* accept e.g. 0xffffff00 */ + *vp = b; + return endp - p0; + } + v |= b << (n * 8); + p = endp; + if (n == 0) + break; + if (*p != '.') + return 0; + ++p; + } + *vp = v; + return p - p0; +} + /* * ipcp_init - Initialize IPCP. @@ -449,15 +596,17 @@ ipcp_resetci(f) ipcp_options *go = &ipcp_gotoptions[f->unit]; wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; - if (wo->ouraddr == 0 || disable_defaultip) + 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; *go = *wo; - if (disable_defaultip) + if (!ask_for_local) go->ouraddr = 0; + if (ip_choose_hook) + ip_choose_hook(&wo->hisaddr); } @@ -1300,7 +1449,7 @@ ip_check_options() * Default our local IP address based on our hostname. * If local IP address already given, don't bother. */ - if (wo->ouraddr == 0) { + if (wo->ouraddr == 0 && !disable_defaultip) { /* * Look up our hostname (possibly with domain name appended) * and take the first IP address as our local IP address. @@ -1313,6 +1462,7 @@ ip_check_options() wo->ouraddr = local; } } + ask_for_local = wo->ouraddr != 0 || !disable_defaultip; } @@ -1335,7 +1485,7 @@ ip_demand_conf(u) /* make up an arbitrary address for us */ wo->ouraddr = htonl(0x0a404040 + ifunit); wo->accept_local = 1; - disable_defaultip = 1; /* don't tell the peer this address */ + ask_for_local = 0; /* don't tell the peer this address */ } if (!sifaddr(u, wo->ouraddr, wo->hisaddr, GetMask(wo->ouraddr))) return 0; @@ -1379,16 +1529,16 @@ ipcp_up(f) if (!ho->neg_addr) ho->hisaddr = wo->hisaddr; - if (ho->hisaddr == 0) { - error("Could not determine remote IP address"); - ipcp_close(f->unit, "Could not determine remote IP address"); - return; - } if (go->ouraddr == 0) { error("Could not determine local IP address"); ipcp_close(f->unit, "Could not determine local IP address"); return; } + if (ho->hisaddr == 0) { + ho->hisaddr = htonl(0x0a404040 + ifunit); + warn("Could not determine remote IP address: defaulting to %I", + ho->hisaddr); + } script_setenv("IPLOCAL", ip_ntoa(go->ouraddr), 0); script_setenv("IPREMOTE", ip_ntoa(ho->hisaddr), 1);