Sat Jun 10 06:30:07 2017 UTC ()
Pull up following revision(s) (requested by manu in ticket #27):
	external/bsd/dhcp/dist/relay/dhcrelay.c: revision 1.7
Fix buggy dhcrelay(8) requirement to stay in foreground
This version of dhcrelay(8) needed to stay inforeground with -d flag in
order to service requests. Running inbackground turned it deaf to DHCP
requests.
This was caused by wrong kqueue(2) usage, where kevent(2) was used with
a file descriptor obtained by a kqueue(2) call done before fork(2).
kqueue(2) man page says "The queue is not inherited by a child created
with fork(2)". As a result, kevent(2) calls always got EBADF.
The fix is to reorder function calls in dhcrelay(8) main() function.
dhcp_context_create(), which causes kqueue(2) to be invoked, is
moved with its dependencies after fork(2). This matches the code layout
of dhclient(8) and dhcpd(8), which do not have the bug.
The fix was not submitted upstream since latest ISC DHCP code was
refactored and does not have the bug anymore.


(snj)
diff -r1.6 -r1.6.8.1 src/external/bsd/dhcp/dist/relay/dhcrelay.c

cvs diff -r1.6 -r1.6.8.1 src/external/bsd/dhcp/dist/relay/Attic/dhcrelay.c (switch to unified diff)

--- src/external/bsd/dhcp/dist/relay/Attic/dhcrelay.c 2016/01/10 20:10:45 1.6
+++ src/external/bsd/dhcp/dist/relay/Attic/dhcrelay.c 2017/06/10 06:30:07 1.6.8.1
@@ -1,1744 +1,1744 @@ @@ -1,1744 +1,1744 @@
1/* $NetBSD: dhcrelay.c,v 1.6 2016/01/10 20:10:45 christos Exp $ */ 1/* $NetBSD: dhcrelay.c,v 1.6.8.1 2017/06/10 06:30:07 snj Exp $ */
2/* dhcrelay.c 2/* dhcrelay.c
3 3
4 DHCP/BOOTP Relay Agent. */ 4 DHCP/BOOTP Relay Agent. */
5 5
6/* 6/*
7 * Copyright(c) 2004-2015 by Internet Systems Consortium, Inc.("ISC") 7 * Copyright(c) 2004-2015 by Internet Systems Consortium, Inc.("ISC")
8 * Copyright(c) 1997-2003 by Internet Software Consortium 8 * Copyright(c) 1997-2003 by Internet Software Consortium
9 * 9 *
10 * Permission to use, copy, modify, and distribute this software for any 10 * Permission to use, copy, modify, and distribute this software for any
11 * purpose with or without fee is hereby granted, provided that the above 11 * purpose with or without fee is hereby granted, provided that the above
12 * copyright notice and this permission notice appear in all copies. 12 * copyright notice and this permission notice appear in all copies.
13 * 13 *
14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 14 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 15 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 16 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 17 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 19 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 20 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * 21 *
22 * Internet Systems Consortium, Inc. 22 * Internet Systems Consortium, Inc.
23 * 950 Charter Street 23 * 950 Charter Street
24 * Redwood City, CA 94063 24 * Redwood City, CA 94063
25 * <info@isc.org> 25 * <info@isc.org>
26 * https://www.isc.org/ 26 * https://www.isc.org/
27 * 27 *
28 */ 28 */
29 29
30#include <sys/cdefs.h> 30#include <sys/cdefs.h>
31__RCSID("$NetBSD: dhcrelay.c,v 1.6 2016/01/10 20:10:45 christos Exp $"); 31__RCSID("$NetBSD: dhcrelay.c,v 1.6.8.1 2017/06/10 06:30:07 snj Exp $");
32 32
33#include "dhcpd.h" 33#include "dhcpd.h"
34#include <syslog.h> 34#include <syslog.h>
35#include <signal.h> 35#include <signal.h>
36#include <sys/time.h> 36#include <sys/time.h>
37 37
38TIME default_lease_time = 43200; /* 12 hours... */ 38TIME default_lease_time = 43200; /* 12 hours... */
39TIME max_lease_time = 86400; /* 24 hours... */ 39TIME max_lease_time = 86400; /* 24 hours... */
40struct tree_cache *global_options[256]; 40struct tree_cache *global_options[256];
41 41
42struct option *requested_opts[2]; 42struct option *requested_opts[2];
43 43
44/* Needed to prevent linking against conflex.c. */ 44/* Needed to prevent linking against conflex.c. */
45int lexline; 45int lexline;
46int lexchar; 46int lexchar;
47char *token_line; 47char *token_line;
48char *tlname; 48char *tlname;
49 49
50const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID; 50const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID;
51isc_boolean_t no_dhcrelay_pid = ISC_FALSE; 51isc_boolean_t no_dhcrelay_pid = ISC_FALSE;
52/* False (default) => we write and use a pid file */ 52/* False (default) => we write and use a pid file */
53isc_boolean_t no_pid_file = ISC_FALSE; 53isc_boolean_t no_pid_file = ISC_FALSE;
54 54
55int bogus_agent_drops = 0; /* Packets dropped because agent option 55int bogus_agent_drops = 0; /* Packets dropped because agent option
56 field was specified and we're not relaying 56 field was specified and we're not relaying
57 packets that already have an agent option 57 packets that already have an agent option
58 specified. */ 58 specified. */
59int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a 59int bogus_giaddr_drops = 0; /* Packets sent to us to relay back to a
60 client, but with a bogus giaddr. */ 60 client, but with a bogus giaddr. */
61int client_packets_relayed = 0; /* Packets relayed from client to server. */ 61int client_packets_relayed = 0; /* Packets relayed from client to server. */
62int server_packet_errors = 0; /* Errors sending packets to servers. */ 62int server_packet_errors = 0; /* Errors sending packets to servers. */
63int server_packets_relayed = 0; /* Packets relayed from server to client. */ 63int server_packets_relayed = 0; /* Packets relayed from server to client. */
64int client_packet_errors = 0; /* Errors sending packets to clients. */ 64int client_packet_errors = 0; /* Errors sending packets to clients. */
65 65
66int add_agent_options = 0; /* If nonzero, add relay agent options. */ 66int add_agent_options = 0; /* If nonzero, add relay agent options. */
67 67
68int agent_option_errors = 0; /* Number of packets forwarded without 68int agent_option_errors = 0; /* Number of packets forwarded without
69 agent options because there was no room. */ 69 agent options because there was no room. */
70int drop_agent_mismatches = 0; /* If nonzero, drop server replies that 70int drop_agent_mismatches = 0; /* If nonzero, drop server replies that
71 don't have matching circuit-id's. */ 71 don't have matching circuit-id's. */
72int corrupt_agent_options = 0; /* Number of packets dropped because 72int corrupt_agent_options = 0; /* Number of packets dropped because
73 relay agent information option was bad. */ 73 relay agent information option was bad. */
74int missing_agent_option = 0; /* Number of packets dropped because no 74int missing_agent_option = 0; /* Number of packets dropped because no
75 RAI option matching our ID was found. */ 75 RAI option matching our ID was found. */
76int bad_circuit_id = 0; /* Circuit ID option in matching RAI option 76int bad_circuit_id = 0; /* Circuit ID option in matching RAI option
77 did not match any known circuit ID. */ 77 did not match any known circuit ID. */
78int missing_circuit_id = 0; /* Circuit ID option in matching RAI option 78int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
79 was missing. */ 79 was missing. */
80int max_hop_count = 10; /* Maximum hop count */ 80int max_hop_count = 10; /* Maximum hop count */
81 81
82#ifdef DHCPv6 82#ifdef DHCPv6
83 /* Force use of DHCPv6 interface-id option. */ 83 /* Force use of DHCPv6 interface-id option. */
84isc_boolean_t use_if_id = ISC_FALSE; 84isc_boolean_t use_if_id = ISC_FALSE;
85#endif 85#endif
86 86
87 /* Maximum size of a packet with agent options added. */ 87 /* Maximum size of a packet with agent options added. */
88int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN; 88int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
89 89
90 /* What to do about packets we're asked to relay that 90 /* What to do about packets we're asked to relay that
91 already have a relay option: */ 91 already have a relay option: */
92enum { forward_and_append, /* Forward and append our own relay option. */ 92enum { forward_and_append, /* Forward and append our own relay option. */
93 forward_and_replace, /* Forward, but replace theirs with ours. */ 93 forward_and_replace, /* Forward, but replace theirs with ours. */
94 forward_untouched, /* Forward without changes. */ 94 forward_untouched, /* Forward without changes. */
95 discard } agent_relay_mode = forward_and_replace; 95 discard } agent_relay_mode = forward_and_replace;
96 96
97u_int16_t local_port; 97u_int16_t local_port;
98u_int16_t remote_port; 98u_int16_t remote_port;
99 99
100/* Relay agent server list. */ 100/* Relay agent server list. */
101struct server_list { 101struct server_list {
102 struct server_list *next; 102 struct server_list *next;
103 struct sockaddr_in to; 103 struct sockaddr_in to;
104} *servers; 104} *servers;
105 105
106#ifdef DHCPv6 106#ifdef DHCPv6
107struct stream_list { 107struct stream_list {
108 struct stream_list *next; 108 struct stream_list *next;
109 struct interface_info *ifp; 109 struct interface_info *ifp;
110 struct sockaddr_in6 link; 110 struct sockaddr_in6 link;
111 int id; 111 int id;
112} *downstreams, *upstreams; 112} *downstreams, *upstreams;
113 113
114static struct stream_list *parse_downstream(char *); 114static struct stream_list *parse_downstream(char *);
115static struct stream_list *parse_upstream(char *); 115static struct stream_list *parse_upstream(char *);
116static void setup_streams(void); 116static void setup_streams(void);
117 117
118/* 118/*
119 * A pointer to a subscriber id to add to the message we forward. 119 * A pointer to a subscriber id to add to the message we forward.
120 * This is primarily for testing purposes as we only have one id 120 * This is primarily for testing purposes as we only have one id
121 * for the entire relay and don't determine one per client which 121 * for the entire relay and don't determine one per client which
122 * would be more useful. 122 * would be more useful.
123 */ 123 */
124char *dhcrelay_sub_id = NULL; 124char *dhcrelay_sub_id = NULL;
125#endif 125#endif
126 126
127static void do_relay4(struct interface_info *, struct dhcp_packet *, 127static void do_relay4(struct interface_info *, struct dhcp_packet *,
128 unsigned int, unsigned int, struct iaddr, 128 unsigned int, unsigned int, struct iaddr,
129 struct hardware *); 129 struct hardware *);
130static int add_relay_agent_options(struct interface_info *, 130static int add_relay_agent_options(struct interface_info *,
131 struct dhcp_packet *, unsigned, 131 struct dhcp_packet *, unsigned,
132 struct in_addr); 132 struct in_addr);
133static int find_interface_by_agent_option(struct dhcp_packet *, 133static int find_interface_by_agent_option(struct dhcp_packet *,
134 struct interface_info **, u_int8_t *, int); 134 struct interface_info **, u_int8_t *, int);
135static int strip_relay_agent_options(struct interface_info *, 135static int strip_relay_agent_options(struct interface_info *,
136 struct interface_info **, 136 struct interface_info **,
137 struct dhcp_packet *, unsigned); 137 struct dhcp_packet *, unsigned);
138 138
139static const char copyright[] = 139static const char copyright[] =
140"Copyright 2004-2015 Internet Systems Consortium."; 140"Copyright 2004-2015 Internet Systems Consortium.";
141static const char arr[] = "All rights reserved."; 141static const char arr[] = "All rights reserved.";
142static const char message[] = 142static const char message[] =
143"Internet Systems Consortium DHCP Relay Agent"; 143"Internet Systems Consortium DHCP Relay Agent";
144static const char url[] = 144static const char url[] =
145"For info, please visit https://www.isc.org/software/dhcp/"; 145"For info, please visit https://www.isc.org/software/dhcp/";
146 146
147#ifdef DHCPv6 147#ifdef DHCPv6
148#define DHCRELAY_USAGE \ 148#define DHCRELAY_USAGE \
149"Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\ 149"Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\
150" [-A <length>] [-c <hops>] [-p <port>]\n" \ 150" [-A <length>] [-c <hops>] [-p <port>]\n" \
151" [-pf <pid-file>] [--no-pid]\n"\ 151" [-pf <pid-file>] [--no-pid]\n"\
152" [-m append|replace|forward|discard]\n" \ 152" [-m append|replace|forward|discard]\n" \
153" [-i interface0 [ ... -i interfaceN]\n" \ 153" [-i interface0 [ ... -i interfaceN]\n" \
154" server0 [ ... serverN]\n\n" \ 154" server0 [ ... serverN]\n\n" \
155" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \ 155" dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
156" [-pf <pid-file>] [--no-pid]\n" \ 156" [-pf <pid-file>] [--no-pid]\n" \
157" [-s <subscriber-id>]\n" \ 157" [-s <subscriber-id>]\n" \
158" -l lower0 [ ... -l lowerN]\n" \ 158" -l lower0 [ ... -l lowerN]\n" \
159" -u upper0 [ ... -u upperN]\n" \ 159" -u upper0 [ ... -u upperN]\n" \
160" lower (client link): [address%%]interface[#index]\n" \ 160" lower (client link): [address%%]interface[#index]\n" \
161" upper (server link): [address%%]interface" 161" upper (server link): [address%%]interface"
162#else 162#else
163#define DHCRELAY_USAGE \ 163#define DHCRELAY_USAGE \
164"Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \ 164"Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
165" [-pf <pid-file>] [--no-pid]\n" \ 165" [-pf <pid-file>] [--no-pid]\n" \
166" [-m append|replace|forward|discard]\n" \ 166" [-m append|replace|forward|discard]\n" \
167" [-i interface0 [ ... -i interfaceN]\n" \ 167" [-i interface0 [ ... -i interfaceN]\n" \
168" server0 [ ... serverN]\n\n" 168" server0 [ ... serverN]\n\n"
169#endif 169#endif
170 170
171static void usage(void) { 171static void usage(void) {
172 log_fatal(DHCRELAY_USAGE); 172 log_fatal(DHCRELAY_USAGE);
173} 173}
174 174
175int  175int
176main(int argc, char **argv) { 176main(int argc, char **argv) {
177 isc_result_t status; 177 isc_result_t status;
178 struct servent *ent; 178 struct servent *ent;
179 struct server_list *sp = NULL; 179 struct server_list *sp = NULL;
180 struct interface_info *tmp = NULL; 180 struct interface_info *tmp = NULL;
181 char *service_local = NULL, *service_remote = NULL; 181 char *service_local = NULL, *service_remote = NULL;
182 u_int16_t port_local = 0, port_remote = 0; 182 u_int16_t port_local = 0, port_remote = 0;
183 int no_daemon = 0, quiet = 0; 183 int no_daemon = 0, quiet = 0;
184 int fd; 184 int fd;
185 int i; 185 int i;
186#ifdef DHCPv6 186#ifdef DHCPv6
187 struct stream_list *sl = NULL; 187 struct stream_list *sl = NULL;
188 int local_family_set = 0; 188 int local_family_set = 0;
189#endif 189#endif
190 190
191 /* Make sure that file descriptors 0(stdin), 1,(stdout), and 191 /* Make sure that file descriptors 0(stdin), 1,(stdout), and
192 2(stderr) are open. To do this, we assume that when we 192 2(stderr) are open. To do this, we assume that when we
193 open a file the lowest available file descriptor is used. */ 193 open a file the lowest available file descriptor is used. */
194 fd = open("/dev/null", O_RDWR); 194 fd = open("/dev/null", O_RDWR);
195 if (fd == 0) 195 if (fd == 0)
196 fd = open("/dev/null", O_RDWR); 196 fd = open("/dev/null", O_RDWR);
197 if (fd == 1) 197 if (fd == 1)
198 fd = open("/dev/null", O_RDWR); 198 fd = open("/dev/null", O_RDWR);
199 if (fd == 2) 199 if (fd == 2)
200 log_perror = 0; /* No sense logging to /dev/null. */ 200 log_perror = 0; /* No sense logging to /dev/null. */
201 else if (fd != -1) 201 else if (fd != -1)
202 close(fd); 202 close(fd);
203 203
204 openlog("dhcrelay", DHCP_LOG_OPTIONS, LOG_DAEMON); 204 openlog("dhcrelay", DHCP_LOG_OPTIONS, LOG_DAEMON);
205 205
206#if !defined(DEBUG) 206#if !defined(DEBUG)
207 setlogmask(LOG_UPTO(LOG_INFO)); 207 setlogmask(LOG_UPTO(LOG_INFO));
208#endif  208#endif
209 209
210 /* Set up the isc and dns library managers */ 
211 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB, 
212 NULL, NULL); 
213 if (status != ISC_R_SUCCESS) 
214 log_fatal("Can't initialize context: %s", 
215 isc_result_totext(status)); 
216 
217 /* Set up the OMAPI. */ 210 /* Set up the OMAPI. */
218 status = omapi_init(); 211 status = omapi_init();
219 if (status != ISC_R_SUCCESS) 212 if (status != ISC_R_SUCCESS)
220 log_fatal("Can't initialize OMAPI: %s", 213 log_fatal("Can't initialize OMAPI: %s",
221 isc_result_totext(status)); 214 isc_result_totext(status));
222 215
223 /* Set up the OMAPI wrappers for the interface object. */ 216 /* Set up the OMAPI wrappers for the interface object. */
224 interface_setup(); 217 interface_setup();
225 218
226 for (i = 1; i < argc; i++) { 219 for (i = 1; i < argc; i++) {
227 if (!strcmp(argv[i], "-4")) { 220 if (!strcmp(argv[i], "-4")) {
228#ifdef DHCPv6 221#ifdef DHCPv6
229 if (local_family_set && (local_family == AF_INET6)) { 222 if (local_family_set && (local_family == AF_INET6)) {
230 usage(); 223 usage();
231 } 224 }
232 local_family_set = 1; 225 local_family_set = 1;
233 local_family = AF_INET; 226 local_family = AF_INET;
234 } else if (!strcmp(argv[i], "-6")) { 227 } else if (!strcmp(argv[i], "-6")) {
235 if (local_family_set && (local_family == AF_INET)) { 228 if (local_family_set && (local_family == AF_INET)) {
236 usage(); 229 usage();
237 } 230 }
238 local_family_set = 1; 231 local_family_set = 1;
239 local_family = AF_INET6; 232 local_family = AF_INET6;
240#endif 233#endif
241 } else if (!strcmp(argv[i], "-d")) { 234 } else if (!strcmp(argv[i], "-d")) {
242 no_daemon = 1; 235 no_daemon = 1;
243 } else if (!strcmp(argv[i], "-q")) { 236 } else if (!strcmp(argv[i], "-q")) {
244 quiet = 1; 237 quiet = 1;
245 quiet_interface_discovery = 1; 238 quiet_interface_discovery = 1;
246 } else if (!strcmp(argv[i], "-p")) { 239 } else if (!strcmp(argv[i], "-p")) {
247 if (++i == argc) 240 if (++i == argc)
248 usage(); 241 usage();
249 local_port = validate_port(argv[i]); 242 local_port = validate_port(argv[i]);
250 log_debug("binding to user-specified port %d", 243 log_debug("binding to user-specified port %d",
251 ntohs(local_port)); 244 ntohs(local_port));
252 } else if (!strcmp(argv[i], "-c")) { 245 } else if (!strcmp(argv[i], "-c")) {
253 int hcount; 246 int hcount;
254 if (++i == argc) 247 if (++i == argc)
255 usage(); 248 usage();
256 hcount = atoi(argv[i]); 249 hcount = atoi(argv[i]);
257 if (hcount <= 255) 250 if (hcount <= 255)
258 max_hop_count= hcount; 251 max_hop_count= hcount;
259 else 252 else
260 usage(); 253 usage();
261 } else if (!strcmp(argv[i], "-i")) { 254 } else if (!strcmp(argv[i], "-i")) {
262#ifdef DHCPv6 255#ifdef DHCPv6
263 if (local_family_set && (local_family == AF_INET6)) { 256 if (local_family_set && (local_family == AF_INET6)) {
264 usage(); 257 usage();
265 } 258 }
266 local_family_set = 1; 259 local_family_set = 1;
267 local_family = AF_INET; 260 local_family = AF_INET;
268#endif 261#endif
269 if (++i == argc) { 262 if (++i == argc) {
270 usage(); 263 usage();
271 } 264 }
272 if (strlen(argv[i]) >= sizeof(tmp->name)) { 265 if (strlen(argv[i]) >= sizeof(tmp->name)) {
273 log_fatal("%s: interface name too long " 266 log_fatal("%s: interface name too long "
274 "(is %ld)", 267 "(is %ld)",
275 argv[i], (long)strlen(argv[i])); 268 argv[i], (long)strlen(argv[i]));
276 } 269 }
277 status = interface_allocate(&tmp, MDL); 270 status = interface_allocate(&tmp, MDL);
278 if (status != ISC_R_SUCCESS) { 271 if (status != ISC_R_SUCCESS) {
279 log_fatal("%s: interface_allocate: %s", 272 log_fatal("%s: interface_allocate: %s",
280 argv[i], 273 argv[i],
281 isc_result_totext(status)); 274 isc_result_totext(status));
282 } 275 }
283 strcpy(tmp->name, argv[i]); 276 strcpy(tmp->name, argv[i]);
284 interface_snorf(tmp, INTERFACE_REQUESTED); 277 interface_snorf(tmp, INTERFACE_REQUESTED);
285 interface_dereference(&tmp, MDL); 278 interface_dereference(&tmp, MDL);
286 } else if (!strcmp(argv[i], "-a")) { 279 } else if (!strcmp(argv[i], "-a")) {
287#ifdef DHCPv6 280#ifdef DHCPv6
288 if (local_family_set && (local_family == AF_INET6)) { 281 if (local_family_set && (local_family == AF_INET6)) {
289 usage(); 282 usage();
290 } 283 }
291 local_family_set = 1; 284 local_family_set = 1;
292 local_family = AF_INET; 285 local_family = AF_INET;
293#endif 286#endif
294 add_agent_options = 1; 287 add_agent_options = 1;
295 } else if (!strcmp(argv[i], "-A")) { 288 } else if (!strcmp(argv[i], "-A")) {
296#ifdef DHCPv6 289#ifdef DHCPv6
297 if (local_family_set && (local_family == AF_INET6)) { 290 if (local_family_set && (local_family == AF_INET6)) {
298 usage(); 291 usage();
299 } 292 }
300 local_family_set = 1; 293 local_family_set = 1;
301 local_family = AF_INET; 294 local_family = AF_INET;
302#endif 295#endif
303 if (++i == argc) 296 if (++i == argc)
304 usage(); 297 usage();
305 298
306 dhcp_max_agent_option_packet_length = atoi(argv[i]); 299 dhcp_max_agent_option_packet_length = atoi(argv[i]);
307 300
308 if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX) 301 if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX)
309 log_fatal("%s: packet length exceeds " 302 log_fatal("%s: packet length exceeds "
310 "longest possible MTU\n", 303 "longest possible MTU\n",
311 argv[i]); 304 argv[i]);
312 } else if (!strcmp(argv[i], "-m")) { 305 } else if (!strcmp(argv[i], "-m")) {
313#ifdef DHCPv6 306#ifdef DHCPv6
314 if (local_family_set && (local_family == AF_INET6)) { 307 if (local_family_set && (local_family == AF_INET6)) {
315 usage(); 308 usage();
316 } 309 }
317 local_family_set = 1; 310 local_family_set = 1;
318 local_family = AF_INET; 311 local_family = AF_INET;
319#endif 312#endif
320 if (++i == argc) 313 if (++i == argc)
321 usage(); 314 usage();
322 if (!strcasecmp(argv[i], "append")) { 315 if (!strcasecmp(argv[i], "append")) {
323 agent_relay_mode = forward_and_append; 316 agent_relay_mode = forward_and_append;
324 } else if (!strcasecmp(argv[i], "replace")) { 317 } else if (!strcasecmp(argv[i], "replace")) {
325 agent_relay_mode = forward_and_replace; 318 agent_relay_mode = forward_and_replace;
326 } else if (!strcasecmp(argv[i], "forward")) { 319 } else if (!strcasecmp(argv[i], "forward")) {
327 agent_relay_mode = forward_untouched; 320 agent_relay_mode = forward_untouched;
328 } else if (!strcasecmp(argv[i], "discard")) { 321 } else if (!strcasecmp(argv[i], "discard")) {
329 agent_relay_mode = discard; 322 agent_relay_mode = discard;
330 } else 323 } else
331 usage(); 324 usage();
332 } else if (!strcmp(argv[i], "-D")) { 325 } else if (!strcmp(argv[i], "-D")) {
333#ifdef DHCPv6 326#ifdef DHCPv6
334 if (local_family_set && (local_family == AF_INET6)) { 327 if (local_family_set && (local_family == AF_INET6)) {
335 usage(); 328 usage();
336 } 329 }
337 local_family_set = 1; 330 local_family_set = 1;
338 local_family = AF_INET; 331 local_family = AF_INET;
339#endif 332#endif
340 drop_agent_mismatches = 1; 333 drop_agent_mismatches = 1;
341#ifdef DHCPv6 334#ifdef DHCPv6
342 } else if (!strcmp(argv[i], "-I")) { 335 } else if (!strcmp(argv[i], "-I")) {
343 if (local_family_set && (local_family == AF_INET)) { 336 if (local_family_set && (local_family == AF_INET)) {
344 usage(); 337 usage();
345 } 338 }
346 local_family_set = 1; 339 local_family_set = 1;
347 local_family = AF_INET6; 340 local_family = AF_INET6;
348 use_if_id = ISC_TRUE; 341 use_if_id = ISC_TRUE;
349 } else if (!strcmp(argv[i], "-l")) { 342 } else if (!strcmp(argv[i], "-l")) {
350 if (local_family_set && (local_family == AF_INET)) { 343 if (local_family_set && (local_family == AF_INET)) {
351 usage(); 344 usage();
352 } 345 }
353 local_family_set = 1; 346 local_family_set = 1;
354 local_family = AF_INET6; 347 local_family = AF_INET6;
355 if (downstreams != NULL) 348 if (downstreams != NULL)
356 use_if_id = ISC_TRUE; 349 use_if_id = ISC_TRUE;
357 if (++i == argc) 350 if (++i == argc)
358 usage(); 351 usage();
359 sl = parse_downstream(argv[i]); 352 sl = parse_downstream(argv[i]);
360 sl->next = downstreams; 353 sl->next = downstreams;
361 downstreams = sl; 354 downstreams = sl;
362 } else if (!strcmp(argv[i], "-u")) { 355 } else if (!strcmp(argv[i], "-u")) {
363 if (local_family_set && (local_family == AF_INET)) { 356 if (local_family_set && (local_family == AF_INET)) {
364 usage(); 357 usage();
365 } 358 }
366 local_family_set = 1; 359 local_family_set = 1;
367 local_family = AF_INET6; 360 local_family = AF_INET6;
368 if (++i == argc) 361 if (++i == argc)
369 usage(); 362 usage();
370 sl = parse_upstream(argv[i]); 363 sl = parse_upstream(argv[i]);
371 sl->next = upstreams; 364 sl->next = upstreams;
372 upstreams = sl; 365 upstreams = sl;
373 } else if (!strcmp(argv[i], "-s")) { 366 } else if (!strcmp(argv[i], "-s")) {
374 if (local_family_set && (local_family == AF_INET)) { 367 if (local_family_set && (local_family == AF_INET)) {
375 usage(); 368 usage();
376 } 369 }
377 local_family_set = 1; 370 local_family_set = 1;
378 local_family = AF_INET6; 371 local_family = AF_INET6;
379 if (++i == argc) 372 if (++i == argc)
380 usage(); 373 usage();
381 dhcrelay_sub_id = argv[i]; 374 dhcrelay_sub_id = argv[i];
382#endif 375#endif
383 } else if (!strcmp(argv[i], "-pf")) { 376 } else if (!strcmp(argv[i], "-pf")) {
384 if (++i == argc) 377 if (++i == argc)
385 usage(); 378 usage();
386 path_dhcrelay_pid = argv[i]; 379 path_dhcrelay_pid = argv[i];
387 no_dhcrelay_pid = ISC_TRUE; 380 no_dhcrelay_pid = ISC_TRUE;
388 } else if (!strcmp(argv[i], "--no-pid")) { 381 } else if (!strcmp(argv[i], "--no-pid")) {
389 no_pid_file = ISC_TRUE; 382 no_pid_file = ISC_TRUE;
390 } else if (!strcmp(argv[i], "--version")) { 383 } else if (!strcmp(argv[i], "--version")) {
391 log_info("isc-dhcrelay-%s", PACKAGE_VERSION); 384 log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
392 exit(0); 385 exit(0);
393 } else if (!strcmp(argv[i], "--help") || 386 } else if (!strcmp(argv[i], "--help") ||
394 !strcmp(argv[i], "-h")) { 387 !strcmp(argv[i], "-h")) {
395 log_info(DHCRELAY_USAGE); 388 log_info(DHCRELAY_USAGE);
396 exit(0); 389 exit(0);
397 } else if (argv[i][0] == '-') { 390 } else if (argv[i][0] == '-') {
398 usage(); 391 usage();
399 } else { 392 } else {
400 struct hostent *he; 393 struct hostent *he;
401 struct in_addr ia, *iap = NULL; 394 struct in_addr ia, *iap = NULL;
402 395
403#ifdef DHCPv6 396#ifdef DHCPv6
404 if (local_family_set && (local_family == AF_INET6)) { 397 if (local_family_set && (local_family == AF_INET6)) {
405 usage(); 398 usage();
406 } 399 }
407 local_family_set = 1; 400 local_family_set = 1;
408 local_family = AF_INET; 401 local_family = AF_INET;
409#endif 402#endif
410 if (inet_aton(argv[i], &ia)) { 403 if (inet_aton(argv[i], &ia)) {
411 iap = &ia; 404 iap = &ia;
412 } else { 405 } else {
413 he = gethostbyname(argv[i]); 406 he = gethostbyname(argv[i]);
414 if (!he) { 407 if (!he) {
415 log_error("%s: host unknown", argv[i]); 408 log_error("%s: host unknown", argv[i]);
416 } else { 409 } else {
417 iap = ((struct in_addr *) 410 iap = ((struct in_addr *)
418 he->h_addr_list[0]); 411 he->h_addr_list[0]);
419 } 412 }
420 } 413 }
421 414
422 if (iap) { 415 if (iap) {
423 sp = ((struct server_list *) 416 sp = ((struct server_list *)
424 dmalloc(sizeof *sp, MDL)); 417 dmalloc(sizeof *sp, MDL));
425 if (!sp) 418 if (!sp)
426 log_fatal("no memory for server.\n"); 419 log_fatal("no memory for server.\n");
427 sp->next = servers; 420 sp->next = servers;
428 servers = sp; 421 servers = sp;
429 memcpy(&sp->to.sin_addr, iap, sizeof *iap); 422 memcpy(&sp->to.sin_addr, iap, sizeof *iap);
430 } 423 }
431 } 424 }
432 } 425 }
433 426
434 /* 427 /*
435 * If the user didn't specify a pid file directly 428 * If the user didn't specify a pid file directly
436 * find one from environment variables or defaults 429 * find one from environment variables or defaults
437 */ 430 */
438 if (no_dhcrelay_pid == ISC_FALSE) { 431 if (no_dhcrelay_pid == ISC_FALSE) {
439 if (local_family == AF_INET) { 432 if (local_family == AF_INET) {
440 path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID"); 433 path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID");
441 if (path_dhcrelay_pid == NULL) 434 if (path_dhcrelay_pid == NULL)
442 path_dhcrelay_pid = _PATH_DHCRELAY_PID; 435 path_dhcrelay_pid = _PATH_DHCRELAY_PID;
443 } 436 }
444#ifdef DHCPv6 437#ifdef DHCPv6
445 else { 438 else {
446 path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID"); 439 path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID");
447 if (path_dhcrelay_pid == NULL) 440 if (path_dhcrelay_pid == NULL)
448 path_dhcrelay_pid = _PATH_DHCRELAY6_PID; 441 path_dhcrelay_pid = _PATH_DHCRELAY6_PID;
449 } 442 }
450#endif 443#endif
451 } 444 }
452 445
453 if (!quiet) { 446 if (!quiet) {
454 log_info("%s %s", message, PACKAGE_VERSION); 447 log_info("%s %s", message, PACKAGE_VERSION);
455 log_info(copyright); 448 log_info(copyright);
456 log_info(arr); 449 log_info(arr);
457 log_info(url); 450 log_info(url);
458 } else  451 } else
459 log_perror = 0; 452 log_perror = 0;
460 453
461 /* Set default port */ 454 /* Set default port */
462 if (local_family == AF_INET) { 455 if (local_family == AF_INET) {
463 service_local = "bootps"; 456 service_local = "bootps";
464 service_remote = "bootpc"; 457 service_remote = "bootpc";
465 port_local = htons(67); 458 port_local = htons(67);
466 port_remote = htons(68); 459 port_remote = htons(68);
467 } 460 }
468#ifdef DHCPv6 461#ifdef DHCPv6
469 else { 462 else {
470 service_local = "dhcpv6-server"; 463 service_local = "dhcpv6-server";
471 service_remote = "dhcpv6-client"; 464 service_remote = "dhcpv6-client";
472 port_local = htons(547); 465 port_local = htons(547);
473 port_remote = htons(546); 466 port_remote = htons(546);
474 } 467 }
475#endif 468#endif
476 469
477 if (!local_port) { 470 if (!local_port) {
478 ent = getservbyname(service_local, "udp"); 471 ent = getservbyname(service_local, "udp");
479 if (ent) 472 if (ent)
480 local_port = ent->s_port; 473 local_port = ent->s_port;
481 else 474 else
482 local_port = port_local; 475 local_port = port_local;
483 476
484 ent = getservbyname(service_remote, "udp"); 477 ent = getservbyname(service_remote, "udp");
485 if (ent) 478 if (ent)
486 remote_port = ent->s_port; 479 remote_port = ent->s_port;
487 else 480 else
488 remote_port = port_remote; 481 remote_port = port_remote;
489 482
490 endservent(); 483 endservent();
491 } 484 }
492 485
493 if (local_family == AF_INET) { 486 if (local_family == AF_INET) {
494 /* We need at least one server */ 487 /* We need at least one server */
495 if (servers == NULL) { 488 if (servers == NULL) {
496 log_fatal("No servers specified."); 489 log_fatal("No servers specified.");
497 } 490 }
498 491
499 492
500 /* Set up the server sockaddrs. */ 493 /* Set up the server sockaddrs. */
501 for (sp = servers; sp; sp = sp->next) { 494 for (sp = servers; sp; sp = sp->next) {
502 sp->to.sin_port = local_port; 495 sp->to.sin_port = local_port;
503 sp->to.sin_family = AF_INET; 496 sp->to.sin_family = AF_INET;
504#ifdef HAVE_SA_LEN 497#ifdef HAVE_SA_LEN
505 sp->to.sin_len = sizeof sp->to; 498 sp->to.sin_len = sizeof sp->to;
506#endif 499#endif
507 } 500 }
508 } 501 }
509#ifdef DHCPv6 502#ifdef DHCPv6
510 else { 503 else {
511 unsigned code; 504 unsigned code;
512 505
513 /* We need at least one upstream and one downstream interface */ 506 /* We need at least one upstream and one downstream interface */
514 if (upstreams == NULL || downstreams == NULL) { 507 if (upstreams == NULL || downstreams == NULL) {
515 log_info("Must specify at least one lower " 508 log_info("Must specify at least one lower "
516 "and one upper interface.\n"); 509 "and one upper interface.\n");
517 usage(); 510 usage();
518 } 511 }
519 512
520 /* Set up the initial dhcp option universe. */ 513 /* Set up the initial dhcp option universe. */
521 initialize_common_option_spaces(); 514 initialize_common_option_spaces();
522 515
523 /* Check requested options. */ 516 /* Check requested options. */
524 code = D6O_RELAY_MSG; 517 code = D6O_RELAY_MSG;
525 if (!option_code_hash_lookup(&requested_opts[0], 518 if (!option_code_hash_lookup(&requested_opts[0],
526 dhcpv6_universe.code_hash, 519 dhcpv6_universe.code_hash,
527 &code, 0, MDL)) 520 &code, 0, MDL))
528 log_fatal("Unable to find the RELAY_MSG " 521 log_fatal("Unable to find the RELAY_MSG "
529 "option definition."); 522 "option definition.");
530 code = D6O_INTERFACE_ID; 523 code = D6O_INTERFACE_ID;
531 if (!option_code_hash_lookup(&requested_opts[1], 524 if (!option_code_hash_lookup(&requested_opts[1],
532 dhcpv6_universe.code_hash, 525 dhcpv6_universe.code_hash,
533 &code, 0, MDL)) 526 &code, 0, MDL))
534 log_fatal("Unable to find the INTERFACE_ID " 527 log_fatal("Unable to find the INTERFACE_ID "
535 "option definition."); 528 "option definition.");
536 } 529 }
537#endif 530#endif
538 531
539 /* Get the current time... */ 
540 gettimeofday(&cur_tv, NULL); 
541 
542 /* Discover all the network interfaces. */ 
543 discover_interfaces(DISCOVER_RELAY); 
544 
545#ifdef DHCPv6 
546 if (local_family == AF_INET6) 
547 setup_streams(); 
548#endif 
549 
550 /* Become a daemon... */ 532 /* Become a daemon... */
551 if (!no_daemon) { 533 if (!no_daemon) {
552 int pid; 534 int pid;
553 FILE *pf; 535 FILE *pf;
554 int pfdesc; 536 int pfdesc;
555 537
556 log_perror = 0; 538 log_perror = 0;
557 539
558 if ((pid = fork()) < 0) 540 if ((pid = fork()) < 0)
559 log_fatal("Can't fork daemon: %m"); 541 log_fatal("Can't fork daemon: %m");
560 else if (pid) 542 else if (pid)
561 exit(0); 543 exit(0);
562 544
563 if (no_pid_file == ISC_FALSE) { 545 if (no_pid_file == ISC_FALSE) {
564 pfdesc = open(path_dhcrelay_pid, 546 pfdesc = open(path_dhcrelay_pid,
565 O_CREAT | O_TRUNC | O_WRONLY, 0644); 547 O_CREAT | O_TRUNC | O_WRONLY, 0644);
566 548
567 if (pfdesc < 0) { 549 if (pfdesc < 0) {
568 log_error("Can't create %s: %m", 550 log_error("Can't create %s: %m",
569 path_dhcrelay_pid); 551 path_dhcrelay_pid);
570 } else { 552 } else {
571 pf = fdopen(pfdesc, "w"); 553 pf = fdopen(pfdesc, "w");
572 if (!pf) 554 if (!pf)
573 log_error("Can't fdopen %s: %m", 555 log_error("Can't fdopen %s: %m",
574 path_dhcrelay_pid); 556 path_dhcrelay_pid);
575 else { 557 else {
576 fprintf(pf, "%ld\n",(long)getpid()); 558 fprintf(pf, "%ld\n",(long)getpid());
577 fclose(pf); 559 fclose(pf);
578 }  560 }
579 } 561 }
580 } 562 }
581 563
582 (void) close(0); 564 (void) close(0);
583 (void) close(1); 565 (void) close(1);
584 (void) close(2); 566 (void) close(2);
585 (void) setsid(); 567 (void) setsid();
586 568
587 IGNORE_RET (chdir("/")); 569 IGNORE_RET (chdir("/"));
588 } 570 }
589 571
 572 /* Set up the isc and dns library managers */
 573 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
 574 NULL, NULL);
 575 if (status != ISC_R_SUCCESS)
 576 log_fatal("Can't initialize context: %s",
 577 isc_result_totext(status));
 578
 579 /* Get the current time... */
 580 gettimeofday(&cur_tv, NULL);
 581
 582 /* Discover all the network interfaces. */
 583 discover_interfaces(DISCOVER_RELAY);
 584
 585#ifdef DHCPv6
 586 if (local_family == AF_INET6)
 587 setup_streams();
 588#endif
 589
