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