diff options
author | Shane Kerr <shane@isc.org> | 2006-08-09 11:26:30 +0000 |
---|---|---|
committer | Shane Kerr <shane@isc.org> | 2006-08-09 11:26:30 +0000 |
commit | c8f0261f9e958a19364946d403a5f69c5b51a853 (patch) | |
tree | fcff3629f804b38d8a091c9dff86a0fc5dcd4960 | |
parent | 8db46562974aebf319aed7b1083715d639ad4cac (diff) | |
download | isc-dhcp-c8f0261f9e958a19364946d403a5f69c5b51a853.tar.gz |
Mostly complete interface code.DHCPv6_socket_pre_parsing
-rw-r--r-- | client/dhclient.c | 8 | ||||
-rw-r--r-- | common/conflex.c | 4 | ||||
-rw-r--r-- | common/discover.c | 519 | ||||
-rw-r--r-- | common/dlpi.c | 10 | ||||
-rw-r--r-- | common/inet.c | 69 | ||||
-rw-r--r-- | common/parse.c | 96 | ||||
-rw-r--r-- | common/socket.c | 121 | ||||
-rw-r--r-- | common/tables.c | 5 | ||||
-rw-r--r-- | dhcpctl/omshell.c | 6 | ||||
-rw-r--r-- | includes/cf/sunos5-5.h | 1 | ||||
-rw-r--r-- | includes/dhcpd.h | 38 | ||||
-rw-r--r-- | includes/dhctoken.h | 5 | ||||
-rw-r--r-- | relay/dhcrelay.c | 8 | ||||
-rw-r--r-- | server/confpars.c | 332 | ||||
-rw-r--r-- | server/dhcpd.c | 23 | ||||
-rw-r--r-- | server/mdb.c | 38 |
16 files changed, 889 insertions, 394 deletions
diff --git a/client/dhclient.c b/client/dhclient.c index 53ac8317..15527054 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -32,7 +32,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhclient.c,v 1.142 2006/07/19 17:14:55 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhclient.c,v 1.142.16.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -79,10 +79,8 @@ static void usage PROTO ((void)); void do_release(struct client_state *); -int main (argc, argv, envp) - int argc; - char **argv, **envp; -{ +int +main(int argc, char **argv) { int fd; int i; struct servent *ent; diff --git a/common/conflex.c b/common/conflex.c index 7184a4aa..405c1c59 100644 --- a/common/conflex.c +++ b/common/conflex.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: conflex.c,v 1.101 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: conflex.c,v 1.101.8.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -1117,6 +1117,8 @@ static enum dhcp_token intern (atom, dfv) return SUBCLASS; if (!strcasecmp(atom + 3, "net")) return SUBNET; + if (!strcasecmp(atom + 3, "net6")) + return SUBNET6; if (!strcasecmp(atom + 3, "string")) return SUBSTRING; break; diff --git a/common/discover.c b/common/discover.c index 4d22d149..e1ebf955 100644 --- a/common/discover.c +++ b/common/discover.c @@ -1,6 +1,6 @@ -/* dispatch.c +/* discover.c - Network input dispatcher... */ + Find and identify the network interfaces. */ /* * Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC") @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: discover.c,v 1.50 2006/02/27 23:56:13 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: discover.c,v 1.50.98.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -51,7 +51,10 @@ isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *); int (*dhcp_interface_shutdown_hook) (struct interface_info *); struct in_addr limited_broadcast; + +int local_family = AF_INET; struct in_addr local_address; +struct in6_addr local_address6; void (*bootp_packet_handler) PROTO ((struct interface_info *, struct dhcp_packet *, unsigned, @@ -116,94 +119,215 @@ isc_result_t interface_initialize (omapi_object_t *ipo, return ISC_R_SUCCESS; } -/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. - For each interface that's of type INET and not the loopback interface, - register that interface with the network I/O software, figure out what - subnet it's on, and add it to the list of interfaces. */ +/* XXX: needs to be autoconfiscated */ +#define HAVE_SIOCGLIFCONF -void discover_interfaces (state) - int state; -{ - struct interface_info *tmp, *ip; - struct interface_info *last, *next; - char buf [2048]; - struct ifconf ic; - struct ifreq ifr; - int i; +/* + * Solaris' extended interface is documented in the if_tcp man page. + */ +#ifdef HAVE_SIOCGLIFCONF +struct iface_conf_list { int sock; - int address_count = 0; - struct subnet *subnet; - struct shared_network *share; - struct sockaddr_in foo; - int ir; - struct ifreq *tif; -#ifdef ALIAS_NAMES_PERMUTED + int num; + struct lifconf conf; + int next; +}; + +struct iface_info { + char name[LIFNAMSIZ]; + struct sockaddr_storage addr; + uint64_t flags; +}; + +int +begin_iface_scan(struct iface_conf_list *ifaces) { + struct lifnum lifnum; + + ifaces->sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + if (ifaces->sock < 0) { + log_error("Error creating socket to list interfaces; %m"); + return 0; + } + + memset(&lifnum, 0, sizeof(lifnum)); + lifnum.lifn_family = AF_UNSPEC; + if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) { + log_error("Error finding total number of interfaces; %m"); + close(ifaces->sock); + ifaces->sock = -1; + return 0; + } + + ifaces->num = lifnum.lifn_count; + memset(&ifaces->conf, 0, sizeof(ifaces->conf)); + ifaces->conf.lifc_family = AF_UNSPEC; + ifaces->conf.lifc_len = ifaces->num * sizeof(struct lifreq); + ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL); + if (ifaces->conf.lifc_buf == NULL) { + log_fatal("Out of memory getting interface list."); + } + + if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) { + log_error("Error getting interfaces configuration list; %m"); + dfree(ifaces->conf.lifc_buf, MDL); + close(ifaces->sock); + ifaces->sock = -1; + return 0; + } + + ifaces->next = 0; + + return 1; +} + +int +next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) { + struct lifreq *p; + struct lifreq tmp; char *s; -#endif - isc_result_t status; - static int setup_fallback = 0; - int wifcount = 0; - /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ - if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - log_fatal ("Can't create addrlist socket"); + do { + if (ifaces->next >= ifaces->num) { + *err = 0; + return 0; + } - /* Get the interface configuration information... */ + p = ifaces->conf.lifc_req; + p += ifaces->next; -#ifdef SIOCGIFCONF_ZERO_PROBE - /* linux will only tell us how long a buffer it wants if we give it - * a null buffer first. So, do a dry run to figure out the length. - * - * XXX this code is duplicated from below because trying to fold - * the logic into the if statement and goto resulted in excesssive - * obfuscation. The intent is that unless you run Linux you shouldn't - * have to deal with this. */ + strcpy(info->name, p->lifr_name); + info->addr = p->lifr_addr; - ic.ifc_len = 0; - ic.ifc_ifcu.ifcu_buf = (caddr_t)NULL; -#else - /* otherwise, we just feed it a starting size, and it'll tell us if - * it needs more */ +#ifdef ALIAS_NAMED_PERMUTED + /* interface aliases look like "eth0:1" or "wlan1:3" */ + s = strchr(info->name, ':'); + if (s != NULL) { + *s = '\0'; + } +#endif - ic.ifc_len = sizeof buf; - ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; +#ifdef SKIP_DUMMY_INTERFACES + } while (strncmp(info->name, "dummy", 5) == 0); +#else + } while (0); #endif + + memset(&tmp, 0, sizeof(tmp)); + strcpy(tmp.lifr_name, p->lifr_name); + if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) { + log_error("Error getting interfaces flags for %s; %m", + p->lifr_name); + *err = 1; + return 0; + } + info->flags = tmp.lifr_flags; - gifconf_again: - i = ioctl(sock, SIOCGIFCONF, &ic); + ifaces->next++; + *err = 0; + return 1; +} - if (i < 0) - log_fatal ("ioctl: SIOCGIFCONF: %m"); +void +end_iface_scan(struct iface_conf_list *ifaces) { + dfree(ifaces->conf.lifc_buf, MDL); + close(ifaces->sock); + ifaces->sock = -1; +} +#else +/* XXX: need non-Solaris versions */ +#endif + +/* XXX: perhaps create drealloc() rather than do it manually */ +void +add_ipv4_addr_to_interface(struct interface_info *iface, + const struct in_addr *addr) { + if (iface->addresses == NULL) { + iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL); + if (iface->addresses == NULL) { + log_fatal("Out of memory saving IPv4 address " + "on interface."); + } + iface->address_count = 0; + iface->address_max = 4; + } else if (iface->address_count >= iface->address_max) { + struct in_addr *tmp; + int new_max; + + new_max = iface->address_max * 2; + tmp = dmalloc(new_max * sizeof(struct in_addr), MDL); + if (tmp == NULL) { + log_fatal("Out of memory saving IPv4 address " + "on interface."); + } + memcpy(tmp, + iface->addresses, + iface->address_max * sizeof(struct in_addr)); + dfree(iface->addresses, MDL); + iface->addresses = tmp; + iface->address_max = new_max; + } + iface->addresses[iface->address_count++] = *addr; +} -#ifdef SIOCGIFCONF_ZERO_PROBE - /* Workaround for SIOCGIFCONF bug on some Linux versions. */ - if (ic.ifc_ifcu.ifcu_buf == 0 && ic.ifc_len == 0) { - ic.ifc_len = sizeof buf; - ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; - goto gifconf_again; +/* XXX: perhaps create drealloc() rather than do it manually */ +void +add_ipv6_addr_to_interface(struct interface_info *iface, + const struct in6_addr *addr) { + if (iface->v6addresses == NULL) { + iface->v6addresses = dmalloc(4 * sizeof(struct in6_addr), MDL); + if (iface->v6addresses == NULL) { + log_fatal("Out of memory saving IPv6 address " + "on interface."); + } + iface->v6address_count = 0; + iface->v6address_max = 4; + } else if (iface->v6address_count >= iface->v6address_max) { + struct in6_addr *tmp; + int new_max; + + new_max = iface->v6address_max * 2; + tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL); + if (tmp == NULL) { + log_fatal("Out of memory saving IPv6 address " + "on interface."); + } + memcpy(tmp, + iface->v6addresses, + iface->v6address_max * sizeof(struct in6_addr)); + dfree(iface->v6addresses, MDL); + iface->v6addresses = tmp; + iface->v6address_max = new_max; } -#endif + iface->v6addresses[iface->v6address_count++] = *addr; +} - /* If the SIOCGIFCONF resulted in more data than would fit in - a buffer, allocate a bigger buffer. */ - if ((ic.ifc_ifcu.ifcu_buf == buf -#ifdef SIOCGIFCONF_ZERO_PROBE - || ic.ifc_ifcu.ifcu_buf == 0 -#endif - ) && ic.ifc_len > sizeof buf) { - ic.ifc_ifcu.ifcu_buf = dmalloc ((size_t)ic.ifc_len, MDL); - if (!ic.ifc_ifcu.ifcu_buf) - log_fatal ("Can't allocate SIOCGIFCONF buffer."); - goto gifconf_again; -#ifdef SIOCGIFCONF_ZERO_PROBE - } else if (ic.ifc_ifcu.ifcu_buf == 0) { - ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; - ic.ifc_len = sizeof buf; - goto gifconf_again; -#endif +/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. + For each interface that's of type INET and not the loopback interface, + register that interface with the network I/O software, figure out what + subnet it's on, and add it to the list of interfaces. */ + +void +discover_interfaces(int state) { + struct iface_conf_list ifaces; + struct iface_info info; + int err; + + struct interface_info *tmp, *ip; + struct interface_info *last, *next; + + char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + + struct subnet *subnet; + int ir; + isc_result_t status; + int wifcount = 0; + + static int setup_fallback = 0; + + if (!begin_iface_scan(&ifaces)) { + log_fatal("Can't get list of interfaces."); } - /* If we already have a list of interfaces, and we're running as a DHCP server, the interfaces were requested. */ if (interfaces && (state == DISCOVER_SERVER || @@ -216,130 +340,81 @@ void discover_interfaces (state) ir = INTERFACE_REQUESTED; /* Cycle through the list of interfaces looking for IP addresses. */ - for (i = 0; i < ic.ifc_len;) { - struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i); -#ifdef HAVE_SA_LEN - if (ifp -> ifr_addr.sa_len > sizeof (struct sockaddr)) - i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len; - else -#endif - i += sizeof *ifp; - -#ifdef ALIAS_NAMES_PERMUTED - if ((s = strrchr (ifp -> ifr_name, ':'))) { - *s = 0; - } -#endif - -#ifdef SKIP_DUMMY_INTERFACES - if (!strncmp (ifp -> ifr_name, "dummy", 5)) - continue; -#endif - - - /* See if this is the sort of interface we want to - deal with. */ - strcpy (ifr.ifr_name, ifp -> ifr_name); - if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) - log_fatal ("Can't get interface flags for %s: %m", - ifr.ifr_name); + while (next_iface(&info, &err, &ifaces)) { /* See if we've seen an interface that matches this one. */ - for (tmp = interfaces; tmp; tmp = tmp -> next) - if (!strcmp (tmp -> name, ifp -> ifr_name)) + for (tmp = interfaces; tmp; tmp = tmp->next) { + if (!strcmp(tmp->name, info.name)) break; + } /* Skip non broadcast interfaces (plus loopback and point-to-point in case an OS incorrectly marks them as broadcast). Also skip down interfaces unless we're trying to get a list of configurable interfaces. */ - if (((!(ifr.ifr_flags & IFF_BROADCAST) || - ifr.ifr_flags & IFF_LOOPBACK || - ifr.ifr_flags & IFF_POINTOPOINT) && !tmp) || - (!(ifr.ifr_flags & IFF_UP) && + if (((!(info.flags & IFF_BROADCAST) || + info.flags & IFF_LOOPBACK || + info.flags & IFF_POINTOPOINT) && !tmp) || + (!(info.flags & IFF_UP) && state != DISCOVER_UNCONFIGURED)) continue; /* If there isn't already an interface by this name, allocate one. */ if (!tmp) { - tmp = (struct interface_info *)0; - status = interface_allocate (&tmp, MDL); - if (status != ISC_R_SUCCESS) - log_fatal ("Error allocating interface %s: %s", - ifp -> ifr_name, - isc_result_totext (status)); - strcpy (tmp -> name, ifp -> ifr_name); - interface_snorf (tmp, ir); - interface_dereference (&tmp, MDL); + tmp = NULL; + status = interface_allocate(&tmp, MDL); + if (status != ISC_R_SUCCESS) { + log_fatal("Error allocating interface %s: %s", + info.name, isc_result_totext(status)); + } + strcpy(tmp->name, info.name); + interface_snorf(tmp, ir); + interface_dereference(&tmp, MDL); tmp = interfaces; /* XXX */ } - if (dhcp_interface_discovery_hook) - (*dhcp_interface_discovery_hook) (tmp); + if (dhcp_interface_discovery_hook) { + (*dhcp_interface_discovery_hook)(tmp); + } /* If we have the capability, extract link information - and record it in a linked list. */ + and record it in. */ #ifdef HAVE_AF_LINK - if (ifp -> ifr_addr.sa_family == AF_LINK) { - struct sockaddr_dl *foo = ((struct sockaddr_dl *) - (&ifp -> ifr_addr)); -#if defined (HAVE_SIN_LEN) - tmp -> hw_address.hlen = foo -> sdl_alen; -#else - tmp -> hw_address.hlen = 6; /* XXX!!! */ -#endif - tmp -> hw_address.hbuf [0] = HTYPE_ETHER; /* XXX */ - memcpy (&tmp -> hw_address.hbuf [1], - LLADDR (foo), tmp -> hw_address.hlen); - tmp -> hw_address.hlen++; /* for type. */ + if (info.addr.ss_family == AF_LINK) { + struct sockaddr_dl *d = (struct sockaddr_dl*)&info.addr; + tmp->hw_address.hlen = d->sdl_alen; + tmp->hw_address.hbuf[0] = HTYPE_ETHER; /* XXX */ + memcpy(&tmp->hw_address.hbuf[1], + LLADDR(d), + tmp->hw_address.hlen); + tmp->hw_address.hlen++; /* for type. */ } else #endif /* AF_LINK */ - if (ifp -> ifr_addr.sa_family == AF_INET) { + if ((info.addr.ss_family == AF_INET) && + (local_family == AF_INET)) { + struct sockaddr_in *a = (struct sockaddr_in*)&info.addr; struct iaddr addr; - /* Get a pointer to the address... */ - memcpy (&foo, &ifp -> ifr_addr, - sizeof ifp -> ifr_addr); - /* We don't want the loopback interface. */ - if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) && - ((tmp -> flags & INTERFACE_AUTOMATIC) && + if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) && + ((tmp->flags & INTERFACE_AUTOMATIC) && state == DISCOVER_SERVER)) continue; /* If the only address we have is 0.0.0.0, we shouldn't consider the interface configured. */ - if (foo.sin_addr.s_addr != htonl(INADDR_ANY)) + if (a->sin_addr.s_addr != htonl(INADDR_ANY)) tmp->configured = 1; - if (!tmp -> addresses) { - tmp -> addresses = - dmalloc (10 * sizeof (struct in_addr), - MDL); - if (!tmp -> addresses) - log_fatal ("no memory for ifaddrlist"); - tmp -> address_count = 0; - tmp -> address_max = 10; - } else if (tmp -> address_count >= tmp -> address_max) { - struct in_addr *ta; - int newmax = tmp -> address_max * 2; - ta = dmalloc (newmax * - sizeof (struct in_addr), MDL); - if (!ta) - log_fatal ("no memory for new " - "ifaddrlist"); - memcpy (ta, tmp -> addresses, - tmp -> address_max * - sizeof (struct in_addr)); - dfree (tmp -> addresses, MDL); - tmp -> addresses = ta; - tmp -> address_max = newmax; - } - tmp -> addresses [tmp -> address_count++] = - foo.sin_addr; + add_ipv4_addr_to_interface(tmp, &a->sin_addr); +/* + * XXX: We don't have ifreq in Solaris-land if we want IPv6. Fortunately, + * we don't actually need this for anything on Solaris. + */ +#if 0 /* If this is the first real IP address we've found, keep a pointer to ifreq structure in which we found it. */ @@ -356,19 +431,71 @@ void discover_interfaces (state) memcpy (tif, ifp, len); tmp -> ifp = tif; } +#endif /* 0 */ - /* Grab the address... */ + /* invoke the setup hook */ addr.len = 4; - memcpy (addr.iabuf, &foo.sin_addr.s_addr, - addr.len); - if (dhcp_interface_setup_hook) - (*dhcp_interface_setup_hook) (tmp, &addr); + memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len); + if (dhcp_interface_setup_hook) { + (*dhcp_interface_setup_hook)(tmp, &addr); + } } + else if ((info.addr.ss_family == AF_INET6) && + (local_family == AF_INET6)) { + struct sockaddr_in6 *a = + (struct sockaddr_in6*)&info.addr; + struct iaddr addr; + + /* We don't want the loopback interface. */ + if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) && + ((tmp->flags & INTERFACE_AUTOMATIC) && + state == DISCOVER_SERVER)) + continue; + + /* If the only address we have is 0.0.0.0, we + shouldn't consider the interface configured. */ + if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr)) + tmp->configured = 1; + + add_ipv6_addr_to_interface(tmp, &a->sin6_addr); + +/* + * XXX: We don't have ifreq in Solaris-land if we want IPv6. Fortunately, + * we don't actually need this for anything on Solaris. + */ +#if 0 + /* If this is the first real IP address we've + found, keep a pointer to ifreq structure in + which we found it. */ + if (!tmp -> ifp) { +#ifdef HAVE_SA_LEN + unsigned len = ((sizeof ifp -> ifr_name) + + ifp -> ifr_addr.sa_len); +#else + unsigned len = sizeof *ifp; +#endif + tif = (struct ifreq *)dmalloc (len, MDL); + if (!tif) + log_fatal ("no space for ifp."); + memcpy (tif, ifp, len); + tmp -> ifp = tif; + } +#endif /* 0 */ + + /* invoke the setup hook */ + addr.len = 16; + memcpy(addr.iabuf, &a->sin6_addr, addr.len); + if (dhcp_interface_setup_hook) { + (*dhcp_interface_setup_hook)(tmp, &addr); + } + } + } + + if (err) { + log_fatal("Error getting interface information."); } - /* If we allocated a buffer, free it. */ - if (ic.ifc_ifcu.ifcu_buf != buf) - dfree (ic.ifc_ifcu.ifcu_buf, MDL); + end_iface_scan(&ifaces); #if defined (LINUX_SLASHPROC_DISCOVERY) /* On Linux, interfaces that don't have IP addresses don't @@ -460,8 +587,10 @@ void discover_interfaces (state) /* Now cycle through all the interfaces we found, looking for hardware addresses. */ + /* XXX: The dlpi interface code will get this information in Solaris */ +#if 0 #if defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) - for (tmp = interfaces; tmp; tmp = tmp -> next) { + for (tmp = interfaces; tmp != NULL; tmp = tmp->next) { struct ifreq ifr; struct sockaddr sa; int b, sk; @@ -568,16 +697,16 @@ void discover_interfaces (state) } } #endif /* defined (HAVE_SIOCGIFHWADDR) && !defined (HAVE_AF_LINK) */ +#endif /* 0 */ /* If we're just trying to get a list of interfaces that we might be able to configure, we can quit now. */ if (state == DISCOVER_UNCONFIGURED) { - close (sock); return; } /* Weed out the interfaces that did not have IP addresses. */ - tmp = last = next = (struct interface_info *)0; + tmp = last = next = NULL; if (interfaces) interface_reference (&tmp, interfaces, MDL); while (tmp) { @@ -596,7 +725,9 @@ void discover_interfaces (state) state == DISCOVER_REQUESTED) tmp -> flags &= ~(INTERFACE_AUTOMATIC | INTERFACE_REQUESTED); - if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { +/* XXX: no ifp in Solaris */ +/* if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {*/ + if (!(tmp->flags & INTERFACE_REQUESTED)) { if ((tmp -> flags & INTERFACE_REQUESTED) != ir) log_fatal ("%s: not found", tmp -> name); if (!last) { @@ -629,15 +760,31 @@ void discover_interfaces (state) } last = tmp; - memcpy (&foo, &tmp -> ifp -> ifr_addr, - sizeof tmp -> ifp -> ifr_addr); +/* XXX: no ifp in Solaris */ +/* memcpy (&foo, &tmp -> ifp -> ifr_addr, + sizeof tmp -> ifp -> ifr_addr);*/ /* We must have a subnet declaration for each interface. */ - if (!tmp -> shared_network && (state == DISCOVER_SERVER)) { - log_error ("%s", ""); - log_error ("No subnet declaration for %s (%s).", - tmp -> name, inet_ntoa (foo.sin_addr)); - if (supports_multiple_interfaces (tmp)) { + if (!tmp->shared_network && (state == DISCOVER_SERVER)) { + log_error("%s", ""); + if (local_family == AF_INET) { + log_error("No subnet declaration for %s (%s).", + tmp->name, + inet_ntoa(tmp->addresses[0])); + } else { + if (tmp->v6addresses != NULL) { + inet_ntop(AF_INET6, + &tmp->v6addresses[0], + abuf, + sizeof(abuf)); + } else { + strcpy(abuf, "no addresses"); + } + log_error("No subnet declaration for %s (%s).", + tmp->name, + abuf); + } + if (supports_multiple_interfaces(tmp)) { log_error ("** Ignoring requests on %s. %s", tmp -> name, "If this is not what"); log_error (" you want, please write %s", @@ -672,7 +819,7 @@ void discover_interfaces (state) to the first address we found. */ subnet -> interface_address.len = 4; memcpy (subnet -> interface_address.iabuf, - &foo.sin_addr.s_addr, 4); + &tmp->addresses[0].s_addr, 4); } } @@ -717,8 +864,6 @@ void discover_interfaces (state) tmp -> name, isc_result_totext (status)); } - close (sock); - if (state == DISCOVER_SERVER && wifcount == 0) { log_info ("%s", ""); log_fatal ("Not configured to listen on any interfaces!"); diff --git a/common/dlpi.c b/common/dlpi.c index e43240c1..bfcb3150 100644 --- a/common/dlpi.c +++ b/common/dlpi.c @@ -77,9 +77,17 @@ * to sleep. */ +/* + * The Open Group Technical Standard can be found here: + * http://www.opengroup.org/onlinepubs/009618899/index.htm + * + * The HP DLPI Programmer's Guide can be found here: + * http://docs.hp.com/en/B2355-90139/index.html + */ + #ifndef lint static char copyright[] = -"$Id: dlpi.c,v 1.29 2005/03/17 20:14:57 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dlpi.c,v 1.29.124.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" diff --git a/common/inet.c b/common/inet.c index 934eba19..7a022e1d 100644 --- a/common/inet.c +++ b/common/inet.c @@ -35,7 +35,7 @@ #ifndef lint static char copyright[] = -"$Id: inet.c,v 1.11 2006/05/15 15:07:49 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; +"$Id: inet.c,v 1.11.68.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -210,29 +210,32 @@ addr_match(addr, match) return 1; } -char *piaddr (addr) - struct iaddr addr; -{ - static char pbuf [4 * 16]; - char *s = pbuf; - int i; +/* XXX: should use a const pointer rather than passing the structure */ +const char * +piaddr(struct iaddr addr) { + static char + pbuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; - if (addr.len > sizeof(addr.iabuf)) - log_fatal("piaddr():%s:%d: Address length too long.", MDL); + /* INSIST((addr.len == 0) || (addr.len == 4) || (addr.len == 16)); */ if (addr.len == 0) { - strcpy (s, "<null address>"); + return "<null address>"; } - for (i = 0; i < addr.len; i++) { - sprintf (s, "%s%d", i ? "." : "", addr.iabuf [i]); - s += strlen (s); + if (addr.len == 4) { + return inet_ntop(AF_INET, addr.iabuf, pbuf, sizeof(pbuf)); + } + if (addr.len == 16) { + return inet_ntop(AF_INET6, addr.iabuf, pbuf, sizeof(pbuf)); } - return pbuf; + + log_fatal("piaddr():%s:%d: Invalid address length %d.", MDL, addr.len); + /* quell compiler warnings */ + return NULL; } -char *piaddrmask (struct iaddr addr, struct iaddr mask, - const char *file, int line) -{ +/* XXX: should use a const pointer rather than passing the structure */ +char * +piaddrmask(struct iaddr addr, struct iaddr mask, const char *file, int line) { char *s, tbuf[sizeof("255.255.255.255/32")]; int mw; unsigned i, oct, bit; @@ -270,3 +273,35 @@ char *piaddrmask (struct iaddr addr, struct iaddr mask, return s; } +char * +piaddrcidr(const struct iaddr *addr, unsigned int bits, + const char *file, int line) { + const char *tmp; + int tmp_len; + char *ret; + + /* INSIST(addr != NULL); */ + /* INSIST((addr->len == 4) || (addr->len == 16)); */ + /* INSIST(bits <= (addr->len * 8)); */ + + tmp = piaddr(*addr); + + /* + * Figure out how much space we need for the address plus + * the bit count, and the trailing NUL character. + * "2001::/96", for instance. + */ + tmp_len = strlen(tmp) + 3; + if (bits >= 100) { + tmp_len += 2; + } else if (bits >= 10) { + tmp_len += 1; + } + + ret = dmalloc(tmp_len, file, line); + if (ret != NULL) { + sprintf(ret, "%s/%d", tmp, bits); + } + return ret; +} + diff --git a/common/parse.c b/common/parse.c index b1c059e6..a8626cbd 100644 --- a/common/parse.c +++ b/common/parse.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: parse.c,v 1.113.2.1 2006/07/25 10:01:33 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: parse.c,v 1.113.2.1.2.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -322,6 +322,88 @@ int parse_ip_addr (cfile, addr) } /* + * Return true if every character in the string is hexidecimal. + */ +static int +is_hex_string(const char *s) { + while (*s != '\0') { + if (!isxdigit(*s)) { + return 0; + } + s++; + } + return 1; +} + +/* + * ip-address6 :== (complicated set of rules) + * + * See section 2.2 of RFC 1884 for details. + * + * We are lazy for this. We pull numbers, names, colons, and dots + * together and then throw the resulting string at the inet_pton() + * function. + */ + +int +parse_ip6_addr(struct parse *cfile, struct iaddr *addr) { + enum dhcp_token token; + const char *val; + int val_len; + + char v6[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")]; + int v6_len; + + v6_len = 0; + for (;;) { + token = peek_token(&val, NULL, cfile); + if ((((token == NAME) || (token == NUMBER_OR_NAME)) && + is_hex_string(val)) || + (token == NUMBER) || + (token == DOT) || + (token == COLON)) { + + next_token(&val, NULL, cfile); + val_len = strlen(val); + if ((v6_len + val_len) >= sizeof(v6)) { + parse_warn(cfile, "Invalid IPv6 address."); + skip_to_semi(cfile); + return 0; + } + memcpy(v6+v6_len, val, val_len); + v6_len += val_len; + + } else { + break; + } + } + v6[v6_len] = '\0'; + + if (inet_pton(AF_INET6, v6, addr->iabuf) <= 0) { + parse_warn(cfile, "Invalid IPv6 address."); + skip_to_semi(cfile); + return 0; + } + addr->len = 16; + return 1; +} + +/* + * Same as parse_ip6_addr() above, but returns the value in the + * expression rather than in an address structure. + */ +int +parse_ip6_addr_expr(struct expression **expr, + struct parse *cfile) { + struct iaddr addr; + + if (!parse_ip6_addr(cfile, &addr)) { + return 0; + } + return make_const_data(expr, addr.iabuf, addr.len, 0, 1, MDL); +} + +/* * ip-address-with-subnet :== ip-address | * ip-address "/" NUMBER */ @@ -1387,6 +1469,9 @@ int parse_option_code_definition (cfile, option) case IP_ADDRESS: type = 'I'; break; + case IP6_ADDRESS: + type = '6'; + break; case DOMAIN_NAME: type = 'd'; goto no_arrays; @@ -4782,6 +4867,15 @@ int parse_option_token (rv, cfile, fmt, expr, uniform, lookups) return 0; } break; + + case '6': /* IPv6 address. */ + if (!parse_ip6_addr(cfile, &addr)) { + return 0; + } + if (!make_const_data(&t, addr.iabuf, addr.len, 0, 1, MDL)) { + return 0; + } + break; case 'T': /* Lease interval. */ token = next_token (&val, (unsigned *)0, cfile); diff --git a/common/socket.c b/common/socket.c index 714321a5..a8d6cc2c 100644 --- a/common/socket.c +++ b/common/socket.c @@ -3,7 +3,7 @@ BSD socket interface code... */ /* - * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") + * Copyright (c) 2004-2006 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1995-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any @@ -42,7 +42,8 @@ #ifndef lint static char copyright[] = -"$Id: socket.c,v 1.58 2005/03/17 20:15:00 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; +"$Id: socket.c,v 1.58.122.1 2006/08/09 11:26:29 shane Exp $ " +"Copyright (c) 2004-2006 Internet Systems Consortium.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -51,6 +52,7 @@ static char copyright[] = # if !defined (USE_SOCKET_SEND) # define if_register_send if_register_fallback # define send_packet send_fallback +# define send_packet6 send_fallback6 # define if_reinitialize_send if_reinitialize_fallback # endif #endif @@ -90,62 +92,89 @@ void if_reinitialize_receive (info) defined (USE_SOCKET_RECEIVE) || \ defined (USE_SOCKET_FALLBACK) /* Generic interface registration routine... */ -int if_register_socket (info) - struct interface_info *info; -{ - struct sockaddr_in name; +int +if_register_socket(struct interface_info *info) { + struct sockaddr_storage name; + int name_len; int sock; int flag; + int domain; + + /* INSIST((local_family == AF_INET) || (local_family == AF_INET6)); */ #if !defined (HAVE_SO_BINDTODEVICE) && !defined (USE_FALLBACK) /* Make sure only one interface is registered. */ - if (once) + if (once) { log_fatal ("The standard socket API can only support %s", "hosts with a single network interface."); + } once = 1; #endif - memset (&name, 0, sizeof (name)); - /* Set up the address we're going to bind to. */ - name.sin_family = AF_INET; - name.sin_port = local_port; - name.sin_addr = local_address; + /* + * Set up the address we're going to bind to, depending on the + * address family. + */ + memset(&name, 0, sizeof(name)); + if (local_family == AF_INET) { + struct sockaddr_in *addr = (struct sockaddr_in *)&name; + addr->sin_family = AF_INET; + addr->sin_port = local_port; + memcpy(&addr->sin_addr, + &local_address, + sizeof(addr->sin_addr)); + name_len = sizeof(*addr); + domain = PF_INET; + } else { + struct sockaddr_in6 *addr = (struct sockaddr_in6 *)&name; + addr->sin6_family = AF_INET6; + addr->sin6_port = local_port; + memcpy(&addr->sin6_addr, + &local_address6, + sizeof(addr->sin6_addr)); + name_len = sizeof(*addr); + domain = PF_INET6; + } /* Make a socket... */ - if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) - log_fatal ("Can't create dhcp socket: %m"); + sock = socket(domain, SOCK_DGRAM, IPPROTO_UDP); + if (sock < 0) { + log_fatal("Can't create dhcp socket: %m"); + } /* Set the REUSEADDR option so that we don't fail to start if we're being restarted. */ flag = 1; - if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&flag, sizeof flag) < 0) - log_fatal ("Can't set SO_REUSEADDR option on dhcp socket: %m"); + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&flag, sizeof(flag)) < 0) { + log_fatal("Can't set SO_REUSEADDR option on dhcp socket: %m"); + } /* Set the BROADCAST option so that we can broadcast DHCP responses. We shouldn't do this for fallback devices, and we can detect that a device is a fallback because it has no ifp structure. */ - if (info -> ifp && - (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, - (char *)&flag, sizeof flag) < 0)) - log_fatal ("Can't set SO_BROADCAST option on dhcp socket: %m"); + if (info->ifp && + (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, + (char *)&flag, sizeof(flag)) < 0)) { + log_fatal("Can't set SO_BROADCAST option on dhcp socket: %m"); + } /* Bind the socket to this interface's IP address. */ - if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0) { - log_error ("Can't bind to dhcp address: %m"); - log_error ("Please make sure there is no other dhcp server"); - log_error ("running and that there's no entry for dhcp or"); - log_error ("bootp in /etc/inetd.conf. Also make sure you"); - log_error ("are not running HP JetAdmin software, which"); - log_fatal ("includes a bootp server."); + if (bind(sock, (struct sockaddr *)&name, name_len) < 0) { + log_error("Can't bind to dhcp address: %m"); + log_error("Please make sure there is no other dhcp server"); + log_error("running and that there's no entry for dhcp or"); + log_error("bootp in /etc/inetd.conf. Also make sure you"); + log_error("are not running HP JetAdmin software, which"); + log_fatal("includes a bootp server."); } #if defined (HAVE_SO_BINDTODEVICE) /* Bind this socket to this interface. */ - if (info -> ifp && - setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, - (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) { - log_fatal ("setsockopt: SO_BINDTODEVICE: %m"); + if (info->ifp && + setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, + (char *)(info -> ifp), sizeof(*(info -> ifp))) < 0) { + log_fatal("setsockopt: SO_BINDTODEVICE: %m"); } #endif @@ -256,6 +285,23 @@ ssize_t send_packet (interface, packet, raw, len, from, to, hto) } return result; } + +ssize_t send_packet6(struct interface_info *interface, + struct packet *packet, + struct dhcp_packet *raw, + size_t len, + struct in6_addr from, + struct sockaddr_in6 *to, + struct hardware *hto) { + int result; + + result = sendto(interface->wfdesc, (char *)raw, len, 0, + (struct sockaddr *)to, sizeof(*to)); + if (result < 0) { + log_error("send_packet6: %m"); + } + return result; +} #endif /* USE_SOCKET_SEND || USE_SOCKET_FALLBACK */ #ifdef USE_SOCKET_RECEIVE @@ -283,6 +329,17 @@ ssize_t receive_packet (interface, buf, len, from, hfrom) #endif return result; } + +ssize_t receive_packet6(struct interface_info *interface, unsigned char *buf, + size_t len, struct sockaddr_in6 *from, + struct hardware *hfrom) { + SOCKLEN_T flen = sizeof(*from); + int result; + + result = recvfrom(interface->rfdesc, (char *)buf, len, 0, + (struct sockaddr *)from, &flen); + return result; +} #endif /* USE_SOCKET_RECEIVE */ #if defined (USE_SOCKET_FALLBACK) diff --git a/common/tables.c b/common/tables.c index eefad58f..e5b4af5d 100644 --- a/common/tables.c +++ b/common/tables.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: tables.c,v 1.56 2006/07/22 02:24:16 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: tables.c,v 1.56.8.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -55,7 +55,8 @@ HASH_FUNCTIONS (option_code, const unsigned *, struct option, Format codes: - I - IP address + I - IPv4 address + 6 - IPv6 address l - 32-bit signed integer L - 32-bit unsigned integer s - 16-bit signed integer diff --git a/dhcpctl/omshell.c b/dhcpctl/omshell.c index afac88ac..ddcb3f5a 100644 --- a/dhcpctl/omshell.c +++ b/dhcpctl/omshell.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: omshell.c,v 1.11 2006/02/24 23:16:29 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: omshell.c,v 1.11.100.1 2006/08/09 11:26:29 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include <time.h> @@ -76,8 +76,8 @@ static void check (isc_result_t status, const char *func) { } } -int main (int argc, char **argv, char **envp) -{ +int +main(int argc, char **argv) { isc_result_t status, waitstatus; dhcpctl_handle connection; dhcpctl_handle authenticator; diff --git a/includes/cf/sunos5-5.h b/includes/cf/sunos5-5.h index e9789d60..198f3c22 100644 --- a/includes/cf/sunos5-5.h +++ b/includes/cf/sunos5-5.h @@ -38,6 +38,7 @@ typedef uint8_t u_int8_t; typedef uint16_t u_int16_t; typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; #else /* Older SunOS has no idea what these things mean. */ typedef int8_t char typedef int16_t short diff --git a/includes/dhcpd.h b/includes/dhcpd.h index 2f66d1c1..3a9eda9a 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -688,6 +688,7 @@ struct subnet { struct iaddr interface_address; struct iaddr net; struct iaddr netmask; + int prefix_len; /* XXX: currently for IPv6 only */ struct group *group; }; @@ -889,6 +890,13 @@ struct interface_info { int address_max; /* Max number of addresses we can store in current buffer. */ + struct in6_addr *v6addresses; /* IPv6 addresses associated with + this interface. */ + int v6address_count; /* Number of IPv6 addresses associated + with this interface. */ + int v6address_max; /* Maximum number of IPv6 addresses + we can store in current buffer. */ + u_int8_t *circuit_id; /* Circuit ID associated with this interface. */ unsigned circuit_id_len; /* Length of Circuit ID, if there @@ -1260,9 +1268,9 @@ extern const char *path_dhcpd_pid; extern int dhcp_max_agent_option_packet_length; -int main PROTO ((int, char **, char **)); -void postconf_initialization (int); -void postdb_startup (void); +int main(int, char **); +void postconf_initialization(int); +void postdb_startup(void); void cleanup PROTO ((void)); void lease_pinged PROTO ((struct iaddr, u_int8_t *, int)); void lease_ping_timeout PROTO ((void *)); @@ -1308,8 +1316,11 @@ int parse_class_declaration PROTO ((struct class **, struct parse *, void parse_shared_net_declaration PROTO ((struct parse *, struct group *)); void parse_subnet_declaration PROTO ((struct parse *, struct shared_network *)); +void parse_subnet6_declaration PROTO ((struct parse *, + struct shared_network *)); void parse_group_declaration PROTO ((struct parse *, struct group *)); -int parse_fixed_addr_param PROTO ((struct option_cache **, struct parse *)); +int parse_fixed_addr_param PROTO ((struct option_cache **, + struct parse *, enum dhcp_token)); TIME parse_timestamp PROTO ((struct parse *)); int parse_lease_declaration PROTO ((struct lease **, struct parse *)); void parse_address_range PROTO ((struct parse *, struct group *, int, @@ -1704,6 +1715,9 @@ ssize_t send_fallback PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); +ssize_t send_fallback6(struct interface_info *, struct packet *, + struct dhcp_packet *, size_t, struct in6_addr, + struct sockaddr_in6 *, struct hardware *); #endif #ifdef USE_SOCKET_SEND @@ -1714,6 +1728,9 @@ ssize_t send_packet PROTO ((struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)); +ssize_t send_packet6(struct interface_info *, struct packet *, + struct dhcp_packet *, size_t, struct in6_addr, + struct sockaddr_in6 *, struct hardware *); #endif #ifdef USE_SOCKET_RECEIVE void if_reinitialize_receive PROTO ((struct interface_info *)); @@ -1722,6 +1739,8 @@ void if_deregister_receive PROTO ((struct interface_info *)); ssize_t receive_packet PROTO ((struct interface_info *, unsigned char *, size_t, struct sockaddr_in *, struct hardware *)); +ssize_t receive_packet6(struct interface_info *, unsigned char *, size_t, + struct sockaddr_in *, struct hardware *); #endif #if defined (USE_SOCKET_FALLBACK) @@ -1868,7 +1887,9 @@ isc_result_t interface_setup (void); void interface_trace_setup (void); extern struct in_addr limited_broadcast; +extern int local_family; extern struct in_addr local_address; +extern struct in6_addr local_address6; extern u_int16_t local_port; extern u_int16_t remote_port; @@ -1967,8 +1988,9 @@ struct iaddr broadcast_addr PROTO ((struct iaddr, struct iaddr)); u_int32_t host_addr PROTO ((struct iaddr, struct iaddr)); int addr_eq PROTO ((struct iaddr, struct iaddr)); int addr_match(struct iaddr *, struct iaddrmatch *); -char *piaddr PROTO ((struct iaddr)); -char *piaddrmask (struct iaddr, struct iaddr, const char *, int); +const char *piaddr PROTO ((struct iaddr)); +char *piaddrmask(struct iaddr, struct iaddr, const char *, int); +char *piaddrcidr(const struct iaddr *, unsigned int, const char *, int); /* dhclient.c */ extern const char *path_dhclient_conf; @@ -2568,12 +2590,12 @@ isc_result_t dhcp_lease_free (omapi_object_t *, const char *, int); isc_result_t dhcp_lease_get (omapi_object_t **, const char *, int); int find_grouped_subnet PROTO ((struct subnet **, struct shared_network *, struct iaddr, const char *, int)); -int find_subnet (struct subnet **, struct iaddr, const char *, int); +int find_subnet(struct subnet **, struct iaddr, const char *, int); void enter_shared_network PROTO ((struct shared_network *)); void new_shared_network_interface PROTO ((struct parse *, struct shared_network *, const char *)); -int subnet_inner_than PROTO ((struct subnet *, struct subnet *, int)); +int subnet_inner_than(const struct subnet *, const struct subnet *, int); void enter_subnet PROTO ((struct subnet *)); void enter_lease PROTO ((struct lease *)); int supersede_lease PROTO ((struct lease *, struct lease *, int, int, int)); diff --git a/includes/dhctoken.h b/includes/dhctoken.h index 0315c7c9..14f2c2fe 100644 --- a/includes/dhctoken.h +++ b/includes/dhctoken.h @@ -323,7 +323,10 @@ enum dhcp_token { MAX_LEASE_OWNERSHIP = 627, MAX_BALANCE = 628, MIN_BALANCE = 629, - DOMAIN_LIST = 630 + DOMAIN_LIST = 630, + IP6_ADDRESS = 631, + FIXED_ADDR6 = 632, + SUBNET6 = 633 }; #define is_identifier(x) ((x) >= FIRST_TOKEN && \ diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c index 859fcf0f..a6921343 100644 --- a/relay/dhcrelay.c +++ b/relay/dhcrelay.c @@ -34,7 +34,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhcrelay.c,v 1.58 2006/05/11 14:48:59 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhcrelay.c,v 1.58.72.1 2006/08/09 11:26:30 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -97,10 +97,8 @@ static char arr [] = "All rights reserved."; static char message [] = "Internet Systems Consortium DHCP Relay Agent"; static char url [] = "For info, please visit http://www.isc.org/sw/dhcp/"; -int main (argc, argv, envp) - int argc; - char **argv, **envp; -{ +int +main(int argc, char **argv) { int fd; int i; struct servent *ent; diff --git a/server/confpars.c b/server/confpars.c index a8907e70..d2a830da 100644 --- a/server/confpars.c +++ b/server/confpars.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: confpars.c,v 1.158 2006/07/20 16:04:03 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: confpars.c,v 1.158.12.1 2006/08/09 11:26:30 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -416,6 +416,7 @@ int parse_statement (cfile, group, type, host_decl, declaration) return 1; case SUBNET: + case SUBNET6: next_token (&val, (unsigned *)0, cfile); if (type == HOST_DECL || type == SUBNET_DECL || type == CLASS_DECL) { @@ -426,9 +427,14 @@ int parse_statement (cfile, group, type, host_decl, declaration) } /* If we're in a subnet declaration, just do the parse. */ - if (group -> shared_network) { - parse_subnet_declaration (cfile, - group -> shared_network); + if (group->shared_network) { + if (token == SUBNET) { + parse_subnet_declaration(cfile, + group->shared_network); + } else { + parse_subnet6_declaration(cfile, + group->shared_network); + } break; } @@ -445,26 +451,37 @@ int parse_statement (cfile, group, type, host_decl, declaration) shared_network_reference (&share -> group -> shared_network, share, MDL); - parse_subnet_declaration (cfile, share); + if (token == SUBNET) { + parse_subnet_declaration(cfile, share); + } else { + parse_subnet6_declaration(cfile, share); + } /* share -> subnets is the subnet we just parsed. */ - if (share -> subnets) { - interface_reference (&share -> interface, - share -> subnets -> interface, - MDL); + if (share->subnets) { + interface_reference(&share->interface, + share->subnets->interface, + MDL); /* Make the shared network name from network number. */ - n = piaddrmask (share -> subnets -> net, - share -> subnets -> netmask, MDL); - share -> name = n; + if (token == SUBNET) { + n = piaddrmask(share->subnets->net, + share->subnets->netmask, MDL); + } else { + n = piaddrcidr(&share->subnets->net, + share->subnets->prefix_len, MDL); + } + + /* XXX: do something if n is NULL */ + share->name = n; /* Copy the authoritative parameter from the subnet, since there is no opportunity to declare it here. */ - share -> group -> authoritative = - share -> subnets -> group -> authoritative; - enter_shared_network (share); + share->group->authoritative = + share->subnets->group->authoritative; + enter_shared_network(share); } - shared_network_dereference (&share, MDL); + shared_network_dereference(&share, MDL); return 1; case VENDOR_CLASS: @@ -531,23 +548,24 @@ int parse_statement (cfile, group, type, host_decl, declaration) break; case FIXED_ADDR: - next_token (&val, (unsigned *)0, cfile); - cache = (struct option_cache *)0; - if (parse_fixed_addr_param (&cache, cfile)) { + case FIXED_ADDR6: + next_token(&val, NULL, cfile); + cache = NULL; + if (parse_fixed_addr_param(&cache, cfile, token)) { if (host_decl) { - if (host_decl -> fixed_addr) { - option_cache_dereference (&cache, MDL); - parse_warn (cfile, - "Only one fixed address%s", - " declaration per host."); + if (host_decl->fixed_addr) { + option_cache_dereference(&cache, MDL); + parse_warn(cfile, + "Only one fixed address " + "declaration per host."); } else { - host_decl -> fixed_addr = cache; + host_decl->fixed_addr = cache; } } else { - parse_warn (cfile, - "fixed-address parameter not %s", - "allowed here."); - option_cache_dereference (&cache, MDL); + parse_warn(cfile, + "fixed-address parameter not " + "allowed here."); + option_cache_dereference(&cache, MDL); } } break; @@ -2318,6 +2336,75 @@ void parse_shared_net_declaration (cfile, group) shared_network_dereference (&share, MDL); } + +static void +common_subnet_parsing(struct parse *cfile, + struct shared_network *share, + struct subnet *subnet) { + enum dhcp_token token; + struct subnet *t, *u; + const char *val; + int declaration = 0; + + enter_subnet(subnet); + + if (!parse_lbrace(cfile)) { + subnet_dereference(&subnet, MDL); + return; + } + + do { + token = peek_token(&val, NULL, cfile); + if (token == RBRACE) { + token = next_token(&val, NULL, cfile); + break; + } else if (token == END_OF_FILE) { + token = next_token(&val, NULL, cfile); + parse_warn (cfile, "unexpected end of file"); + break; + } else if (token == INTERFACE) { + token = next_token(&val, NULL, cfile); + token = next_token(&val, NULL, cfile); + new_shared_network_interface(cfile, share, val); + if (!parse_semi(cfile)) + break; + continue; + } + declaration = parse_statement(cfile, subnet->group, + SUBNET_DECL, + NULL, + declaration); + } while (1); + + /* Add the subnet to the list of subnets in this shared net. */ + if (share->subnets == NULL) { + subnet_reference(&share->subnets, subnet, MDL); + } else { + u = NULL; + for (t = share->subnets; t->next_sibling; t = t->next_sibling) { + if (subnet_inner_than(subnet, t, 0)) { + subnet_reference(&subnet->next_sibling, t, MDL); + if (u) { + subnet_dereference(&u->next_sibling, + MDL); + subnet_reference(&u->next_sibling, + subnet, MDL); + } else { + subnet_dereference(&share->subnets, + MDL); + subnet_reference(&share->subnets, + subnet, MDL); + } + subnet_dereference(&subnet, MDL); + return; + } + u = t; + } + subnet_reference(&t->next_sibling, subnet, MDL); + } + subnet_dereference(&subnet, MDL); +} + /* subnet-declaration :== net NETMASK netmask RBRACE parameters declarations LBRACE */ @@ -2331,8 +2418,6 @@ void parse_subnet_declaration (cfile, share) struct iaddr iaddr; unsigned char addr [4]; unsigned len = sizeof addr; - int declaration = 0; - struct interface_info *ip; isc_result_t status; subnet = (struct subnet *)0; @@ -2384,65 +2469,86 @@ void parse_subnet_declaration (cfile, share) return; } - enter_subnet (subnet); + common_subnet_parsing(cfile, share, subnet); +} - if (!parse_lbrace (cfile)) { - subnet_dereference (&subnet, MDL); +/* subnet6-declaration :== + net / bits RBRACE parameters declarations LBRACE */ + +void +parse_subnet6_declaration(struct parse *cfile, struct shared_network *share) { + struct subnet *subnet; + isc_result_t status; + enum dhcp_token token; + const char *val; + char *endp; + int ofs; + const static int mask[] = { 0x00, 0x80, 0xC0, 0xE0, + 0xF0, 0xF8, 0xFC, 0xFE }; + struct iaddr iaddr; + + subnet = NULL; + status = subnet_allocate(&subnet, MDL); + if (status != ISC_R_SUCCESS) { + log_fatal("Allocation of new subnet failed: %s", + isc_result_totext(status)); + } + shared_network_reference(&subnet->shared_network, share, MDL); + if (!clone_group(&subnet->group, share->group, MDL)) { + log_fatal("Allocation of group for new subnet failed."); + } + subnet_reference(&subnet->group->subnet, subnet, MDL); + + if (!parse_ip6_addr(cfile, &subnet->net)) { + subnet_dereference(&subnet, MDL); return; } - do { - token = peek_token (&val, (unsigned *)0, cfile); - if (token == RBRACE) { - token = next_token (&val, (unsigned *)0, cfile); - break; - } else if (token == END_OF_FILE) { - token = next_token (&val, (unsigned *)0, cfile); - parse_warn (cfile, "unexpected end of file"); - break; - } else if (token == INTERFACE) { - token = next_token (&val, (unsigned *)0, cfile); - token = next_token (&val, (unsigned *)0, cfile); - new_shared_network_interface (cfile, share, val); - if (!parse_semi (cfile)) - break; - continue; - } - declaration = parse_statement (cfile, subnet -> group, - SUBNET_DECL, - (struct host_decl *)0, - declaration); - } while (1); + token = next_token(&val, NULL, cfile); + if (token != SLASH) { + parse_warn(cfile, "Expecting a '/'."); + skip_to_semi(cfile); + return; + } - /* Add the subnet to the list of subnets in this shared net. */ - if (!share -> subnets) - subnet_reference (&share -> subnets, subnet, MDL); - else { - u = (struct subnet *)0; - for (t = share -> subnets; - t -> next_sibling; t = t -> next_sibling) { - if (subnet_inner_than (subnet, t, 0)) { - subnet_reference (&subnet -> next_sibling, - t, MDL); - if (u) { - subnet_dereference (&u -> next_sibling, - MDL); - subnet_reference (&u -> next_sibling, - subnet, MDL); - } else { - subnet_dereference (&share -> subnets, - MDL); - subnet_reference (&share -> subnets, - subnet, MDL); - } - subnet_dereference (&subnet, MDL); - return; - } - u = t; - } - subnet_reference (&t -> next_sibling, subnet, MDL); + token = next_token(&val, NULL, cfile); + if (token != NUMBER) { + parse_warn(cfile, "Expecting a number."); + skip_to_semi(cfile); + return; + } + + subnet->prefix_len = strtol(val, &endp, 10); + if ((subnet->prefix_len < 0) || + (subnet->prefix_len > 128) || + (*endp != '\0')) { + parse_warn(cfile, "Expecting a number between 0 and 128."); + skip_to_semi(cfile); + return; } - subnet_dereference (&subnet, MDL); + + /* + * Create a netmask. + */ + subnet->netmask.len = 16; + ofs = subnet->prefix_len / 8; + subnet->netmask.iabuf[ofs--] = mask[subnet->prefix_len % 8]; + while (ofs >= 0) { + subnet->netmask.iabuf[ofs--] = 0xFF; + } + + /* Validate the network number/netmask pair. */ + iaddr = subnet_number(subnet->net, subnet->netmask); + if (memcmp(&iaddr, &subnet->net, 16) != 0) { + parse_warn(cfile, + "subnet %s/%d: prefix not long enough for address.", + piaddr(subnet->net), subnet->prefix_len); + subnet_dereference(&subnet, MDL); + skip_to_semi(cfile); + return; + } + + common_subnet_parsing(cfile, share, subnet); } /* group-declaration :== RBRACE parameters declarations LBRACE */ @@ -2540,47 +2646,59 @@ void parse_group_declaration (cfile, group) ip-addrs-or-hostnames :== ip-addr-or-hostname | ip-addrs-or-hostnames ip-addr-or-hostname */ -int parse_fixed_addr_param (oc, cfile) - struct option_cache **oc; - struct parse *cfile; -{ +int +parse_fixed_addr_param(struct option_cache **oc, + struct parse *cfile, + enum dhcp_token type) { + int parse_ok; const char *val; enum dhcp_token token; - struct expression *expr = (struct expression *)0; + struct expression *expr = NULL; struct expression *tmp, *new; int status; do { - tmp = (struct expression *)0; - if (parse_ip_addr_or_hostname (&tmp, cfile, 1)) { - if (expr) { - new = (struct expression *)0; - status = make_concat (&new, expr, tmp); - expression_dereference (&expr, MDL); - expression_dereference (&tmp, MDL); - if (!status) + tmp = NULL; + if (type == FIXED_ADDR) { + parse_ok = parse_ip_addr_or_hostname(&tmp, cfile, 1); + } else { + /* INSIST(type == FIXED_ADDR6); */ + parse_ok = parse_ip6_addr_expr(&tmp, cfile); + } + if (parse_ok) { + if (expr != NULL) { + new = NULL; + status = make_concat(&new, expr, tmp); + expression_dereference(&expr, MDL); + expression_dereference(&tmp, MDL); + if (!status) { return 0; + } expr = new; - } else + } else { expr = tmp; + } } else { - if (expr) + if (expr != NULL) { expression_dereference (&expr, MDL); + } return 0; } - token = peek_token (&val, (unsigned *)0, cfile); - if (token == COMMA) - token = next_token (&val, (unsigned *)0, cfile); + token = peek_token(&val, NULL, cfile); + if (token == COMMA) { + token = next_token(&val, NULL, cfile); + } } while (token == COMMA); - if (!parse_semi (cfile)) { - if (expr) + if (!parse_semi(cfile)) { + if (expr) { expression_dereference (&expr, MDL); + } return 0; } - status = option_cache (oc, (struct data_string *)0, expr, - (struct option *)0, MDL); - expression_dereference (&expr, MDL); + + status = option_cache(oc, NULL, expr, NULL, MDL); + expression_dereference(&expr, MDL); return status; } diff --git a/server/dhcpd.c b/server/dhcpd.c index 6eb66cdf..825c394b 100644 --- a/server/dhcpd.c +++ b/server/dhcpd.c @@ -34,7 +34,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhcpd.c,v 1.121 2006/07/17 15:21:45 dhankins Exp $ Copyright 2004-2006 Internet Systems Consortium."; +"$Id: dhcpd.c,v 1.121.26.1 2006/08/09 11:26:30 shane Exp $ Copyright 2004-2006 Internet Systems Consortium."; #endif static char copyright[] = @@ -193,10 +193,8 @@ static void omapi_listener_start (void *foo) omapi_object_dereference (&listener, MDL); } -int main (argc, argv, envp) - int argc; - char **argv, **envp; -{ +int +main(int argc, char **argv) { int fd; int i, status; struct servent *ent; @@ -222,6 +220,7 @@ int main (argc, argv, envp) int no_dhcpd_conf = 0; int no_dhcpd_db = 0; int no_dhcpd_pid = 0; + int local_family_set = 0; #if defined (TRACING) char *traceinfile = (char *)0; char *traceoutfile = (char *)0; @@ -324,6 +323,20 @@ int main (argc, argv, envp) } else if (!strcmp (argv [i], "-q")) { quiet = 1; quiet_interface_discovery = 1; + } else if (!strcmp(argv[i], "-4")) { + if (local_family_set && (local_family != AF_INET)) { + log_fatal("Server cannot run in both IPv4 and " + "IPv6 mode at the same time."); + } + local_family = AF_INET; + local_family_set = 1; + } else if (!strcmp(argv[i], "-6")) { + if (local_family_set && (local_family != AF_INET6)) { + log_fatal("Server cannot run in both IPv4 and " + "IPv6 mode at the same time."); + } + local_family = AF_INET6; + local_family_set = 1; } else if (!strcmp (argv [i], "--version")) { log_info ("isc-dhcpd-%s", DHCP_VERSION); exit (0); diff --git a/server/mdb.c b/server/mdb.c index 000f027b..446b16d2 100644 --- a/server/mdb.c +++ b/server/mdb.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: mdb.c,v 1.82 2006/07/18 18:15:53 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: mdb.c,v 1.82.16.1 2006/08/09 11:26:30 shane Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -686,29 +686,29 @@ int find_grouped_subnet (struct subnet **sp, return 0; } -int subnet_inner_than (subnet, scan, warnp) - struct subnet *subnet, *scan; - int warnp; -{ - if (addr_eq (subnet_number (subnet -> net, scan -> netmask), - scan -> net) || - addr_eq (subnet_number (scan -> net, subnet -> netmask), - subnet -> net)) { - char n1buf [16]; +/* XXX: could speed up if everyone had a prefix length */ +int +subnet_inner_than(const struct subnet *subnet, + const struct subnet *scan, + int warnp) { + if (addr_eq(subnet_number(subnet->net, scan->netmask), scan->net) || + addr_eq(subnet_number(scan->net, subnet->netmask), subnet->net)) { + char n1buf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255")]; int i, j; - for (i = 0; i < 32; i++) - if (subnet -> netmask.iabuf [3 - (i >> 3)] + for (i = 0; i < 128; i++) + if (subnet->netmask.iabuf[3 - (i >> 3)] & (1 << (i & 7))) break; - for (j = 0; j < 32; j++) - if (scan -> netmask.iabuf [3 - (j >> 3)] & + for (j = 0; j < 128; j++) + if (scan->netmask.iabuf[3 - (j >> 3)] & (1 << (j & 7))) break; - strcpy (n1buf, piaddr (subnet -> net)); - if (warnp) - log_error ("%ssubnet %s/%d overlaps subnet %s/%d", - "Warning: ", n1buf, 32 - i, - piaddr (scan -> net), 32 - j); + if (warnp) { + strcpy(n1buf, piaddr(subnet->net)); + log_error("Warning: subnet %s/%d overlaps subnet %s/%d", + n1buf, 32 - i, + piaddr(scan->net), 32 - j); + } if (i < j) return 1; } |