590 /* Set up the packet handler... */ 590 /* Set up the packet handler... */
591 if (local_family == AF_INET) 591 if (local_family == AF_INET)
592 bootp_packet_handler = do_relay4; 592 bootp_packet_handler = do_relay4;
593#ifdef DHCPv6 593#ifdef DHCPv6
594 else 594 else
595 dhcpv6_packet_handler = do_packet6; 595 dhcpv6_packet_handler = do_packet6;
596#endif 596#endif
597 597
598#if defined(ENABLE_GENTLE_SHUTDOWN) 598#if defined(ENABLE_GENTLE_SHUTDOWN)
599 /* no signal handlers until we deal with the side effects */ 599 /* no signal handlers until we deal with the side effects */
600 /* install signal handlers */ 600 /* install signal handlers */
601 signal(SIGINT, dhcp_signal_handler); /* control-c */ 601 signal(SIGINT, dhcp_signal_handler); /* control-c */
602 signal(SIGTERM, dhcp_signal_handler); /* kill */ 602 signal(SIGTERM, dhcp_signal_handler); /* kill */
603#endif 603#endif
604 604
605 /* Start dispatching packets and timeouts... */ 605 /* Start dispatching packets and timeouts... */
606 dispatch(); 606 dispatch();
607 607
608 /* In fact dispatch() never returns. */ 608 /* In fact dispatch() never returns. */
609 return (0); 609 return (0);
610} 610}
611 611
612static void 612static void
613do_relay4(struct interface_info *ip, struct dhcp_packet *packet, 613do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
614 unsigned int length, unsigned int from_port, struct iaddr from, 614 unsigned int length, unsigned int from_port, struct iaddr from,
615 struct hardware *hfrom) { 615 struct hardware *hfrom) {
616 struct server_list *sp; 616 struct server_list *sp;
617 struct sockaddr_in to; 617 struct sockaddr_in to;
618 struct interface_info *out; 618 struct interface_info *out;
619 struct hardware hto, *htop; 619 struct hardware hto, *htop;
620 620
621 if (packet->hlen > sizeof packet->chaddr) { 621 if (packet->hlen > sizeof packet->chaddr) {
622 log_info("Discarding packet with invalid hlen, received on " 622 log_info("Discarding packet with invalid hlen, received on "
623 "%s interface.", ip->name); 623 "%s interface.", ip->name);
624 return; 624 return;
625 } 625 }
626 if (ip->address_count < 1 || ip->addresses == NULL) { 626 if (ip->address_count < 1 || ip->addresses == NULL) {
627 log_info("Discarding packet received on %s interface that " 627 log_info("Discarding packet received on %s interface that "
628 "has no IPv4 address assigned.", ip->name); 628 "has no IPv4 address assigned.", ip->name);
629 return; 629 return;
630 } 630 }
631 631
632 /* Find the interface that corresponds to the giaddr 632 /* Find the interface that corresponds to the giaddr
633 in the packet. */ 633 in the packet. */
634 if (packet->giaddr.s_addr) { 634 if (packet->giaddr.s_addr) {
635 for (out = interfaces; out; out = out->next) { 635 for (out = interfaces; out; out = out->next) {
636 int i; 636 int i;
637 637
638 for (i = 0 ; i < out->address_count ; i++ ) { 638 for (i = 0 ; i < out->address_count ; i++ ) {
639 if (out->addresses[i].s_addr == 639 if (out->addresses[i].s_addr ==
640 packet->giaddr.s_addr) { 640 packet->giaddr.s_addr) {
641 i = -1; 641 i = -1;
642 break; 642 break;
643 } 643 }
644 } 644 }
645 645
646 if (i == -1) 646 if (i == -1)
647 break; 647 break;
648 } 648 }
649 } else { 649 } else {
650 out = NULL; 650 out = NULL;
651 } 651 }
652 652
653 /* If it's a bootreply, forward it to the client. */ 653 /* If it's a bootreply, forward it to the client. */
654 if (packet->op == BOOTREPLY) { 654 if (packet->op == BOOTREPLY) {
655 if (!(packet->flags & htons(BOOTP_BROADCAST)) && 655 if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
656 can_unicast_without_arp(out)) { 656 can_unicast_without_arp(out)) {
657 to.sin_addr = packet->yiaddr; 657 to.sin_addr = packet->yiaddr;
658 to.sin_port = remote_port; 658 to.sin_port = remote_port;
659 659
660 /* and hardware address is not broadcast */ 660 /* and hardware address is not broadcast */
661 htop = &hto; 661 htop = &hto;
662 } else { 662 } else {
663 to.sin_addr.s_addr = htonl(INADDR_BROADCAST); 663 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
664 to.sin_port = remote_port; 664 to.sin_port = remote_port;
665 665
666 /* hardware address is broadcast */ 666 /* hardware address is broadcast */
667 htop = NULL; 667 htop = NULL;
668 } 668 }
669 to.sin_family = AF_INET; 669 to.sin_family = AF_INET;
670#ifdef HAVE_SA_LEN 670#ifdef HAVE_SA_LEN
671 to.sin_len = sizeof to; 671 to.sin_len = sizeof to;
672#endif 672#endif
673 673
674 memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen); 674 memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen);
675 hto.hbuf[0] = packet->htype; 675 hto.hbuf[0] = packet->htype;
676 hto.hlen = packet->hlen + 1; 676 hto.hlen = packet->hlen + 1;
677 677
678 /* Wipe out the agent relay options and, if possible, figure 678 /* Wipe out the agent relay options and, if possible, figure
679 out which interface to use based on the contents of the 679 out which interface to use based on the contents of the
680 option that we put on the request to which the server is 680 option that we put on the request to which the server is
681 replying. */ 681 replying. */
682 if (!(length = 682 if (!(length =
683 strip_relay_agent_options(ip, &out, packet, length))) 683 strip_relay_agent_options(ip, &out, packet, length)))
684 return; 684 return;
685 685
686 if (!out) { 686 if (!out) {
687 log_error("Packet to bogus giaddr %s.\n", 687 log_error("Packet to bogus giaddr %s.\n",
688 inet_ntoa(packet->giaddr)); 688 inet_ntoa(packet->giaddr));
689 ++bogus_giaddr_drops; 689 ++bogus_giaddr_drops;
690 return; 690 return;
691 } 691 }
692 692
693 if (send_packet(out, NULL, packet, length, out->addresses[0], 693 if (send_packet(out, NULL, packet, length, out->addresses[0],
694 &to, htop) < 0) { 694 &to, htop) < 0) {
695 ++server_packet_errors; 695 ++server_packet_errors;
696 } else { 696 } else {
697 log_debug("Forwarded BOOTREPLY for %s to %s", 697 log_debug("Forwarded BOOTREPLY for %s to %s",
698 print_hw_addr(packet->htype, packet->hlen, 698 print_hw_addr(packet->htype, packet->hlen,
699 packet->chaddr), 699 packet->chaddr),
700 inet_ntoa(to.sin_addr)); 700 inet_ntoa(to.sin_addr));
701 701
702 ++server_packets_relayed; 702 ++server_packets_relayed;
703 } 703 }
704 return; 704 return;
705 } 705 }
706 706
707 /* If giaddr matches one of our addresses, ignore the packet - 707 /* If giaddr matches one of our addresses, ignore the packet -
708 we just sent it. */ 708 we just sent it. */
709 if (out) 709 if (out)
710 return; 710 return;
711 711
712 /* Add relay agent options if indicated. If something goes wrong, 712 /* Add relay agent options if indicated. If something goes wrong,
713 drop the packet. */ 713 drop the packet. */
714 if (!(length = add_relay_agent_options(ip, packet, length, 714 if (!(length = add_relay_agent_options(ip, packet, length,
715 ip->addresses[0]))) 715 ip->addresses[0])))
716 return; 716 return;
717 717
718 /* If giaddr is not already set, Set it so the server can 718 /* If giaddr is not already set, Set it so the server can
719 figure out what net it's from and so that we can later 719 figure out what net it's from and so that we can later
720 forward the response to the correct net. If it's already 720 forward the response to the correct net. If it's already
721 set, the response will be sent directly to the relay agent 721 set, the response will be sent directly to the relay agent
722 that set giaddr, so we won't see it. */ 722 that set giaddr, so we won't see it. */
723 if (!packet->giaddr.s_addr) 723 if (!packet->giaddr.s_addr)
724 packet->giaddr = ip->addresses[0]; 724 packet->giaddr = ip->addresses[0];
725 if (packet->hops < max_hop_count) 725 if (packet->hops < max_hop_count)
726 packet->hops = packet->hops + 1; 726 packet->hops = packet->hops + 1;
727 else 727 else
728 return; 728 return;
729 729
730 /* Otherwise, it's a BOOTREQUEST, so forward it to all the 730 /* Otherwise, it's a BOOTREQUEST, so forward it to all the
731 servers. */ 731 servers. */
732 for (sp = servers; sp; sp = sp->next) { 732 for (sp = servers; sp; sp = sp->next) {
733 if (send_packet((fallback_interface 733 if (send_packet((fallback_interface
734 ? fallback_interface : interfaces), 734 ? fallback_interface : interfaces),
735 NULL, packet, length, ip->addresses[0], 735 NULL, packet, length, ip->addresses[0],
736 &sp->to, NULL) < 0) { 736 &sp->to, NULL) < 0) {
737 ++client_packet_errors; 737 ++client_packet_errors;
738 } else { 738 } else {
739 log_debug("Forwarded BOOTREQUEST for %s to %s", 739 log_debug("Forwarded BOOTREQUEST for %s to %s",
740 print_hw_addr(packet->htype, packet->hlen, 740 print_hw_addr(packet->htype, packet->hlen,
741 packet->chaddr), 741 packet->chaddr),
742 inet_ntoa(sp->to.sin_addr)); 742 inet_ntoa(sp->to.sin_addr));
743 ++client_packets_relayed; 743 ++client_packets_relayed;
744 } 744 }
745 } 745 }
746  746
747} 747}
748 748
749/* Strip any Relay Agent Information options from the DHCP packet 749/* Strip any Relay Agent Information options from the DHCP packet
750 option buffer. If there is a circuit ID suboption, look up the 750 option buffer. If there is a circuit ID suboption, look up the
751 outgoing interface based upon it. */ 751 outgoing interface based upon it. */
752 752
753static int 753static int
754strip_relay_agent_options(struct interface_info *in, 754strip_relay_agent_options(struct interface_info *in,
755 struct interface_info **out, 755 struct interface_info **out,
756 struct dhcp_packet *packet, 756 struct dhcp_packet *packet,
757 unsigned length) { 757 unsigned length) {
758 int is_dhcp = 0; 758 int is_dhcp = 0;
759 u_int8_t *op, *nextop, *sp, *max; 759 u_int8_t *op, *nextop, *sp, *max;
760 int good_agent_option = 0; 760 int good_agent_option = 0;
761 int status; 761 int status;
762 762
763 /* If we're not adding agent options to packets, we're not taking 763 /* If we're not adding agent options to packets, we're not taking
764 them out either. */ 764 them out either. */
765 if (!add_agent_options) 765 if (!add_agent_options)
766 return (length); 766 return (length);
767 767
768 /* If there's no cookie, it's a bootp packet, so we should just 768 /* If there's no cookie, it's a bootp packet, so we should just
769 forward it unchanged. */ 769 forward it unchanged. */
770 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4)) 770 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
771 return (length); 771 return (length);
772 772
773 max = ((u_int8_t *)packet) + length; 773 max = ((u_int8_t *)packet) + length;
774 sp = op = &packet->options[4]; 774 sp = op = &packet->options[4];
775 775
776 while (op < max) { 776 while (op < max) {
777 switch(*op) { 777 switch(*op) {
778 /* Skip padding... */ 778 /* Skip padding... */
779 case DHO_PAD: 779 case DHO_PAD:
780 if (sp != op) 780 if (sp != op)
781 *sp = *op; 781 *sp = *op;
782 ++op; 782 ++op;
783 ++sp; 783 ++sp;
784 continue; 784 continue;
785 785
786 /* If we see a message type, it's a DHCP packet. */ 786 /* If we see a message type, it's a DHCP packet. */
787 case DHO_DHCP_MESSAGE_TYPE: 787 case DHO_DHCP_MESSAGE_TYPE:
788 is_dhcp = 1; 788 is_dhcp = 1;
789 goto skip; 789 goto skip;
790 break; 790 break;
791 791
792 /* Quit immediately if we hit an End option. */ 792 /* Quit immediately if we hit an End option. */
793 case DHO_END: 793 case DHO_END:
794 if (sp != op) 794 if (sp != op)
795 *sp++ = *op++; 795 *sp++ = *op++;
796 goto out; 796 goto out;
797 797
798 case DHO_DHCP_AGENT_OPTIONS: 798 case DHO_DHCP_AGENT_OPTIONS:
799 /* We shouldn't see a relay agent option in a 799 /* We shouldn't see a relay agent option in a
800 packet before we've seen the DHCP packet type, 800 packet before we've seen the DHCP packet type,
801 but if we do, we have to leave it alone. */ 801 but if we do, we have to leave it alone. */
802 if (!is_dhcp) 802 if (!is_dhcp)
803 goto skip; 803 goto skip;
804 804
805 /* Do not process an agent option if it exceeds the 805 /* Do not process an agent option if it exceeds the
806 * buffer. Fail this packet. 806 * buffer. Fail this packet.
807 */ 807 */
808 nextop = op + op[1] + 2; 808 nextop = op + op[1] + 2;
809 if (nextop > max) 809 if (nextop > max)
810 return (0); 810 return (0);
811 811
812 status = find_interface_by_agent_option(packet, 812 status = find_interface_by_agent_option(packet,
813 out, op + 2, 813 out, op + 2,
814 op[1]); 814 op[1]);
815 if (status == -1 && drop_agent_mismatches) 815 if (status == -1 && drop_agent_mismatches)
816 return (0); 816 return (0);
817 if (status) 817 if (status)
818 good_agent_option = 1; 818 good_agent_option = 1;
819 op = nextop; 819 op = nextop;
820 break; 820 break;
821 821
822 skip: 822 skip:
823 /* Skip over other options. */ 823 /* Skip over other options. */
824 default: 824 default:
825 /* Fail if processing this option will exceed the 825 /* Fail if processing this option will exceed the
826 * buffer(op[1] is malformed). 826 * buffer(op[1] is malformed).
827 */ 827 */
828 nextop = op + op[1] + 2; 828 nextop = op + op[1] + 2;
829 if (nextop > max) 829 if (nextop > max)
830 return (0); 830 return (0);
831 831
832 if (sp != op) { 832 if (sp != op) {
833 memmove(sp, op, op[1] + 2); 833 memmove(sp, op, op[1] + 2);
834 sp += op[1] + 2; 834 sp += op[1] + 2;
835 op = nextop; 835 op = nextop;
836 } else 836 } else
837 op = sp = nextop; 837 op = sp = nextop;
838 838
839 break; 839 break;
840 } 840 }
841 } 841 }
842 out: 842 out:
843 843
844 /* If it's not a DHCP packet, we're not supposed to touch it. */ 844 /* If it's not a DHCP packet, we're not supposed to touch it. */
845 if (!is_dhcp) 845 if (!is_dhcp)
846 return (length); 846 return (length);
847 847
848 /* If none of the agent options we found matched, or if we didn't 848 /* If none of the agent options we found matched, or if we didn't
849 find any agent options, count this packet as not having any 849 find any agent options, count this packet as not having any
850 matching agent options, and if we're relying on agent options 850 matching agent options, and if we're relying on agent options
851 to determine the outgoing interface, drop the packet. */ 851 to determine the outgoing interface, drop the packet. */
852 852
853 if (!good_agent_option) { 853 if (!good_agent_option) {
854 ++missing_agent_option; 854 ++missing_agent_option;
855 if (drop_agent_mismatches) 855 if (drop_agent_mismatches)
856 return (0); 856 return (0);
857 } 857 }
858 858
859 /* Adjust the length... */ 859 /* Adjust the length... */
860 if (sp != op) { 860 if (sp != op) {
861 length = sp -((u_int8_t *)packet); 861 length = sp -((u_int8_t *)packet);
862 862
863 /* Make sure the packet isn't short(this is unlikely, 863 /* Make sure the packet isn't short(this is unlikely,
864 but WTH) */ 864 but WTH) */
865 if (length < BOOTP_MIN_LEN) { 865 if (length < BOOTP_MIN_LEN) {
866 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length); 866 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
867 length = BOOTP_MIN_LEN; 867 length = BOOTP_MIN_LEN;
868 } 868 }
869 } 869 }
870 return (length); 870 return (length);
871} 871}
872 872
873 873
874/* Find an interface that matches the circuit ID specified in the 874/* Find an interface that matches the circuit ID specified in the
875 Relay Agent Information option. If one is found, store it through 875 Relay Agent Information option. If one is found, store it through
876 the pointer given; otherwise, leave the existing pointer alone. 876 the pointer given; otherwise, leave the existing pointer alone.
877 877
878 We actually deviate somewhat from the current specification here: 878 We actually deviate somewhat from the current specification here:
879 if the option buffer is corrupt, we suggest that the caller not 879 if the option buffer is corrupt, we suggest that the caller not
880 respond to this packet. If the circuit ID doesn't match any known 880 respond to this packet. If the circuit ID doesn't match any known
881 interface, we suggest that the caller to drop the packet. Only if 881 interface, we suggest that the caller to drop the packet. Only if
882 we find a circuit ID that matches an existing interface do we tell 882 we find a circuit ID that matches an existing interface do we tell
883 the caller to go ahead and process the packet. */ 883 the caller to go ahead and process the packet. */
884 884
885static int 885static int
886find_interface_by_agent_option(struct dhcp_packet *packet, 886find_interface_by_agent_option(struct dhcp_packet *packet,
887 struct interface_info **out, 887 struct interface_info **out,
888 u_int8_t *buf, int len) { 888 u_int8_t *buf, int len) {
889 int i = 0; 889 int i = 0;
890 u_int8_t *circuit_id = 0; 890 u_int8_t *circuit_id = 0;
891 unsigned circuit_id_len = 0; 891 unsigned circuit_id_len = 0;
892 struct interface_info *ip; 892 struct interface_info *ip;
893 893
894 while (i < len) { 894 while (i < len) {
895 /* If the next agent option overflows the end of the 895 /* If the next agent option overflows the end of the
896 packet, the agent option buffer is corrupt. */ 896 packet, the agent option buffer is corrupt. */
897 if (i + 1 == len || 897 if (i + 1 == len ||
898 i + buf[i + 1] + 2 > len) { 898 i + buf[i + 1] + 2 > len) {
899 ++corrupt_agent_options; 899 ++corrupt_agent_options;
900 return (-1); 900 return (-1);
901 } 901 }
902 switch(buf[i]) { 902 switch(buf[i]) {
903 /* Remember where the circuit ID is... */ 903 /* Remember where the circuit ID is... */
904 case RAI_CIRCUIT_ID: 904 case RAI_CIRCUIT_ID:
905 circuit_id = &buf[i + 2]; 905 circuit_id = &buf[i + 2];
906 circuit_id_len = buf[i + 1]; 906 circuit_id_len = buf[i + 1];
907 i += circuit_id_len + 2; 907 i += circuit_id_len + 2;
908 continue; 908 continue;
909 909
910 default: 910 default:
911 i += buf[i + 1] + 2; 911 i += buf[i + 1] + 2;
912 break; 912 break;
913 } 913 }
914 } 914 }
915 915
916 /* If there's no circuit ID, it's not really ours, tell the caller 916 /* If there's no circuit ID, it's not really ours, tell the caller
917 it's no good. */ 917 it's no good. */
918 if (!circuit_id) { 918 if (!circuit_id) {
919 ++missing_circuit_id; 919 ++missing_circuit_id;
920 return (-1); 920 return (-1);
921 } 921 }
922 922
923 /* Scan the interface list looking for an interface whose 923 /* Scan the interface list looking for an interface whose
924 name matches the one specified in circuit_id. */ 924 name matches the one specified in circuit_id. */
925 925
926 for (ip = interfaces; ip; ip = ip->next) { 926 for (ip = interfaces; ip; ip = ip->next) {
927 if (ip->circuit_id && 927 if (ip->circuit_id &&
928 ip->circuit_id_len == circuit_id_len && 928 ip->circuit_id_len == circuit_id_len &&
929 !memcmp(ip->circuit_id, circuit_id, circuit_id_len)) 929 !memcmp(ip->circuit_id, circuit_id, circuit_id_len))
930 break; 930 break;
931 } 931 }
932 932
933 /* If we got a match, use it. */ 933 /* If we got a match, use it. */
934 if (ip) { 934 if (ip) {
935 *out = ip; 935 *out = ip;
936 return (1); 936 return (1);
937 } 937 }
938 938
939 /* If we didn't get a match, the circuit ID was bogus. */ 939 /* If we didn't get a match, the circuit ID was bogus. */
940 ++bad_circuit_id; 940 ++bad_circuit_id;
941 return (-1); 941 return (-1);
942} 942}
943 943
944/* 944/*
945 * Examine a packet to see if it's a candidate to have a Relay 945 * Examine a packet to see if it's a candidate to have a Relay
946 * Agent Information option tacked onto its tail. If it is, tack 946 * Agent Information option tacked onto its tail. If it is, tack
947 * the option on. 947 * the option on.
948 */ 948 */
949 949
950#include <sys/cdefs.h> 950#include <sys/cdefs.h>
951__RCSID("$NetBSD: dhcrelay.c,v 1.6 2016/01/10 20:10:45 christos Exp $"); 951__RCSID("$NetBSD: dhcrelay.c,v 1.6.8.1 2017/06/10 06:30:07 snj Exp $");
952static int 952static int
953add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet, 953add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
954 unsigned length, struct in_addr giaddr) { 954 unsigned length, struct in_addr giaddr) {
955 int is_dhcp = 0, mms; 955 int is_dhcp = 0, mms;
956 unsigned optlen; 956 unsigned optlen;
957 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL; 957 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
958 958
959 /* If we're not adding agent options to packets, we can skip 959 /* If we're not adding agent options to packets, we can skip
960 this. */ 960 this. */
961 if (!add_agent_options) 961 if (!add_agent_options)
962 return (length); 962 return (length);
963 963
964 /* If there's no cookie, it's a bootp packet, so we should just 964 /* If there's no cookie, it's a bootp packet, so we should just
965 forward it unchanged. */ 965 forward it unchanged. */
966 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4)) 966 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
967 return (length); 967 return (length);
968 968
969 max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length; 969 max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length;
970 970
971 /* Commence processing after the cookie. */ 971 /* Commence processing after the cookie. */
972 sp = op = &packet->options[4]; 972 sp = op = &packet->options[4];
973 973
974 while (op < max) { 974 while (op < max) {
975 switch(*op) { 975 switch(*op) {
976 /* Skip padding... */ 976 /* Skip padding... */
977 case DHO_PAD: 977 case DHO_PAD:
978 /* Remember the first pad byte so we can commandeer 978 /* Remember the first pad byte so we can commandeer
979 * padded space. 979 * padded space.
980 * 980 *
981 * XXX: Is this really a good idea? Sure, we can 981 * XXX: Is this really a good idea? Sure, we can
982 * seemingly reduce the packet while we're looking, 982 * seemingly reduce the packet while we're looking,
983 * but if the packet was signed by the client then 983 * but if the packet was signed by the client then
984 * this padding is part of the checksum(RFC3118), 984 * this padding is part of the checksum(RFC3118),
985 * and its nonpresence would break authentication. 985 * and its nonpresence would break authentication.
986 */ 986 */
987 if (end_pad == NULL) 987 if (end_pad == NULL)
988 end_pad = sp; 988 end_pad = sp;
989 989
990 if (sp != op) 990 if (sp != op)
991 *sp++ = *op++; 991 *sp++ = *op++;
992 else 992 else
993 sp = ++op; 993 sp = ++op;
994 994
995 continue; 995 continue;
996 996
997 /* If we see a message type, it's a DHCP packet. */ 997 /* If we see a message type, it's a DHCP packet. */
998 case DHO_DHCP_MESSAGE_TYPE: 998 case DHO_DHCP_MESSAGE_TYPE:
999 is_dhcp = 1; 999 is_dhcp = 1;
1000 goto skip; 1000 goto skip;
1001 1001
1002 /* 1002 /*
1003 * If there's a maximum message size option, we 1003 * If there's a maximum message size option, we
1004 * should pay attention to it 1004 * should pay attention to it
1005 */ 1005 */
1006 case DHO_DHCP_MAX_MESSAGE_SIZE: 1006 case DHO_DHCP_MAX_MESSAGE_SIZE:
1007 mms = ntohs(*(op + 2)); 1007 mms = ntohs(*(op + 2));
1008 if (mms < dhcp_max_agent_option_packet_length && 1008 if (mms < dhcp_max_agent_option_packet_length &&
1009 mms >= DHCP_MTU_MIN) 1009 mms >= DHCP_MTU_MIN)
1010 max = ((u_int8_t *)packet) + mms; 1010 max = ((u_int8_t *)packet) + mms;
1011 goto skip; 1011 goto skip;
1012 1012
1013 /* Quit immediately if we hit an End option. */ 1013 /* Quit immediately if we hit an End option. */
1014 case DHO_END: 1014 case DHO_END:
1015 goto out; 1015 goto out;
1016 1016
1017 case DHO_DHCP_AGENT_OPTIONS: 1017 case DHO_DHCP_AGENT_OPTIONS:
1018 /* We shouldn't see a relay agent option in a 1018 /* We shouldn't see a relay agent option in a
1019 packet before we've seen the DHCP packet type, 1019 packet before we've seen the DHCP packet type,
1020 but if we do, we have to leave it alone. */ 1020 but if we do, we have to leave it alone. */
1021 if (!is_dhcp) 1021 if (!is_dhcp)
1022 goto skip; 1022 goto skip;
1023 1023
1024 end_pad = NULL; 1024 end_pad = NULL;
1025 1025
1026 /* There's already a Relay Agent Information option 1026 /* There's already a Relay Agent Information option
1027 in this packet. How embarrassing. Decide what 1027 in this packet. How embarrassing. Decide what
1028 to do based on the mode the user specified. */ 1028 to do based on the mode the user specified. */
1029 1029
1030 switch(agent_relay_mode) { 1030 switch(agent_relay_mode) {
1031 case forward_and_append: 1031 case forward_and_append:
1032 goto skip; 1032 goto skip;
1033 case forward_untouched: 1033 case forward_untouched:
1034 return (length); 1034 return (length);
1035 case discard: 1035 case discard:
1036 return (0); 1036 return (0);
1037 case forward_and_replace: 1037 case forward_and_replace:
1038 default: 1038 default:
1039 break; 1039 break;
1040 } 1040 }
1041 1041
1042 /* Skip over the agent option and start copying 1042 /* Skip over the agent option and start copying
1043 if we aren't copying already. */ 1043 if we aren't copying already. */
1044 op += op[1] + 2; 1044 op += op[1] + 2;
1045 break; 1045 break;
1046 1046
1047 skip: 1047 skip:
1048 /* Skip over other options. */ 1048 /* Skip over other options. */
1049 default: 1049 default:
1050 /* Fail if processing this option will exceed the 1050 /* Fail if processing this option will exceed the
1051 * buffer(op[1] is malformed). 1051 * buffer(op[1] is malformed).
1052 */ 1052 */
1053 nextop = op + op[1] + 2; 1053 nextop = op + op[1] + 2;
1054 if (nextop > max) 1054 if (nextop > max)
1055 return (0); 1055 return (0);
1056 1056
1057 end_pad = NULL; 1057 end_pad = NULL;
1058 1058
1059 if (sp != op) { 1059 if (sp != op) {
1060 memmove(sp, op, op[1] + 2); 1060 memmove(sp, op, op[1] + 2);
1061 sp += op[1] + 2; 1061 sp += op[1] + 2;
1062 op = nextop; 1062 op = nextop;
1063 } else 1063 } else
1064 op = sp = nextop; 1064 op = sp = nextop;
1065 1065
1066 break; 1066 break;
1067 } 1067 }
1068 } 1068 }
1069 out: 1069 out:
1070 1070
1071 /* If it's not a DHCP packet, we're not supposed to touch it. */ 1071 /* If it's not a DHCP packet, we're not supposed to touch it. */
1072 if (!is_dhcp) 1072 if (!is_dhcp)
1073 return (length); 1073 return (length);
1074 1074
1075 /* If the packet was padded out, we can store the agent option 1075 /* If the packet was padded out, we can store the agent option
1076 at the beginning of the padding. */ 1076 at the beginning of the padding. */
1077 1077
1078 if (end_pad != NULL) 1078 if (end_pad != NULL)
1079 sp = end_pad; 1079 sp = end_pad;
1080 1080
1081#if 0 1081#if 0
1082 /* Remember where the end of the packet was after parsing 1082 /* Remember where the end of the packet was after parsing
1083 it. */ 1083 it. */
1084 op = sp; 1084 op = sp;
1085#endif 1085#endif
1086 1086
1087 /* Sanity check. Had better not ever happen. */ 1087 /* Sanity check. Had better not ever happen. */
1088 if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1)) 1088 if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
1089 log_fatal("Circuit ID length %d out of range [1-255] on " 1089 log_fatal("Circuit ID length %d out of range [1-255] on "
1090 "%s\n", ip->circuit_id_len, ip->name); 1090 "%s\n", ip->circuit_id_len, ip->name);
1091 optlen = ip->circuit_id_len + 2; /* RAI_CIRCUIT_ID + len */ 1091 optlen = ip->circuit_id_len + 2; /* RAI_CIRCUIT_ID + len */
1092 1092
1093 if (ip->remote_id) { 1093 if (ip->remote_id) {
1094 if (ip->remote_id_len > 255 || ip->remote_id_len < 1) 1094 if (ip->remote_id_len > 255 || ip->remote_id_len < 1)
1095 log_fatal("Remote ID length %d out of range [1-255] " 1095 log_fatal("Remote ID length %d out of range [1-255] "
1096 "on %s\n", ip->circuit_id_len, ip->name); 1096 "on %s\n", ip->circuit_id_len, ip->name);
1097 optlen += ip->remote_id_len + 2; /* RAI_REMOTE_ID + len */ 1097 optlen += ip->remote_id_len + 2; /* RAI_REMOTE_ID + len */
1098 } 1098 }
1099 1099
1100 /* We do not support relay option fragmenting(multiple options to 1100 /* We do not support relay option fragmenting(multiple options to
1101 * support an option data exceeding 255 bytes). 1101 * support an option data exceeding 255 bytes).
1102 */ 1102 */
1103 if ((optlen < 3) ||(optlen > 255)) 1103 if ((optlen < 3) ||(optlen > 255))
1104 log_fatal("Total agent option length(%u) out of range " 1104 log_fatal("Total agent option length(%u) out of range "
1105 "[3 - 255] on %s\n", optlen, ip->name); 1105 "[3 - 255] on %s\n", optlen, ip->name);
1106 1106
1107 /* 1107 /*
1108 * Is there room for the option, its code+len, and DHO_END? 1108 * Is there room for the option, its code+len, and DHO_END?
1109 * If not, forward without adding the option. 1109 * If not, forward without adding the option.
1110 */ 1110 */
1111 if (max - sp >= optlen + 3) { 1111 if (max - sp >= optlen + 3) {
1112 log_debug("Adding %d-byte relay agent option", optlen + 3); 1112 log_debug("Adding %d-byte relay agent option", optlen + 3);
1113 1113
1114 /* Okay, cons up *our* Relay Agent Information option. */ 1114 /* Okay, cons up *our* Relay Agent Information option. */
1115 *sp++ = DHO_DHCP_AGENT_OPTIONS; 1115 *sp++ = DHO_DHCP_AGENT_OPTIONS;
1116 *sp++ = optlen; 1116 *sp++ = optlen;
1117 1117
1118 /* Copy in the circuit id... */ 1118 /* Copy in the circuit id... */
1119 *sp++ = RAI_CIRCUIT_ID; 1119 *sp++ = RAI_CIRCUIT_ID;
1120 *sp++ = ip->circuit_id_len; 1120 *sp++ = ip->circuit_id_len;
1121 memcpy(sp, ip->circuit_id, ip->circuit_id_len); 1121 memcpy(sp, ip->circuit_id, ip->circuit_id_len);
1122 sp += ip->circuit_id_len; 1122 sp += ip->circuit_id_len;
1123 1123
1124 /* Copy in remote ID... */ 1124 /* Copy in remote ID... */
1125 if (ip->remote_id) { 1125 if (ip->remote_id) {
1126 *sp++ = RAI_REMOTE_ID; 1126 *sp++ = RAI_REMOTE_ID;
1127 *sp++ = ip->remote_id_len; 1127 *sp++ = ip->remote_id_len;
1128 memcpy(sp, ip->remote_id, ip->remote_id_len); 1128 memcpy(sp, ip->remote_id, ip->remote_id_len);
1129 sp += ip->remote_id_len; 1129 sp += ip->remote_id_len;
1130 } 1130 }
1131 } else { 1131 } else {
1132 ++agent_option_errors; 1132 ++agent_option_errors;
1133 log_error("No room in packet (used %d of %d) " 1133 log_error("No room in packet (used %d of %d) "
1134 "for %d-byte relay agent option: omitted", 1134 "for %d-byte relay agent option: omitted",
1135 (int) (sp - ((u_int8_t *) packet)), 1135 (int) (sp - ((u_int8_t *) packet)),
1136 (int) (max - ((u_int8_t *) packet)), 1136 (int) (max - ((u_int8_t *) packet)),
1137 optlen + 3); 1137 optlen + 3);
1138 } 1138 }
1139 1139
1140 /* 1140 /*
1141 * Deposit an END option unless the packet is full (shouldn't 1141 * Deposit an END option unless the packet is full (shouldn't
1142 * be possible). 1142 * be possible).
1143 */ 1143 */
1144 if (sp < max) 1144 if (sp < max)
1145 *sp++ = DHO_END; 1145 *sp++ = DHO_END;
1146 1146
1147 /* Recalculate total packet length. */ 1147 /* Recalculate total packet length. */
1148 length = sp -((u_int8_t *)packet); 1148 length = sp -((u_int8_t *)packet);
1149 1149
1150 /* Make sure the packet isn't short(this is unlikely, but WTH) */ 1150 /* Make sure the packet isn't short(this is unlikely, but WTH) */
1151 if (length < BOOTP_MIN_LEN) { 1151 if (length < BOOTP_MIN_LEN) {
1152 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length); 1152 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
1153 return (BOOTP_MIN_LEN); 1153 return (BOOTP_MIN_LEN);
1154 } 1154 }
1155 1155
1156 return (length); 1156 return (length);
1157} 1157}
1158 1158
1159#ifdef DHCPv6 1159#ifdef DHCPv6
1160/* 1160/*
1161 * Parse a downstream argument: [address%]interface[#index]. 1161 * Parse a downstream argument: [address%]interface[#index].
1162 */ 1162 */
1163static struct stream_list * 1163static struct stream_list *
1164parse_downstream(char *arg) { 1164parse_downstream(char *arg) {
1165 struct stream_list *dp, *up; 1165 struct stream_list *dp, *up;
1166 struct interface_info *ifp = NULL; 1166 struct interface_info *ifp = NULL;
1167 char *ifname, *addr, *iid; 1167 char *ifname, *addr, *iid;
1168 isc_result_t status; 1168 isc_result_t status;
1169 1169
1170 if (!supports_multiple_interfaces(ifp) && 1170 if (!supports_multiple_interfaces(ifp) &&
1171 (downstreams != NULL)) 1171 (downstreams != NULL))
1172 log_fatal("No support for multiple interfaces."); 1172 log_fatal("No support for multiple interfaces.");
1173 1173
1174 /* Decode the argument. */ 1174 /* Decode the argument. */
1175 ifname = strchr(arg, '%'); 1175 ifname = strchr(arg, '%');
1176 if (ifname == NULL) { 1176 if (ifname == NULL) {
1177 ifname = arg; 1177 ifname = arg;
1178 addr = NULL; 1178 addr = NULL;
1179 } else { 1179 } else {
1180 *ifname++ = '\0'; 1180 *ifname++ = '\0';
1181 addr = arg; 1181 addr = arg;
1182 } 1182 }
1183 iid = strchr(ifname, '#'); 1183 iid = strchr(ifname, '#');
1184 if (iid != NULL) { 1184 if (iid != NULL) {
1185 *iid++ = '\0'; 1185 *iid++ = '\0';
1186 } 1186 }
1187 if (strlen(ifname) >= sizeof(ifp->name)) { 1187 if (strlen(ifname) >= sizeof(ifp->name)) {
1188 log_error("Interface name '%s' too long", ifname); 1188 log_error("Interface name '%s' too long", ifname);
1189 usage(); 1189 usage();
1190 } 1190 }
1191 1191
1192 /* Don't declare twice. */ 1192 /* Don't declare twice. */
1193 for (dp = downstreams; dp; dp = dp->next) { 1193 for (dp = downstreams; dp; dp = dp->next) {
1194 if (strcmp(ifname, dp->ifp->name) == 0) 1194 if (strcmp(ifname, dp->ifp->name) == 0)
1195 log_fatal("Down interface '%s' declared twice.", 1195 log_fatal("Down interface '%s' declared twice.",
1196 ifname); 1196 ifname);
1197 } 1197 }
1198 1198
1199 /* Share with up side? */ 1199 /* Share with up side? */
1200 for (up = upstreams; up; up = up->next) { 1200 for (up = upstreams; up; up = up->next) {
1201 if (strcmp(ifname, up->ifp->name) == 0) { 1201 if (strcmp(ifname, up->ifp->name) == 0) {
1202 log_info("parse_downstream: Interface '%s' is " 1202 log_info("parse_downstream: Interface '%s' is "
1203 "both down and up.", ifname); 1203 "both down and up.", ifname);
1204 ifp = up->ifp; 1204 ifp = up->ifp;
1205 break; 1205 break;
1206 } 1206 }
1207 } 1207 }
1208 1208
1209 /* New interface. */ 1209 /* New interface. */
1210 if (ifp == NULL) { 1210 if (ifp == NULL) {
1211 status = interface_allocate(&ifp, MDL); 1211 status = interface_allocate(&ifp, MDL);
1212 if (status != ISC_R_SUCCESS) 1212 if (status != ISC_R_SUCCESS)
1213 log_fatal("%s: interface_allocate: %s", 1213 log_fatal("%s: interface_allocate: %s",
1214 arg, isc_result_totext(status)); 1214 arg, isc_result_totext(status));
1215 strcpy(ifp->name, ifname); 1215 strcpy(ifp->name, ifname);
1216 if (interfaces) { 1216 if (interfaces) {
1217 interface_reference(&ifp->next, interfaces, MDL); 1217 interface_reference(&ifp->next, interfaces, MDL);
1218 interface_dereference(&interfaces, MDL); 1218 interface_dereference(&interfaces, MDL);
1219 } 1219 }
1220 interface_reference(&interfaces, ifp, MDL); 1220 interface_reference(&interfaces, ifp, MDL);
1221 } 1221 }
1222 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM; 1222 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM;
1223 1223
1224 /* New downstream. */ 1224 /* New downstream. */
1225 dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL); 1225 dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL);
1226 if (!dp) 1226 if (!dp)
1227 log_fatal("No memory for downstream."); 1227 log_fatal("No memory for downstream.");
1228 dp->ifp = ifp; 1228 dp->ifp = ifp;
1229 if (iid != NULL) { 1229 if (iid != NULL) {
1230 dp->id = atoi(iid); 1230 dp->id = atoi(iid);
1231 } else { 1231 } else {
1232 dp->id = -1; 1232 dp->id = -1;
1233 } 1233 }
1234 /* !addr case handled by setup. */ 1234 /* !addr case handled by setup. */
1235 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0)) 1235 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
1236 log_fatal("Bad link address '%s'", addr); 1236 log_fatal("Bad link address '%s'", addr);
1237 1237
1238 return dp; 1238 return dp;
1239} 1239}
1240 1240
1241/* 1241/*
1242 * Parse an upstream argument: [address]%interface. 1242 * Parse an upstream argument: [address]%interface.
1243 */ 1243 */
1244static struct stream_list * 1244static struct stream_list *
1245parse_upstream(char *arg) { 1245parse_upstream(char *arg) {
1246 struct stream_list *up, *dp; 1246 struct stream_list *up, *dp;
1247 struct interface_info *ifp = NULL; 1247 struct interface_info *ifp = NULL;
1248 char *ifname, *addr; 1248 char *ifname, *addr;
1249 isc_result_t status; 1249 isc_result_t status;
1250 1250
1251 /* Decode the argument. */ 1251 /* Decode the argument. */
1252 ifname = strchr(arg, '%'); 1252 ifname = strchr(arg, '%');
1253 if (ifname == NULL) { 1253 if (ifname == NULL) {
1254 ifname = arg; 1254 ifname = arg;
1255 addr = All_DHCP_Servers; 1255 addr = All_DHCP_Servers;
1256 } else { 1256 } else {
1257 *ifname++ = '\0'; 1257 *ifname++ = '\0';
1258 addr = arg; 1258 addr = arg;
1259 } 1259 }
1260 if (strlen(ifname) >= sizeof(ifp->name)) { 1260 if (strlen(ifname) >= sizeof(ifp->name)) {
1261 log_fatal("Interface name '%s' too long", ifname); 1261 log_fatal("Interface name '%s' too long", ifname);
1262 } 1262 }
1263 1263
1264 /* Shared up interface? */ 1264 /* Shared up interface? */
1265 for (up = upstreams; up; up = up->next) { 1265 for (up = upstreams; up; up = up->next) {
1266 if (strcmp(ifname, up->ifp->name) == 0) { 1266 if (strcmp(ifname, up->ifp->name) == 0) {
1267 ifp = up->ifp; 1267 ifp = up->ifp;
1268 break; 1268 break;
1269 } 1269 }
1270 } 1270 }
1271 for (dp = downstreams; dp; dp = dp->next) { 1271 for (dp = downstreams; dp; dp = dp->next) {
1272 if (strcmp(ifname, dp->ifp->name) == 0) { 1272 if (strcmp(ifname, dp->ifp->name) == 0) {
1273 log_info("parse_upstream: Interface '%s' is " 1273 log_info("parse_upstream: Interface '%s' is "
1274 "both down and up.", ifname); 1274 "both down and up.", ifname);
1275 ifp = dp->ifp; 1275 ifp = dp->ifp;
1276 break; 1276 break;
1277 } 1277 }
1278 } 1278 }
1279 1279
1280 /* New interface. */ 1280 /* New interface. */
1281 if (ifp == NULL) { 1281 if (ifp == NULL) {
1282 status = interface_allocate(&ifp, MDL); 1282 status = interface_allocate(&ifp, MDL);
1283 if (status != ISC_R_SUCCESS) 1283 if (status != ISC_R_SUCCESS)
1284 log_fatal("%s: interface_allocate: %s", 1284 log_fatal("%s: interface_allocate: %s",
1285 arg, isc_result_totext(status)); 1285 arg, isc_result_totext(status));
1286 strcpy(ifp->name, ifname); 1286 strcpy(ifp->name, ifname);
1287 if (interfaces) { 1287 if (interfaces) {
1288 interface_reference(&ifp->next, interfaces, MDL); 1288 interface_reference(&ifp->next, interfaces, MDL);
1289 interface_dereference(&interfaces, MDL); 1289 interface_dereference(&interfaces, MDL);
1290 } 1290 }
1291 interface_reference(&interfaces, ifp, MDL); 1291 interface_reference(&interfaces, ifp, MDL);
1292 } 1292 }
1293 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM; 1293 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM;
1294 1294
1295 /* New upstream. */ 1295 /* New upstream. */
1296 up = (struct stream_list *) dmalloc(sizeof(*up), MDL); 1296 up = (struct stream_list *) dmalloc(sizeof(*up), MDL);
1297 if (up == NULL) 1297 if (up == NULL)
1298 log_fatal("No memory for upstream."); 1298 log_fatal("No memory for upstream.");
1299 1299
1300 up->ifp = ifp; 1300 up->ifp = ifp;
1301 1301
1302 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0) 1302 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
1303 log_fatal("Bad address %s", addr); 1303 log_fatal("Bad address %s", addr);
1304 1304
1305 return up; 1305 return up;
1306} 1306}
1307 1307
1308/* 1308/*
1309 * Setup downstream interfaces. 1309 * Setup downstream interfaces.
1310 */ 1310 */
1311static void 1311static void
1312setup_streams(void) { 1312setup_streams(void) {
1313 struct stream_list *dp, *up; 1313 struct stream_list *dp, *up;
1314 int i; 1314 int i;
1315 isc_boolean_t link_is_set; 1315 isc_boolean_t link_is_set;
1316 1316
1317 for (dp = downstreams; dp; dp = dp->next) { 1317 for (dp = downstreams; dp; dp = dp->next) {
1318 /* Check interface */ 1318 /* Check interface */
1319 if (dp->ifp->v6address_count == 0) 1319 if (dp->ifp->v6address_count == 0)
1320 log_fatal("Interface '%s' has no IPv6 addresses.", 1320 log_fatal("Interface '%s' has no IPv6 addresses.",
1321 dp->ifp->name); 1321 dp->ifp->name);
1322 1322
1323 /* Check/set link. */ 1323 /* Check/set link. */
1324 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr)) 1324 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
1325 link_is_set = ISC_FALSE; 1325 link_is_set = ISC_FALSE;
1326 else 1326 else
1327 link_is_set = ISC_TRUE; 1327 link_is_set = ISC_TRUE;
1328 for (i = 0; i < dp->ifp->v6address_count; i++) { 1328 for (i = 0; i < dp->ifp->v6address_count; i++) {
1329 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i])) 1329 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
1330 continue; 1330 continue;
1331 if (!link_is_set) 1331 if (!link_is_set)
1332 break; 1332 break;
1333 if (!memcmp(&dp->ifp->v6addresses[i], 1333 if (!memcmp(&dp->ifp->v6addresses[i],
1334 &dp->link.sin6_addr, 1334 &dp->link.sin6_addr,
1335 sizeof(dp->link.sin6_addr))) 1335 sizeof(dp->link.sin6_addr)))
1336 break; 1336 break;
1337 } 1337 }
1338 if (i == dp->ifp->v6address_count) 1338 if (i == dp->ifp->v6address_count)
1339 log_fatal("Interface %s does not have global IPv6 " 1339 log_fatal("Interface %s does not have global IPv6 "
1340 "address assigned.", dp->ifp->name); 1340 "address assigned.", dp->ifp->name);
1341 if (!link_is_set) 1341 if (!link_is_set)
1342 memcpy(&dp->link.sin6_addr, 1342 memcpy(&dp->link.sin6_addr,
1343 &dp->ifp->v6addresses[i], 1343 &dp->ifp->v6addresses[i],
1344 sizeof(dp->link.sin6_addr)); 1344 sizeof(dp->link.sin6_addr));
1345 1345
1346 /* Set interface-id. */ 1346 /* Set interface-id. */
1347 if (dp->id == -1) 1347 if (dp->id == -1)
1348 dp->id = dp->ifp->index; 1348 dp->id = dp->ifp->index;
1349 } 1349 }
1350 1350
1351 for (up = upstreams; up; up = up->next) { 1351 for (up = upstreams; up; up = up->next) {
1352 up->link.sin6_port = local_port; 1352 up->link.sin6_port = local_port;
1353 up->link.sin6_family = AF_INET6; 1353 up->link.sin6_family = AF_INET6;
1354#ifdef HAVE_SA_LEN 1354#ifdef HAVE_SA_LEN
1355 up->link.sin6_len = sizeof(up->link); 1355 up->link.sin6_len = sizeof(up->link);
1356#endif 1356#endif
1357 1357
1358 if (up->ifp->v6address_count == 0) 1358 if (up->ifp->v6address_count == 0)
1359 log_fatal("Interface '%s' has no IPv6 addresses.", 1359 log_fatal("Interface '%s' has no IPv6 addresses.",
1360 up->ifp->name); 1360 up->ifp->name);
1361 1361
1362 /* RFC 3315 Sec 20 - "If the relay agent relays messages to 1362 /* RFC 3315 Sec 20 - "If the relay agent relays messages to
1363 * the All_DHCP_Servers address or other multicast addresses, 1363 * the All_DHCP_Servers address or other multicast addresses,
1364 * it sets the Hop Limit field to 32." */ 1364 * it sets the Hop Limit field to 32." */
1365 if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) { 1365 if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) {
1366 set_multicast_hop_limit(up->ifp, HOP_COUNT_LIMIT); 1366 set_multicast_hop_limit(up->ifp, HOP_COUNT_LIMIT);
1367 } 1367 }
1368 } 1368 }
1369} 1369}
1370 1370
1371/* 1371/*
1372 * Add DHCPv6 agent options here. 1372 * Add DHCPv6 agent options here.
1373 */ 1373 */
1374static const int required_forw_opts[] = { 1374static const int required_forw_opts[] = {
1375 D6O_INTERFACE_ID, 1375 D6O_INTERFACE_ID,
1376 D6O_SUBSCRIBER_ID, 1376 D6O_SUBSCRIBER_ID,
1377 D6O_RELAY_MSG, 1377 D6O_RELAY_MSG,
1378 0 1378 0
1379}; 1379};
1380 1380
1381/* 1381/*
1382 * Process a packet upwards, i.e., from client to server. 1382 * Process a packet upwards, i.e., from client to server.
1383 */ 1383 */
1384static void 1384static void
1385process_up6(struct packet *packet, struct stream_list *dp) { 1385process_up6(struct packet *packet, struct stream_list *dp) {
1386 char forw_data[65535]; 1386 char forw_data[65535];
1387 unsigned cursor; 1387 unsigned cursor;
1388 struct dhcpv6_relay_packet *relay; 1388 struct dhcpv6_relay_packet *relay;
1389 struct option_state *opts; 1389 struct option_state *opts;
1390 struct stream_list *up; 1390 struct stream_list *up;
1391 1391
1392 /* Check if the message should be relayed to the server. */ 1392 /* Check if the message should be relayed to the server. */
1393 switch (packet->dhcpv6_msg_type) { 1393 switch (packet->dhcpv6_msg_type) {
1394 case DHCPV6_SOLICIT: 1394 case DHCPV6_SOLICIT:
1395 case DHCPV6_REQUEST: 1395 case DHCPV6_REQUEST:
1396 case DHCPV6_CONFIRM: 1396 case DHCPV6_CONFIRM:
1397 case DHCPV6_RENEW: 1397 case DHCPV6_RENEW:
1398 case DHCPV6_REBIND: 1398 case DHCPV6_REBIND:
1399 case DHCPV6_RELEASE: 1399 case DHCPV6_RELEASE:
1400 case DHCPV6_DECLINE: 1400 case DHCPV6_DECLINE:
1401 case DHCPV6_INFORMATION_REQUEST: 1401 case DHCPV6_INFORMATION_REQUEST:
1402 case DHCPV6_RELAY_FORW: 1402 case DHCPV6_RELAY_FORW:
1403 case DHCPV6_LEASEQUERY: 1403 case DHCPV6_LEASEQUERY:
1404 log_info("Relaying %s from %s port %d going up.", 1404 log_info("Relaying %s from %s port %d going up.",
1405 dhcpv6_type_names[packet->dhcpv6_msg_type], 1405 dhcpv6_type_names[packet->dhcpv6_msg_type],
1406 piaddr(packet->client_addr), 1406 piaddr(packet->client_addr),
1407 ntohs(packet->client_port)); 1407 ntohs(packet->client_port));
1408 break; 1408 break;
1409 1409
1410 case DHCPV6_ADVERTISE: 1410 case DHCPV6_ADVERTISE:
1411 case DHCPV6_REPLY: 1411 case DHCPV6_REPLY:
1412 case DHCPV6_RECONFIGURE: 1412 case DHCPV6_RECONFIGURE:
1413 case DHCPV6_RELAY_REPL: 1413 case DHCPV6_RELAY_REPL:
1414 case DHCPV6_LEASEQUERY_REPLY: 1414 case DHCPV6_LEASEQUERY_REPLY:
1415 log_info("Discarding %s from %s port %d going up.", 1415 log_info("Discarding %s from %s port %d going up.",
1416 dhcpv6_type_names[packet->dhcpv6_msg_type], 1416 dhcpv6_type_names[packet->dhcpv6_msg_type],
1417 piaddr(packet->client_addr), 1417 piaddr(packet->client_addr),
1418 ntohs(packet->client_port)); 1418 ntohs(packet->client_port));
1419 return; 1419 return;
1420 1420
1421 default: 1421 default:
1422 log_info("Unknown %d type from %s port %d going up.", 1422 log_info("Unknown %d type from %s port %d going up.",
1423 packet->dhcpv6_msg_type, 1423 packet->dhcpv6_msg_type,
1424 piaddr(packet->client_addr), 1424 piaddr(packet->client_addr),
1425 ntohs(packet->client_port)); 1425 ntohs(packet->client_port));
1426 return; 1426 return;
1427 } 1427 }
1428 1428
1429 /* Build the relay-forward header. */ 1429 /* Build the relay-forward header. */
1430 relay = (struct dhcpv6_relay_packet *) forw_data; 1430 relay = (struct dhcpv6_relay_packet *) forw_data;
1431 cursor = offsetof(struct dhcpv6_relay_packet, options); 1431 cursor = offsetof(struct dhcpv6_relay_packet, options);
1432 relay->msg_type = DHCPV6_RELAY_FORW; 1432 relay->msg_type = DHCPV6_RELAY_FORW;
1433 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) { 1433 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
1434 if (packet->dhcpv6_hop_count >= max_hop_count) { 1434 if (packet->dhcpv6_hop_count >= max_hop_count) {
1435 log_info("Hop count exceeded,"); 1435 log_info("Hop count exceeded,");
1436 return; 1436 return;
1437 } 1437 }
1438 relay->hop_count = packet->dhcpv6_hop_count + 1; 1438 relay->hop_count = packet->dhcpv6_hop_count + 1;
1439 if (dp) { 1439 if (dp) {
1440 memcpy(&relay->link_address, &dp->link.sin6_addr, 16); 1440 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1441 } else { 1441 } else {
1442 /* On smart relay add: && !global. */ 1442 /* On smart relay add: && !global. */
1443 if (!use_if_id && downstreams->next) { 1443 if (!use_if_id && downstreams->next) {
1444 log_info("Shan't get back the interface."); 1444 log_info("Shan't get back the interface.");
1445 return; 1445 return;
1446 } 1446 }
1447 memset(&relay->link_address, 0, 16); 1447 memset(&relay->link_address, 0, 16);
1448 } 1448 }
1449 } else { 1449 } else {
1450 relay->hop_count = 0; 1450 relay->hop_count = 0;
1451 if (!dp) 1451 if (!dp)
1452 return; 1452 return;
1453 memcpy(&relay->link_address, &dp->link.sin6_addr, 16); 1453 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1454 } 1454 }
1455 memcpy(&relay->peer_address, packet->client_addr.iabuf, 16); 1455 memcpy(&relay->peer_address, packet->client_addr.iabuf, 16);
1456 1456
1457 /* Get an option state. */ 1457 /* Get an option state. */
1458 opts = NULL; 1458 opts = NULL;
1459 if (!option_state_allocate(&opts, MDL)) { 1459 if (!option_state_allocate(&opts, MDL)) {
1460 log_fatal("No memory for upwards options."); 1460 log_fatal("No memory for upwards options.");
1461 } 1461 }
1462  1462
1463 /* Add an interface-id (if used). */ 1463 /* Add an interface-id (if used). */
1464 if (use_if_id) { 1464 if (use_if_id) {
1465 int if_id; 1465 int if_id;
1466 1466
1467 if (dp) { 1467 if (dp) {
1468 if_id = dp->id; 1468 if_id = dp->id;
1469 } else if (!downstreams->next) { 1469 } else if (!downstreams->next) {
1470 if_id = downstreams->id; 1470 if_id = downstreams->id;
1471 } else { 1471 } else {
1472 log_info("Don't know the interface."); 1472 log_info("Don't know the interface.");
1473 option_state_dereference(&opts, MDL); 1473 option_state_dereference(&opts, MDL);
1474 return; 1474 return;
1475 } 1475 }
1476 1476
1477 if (!save_option_buffer(&dhcpv6_universe, opts, 1477 if (!save_option_buffer(&dhcpv6_universe, opts,
1478 NULL, (unsigned char *) &if_id, 1478 NULL, (unsigned char *) &if_id,
1479 sizeof(int), 1479 sizeof(int),
1480 D6O_INTERFACE_ID, 0)) { 1480 D6O_INTERFACE_ID, 0)) {
1481 log_error("Can't save interface-id."); 1481 log_error("Can't save interface-id.");
1482 option_state_dereference(&opts, MDL); 1482 option_state_dereference(&opts, MDL);
1483 return; 1483 return;
1484 } 1484 }
1485 } 1485 }
1486 1486
1487 /* Add a subscriber-id if desired. */ 1487 /* Add a subscriber-id if desired. */
1488 /* This is for testing rather than general use */ 1488 /* This is for testing rather than general use */
1489 if (dhcrelay_sub_id != NULL) { 1489 if (dhcrelay_sub_id != NULL) {
1490 if (!save_option_buffer(&dhcpv6_universe, opts, NULL, 1490 if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
1491 (unsigned char *) dhcrelay_sub_id, 1491 (unsigned char *) dhcrelay_sub_id,
1492 strlen(dhcrelay_sub_id), 1492 strlen(dhcrelay_sub_id),
1493 D6O_SUBSCRIBER_ID, 0)) { 1493 D6O_SUBSCRIBER_ID, 0)) {
1494 log_error("Can't save subsriber-id."); 1494 log_error("Can't save subsriber-id.");
1495 option_state_dereference(&opts, MDL); 1495 option_state_dereference(&opts, MDL);
1496 return; 1496 return;
1497 } 1497 }
1498 } 1498 }
1499  1499
1500 1500
1501 /* Add the relay-msg carrying the packet. */ 1501 /* Add the relay-msg carrying the packet. */
1502 if (!save_option_buffer(&dhcpv6_universe, opts, 1502 if (!save_option_buffer(&dhcpv6_universe, opts,
1503 NULL, (unsigned char *) packet->raw, 1503 NULL, (unsigned char *) packet->raw,
1504 packet->packet_length, 1504 packet->packet_length,
1505 D6O_RELAY_MSG, 0)) { 1505 D6O_RELAY_MSG, 0)) {
1506 log_error("Can't save relay-msg."); 1506 log_error("Can't save relay-msg.");
1507 option_state_dereference(&opts, MDL); 1507 option_state_dereference(&opts, MDL);
1508 return; 1508 return;
1509 } 1509 }
1510 1510
1511 /* Finish the relay-forward message. */ 1511 /* Finish the relay-forward message. */
1512 cursor += store_options6(forw_data + cursor, 1512 cursor += store_options6(forw_data + cursor,
1513 sizeof(forw_data) - cursor, 1513 sizeof(forw_data) - cursor,
1514 opts, packet,  1514 opts, packet,
1515 required_forw_opts, NULL); 1515 required_forw_opts, NULL);
1516 option_state_dereference(&opts, MDL); 1516 option_state_dereference(&opts, MDL);
1517 1517
1518 /* Send it to all upstreams. */ 1518 /* Send it to all upstreams. */
1519 for (up = upstreams; up; up = up->next) { 1519 for (up = upstreams; up; up = up->next) {
1520 send_packet6(up->ifp, (unsigned char *) forw_data, 1520 send_packet6(up->ifp, (unsigned char *) forw_data,
1521 (size_t) cursor, &up->link); 1521 (size_t) cursor, &up->link);
1522 } 1522 }
1523} 1523}
1524  1524
1525/* 1525/*
1526 * Process a packet downwards, i.e., from server to client. 1526 * Process a packet downwards, i.e., from server to client.
1527 */ 1527 */
1528static void 1528static void
1529process_down6(struct packet *packet) { 1529process_down6(struct packet *packet) {
1530 struct stream_list *dp; 1530 struct stream_list *dp;
1531 struct option_cache *oc; 1531 struct option_cache *oc;
1532 struct data_string relay_msg; 1532 struct data_string relay_msg;
1533 const struct dhcpv6_packet *msg; 1533 const struct dhcpv6_packet *msg;
1534 struct data_string if_id; 1534 struct data_string if_id;
1535 struct sockaddr_in6 to; 1535 struct sockaddr_in6 to;
1536 struct iaddr peer; 1536 struct iaddr peer;
1537 1537
1538 /* The packet must be a relay-reply message. */ 1538 /* The packet must be a relay-reply message. */
1539 if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) { 1539 if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) {
1540 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max) 1540 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max)
1541 log_info("Discarding %s from %s port %d going down.", 1541 log_info("Discarding %s from %s port %d going down.",
1542 dhcpv6_type_names[packet->dhcpv6_msg_type], 1542 dhcpv6_type_names[packet->dhcpv6_msg_type],
1543 piaddr(packet->client_addr), 1543 piaddr(packet->client_addr),
1544 ntohs(packet->client_port)); 1544 ntohs(packet->client_port));
1545 else 1545 else
1546 log_info("Unknown %d type from %s port %d going down.", 1546 log_info("Unknown %d type from %s port %d going down.",
1547 packet->dhcpv6_msg_type, 1547 packet->dhcpv6_msg_type,
1548 piaddr(packet->client_addr), 1548 piaddr(packet->client_addr),
1549 ntohs(packet->client_port)); 1549 ntohs(packet->client_port));
1550 return; 1550 return;
1551 } 1551 }
1552 1552
1553 /* Inits. */ 1553 /* Inits. */
1554 memset(&relay_msg, 0, sizeof(relay_msg)); 1554 memset(&relay_msg, 0, sizeof(relay_msg));
1555 memset(&if_id, 0, sizeof(if_id)); 1555 memset(&if_id, 0, sizeof(if_id));
1556 memset(&to, 0, sizeof(to)); 1556 memset(&to, 0, sizeof(to));
1557 to.sin6_family = AF_INET6; 1557 to.sin6_family = AF_INET6;
1558#ifdef HAVE_SA_LEN 1558#ifdef HAVE_SA_LEN
1559 to.sin6_len = sizeof(to); 1559 to.sin6_len = sizeof(to);
1560#endif 1560#endif
1561 to.sin6_port = remote_port; 1561 to.sin6_port = remote_port;
1562 peer.len = 16; 1562 peer.len = 16;
1563 1563
1564 /* Get the relay-msg option (carrying the message to relay). */ 1564 /* Get the relay-msg option (carrying the message to relay). */
1565 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG); 1565 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
1566 if (oc == NULL) { 1566 if (oc == NULL) {
1567 log_info("No relay-msg."); 1567 log_info("No relay-msg.");
1568 return; 1568 return;
1569 } 1569 }
1570 if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL, 1570 if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL,
1571 packet->options, NULL, 1571 packet->options, NULL,
1572 &global_scope, oc, MDL) || 1572 &global_scope, oc, MDL) ||
1573 (relay_msg.len < offsetof(struct dhcpv6_packet, options))) { 1573 (relay_msg.len < offsetof(struct dhcpv6_packet, options))) {
1574 log_error("Can't evaluate relay-msg."); 1574 log_error("Can't evaluate relay-msg.");
1575 return; 1575 return;
1576 } 1576 }
1577 msg = (const struct dhcpv6_packet *) relay_msg.data; 1577 msg = (const struct dhcpv6_packet *) relay_msg.data;
1578 1578
1579 /* Get the interface-id (if exists) and the downstream. */ 1579 /* Get the interface-id (if exists) and the downstream. */
1580 oc = lookup_option(&dhcpv6_universe, packet->options, 1580 oc = lookup_option(&dhcpv6_universe, packet->options,
1581 D6O_INTERFACE_ID); 1581 D6O_INTERFACE_ID);
1582 if (oc != NULL) { 1582 if (oc != NULL) {
1583 int if_index; 1583 int if_index;
1584 1584
1585 if (!evaluate_option_cache(&if_id, packet, NULL, NULL, 1585 if (!evaluate_option_cache(&if_id, packet, NULL, NULL,
1586 packet->options, NULL, 1586 packet->options, NULL,
1587 &global_scope, oc, MDL) || 1587 &global_scope, oc, MDL) ||
1588 (if_id.len != sizeof(int))) { 1588 (if_id.len != sizeof(int))) {
1589 log_info("Can't evaluate interface-id."); 1589 log_info("Can't evaluate interface-id.");
1590 goto cleanup; 1590 goto cleanup;
1591 } 1591 }
1592 memcpy(&if_index, if_id.data, sizeof(int)); 1592 memcpy(&if_index, if_id.data, sizeof(int));
1593 for (dp = downstreams; dp; dp = dp->next) { 1593 for (dp = downstreams; dp; dp = dp->next) {
1594 if (dp->id == if_index) 1594 if (dp->id == if_index)
1595 break; 1595 break;
1596 } 1596 }
1597 } else { 1597 } else {
1598 if (use_if_id) { 1598 if (use_if_id) {
1599 /* Require an interface-id. */ 1599 /* Require an interface-id. */
1600 log_info("No interface-id."); 1600 log_info("No interface-id.");
1601 goto cleanup; 1601 goto cleanup;
1602 } 1602 }
1603 for (dp = downstreams; dp; dp = dp->next) { 1603 for (dp = downstreams; dp; dp = dp->next) {
1604 /* Get the first matching one. */ 1604 /* Get the first matching one. */
1605 if (!memcmp(&dp->link.sin6_addr, 1605 if (!memcmp(&dp->link.sin6_addr,
1606 &packet->dhcpv6_link_address, 1606 &packet->dhcpv6_link_address,
1607 sizeof(struct in6_addr))) 1607 sizeof(struct in6_addr)))
1608 break; 1608 break;
1609 } 1609 }
1610 } 1610 }
1611 /* Why bother when there is no choice. */ 1611 /* Why bother when there is no choice. */
1612 if (!dp && downstreams && !downstreams->next) 1612 if (!dp && downstreams && !downstreams->next)
1613 dp = downstreams; 1613 dp = downstreams;
1614 if (!dp) { 1614 if (!dp) {
1615 log_info("Can't find the down interface."); 1615 log_info("Can't find the down interface.");
1616 goto cleanup; 1616 goto cleanup;
1617 } 1617 }
1618 memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len); 1618 memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len);
1619 to.sin6_addr = packet->dhcpv6_peer_address; 1619 to.sin6_addr = packet->dhcpv6_peer_address;
1620 1620
1621 /* Check if we should relay the carried message. */ 1621 /* Check if we should relay the carried message. */
1622 switch (msg->msg_type) { 1622 switch (msg->msg_type) {
1623 /* Relay-Reply of for another relay, not a client. */ 1623 /* Relay-Reply of for another relay, not a client. */
1624 case DHCPV6_RELAY_REPL: 1624 case DHCPV6_RELAY_REPL:
1625 to.sin6_port = local_port; 1625 to.sin6_port = local_port;
1626 /* Fall into: */ 1626 /* Fall into: */
1627 1627
1628 case DHCPV6_ADVERTISE: 1628 case DHCPV6_ADVERTISE:
1629 case DHCPV6_REPLY: 1629 case DHCPV6_REPLY:
1630 case DHCPV6_RECONFIGURE: 1630 case DHCPV6_RECONFIGURE:
1631 case DHCPV6_RELAY_FORW: 1631 case DHCPV6_RELAY_FORW:
1632 case DHCPV6_LEASEQUERY_REPLY: 1632 case DHCPV6_LEASEQUERY_REPLY:
1633 log_info("Relaying %s to %s port %d down.", 1633 log_info("Relaying %s to %s port %d down.",
1634 dhcpv6_type_names[msg->msg_type], 1634 dhcpv6_type_names[msg->msg_type],
1635 piaddr(peer), 1635 piaddr(peer),
1636 ntohs(to.sin6_port)); 1636 ntohs(to.sin6_port));
1637 break; 1637 break;
1638 1638
1639 case DHCPV6_SOLICIT: 1639 case DHCPV6_SOLICIT:
1640 case DHCPV6_REQUEST: 1640 case DHCPV6_REQUEST:
1641 case DHCPV6_CONFIRM: 1641 case DHCPV6_CONFIRM:
1642 case DHCPV6_RENEW: 1642 case DHCPV6_RENEW:
1643 case DHCPV6_REBIND: 1643 case DHCPV6_REBIND:
1644 case DHCPV6_RELEASE: 1644 case DHCPV6_RELEASE:
1645 case DHCPV6_DECLINE: 1645 case DHCPV6_DECLINE:
1646 case DHCPV6_INFORMATION_REQUEST: 1646 case DHCPV6_INFORMATION_REQUEST:
1647 case DHCPV6_LEASEQUERY: 1647 case DHCPV6_LEASEQUERY:
1648 log_info("Discarding %s to %s port %d down.", 1648 log_info("Discarding %s to %s port %d down.",
1649 dhcpv6_type_names[msg->msg_type], 1649 dhcpv6_type_names[msg->msg_type],
1650 piaddr(peer), 1650 piaddr(peer),
1651 ntohs(to.sin6_port)); 1651 ntohs(to.sin6_port));
1652 goto cleanup; 1652 goto cleanup;
1653 1653
1654 default: 1654 default:
1655 log_info("Unknown %d type to %s port %d down.", 1655 log_info("Unknown %d type to %s port %d down.",
1656 msg->msg_type, 1656 msg->msg_type,
1657 piaddr(peer), 1657 piaddr(peer),
1658 ntohs(to.sin6_port)); 1658 ntohs(to.sin6_port));
1659 goto cleanup; 1659 goto cleanup;
1660 } 1660 }
1661 1661
1662 /* Send the message to the downstream. */ 1662 /* Send the message to the downstream. */
1663 send_packet6(dp->ifp, (unsigned char *) relay_msg.data, 1663 send_packet6(dp->ifp, (unsigned char *) relay_msg.data,
1664 (size_t) relay_msg.len, &to); 1664 (size_t) relay_msg.len, &to);
1665 1665
1666 cleanup: 1666 cleanup:
1667 if (relay_msg.data != NULL) 1667 if (relay_msg.data != NULL)
1668 data_string_forget(&relay_msg, MDL); 1668 data_string_forget(&relay_msg, MDL);
1669 if (if_id.data != NULL) 1669 if (if_id.data != NULL)
1670 data_string_forget(&if_id, MDL); 1670 data_string_forget(&if_id, MDL);
1671} 1671}
1672 1672
1673/* 1673/*
1674 * Called by the dispatch packet handler with a decoded packet. 1674 * Called by the dispatch packet handler with a decoded packet.
1675 */ 1675 */
1676void 1676void
1677dhcpv6(struct packet *packet) { 1677dhcpv6(struct packet *packet) {
1678 struct stream_list *dp; 1678 struct stream_list *dp;
1679 1679
1680 /* Try all relay-replies downwards. */ 1680 /* Try all relay-replies downwards. */
1681 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) { 1681 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) {
1682 process_down6(packet); 1682 process_down6(packet);
1683 return; 1683 return;
1684 } 1684 }
1685 /* Others are candidates to go up if they come from down. */ 1685 /* Others are candidates to go up if they come from down. */
1686 for (dp = downstreams; dp; dp = dp->next) { 1686 for (dp = downstreams; dp; dp = dp->next) {
1687 if (packet->interface != dp->ifp) 1687 if (packet->interface != dp->ifp)
1688 continue; 1688 continue;
1689 process_up6(packet, dp); 1689 process_up6(packet, dp);
1690 return; 1690 return;
1691 } 1691 }
1692 /* Relay-forward could work from an unknown interface. */ 1692 /* Relay-forward could work from an unknown interface. */
1693 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) { 1693 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
1694 process_up6(packet, NULL); 1694 process_up6(packet, NULL);
1695 return; 1695 return;
1696 } 1696 }
1697 1697
1698 log_info("Can't process packet from interface '%s'.", 1698 log_info("Can't process packet from interface '%s'.",
1699 packet->interface->name); 1699 packet->interface->name);
1700} 1700}
1701#endif 1701#endif
1702 1702
1703/* Stub routines needed for linking with DHCP libraries. */ 1703/* Stub routines needed for linking with DHCP libraries. */
1704void 1704void
1705bootp(struct packet *packet) { 1705bootp(struct packet *packet) {
1706 return; 1706 return;
1707} 1707}
1708 1708
1709void 1709void
1710dhcp(struct packet *packet) { 1710dhcp(struct packet *packet) {
1711 return; 1711 return;
1712} 1712}
1713 1713
1714void 1714void
1715classify(struct packet *p, struct class *c) { 1715classify(struct packet *p, struct class *c) {
1716 return; 1716 return;
1717} 1717}
1718 1718
1719int 1719int
1720check_collection(struct packet *p, struct lease *l, struct collection *c) { 1720check_collection(struct packet *p, struct lease *l, struct collection *c) {
1721 return 0; 1721 return 0;
1722} 1722}
1723 1723
1724isc_result_t 1724isc_result_t
1725find_class(struct class **class, const char *c1, const char *c2, int i) { 1725find_class(struct class **class, const char *c1, const char *c2, int i) {
1726 return ISC_R_NOTFOUND; 1726 return ISC_R_NOTFOUND;
1727} 1727}
1728 1728
1729int 1729int
1730parse_allow_deny(struct option_cache **oc, struct parse *p, int i) { 1730parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
1731 return 0; 1731 return 0;
1732} 1732}
1733 1733
1734isc_result_t 1734isc_result_t
1735dhcp_set_control_state(control_object_state_t oldstate, 1735dhcp_set_control_state(control_object_state_t oldstate,
1736 control_object_state_t newstate) { 1736 control_object_state_t newstate) {
1737 if (newstate != server_shutdown) 1737 if (newstate != server_shutdown)
1738 return ISC_R_SUCCESS; 1738 return ISC_R_SUCCESS;
1739 1739
1740 if (no_pid_file == ISC_FALSE) 1740 if (no_pid_file == ISC_FALSE)
1741 (void) unlink(path_dhcrelay_pid); 1741 (void) unlink(path_dhcrelay_pid);
1742 1742
1743 exit(0); 1743 exit(0);
1744} 1744}