* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
-#define RCSID "$Id: ipcp.c,v 1.53 2000/04/04 07:06:49 paulus Exp $"
+#define RCSID "$Id: ipcp.c,v 1.56 2001/02/22 03:15:16 paulus Exp $"
/*
* TODO:
#include <stdio.h>
#include <string.h>
+#include <stdlib.h>
#include <netdb.h>
#include <sys/param.h>
#include <sys/types.h>
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 */
/* 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)
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,
{ "-vjccomp", o_bool, &ipcp_wantoptions[0].cflag,
"Disable VJ connection-ID compression", OPT_A2COPY,
&ipcp_allowoptions[0].cflag },
- { "vj-max-slots", 1, 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 },
"Set ip script parameter" },
{ "noipdefault", o_bool, &disable_defaultip,
"Don't use name for default IP adrs", 1 },
- { "ms-dns", 1, setdnsaddr,
+ { "ms-dns", 1, (void *)setdnsaddr,
"DNS address for the peer's use" },
- { "ms-wins", 1, setwinsaddr,
+ { "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" },
&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 }
};
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.
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);
}
* 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.
wo->ouraddr = local;
}
}
+ ask_for_local = wo->ouraddr != 0 || !disable_defaultip;
}
/* 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;
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);
case TERMREQ:
if (len > 0 && *p >= ' ' && *p < 0x7f) {
printer(arg, " ");
- print_string(p, len, printer, arg);
+ print_string((char *)p, len, printer, arg);
p += len;
len = 0;
}