X-Git-Url: http://git.ozlabs.org/?p=ppp.git;a=blobdiff_plain;f=pppd%2Fipcp.c;h=3fc5f27f1736bdc9c1f1c597cabd777c4d653cf7;hp=8c09d705be3f5b29f0d4d8926500a23293b56428;hb=05c09ae62d0b4ff67fb26c37a01e6a07bb593c0c;hpb=52a17b6d41d64d0502a73e5b4224546360581b49 diff --git a/pppd/ipcp.c b/pppd/ipcp.c index 8c09d70..3fc5f27 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.55 2000/06/30 04:54:20 paulus Exp $" +#define RCSID "$Id: ipcp.c,v 1.60 2002/01/22 16:02:58 dfs Exp $" /* * TODO: @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -42,9 +43,11 @@ static const char rcsid[] = RCSID; /* global vars */ ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ 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_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 */ @@ -56,12 +59,18 @@ 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; +/* Notifiers for when IPCP goes up and down */ +struct notifier *ip_up_notifier = NULL; +struct notifier *ip_down_notifier = 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 */ +static char vj_value[8]; /* string form of vj option value */ +static char netmask_str[20]; /* string form of netmask value */ /* * Callbacks for fsm code. (CI = Configuration Information) @@ -103,62 +112,86 @@ 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 **)); +int setipaddr __P((char *, char **, int)); +static void printipaddr __P((option_t *, void (*)(void *, char *,...),void *)); 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" }, + "Disable IP and IPCP", OPT_ALIAS }, + { "novj", o_bool, &ipcp_wantoptions[0].neg_vj, - "Disable VJ compression", OPT_A2COPY, &ipcp_allowoptions[0].neg_vj }, + "Disable VJ compression", OPT_A2CLR, &ipcp_allowoptions[0].neg_vj }, { "-vj", o_bool, &ipcp_wantoptions[0].neg_vj, - "Disable VJ compression", OPT_A2COPY, &ipcp_allowoptions[0].neg_vj }, + "Disable VJ compression", OPT_ALIAS | OPT_A2CLR, + &ipcp_allowoptions[0].neg_vj }, + { "novjccomp", o_bool, &ipcp_wantoptions[0].cflag, - "Disable VJ connection-ID compression", OPT_A2COPY, + "Disable VJ connection-ID compression", OPT_A2CLR, &ipcp_allowoptions[0].cflag }, { "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag, - "Disable VJ connection-ID compression", OPT_A2COPY, + "Disable VJ connection-ID compression", OPT_ALIAS | OPT_A2CLR, &ipcp_allowoptions[0].cflag }, - { "vj-max-slots", 1, (void *)setvjslots, - "Set maximum VJ header slots" }, + + { "vj-max-slots", o_special, (void *)setvjslots, + "Set maximum VJ header slots", + OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, vj_value }, + { "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" }, + "Set ip script parameter", OPT_PRIO }, + { "noipdefault", o_bool, &disable_defaultip, "Don't use name for default IP adrs", 1 }, + { "ms-dns", 1, (void *)setdnsaddr, "DNS address for the peer's use" }, { "ms-wins", 1, (void *)setwinsaddr, "Nameserver for SMB over TCP/IP for peer" }, + { "ipcp-restart", o_int, &ipcp_fsm[0].timeouttime, - "Set timeout for IPCP" }, + "Set timeout for IPCP", OPT_PRIO }, { "ipcp-max-terminate", o_int, &ipcp_fsm[0].maxtermtransmits, - "Set max #xmits for term-reqs" }, + "Set max #xmits for term-reqs", OPT_PRIO }, { "ipcp-max-configure", o_int, &ipcp_fsm[0].maxconfreqtransmits, - "Set max #xmits for conf-reqs" }, + "Set max #xmits for conf-reqs", OPT_PRIO }, { "ipcp-max-failure", o_int, &ipcp_fsm[0].maxnakloops, - "Set max #conf-naks for IPCP" }, + "Set max #conf-naks for IPCP", OPT_PRIO }, + { "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, + "disable defaultroute option", OPT_A2CLR, &ipcp_wantoptions[0].default_route }, { "-defaultroute", o_bool, &ipcp_allowoptions[0].default_route, - "disable defaultroute option", OPT_A2COPY, + "disable defaultroute option", OPT_ALIAS | OPT_A2CLR, &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, + "disable proxyarp option", OPT_A2CLR, &ipcp_wantoptions[0].proxy_arp }, { "-proxyarp", o_bool, &ipcp_allowoptions[0].proxy_arp, - "disable proxyarp option", OPT_A2COPY, + "disable proxyarp option", OPT_ALIAS | OPT_A2CLR, &ipcp_wantoptions[0].proxy_arp }, + { "usepeerdns", o_bool, &usepeerdns, "Ask peer for DNS address(es)", 1 }, + + { "netmask", o_special, (void *)setnetmask, + "set netmask", OPT_PRIO | OPT_A2STRVAL | OPT_STATIC, netmask_str }, + + { "IP addresses", o_wild, (void *) &setipaddr, + "set local and remote IP addresses", + OPT_NOARG | OPT_A2PRINTER, (void *) &printipaddr }, + { NULL } }; @@ -260,6 +293,7 @@ setvjslots(argv) } ipcp_wantoptions [0].maxslotindex = ipcp_allowoptions[0].maxslotindex = value - 1; + slprintf(vj_value, sizeof(vj_value), "%d", value); return 1; } @@ -283,11 +317,15 @@ setdnsaddr(argv) dns = *(u_int32_t *)hp->h_addr; } - /* if there is no primary then update it. */ - if (ipcp_allowoptions[0].dnsaddr[0] == 0) + /* We take the last 2 values given, the 2nd-last as the primary + and the last as the secondary. If only one is given it + becomes both primary and secondary. */ + if (ipcp_allowoptions[0].dnsaddr[1] == 0) ipcp_allowoptions[0].dnsaddr[0] = dns; + else + ipcp_allowoptions[0].dnsaddr[0] = ipcp_allowoptions[0].dnsaddr[1]; - /* always set the secondary address value to the same value. */ + /* always set the secondary address value. */ ipcp_allowoptions[0].dnsaddr[1] = dns; return (1); @@ -315,16 +353,172 @@ setwinsaddr(argv) wins = *(u_int32_t *)hp->h_addr; } - /* if there is no primary then update it. */ - if (ipcp_allowoptions[0].winsaddr[0] == 0) + /* We take the last 2 values given, the 2nd-last as the primary + and the last as the secondary. If only one is given it + becomes both primary and secondary. */ + if (ipcp_allowoptions[0].winsaddr[1] == 0) ipcp_allowoptions[0].winsaddr[0] = wins; + else + ipcp_allowoptions[0].winsaddr[0] = ipcp_allowoptions[0].winsaddr[1]; - /* always set the secondary address value to the same value. */ + /* always set the secondary address value. */ ipcp_allowoptions[0].winsaddr[1] = wins; 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. + * Not static so that plugins can call it to set the addresses + */ +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; +} + +static void +printipaddr(opt, printer, arg) + option_t *opt; + void (*printer) __P((void *, char *, ...)); + void *arg; +{ + ipcp_options *wo = &ipcp_wantoptions[0]; + + if (wo->ouraddr != 0) + printer(arg, "%I", wo->ouraddr); + printer(arg, ":"); + if (wo->hisaddr != 0) + printer(arg, "%I", wo->hisaddr); +} + +/* + * 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; + slprintf(netmask_str, sizeof(netmask_str), "%I", 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. @@ -462,8 +656,12 @@ ipcp_resetci(f) *go = *wo; if (!ask_for_local) go->ouraddr = 0; - if (ip_choose_hook) + if (ip_choose_hook) { ip_choose_hook(&wo->hisaddr); + if (wo->hisaddr) { + wo->accept_remote = 0; + } + } } @@ -1520,6 +1718,7 @@ ipcp_up(f) np_up(f->unit, PPP_IP); ipcp_is_up = 1; + notify(ip_up_notifier, 0); if (ip_up_hook) ip_up_hook(); @@ -1548,6 +1747,7 @@ ipcp_down(f) /* XXX a bit IPv4-centric here, we only need to get the stats * before the interface is marked down. */ update_link_stats(f->unit); + notify(ip_down_notifier, 0); if (ip_down_hook) ip_down_hook(); if (ipcp_is_up) { @@ -1823,7 +2023,9 @@ ipcp_printpkt(p, plen, printer, arg) */ #define IP_HDRLEN 20 /* bytes */ #define IP_OFFMASK 0x1fff +#ifndef IPPROTO_TCP #define IPPROTO_TCP 6 +#endif #define TCP_HDRLEN 20 #define TH_FIN 0x01