From: David Hankins Date: Mon, 27 Feb 2006 23:56:13 +0000 (+0000) Subject: - The IO system now tracks all local IP addresses, so that the DHCP X-Git-Tag: DHCPv6_parsing_base~49 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=25b988c68faa02465ec5d92dd7bb01039839313d;p=thirdparty%2Fdhcp.git - The IO system now tracks all local IP addresses, so that the DHCP applications (particularly the dhcrelay) can discern between what frames were tranmsitted to it, and what frames are being carried through it which it should not intercept. [ISC-Bugs #15573] --- diff --git a/RELNOTES b/RELNOTES index 692af08e8..727e0b662 100644 --- a/RELNOTES +++ b/RELNOTES @@ -63,6 +63,10 @@ and for prodding me into improving it. - RFC3942 compliance, site-local option spaces start at 224 now, not 128. ||| THIS NEEDS TO BE SPELLED OUT IN THE NEW FEATURES LIST ||| +- The IO system now tracks all local IP addresses, so that the DHCP + applications (particularly the dhcrelay) can discern between what frames + were tranmsitted to it, and what frames are being carried through it which + it should not intercept. Changes since 3.0.4b2 diff --git a/client/dhclient.c b/client/dhclient.c index 762d6d76c..29d600e9c 100644 --- a/client/dhclient.c +++ b/client/dhclient.c @@ -32,7 +32,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhclient.c,v 1.133 2006/02/24 23:16:27 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhclient.c,v 1.134 2006/02/27 23:56:12 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -227,6 +227,8 @@ int main (argc, argv, envp) } } + limited_broadcast.s_addr = INADDR_BROADCAST; + if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) { path_dhclient_conf = s; } diff --git a/common/ctrace.c b/common/ctrace.c index e5042ec6d..5e8bcc09f 100644 --- a/common/ctrace.c +++ b/common/ctrace.c @@ -32,7 +32,7 @@ #ifndef lint static char copyright[] = -"$Id: ctrace.c,v 1.4 2005/03/17 20:14:57 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; +"$Id: ctrace.c,v 1.5 2006/02/27 23:56:13 dhankins Exp $ Copyright (c) 2004 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -46,8 +46,10 @@ void trace_interface_register (trace_type_t *ttype, struct interface_info *ip) memset (&tipkt, 0, sizeof tipkt); memcpy (&tipkt.hw_address, &ip -> hw_address, sizeof ip -> hw_address); - memcpy (&tipkt.primary_address, - &ip -> primary_address, sizeof ip -> primary_address); + if (ip -> address_count > 0) + memcpy (&tipkt.primary_address, + &ip -> addresses [0], + sizeof ip -> addresses [0]); memcpy (tipkt.name, ip -> name, sizeof ip -> name); tipkt.index = htonl (ip -> index); @@ -87,8 +89,12 @@ void trace_interface_input (trace_type_t *ttype, unsigned len, char *buf) memcpy (&ip -> hw_address, &tipkt -> hw_address, sizeof ip -> hw_address); - memcpy (&ip -> primary_address, &tipkt -> primary_address, - sizeof ip -> primary_address); + ip -> address_count = ip -> address_max = 1; + ip -> addresses = dmalloc (sizeof (struct in_addr), MDL); + if (!ip -> addresses) + log_fatal ("Can't allocate address buffer for trace interface"); + memcpy (&ip -> addresses [0], &tipkt -> primary_address, + sizeof ip -> addresses [0]); memcpy (ip -> name, tipkt -> name, sizeof ip -> name); ip -> index = ntohl (tipkt -> index); @@ -102,7 +108,7 @@ void trace_interface_input (trace_type_t *ttype, unsigned len, char *buf) ip -> ifp -> ifr_addr.sa_len = sizeof (struct sockaddr_in); #endif sin = (struct sockaddr_in *)&ip -> ifp -> ifr_addr; - sin -> sin_addr = ip -> primary_address; + sin -> sin_addr = ip -> addresses [0]; addr.len = 4; memcpy (addr.iabuf, &sin -> sin_addr.s_addr, addr.len); diff --git a/common/discover.c b/common/discover.c index 16796d783..4d22d149e 100644 --- a/common/discover.c +++ b/common/discover.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: discover.c,v 1.49 2006/02/24 23:16:28 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$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"; #endif /* not lint */ #include "dhcpd.h" @@ -307,8 +307,38 @@ void discover_interfaces (state) if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK) && ((tmp -> flags & INTERFACE_AUTOMATIC) && state == DISCOVER_SERVER)) - continue; + 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)) + 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; /* If this is the first real IP address we've found, keep a pointer to ifreq structure in @@ -325,7 +355,6 @@ void discover_interfaces (state) log_fatal ("no space for ifp."); memcpy (tif, ifp, len); tmp -> ifp = tif; - tmp -> primary_address = foo.sin_addr; } /* Grab the address... */ @@ -1138,6 +1167,12 @@ void interface_stash (struct interface_info *tptr) } interface_vector = vec; } + if (interface_vector [tptr -> index]) { + log_fatal("invalid tracefile - two interfaces with " + "same index - %s and %s", + interface_vector [tptr->index] -> name, + tptr -> name); + } interface_reference (&interface_vector [tptr -> index], tptr, MDL); if (tptr -> index >= interface_count) interface_count = tptr -> index + 1; diff --git a/common/packet.c b/common/packet.c index 830c276a5..57702fcbc 100644 --- a/common/packet.c +++ b/common/packet.c @@ -33,7 +33,7 @@ #ifndef lint static char copyright[] = -"$Id: packet.c,v 1.42 2005/03/17 20:14:59 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; +"$Id: packet.c,v 1.43 2006/02/27 23:56:13 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -231,6 +231,8 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen) unsigned len; unsigned ulen; int ignore = 0; + struct interface_info *ii; + int i; memcpy(&ip, buf + bufix, sizeof (struct ip)); udp = (struct udphdr *)(buf + bufix + ip_len); @@ -245,6 +247,38 @@ ssize_t decode_udp_ip_header (interface, buf, bufix, from, buflen) return -1; #endif /* USERLAND_FILTER */ + /* Eliminate packets that we might have accidentally intercepted because + we are doing routing. */ + + /* The DHCP client may not have an IP address; in that case, if we + got the packet, we need to look at it. So if address_count is + zero on the interface on which we received the packet, accept the + packet. */ + if (!interface -> configured) + goto good; + + /* XXX we should handle subnet broadcast addresses here. */ + /* XXX we should compare against 255.255.255.255, not limited_broadcast, + XXX because sometimes we tweak limited_broadcast for debugging. + XXX This is only currently a problem on the server. */ + if (ip.ip_dst.s_addr == limited_broadcast.s_addr) + goto good; + + /* Check IP addresses of _all_ interfaces - it's perfectly okay to send + a packet to an IP address on one interface that happens to arrive + through another interface. */ + /* XXX if the user excluded some interfaces, we will not accept packets + XXX for those interfaces. */ + for (ii = interfaces; ii; ii = ii -> next) { + for (i = 0; i < ii -> address_count; i++) { + if (ii -> addresses [i].s_addr == ip.ip_dst.s_addr) + goto good; + } + } + /* The IP destination address didn't match any of our addresses. */ + return -1; + + good: ulen = ntohs (udp -> uh_ulen); if (ulen < sizeof *udp || ((unsigned char *)udp) + ulen > buf + bufix + buflen) { diff --git a/includes/dhcpd.h b/includes/dhcpd.h index d9c911fce..36b74c81c 100644 --- a/includes/dhcpd.h +++ b/includes/dhcpd.h @@ -779,6 +779,12 @@ struct client_state { struct option_state *sent_options; /* Options we sent. */ }; +/* Relay agent server list. */ +struct server_list { + struct server_list *next; + struct sockaddr_in to; +} *servers; + /* Information about each network interface. */ struct interface_info { @@ -787,7 +793,12 @@ struct interface_info { struct shared_network *shared_network; /* Networks connected to this interface. */ struct hardware hw_address; /* Its physical address. */ - struct in_addr primary_address; /* Primary interface address. */ + struct in_addr *addresses; /* Addresses associated with + interface. */ + int address_count; /* Number of addresses associated with + interface. */ + int address_max; /* Max number of addresses we can + store in current buffer. */ u_int8_t *circuit_id; /* Circuit ID associated with this interface. */ @@ -796,6 +807,8 @@ struct interface_info { u_int8_t *remote_id; /* Remote ID associated with this interface (if any). */ unsigned remote_id_len; /* Length of Remote ID. */ + struct server_list *servers; /* List of relay servers for this + interface. */ char name [IFNAMSIZ]; /* Its name... */ int index; /* Its index. */ @@ -808,6 +821,9 @@ struct interface_info { size_t rbuf_len; /* Length of data in buffer. */ struct ifreq *ifp; /* Pointer to ifreq struct. */ + int configured; /* If set to 1, interface has at + * least one valid IP address. + */ u_int32_t flags; /* Control flags... */ #define INTERFACE_REQUESTED 1 #define INTERFACE_AUTOMATIC 2 @@ -2037,6 +2053,7 @@ int parse_ip_addr PROTO ((struct parse *, struct iaddr *)); void parse_reject_statement PROTO ((struct parse *, struct client_config *)); /* dhcrelay.c */ +void new_relay_server (char *, struct server_list **); void relay PROTO ((struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)); int strip_relay_agent_options PROTO ((struct interface_info *, diff --git a/relay/dhcrelay.8 b/relay/dhcrelay.8 index 05b6dabc4..1e0a9a9c2 100644 --- a/relay/dhcrelay.8 +++ b/relay/dhcrelay.8 @@ -27,7 +27,7 @@ .\" see ``http://www.isc.org/isc''. To learn more about Vixie .\" Enterprises, see ``http://www.vix.com''. .\" -.\" $Id: dhcrelay.8,v 1.10 2005/03/17 20:15:24 dhankins Exp $ +.\" $Id: dhcrelay.8,v 1.11 2006/02/27 23:56:13 dhankins Exp $ .\" .TH dhcrelay 8 .SH NAME @@ -48,6 +48,11 @@ dhcrelay - Dynamic Host Configuration Protocol Relay Agent .B -i .I if0 [ +.B -is +.I server +... +] +[ .B ... .B -i .I ifN @@ -114,6 +119,11 @@ server) is attached. However, in some cases it may be necessary to exclude some networks; in this case, you must list all those network interfaces that should \fInot\fR be excluded using the \fB-i\fR flag. .PP +The +.B -is +flag can be used to indicate that for the previous interface specified with +-i, packets should be forwarded to the specified server. +.PP In some cases it .I is helpful for the relay agent to forward requests from networks on which diff --git a/relay/dhcrelay.c b/relay/dhcrelay.c index 452724b10..4abc52502 100644 --- a/relay/dhcrelay.c +++ b/relay/dhcrelay.c @@ -34,7 +34,7 @@ #ifndef lint static char ocopyright[] = -"$Id: dhcrelay.c,v 1.54 2006/02/24 23:16:30 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhcrelay.c,v 1.55 2006/02/27 23:56:13 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -92,11 +92,6 @@ enum { forward_and_append, /* Forward and append our own relay option. */ u_int16_t local_port; u_int16_t remote_port; -struct server_list { - struct server_list *next; - struct sockaddr_in to; -} *servers; - static char copyright [] = "Copyright 2004-2005 Internet Systems Consortium."; static char arr [] = "All rights reserved."; static char message [] = "Internet Systems Consortium DHCP Relay Agent"; @@ -113,6 +108,7 @@ int main (argc, argv, envp) int quiet = 0; isc_result_t status; char *s; + struct interface_info *tmp = (struct interface_info *)0; /* Make sure we have stdin, stdout and stderr. */ i = open ("/dev/null", O_RDWR); @@ -154,8 +150,8 @@ int main (argc, argv, envp) } else if (!strcmp (argv [i], "-d")) { no_daemon = 1; } else if (!strcmp (argv [i], "-i")) { - struct interface_info *tmp = - (struct interface_info *)0; + if (tmp) + interface_dereference (&tmp, MDL); status = interface_allocate (&tmp, MDL); if (status != ISC_R_SUCCESS) log_fatal ("%s: interface_allocate: %s", @@ -166,7 +162,14 @@ int main (argc, argv, envp) } strcpy (tmp -> name, argv [i]); interface_snorf (tmp, INTERFACE_REQUESTED); - interface_dereference (&tmp, MDL); + } else if (!strcmp (argv [i], "-is")) { + if (++i == argc) + usage (); + if (!tmp) { + log_error ("-is must follow -i."); + usage (); + } + new_relay_server (argv [i], &tmp -> servers); } else if (!strcmp (argv [i], "-q")) { quiet = 1; quiet_interface_discovery = 1; @@ -206,33 +209,15 @@ int main (argc, argv, envp) log_info ("isc-dhcrelay-%s", DHCP_VERSION); exit (0); } else { - struct hostent *he; - struct in_addr ia, *iap = (struct in_addr *)0; - if (inet_aton (argv [i], &ia)) { - iap = &ia; - } else { - he = gethostbyname (argv [i]); - if (!he) { - log_error ("%s: host unknown", - argv [i]); - } else { - iap = ((struct in_addr *) - he -> h_addr_list [0]); - } - } - if (iap) { - sp = ((struct server_list *) - dmalloc (sizeof *sp, MDL)); - if (!sp) - log_fatal ("no memory for server.\n"); - sp -> next = servers; - servers = sp; - memcpy (&sp -> to.sin_addr, - iap, sizeof *iap); - } + new_relay_server (argv [i], &servers); } } + limited_broadcast.s_addr = INADDR_BROADCAST; + + if (tmp) + interface_dereference (&tmp, MDL); + if ((s = getenv ("PATH_DHCRELAY_PID"))) { path_dhcrelay_pid = s; } @@ -259,7 +244,7 @@ int main (argc, argv, envp) remote_port = htons (ntohs (local_port) + 1); /* We need at least one server. */ - if (!sp) { + if (!servers) { usage (); } @@ -272,6 +257,29 @@ int main (argc, argv, envp) #endif } + if (interfaces) { + interface_reference (&tmp, interfaces, MDL); + do { + struct interface_info *next = NULL; + if (tmp -> next) + interface_reference (&next, tmp -> next, MDL); + + for (sp = tmp -> servers; sp; sp = sp -> next) { + sp -> to.sin_port = local_port; + sp -> to.sin_family = AF_INET; +#ifdef HAVE_SA_LEN + sp -> to.sin_len = sizeof sp -> to; +#endif + } + + interface_dereference (&tmp, MDL); + if (next) { + interface_reference (&tmp, next, MDL); + interface_dereference (&next, MDL); + } + } while (tmp); + } + /* Get the current time... */ GET_TIME (&cur_time); @@ -323,6 +331,36 @@ int main (argc, argv, envp) return 0; } +void new_relay_server (char *arg, struct server_list **servers) +{ + struct hostent *he; + struct in_addr ia, *iap = (struct in_addr *)0; + struct server_list *sp; + + if (inet_aton (arg, &ia)) { + iap = &ia; + } else { + he = gethostbyname (arg); + if (!he) { + log_error ("%s: host unknown", arg); + } else { + iap = ((struct in_addr *) + he -> h_addr_list [0]); + } + } + if (iap) { + sp = ((struct server_list *) + dmalloc (sizeof *sp, MDL)); + if (!sp) + log_fatal ("no memory for server.\n"); + memset(sp, 0, sizeof *sp); + sp -> next = *servers; + *servers = sp; + memcpy (&sp -> to.sin_addr, + iap, sizeof *iap); + } +} + void relay (ip, packet, length, from_port, from, hfrom) struct interface_info *ip; struct dhcp_packet *packet; @@ -335,6 +373,7 @@ void relay (ip, packet, length, from_port, from, hfrom) struct sockaddr_in to; struct interface_info *out; struct hardware hto, *htop; + int i; if (packet -> hlen > sizeof packet -> chaddr) { log_info ("Discarding packet with invalid hlen."); @@ -345,14 +384,16 @@ void relay (ip, packet, length, from_port, from, hfrom) in the packet. */ if (packet -> giaddr.s_addr) { for (out = interfaces; out; out = out -> next) { - if (!memcmp (&out -> primary_address, - &packet -> giaddr, - sizeof packet -> giaddr)) - break; + for (i = 0; i < out -> address_count; i++) { + if (out -> addresses [i].s_addr == + packet -> giaddr.s_addr) + goto matched; + } } } else { out = (struct interface_info *)0; } + matched: /* If it's a bootreply, forward it to the client. */ if (packet -> op == BOOTREPLY) { @@ -388,15 +429,18 @@ void relay (ip, packet, length, from_port, from, hfrom) return; if (!out) { - log_error ("packet to bogus giaddr %s.\n", + log_error ("packet to bogus giaddr %s.", inet_ntoa (packet -> giaddr)); ++bogus_giaddr_drops; return; } + if (out -> address_count < 1) + log_fatal ("no IP address on interface %s!", + out -> name); if (send_packet (out, (struct packet *)0, - packet, length, out -> primary_address, + packet, length, out -> addresses [0], &to, htop) < 0) { ++server_packet_errors; } else { @@ -415,10 +459,13 @@ void relay (ip, packet, length, from_port, from, hfrom) if (out) return; + if (ip -> address_count < 1) + log_fatal ("no IP address on interface %s", ip -> name); + /* Add relay agent options if indicated. If something goes wrong, drop the packet. */ if (!(length = add_relay_agent_options (ip, packet, length, - ip -> primary_address))) + ip -> addresses [0]))) return; /* If giaddr is not already set, Set it so the server can @@ -427,7 +474,7 @@ void relay (ip, packet, length, from_port, from, hfrom) set, the response will be sent directly to the relay agent that set giaddr, so we won't see it. */ if (!packet -> giaddr.s_addr) - packet -> giaddr = ip -> primary_address; + packet -> giaddr = ip -> addresses [0]; if (packet -> hops < max_hop_count) packet -> hops = packet -> hops + 1; else @@ -435,11 +482,12 @@ void relay (ip, packet, length, from_port, from, hfrom) /* Otherwise, it's a BOOTREQUEST, so forward it to all the servers. */ - for (sp = servers; sp; sp = sp -> next) { + for (sp = (ip -> servers + ? ip -> servers : servers); sp; sp = sp -> next) { if (send_packet ((fallback_interface ? fallback_interface : interfaces), (struct packet *)0, - packet, length, ip -> primary_address, + packet, length, ip -> addresses [0], &sp -> to, (struct hardware *)0) < 0) { ++client_packet_errors; } else { @@ -450,13 +498,12 @@ void relay (ip, packet, length, from_port, from, hfrom) ++client_packets_relayed; } } - } static void usage () { log_fatal ("Usage: dhcrelay [-p ] [-d] [-D] [-i %s%s%s%s", - "interface] [-q] [-a]\n ", + "interface [-is server ... ]]\n ", "[-c count] [-A length] ", "[-m append|replace|forward|discard]\n", " [server1 [... serverN]]"); diff --git a/server/bootp.c b/server/bootp.c index c5b2ae0b6..6600fc408 100644 --- a/server/bootp.c +++ b/server/bootp.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: bootp.c,v 1.73 2005/07/07 16:39:07 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; +"$Id: bootp.c,v 1.74 2006/02/27 23:56:13 dhankins Exp $ Copyright (c) 2004-2005 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -271,11 +271,13 @@ void bootp (packet) memcpy (&raw.siaddr, d1.data, 4); data_string_forget (&d1, MDL); } else { - if (lease -> subnet -> shared_network -> interface) + if (lease -> subnet -> shared_network -> interface && + lease -> subnet -> + shared_network -> interface -> address_count) raw.siaddr = (lease -> subnet -> shared_network -> - interface -> primary_address); - else - raw.siaddr = packet -> interface -> primary_address; + interface -> addresses [0]); + else if (packet -> interface -> address_count) + raw.siaddr = packet -> interface -> addresses [0]; } raw.giaddr = packet -> raw -> giaddr; @@ -325,7 +327,8 @@ void bootp (packet) hto.hlen = packet -> raw -> hlen + 1; memcpy (&hto.hbuf [1], packet -> raw -> chaddr, packet -> raw -> hlen); - from = packet -> interface -> primary_address; + if (packet -> interface -> address_count) + from = packet -> interface -> addresses [0]; /* Report what we're doing... */ log_info ("%s", msgbuf); diff --git a/server/dhcp.c b/server/dhcp.c index 8eb7524bb..fada817a7 100644 --- a/server/dhcp.c +++ b/server/dhcp.c @@ -34,7 +34,7 @@ #ifndef lint static char copyright[] = -"$Id: dhcp.c,v 1.200 2006/02/24 23:16:30 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; +"$Id: dhcp.c,v 1.201 2006/02/27 23:56:13 dhankins Exp $ Copyright (c) 2004-2006 Internet Systems Consortium. All rights reserved.\n"; #endif /* not lint */ #include "dhcpd.h" @@ -1092,21 +1092,21 @@ void dhcpinform (packet, ms_nulltp) if (!(oc = lookup_option (&dhcp_universe, options, i))) { use_primary: oc = (struct option_cache *)0; + if (packet -> interface -> address_count > 0) { if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, ((unsigned char *) - &packet -> interface -> primary_address), - sizeof packet -> interface -> primary_address, + &packet -> interface -> addresses [0]), + sizeof packet -> interface -> addresses [0], 0, 0, MDL)) { - oc -> option = - dhcp_universe.options [i]; - save_option (&dhcp_universe, - options, oc); + oc -> option = dhcp_universe.options [i]; + save_option (&dhcp_universe, options, oc); } option_cache_dereference (&oc, MDL); } - from = packet -> interface -> primary_address; + from = packet -> interface -> addresses [0]; + } } else { if (evaluate_option_cache (&d1, packet, (struct lease *)0, (struct client_state *)0, @@ -1358,15 +1358,16 @@ void nak_lease (packet, cip) option_cache_dereference (&oc, MDL); i = DHO_DHCP_SERVER_IDENTIFIER; - if (!(oc = lookup_option (&dhcp_universe, options, i))) { + if (packet -> interface -> address_count > 0) { + if (!(oc = lookup_option (&dhcp_universe, options, i))) { use_primary: oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, ((unsigned char *) - &packet -> interface -> primary_address), - sizeof packet -> interface -> primary_address, + &packet -> interface -> addresses [0]), + sizeof packet -> interface -> addresses [0], 0, 0, MDL)) { oc -> option = dhcp_universe.options [i]; @@ -1374,9 +1375,10 @@ void nak_lease (packet, cip) } option_cache_dereference (&oc, MDL); } - myfrom.len = sizeof packet -> interface -> primary_address; + myfrom.len = sizeof packet -> interface -> addresses [0]; memcpy (myfrom.iabuf, - &packet -> interface -> primary_address, myfrom.len); + &packet -> interface -> addresses [0], myfrom.len); + } } else { memset (&data, 0, sizeof data); if (evaluate_option_cache (&data, packet, (struct lease *)0, @@ -1421,7 +1423,8 @@ void nak_lease (packet, cip) option_state_dereference (&options, MDL); /* memset (&raw.ciaddr, 0, sizeof raw.ciaddr);*/ - raw.siaddr = packet -> interface -> primary_address; + if (packet -> interface -> address_count) + raw.siaddr = packet -> interface -> addresses [0]; raw.giaddr = packet -> raw -> giaddr; memcpy (raw.chaddr, packet -> raw -> chaddr, sizeof raw.chaddr); raw.hlen = packet -> raw -> hlen; @@ -2401,13 +2404,14 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) if (!(oc = lookup_option (&dhcp_universe, state -> options, i))) { use_primary: + if (state -> ip -> address_count > 0) { oc = (struct option_cache *)0; if (option_cache_allocate (&oc, MDL)) { if (make_const_data (&oc -> expression, ((unsigned char *) - &state -> ip -> primary_address), - sizeof state -> ip -> primary_address, + &state -> ip -> addresses [0]), + sizeof state -> ip -> addresses [0], 0, 0, MDL)) { oc -> option = dhcp_universe.options [i]; @@ -2417,10 +2421,11 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) option_cache_dereference (&oc, MDL); } state -> from.len = - sizeof state -> ip -> primary_address; + sizeof state -> ip -> addresses [0]; memcpy (state -> from.iabuf, - &state -> ip -> primary_address, + &state -> ip -> addresses [0], state -> from.len); + } } else { if (evaluate_option_cache (&d1, packet, lease, (struct client_state *)0, @@ -2505,11 +2510,13 @@ void ack_lease (packet, lease, offer, when, msg, ms_nulltp, hp) option_cache_dereference (&oc, MDL); } } else { - state -> from.len = - sizeof state -> ip -> primary_address; - memcpy (state -> from.iabuf, - &state -> ip -> primary_address, - state -> from.len); + if (state -> ip -> address_count) { + state -> from.len = + sizeof state -> ip -> addresses [0]; + memcpy (state -> from.iabuf, + &state -> ip -> addresses [0], + state -> from.len); + } } /* Figure out the address of the boot file server. */