summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShane Kerr <shane@isc.org>2006-08-09 11:26:30 +0000
committerShane Kerr <shane@isc.org>2006-08-09 11:26:30 +0000
commitc8f0261f9e958a19364946d403a5f69c5b51a853 (patch)
treefcff3629f804b38d8a091c9dff86a0fc5dcd4960
parent8db46562974aebf319aed7b1083715d639ad4cac (diff)
downloadisc-dhcp-c8f0261f9e958a19364946d403a5f69c5b51a853.tar.gz
Mostly complete interface code.DHCPv6_socket_pre_parsing
-rw-r--r--client/dhclient.c8
-rw-r--r--common/conflex.c4
-rw-r--r--common/discover.c519
-rw-r--r--common/dlpi.c10
-rw-r--r--common/inet.c69
-rw-r--r--common/parse.c96
-rw-r--r--common/socket.c121
-rw-r--r--common/tables.c5
-rw-r--r--dhcpctl/omshell.c6
-rw-r--r--includes/cf/sunos5-5.h1
-rw-r--r--includes/dhcpd.h38
-rw-r--r--includes/dhctoken.h5
-rw-r--r--relay/dhcrelay.c8
-rw-r--r--server/confpars.c332
-rw-r--r--server/dhcpd.c23
-rw-r--r--server/mdb.c38
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;
}