- 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
#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"
}
}
+ limited_broadcast.s_addr = INADDR_BROADCAST;
+
if (!no_dhclient_conf && (s = getenv ("PATH_DHCLIENT_CONF"))) {
path_dhclient_conf = s;
}
#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"
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);
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);
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);
#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"
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
log_fatal ("no space for ifp.");
memcpy (tif, ifp, len);
tmp -> ifp = tif;
- tmp -> primary_address = foo.sin_addr;
}
/* Grab the address... */
}
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;
#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"
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);
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) {
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 {
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. */
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. */
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
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 *,
.\" 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
.B -i
.I if0
[
+.B -is
+.I server
+...
+]
+[
.B ...
.B -i
.I ifN
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
#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"
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";
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);
} 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",
}
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;
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;
}
remote_port = htons (ntohs (local_port) + 1);
/* We need at least one server. */
- if (!sp) {
+ if (!servers) {
usage ();
}
#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);
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;
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.");
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) {
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 {
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
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
/* 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 {
++client_packets_relayed;
}
}
-
}
static void usage ()
{
log_fatal ("Usage: dhcrelay [-p <port>] [-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]]");
#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"
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;
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);
#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"
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,
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];
}
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,
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;
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];
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,
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. */