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