dhcrelay.c revision 1.5
1/*	$NetBSD: dhcrelay.c,v 1.5 2021/05/26 22:52:32 christos Exp $	*/
2
3/* dhcrelay.c
4
5   DHCP/BOOTP Relay Agent. */
6
7/*
8 * Copyright(c) 2004-2021 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.5 2021/05/26 22:52:32 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-2021 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.5 2021/05/26 22:52:32 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#ifndef UNIT_TEST
1469
1470#ifdef DHCPv6
1471/*
1472 * Parse a downstream argument: [address%]interface[#index].
1473 */
1474static struct stream_list *
1475parse_downstream(char *arg) {
1476	struct stream_list *dp, *up;
1477	struct interface_info *ifp = NULL;
1478	char *ifname, *addr, *iid;
1479	isc_result_t status;
1480
1481	if (!supports_multiple_interfaces(ifp) &&
1482	    (downstreams != NULL))
1483		log_fatal("No support for multiple interfaces.");
1484
1485	/* Decode the argument. */
1486	ifname = strchr(arg, '%');
1487	if (ifname == NULL) {
1488		ifname = arg;
1489		addr = NULL;
1490	} else {
1491		*ifname++ = '\0';
1492		addr = arg;
1493	}
1494	iid = strchr(ifname, '#');
1495	if (iid != NULL) {
1496		*iid++ = '\0';
1497	}
1498	if (strlen(ifname) >= sizeof(ifp->name)) {
1499		usage("Interface name '%s' too long", ifname);
1500	}
1501
1502	/* Don't declare twice. */
1503	for (dp = downstreams; dp; dp = dp->next) {
1504		if (strcmp(ifname, dp->ifp->name) == 0)
1505			log_fatal("Down interface '%s' declared twice.",
1506				  ifname);
1507	}
1508
1509	/* Share with up side? */
1510	for (up = upstreams; up; up = up->next) {
1511		if (strcmp(ifname, up->ifp->name) == 0) {
1512			log_info("parse_downstream: Interface '%s' is "
1513				 "both down and up.", ifname);
1514			ifp = up->ifp;
1515			break;
1516		}
1517	}
1518
1519	/* New interface. */
1520	if (ifp == NULL) {
1521		status = interface_allocate(&ifp, MDL);
1522		if (status != ISC_R_SUCCESS)
1523			log_fatal("%s: interface_allocate: %s",
1524				  arg, isc_result_totext(status));
1525		strcpy(ifp->name, ifname);
1526		if (interfaces) {
1527			interface_reference(&ifp->next, interfaces, MDL);
1528			interface_dereference(&interfaces, MDL);
1529		}
1530		interface_reference(&interfaces, ifp, MDL);
1531	}
1532	ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM;
1533
1534	/* New downstream. */
1535	dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL);
1536	if (!dp)
1537		log_fatal("No memory for downstream.");
1538	dp->ifp = ifp;
1539	if (iid != NULL) {
1540		dp->id = atoi(iid);
1541	} else {
1542		dp->id = -1;
1543	}
1544	/* !addr case handled by setup. */
1545	if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
1546		log_fatal("Bad link address '%s'", addr);
1547
1548	return dp;
1549}
1550
1551/*
1552 * Parse an upstream argument: [address]%interface.
1553 */
1554static struct stream_list *
1555parse_upstream(char *arg) {
1556	struct stream_list *up, *dp;
1557	struct interface_info *ifp = NULL;
1558	char *ifname, *addr;
1559	isc_result_t status;
1560
1561	/* Decode the argument. */
1562	ifname = strchr(arg, '%');
1563	if (ifname == NULL) {
1564		ifname = arg;
1565		addr = All_DHCP_Servers;
1566	} else {
1567		*ifname++ = '\0';
1568		addr = arg;
1569	}
1570	if (strlen(ifname) >= sizeof(ifp->name)) {
1571		log_fatal("Interface name '%s' too long", ifname);
1572	}
1573
1574	/* Shared up interface? */
1575	for (up = upstreams; up; up = up->next) {
1576		if (strcmp(ifname, up->ifp->name) == 0) {
1577			ifp = up->ifp;
1578			break;
1579		}
1580	}
1581	for (dp = downstreams; dp; dp = dp->next) {
1582		if (strcmp(ifname, dp->ifp->name) == 0) {
1583			log_info("parse_upstream: Interface '%s' is "
1584				 "both down and up.", ifname);
1585			ifp = dp->ifp;
1586			break;
1587		}
1588	}
1589
1590	/* New interface. */
1591	if (ifp == NULL) {
1592		status = interface_allocate(&ifp, MDL);
1593		if (status != ISC_R_SUCCESS)
1594			log_fatal("%s: interface_allocate: %s",
1595				  arg, isc_result_totext(status));
1596		strcpy(ifp->name, ifname);
1597		if (interfaces) {
1598			interface_reference(&ifp->next, interfaces, MDL);
1599			interface_dereference(&interfaces, MDL);
1600		}
1601		interface_reference(&interfaces, ifp, MDL);
1602	}
1603	ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM;
1604
1605	/* New upstream. */
1606	up = (struct stream_list *) dmalloc(sizeof(*up), MDL);
1607	if (up == NULL)
1608		log_fatal("No memory for upstream.");
1609
1610	up->ifp = ifp;
1611
1612	if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
1613		log_fatal("Bad address %s", addr);
1614
1615	return up;
1616}
1617
1618/*
1619 * Setup downstream interfaces.
1620 */
1621static void
1622setup_streams(void) {
1623	struct stream_list *dp, *up;
1624	int i;
1625	isc_boolean_t link_is_set;
1626
1627	for (dp = downstreams; dp; dp = dp->next) {
1628		/* Check interface */
1629		if (dp->ifp->v6address_count == 0)
1630			log_fatal("Interface '%s' has no IPv6 addresses.",
1631				  dp->ifp->name);
1632
1633		/* Check/set link. */
1634		if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
1635			link_is_set = ISC_FALSE;
1636		else
1637			link_is_set = ISC_TRUE;
1638		for (i = 0; i < dp->ifp->v6address_count; i++) {
1639			if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
1640				continue;
1641			if (!link_is_set)
1642				break;
1643			if (!memcmp(&dp->ifp->v6addresses[i],
1644				    &dp->link.sin6_addr,
1645				    sizeof(dp->link.sin6_addr)))
1646				break;
1647		}
1648		if (i == dp->ifp->v6address_count)
1649			log_fatal("Interface %s does not have global IPv6 "
1650				  "address assigned.", dp->ifp->name);
1651		if (!link_is_set)
1652			memcpy(&dp->link.sin6_addr,
1653			       &dp->ifp->v6addresses[i],
1654			       sizeof(dp->link.sin6_addr));
1655
1656		/* Set interface-id. */
1657		if (dp->id == -1)
1658			dp->id = dp->ifp->index;
1659	}
1660
1661	for (up = upstreams; up; up = up->next) {
1662		up->link.sin6_port = local_port;
1663		up->link.sin6_family = AF_INET6;
1664#ifdef HAVE_SA_LEN
1665		up->link.sin6_len = sizeof(up->link);
1666#endif
1667
1668		if (up->ifp->v6address_count == 0)
1669			log_fatal("Interface '%s' has no IPv6 addresses.",
1670				  up->ifp->name);
1671
1672		/* RFC 3315 Sec 20 - "If the relay agent relays messages to
1673		 * the All_DHCP_Servers address or other multicast addresses,
1674		 * it sets the Hop Limit field to 32." */
1675		if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) {
1676			set_multicast_hop_limit(up->ifp, HOP_COUNT_LIMIT);
1677		}
1678	}
1679}
1680
1681/*
1682 * Add DHCPv6 agent options here.
1683 */
1684static const int required_forw_opts[] = {
1685	D6O_INTERFACE_ID,
1686	D6O_SUBSCRIBER_ID,
1687#if defined(RELAY_PORT)
1688	D6O_RELAY_SOURCE_PORT,
1689#endif
1690	D6O_RELAY_MSG,
1691	0
1692};
1693
1694/*
1695 * Process a packet upwards, i.e., from client to server.
1696 */
1697static void
1698process_up6(struct packet *packet, struct stream_list *dp) {
1699	char forw_data[65535];
1700	unsigned cursor;
1701	struct dhcpv6_relay_packet *relay;
1702	struct option_state *opts;
1703	struct stream_list *up;
1704	u_int16_t relay_client_port = 0;
1705
1706	/* Check if the message should be relayed to the server. */
1707	switch (packet->dhcpv6_msg_type) {
1708	      case DHCPV6_SOLICIT:
1709	      case DHCPV6_REQUEST:
1710	      case DHCPV6_CONFIRM:
1711	      case DHCPV6_RENEW:
1712	      case DHCPV6_REBIND:
1713	      case DHCPV6_RELEASE:
1714	      case DHCPV6_DECLINE:
1715	      case DHCPV6_INFORMATION_REQUEST:
1716	      case DHCPV6_RELAY_FORW:
1717	      case DHCPV6_LEASEQUERY:
1718	      case DHCPV6_DHCPV4_QUERY:
1719		log_info("Relaying %s from %s port %d going up.",
1720			 dhcpv6_type_names[packet->dhcpv6_msg_type],
1721			 piaddr(packet->client_addr),
1722			 ntohs(packet->client_port));
1723		break;
1724
1725	      case DHCPV6_ADVERTISE:
1726	      case DHCPV6_REPLY:
1727	      case DHCPV6_RECONFIGURE:
1728	      case DHCPV6_RELAY_REPL:
1729	      case DHCPV6_LEASEQUERY_REPLY:
1730	      case DHCPV6_DHCPV4_RESPONSE:
1731		log_info("Discarding %s from %s port %d going up.",
1732			 dhcpv6_type_names[packet->dhcpv6_msg_type],
1733			 piaddr(packet->client_addr),
1734			 ntohs(packet->client_port));
1735		return;
1736
1737	      default:
1738		log_info("Unknown %d type from %s port %d going up.",
1739			 packet->dhcpv6_msg_type,
1740			 piaddr(packet->client_addr),
1741			 ntohs(packet->client_port));
1742		return;
1743	}
1744
1745	/* Build the relay-forward header. */
1746	relay = (struct dhcpv6_relay_packet *) forw_data;
1747	cursor = offsetof(struct dhcpv6_relay_packet, options);
1748	relay->msg_type = DHCPV6_RELAY_FORW;
1749	if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
1750		if (packet->dhcpv6_hop_count >= max_hop_count) {
1751			log_info("Hop count exceeded,");
1752			return;
1753		}
1754		relay->hop_count = packet->dhcpv6_hop_count + 1;
1755		if (dp) {
1756			memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1757		} else {
1758			/* On smart relay add: && !global. */
1759			if (!use_if_id && downstreams->next) {
1760				log_info("Shan't get back the interface.");
1761				return;
1762			}
1763			memset(&relay->link_address, 0, 16);
1764		}
1765
1766		if (packet->client_port != htons(547)) {
1767			relay_client_port = packet->client_port;
1768		}
1769	} else {
1770		relay->hop_count = 0;
1771		if (!dp)
1772			return;
1773		memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1774	}
1775	memcpy(&relay->peer_address, packet->client_addr.iabuf, 16);
1776
1777	/* Get an option state. */
1778	opts = NULL;
1779	if (!option_state_allocate(&opts, MDL)) {
1780		log_fatal("No memory for upwards options.");
1781	}
1782
1783	/* Add an interface-id (if used). */
1784	if (use_if_id) {
1785		int if_id;
1786
1787		if (dp) {
1788			if_id = dp->id;
1789		} else if (!downstreams->next) {
1790			if_id = downstreams->id;
1791		} else {
1792			log_info("Don't know the interface.");
1793			option_state_dereference(&opts, MDL);
1794			return;
1795		}
1796
1797		if (!save_option_buffer(&dhcpv6_universe, opts,
1798					NULL, (unsigned char *) &if_id,
1799					sizeof(int),
1800					D6O_INTERFACE_ID, 0)) {
1801			log_error("Can't save interface-id.");
1802			option_state_dereference(&opts, MDL);
1803			return;
1804		}
1805	}
1806
1807	/* Add a subscriber-id if desired. */
1808	/* This is for testing rather than general use */
1809	if (dhcrelay_sub_id != NULL) {
1810		if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
1811					(unsigned char *) dhcrelay_sub_id,
1812					strlen(dhcrelay_sub_id),
1813					D6O_SUBSCRIBER_ID, 0)) {
1814			log_error("Can't save subsriber-id.");
1815			option_state_dereference(&opts, MDL);
1816			return;
1817		}
1818	}
1819
1820
1821#if defined(RELAY_PORT)
1822	/*
1823	 * If we use a non-547 UDP source port or if we have received
1824	 * from a downstream relay agent uses a non-547 port, we need
1825	 * to include the RELAY-SOURCE-PORT option. The "Downstream
1826	 * UDP Port" field value in the option allow us to send
1827	 * relay-reply message back to the downstream relay agent
1828	 * with the correct UDP source port.
1829        */
1830	if (relay_port || relay_client_port) {
1831		if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
1832					(unsigned char *) &relay_client_port,
1833					sizeof(u_int16_t),
1834					D6O_RELAY_SOURCE_PORT, 0)) {
1835			log_error("Can't save relay-source-port.");
1836			option_state_dereference(&opts, MDL);
1837			return;
1838		}
1839	}
1840#else
1841	/* Avoid unused but set warning, */
1842	(void)(relay_client_port);
1843#endif
1844
1845	/* Add the relay-msg carrying the packet. */
1846	if (!save_option_buffer(&dhcpv6_universe, opts,
1847				NULL, (unsigned char *) packet->raw,
1848				packet->packet_length,
1849				D6O_RELAY_MSG, 0)) {
1850		log_error("Can't save relay-msg.");
1851		option_state_dereference(&opts, MDL);
1852		return;
1853	}
1854
1855	/* Finish the relay-forward message. */
1856	cursor += store_options6(forw_data + cursor,
1857				 sizeof(forw_data) - cursor,
1858				 opts, packet,
1859				 required_forw_opts, NULL);
1860	option_state_dereference(&opts, MDL);
1861
1862	/* Send it to all upstreams. */
1863	for (up = upstreams; up; up = up->next) {
1864		send_packet6(up->ifp, (unsigned char *) forw_data,
1865			     (size_t) cursor, &up->link);
1866	}
1867}
1868
1869/*
1870 * Process a packet downwards, i.e., from server to client.
1871 */
1872static void
1873process_down6(struct packet *packet) {
1874	struct stream_list *dp;
1875	struct option_cache *oc;
1876	struct data_string relay_msg;
1877	const struct dhcpv6_packet *msg;
1878	struct data_string if_id;
1879#if defined(RELAY_PORT)
1880	struct data_string down_port;
1881#endif
1882	struct sockaddr_in6 to;
1883	struct iaddr peer;
1884
1885	/* The packet must be a relay-reply message. */
1886	if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) {
1887		if (packet->dhcpv6_msg_type < dhcpv6_type_name_max)
1888			log_info("Discarding %s from %s port %d going down.",
1889				 dhcpv6_type_names[packet->dhcpv6_msg_type],
1890				 piaddr(packet->client_addr),
1891				 ntohs(packet->client_port));
1892		else
1893			log_info("Unknown %d type from %s port %d going down.",
1894				 packet->dhcpv6_msg_type,
1895				 piaddr(packet->client_addr),
1896				 ntohs(packet->client_port));
1897		return;
1898	}
1899
1900	/* Inits. */
1901	memset(&relay_msg, 0, sizeof(relay_msg));
1902	memset(&if_id, 0, sizeof(if_id));
1903#if defined(RELAY_PORT)
1904	memset(&down_port, 0, sizeof(down_port));
1905#endif
1906	memset(&to, 0, sizeof(to));
1907	to.sin6_family = AF_INET6;
1908#ifdef HAVE_SA_LEN
1909	to.sin6_len = sizeof(to);
1910#endif
1911	to.sin6_port = remote_port;
1912	peer.len = 16;
1913
1914	/* Get the relay-msg option (carrying the message to relay). */
1915	oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
1916	if (oc == NULL) {
1917		log_info("No relay-msg.");
1918		return;
1919	}
1920	if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL,
1921				   packet->options, NULL,
1922				   &global_scope, oc, MDL) ||
1923	    (relay_msg.len < offsetof(struct dhcpv6_packet, options))) {
1924		log_error("Can't evaluate relay-msg.");
1925		goto cleanup;
1926	}
1927	msg = (const struct dhcpv6_packet *) relay_msg.data;
1928
1929	/* Get the interface-id (if exists) and the downstream. */
1930	oc = lookup_option(&dhcpv6_universe, packet->options,
1931			   D6O_INTERFACE_ID);
1932	if (oc != NULL) {
1933		int if_index;
1934
1935		if (!evaluate_option_cache(&if_id, packet, NULL, NULL,
1936					   packet->options, NULL,
1937					   &global_scope, oc, MDL) ||
1938		    (if_id.len != sizeof(int))) {
1939			log_info("Can't evaluate interface-id.");
1940			goto cleanup;
1941		}
1942		memcpy(&if_index, if_id.data, sizeof(int));
1943		for (dp = downstreams; dp; dp = dp->next) {
1944			if (dp->id == if_index)
1945				break;
1946		}
1947	} else {
1948		if (use_if_id) {
1949			/* Require an interface-id. */
1950			log_info("No interface-id.");
1951			goto cleanup;
1952		}
1953		for (dp = downstreams; dp; dp = dp->next) {
1954			/* Get the first matching one. */
1955			if (!memcmp(&dp->link.sin6_addr,
1956				    &packet->dhcpv6_link_address,
1957				    sizeof(struct in6_addr)))
1958				break;
1959		}
1960	}
1961	/* Why bother when there is no choice. */
1962	if (!dp && downstreams && !downstreams->next)
1963		dp = downstreams;
1964	if (!dp) {
1965		log_info("Can't find the down interface.");
1966		goto cleanup;
1967	}
1968	memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len);
1969	to.sin6_addr = packet->dhcpv6_peer_address;
1970
1971	/* Check if we should relay the carried message. */
1972	switch (msg->msg_type) {
1973		/* Relay-Reply of for another relay, not a client. */
1974	      case DHCPV6_RELAY_REPL:
1975		to.sin6_port = local_port;
1976
1977#if defined(RELAY_PORT)
1978		oc = lookup_option(&dhcpv6_universe, packet->options,
1979				   D6O_RELAY_SOURCE_PORT);
1980		if (oc != NULL) {
1981			u_int16_t down_relay_port;
1982
1983			memset(&down_port, 0, sizeof(down_port));
1984			if (!evaluate_option_cache(&down_port, packet, NULL,
1985						   NULL, packet->options, NULL,
1986						   &global_scope, oc, MDL) ||
1987			    (down_port.len != sizeof(u_int16_t))) {
1988				log_info("Can't evaluate down "
1989					 "relay-source-port.");
1990				goto cleanup;
1991			}
1992			memcpy(&down_relay_port, down_port.data,
1993			       sizeof(u_int16_t));
1994			/*
1995			 * If the down_relay_port value is non-zero,
1996			 * that means our downstream relay agent uses
1997			 * a non-547 UDP source port sending
1998			 * relay-forw message to us. We need to use
1999			 * the same UDP port sending reply back.
2000			 */
2001			if (down_relay_port) {
2002				to.sin6_port = down_relay_port;
2003			}
2004		}
2005#endif
2006
2007		/* Fall into: */
2008
2009	      case DHCPV6_ADVERTISE:
2010	      case DHCPV6_REPLY:
2011	      case DHCPV6_RECONFIGURE:
2012	      case DHCPV6_RELAY_FORW:
2013	      case DHCPV6_LEASEQUERY_REPLY:
2014	      case DHCPV6_DHCPV4_RESPONSE:
2015		log_info("Relaying %s to %s port %d down.",
2016			 dhcpv6_type_names[msg->msg_type],
2017			 piaddr(peer),
2018			 ntohs(to.sin6_port));
2019		break;
2020
2021	      case DHCPV6_SOLICIT:
2022	      case DHCPV6_REQUEST:
2023	      case DHCPV6_CONFIRM:
2024	      case DHCPV6_RENEW:
2025	      case DHCPV6_REBIND:
2026	      case DHCPV6_RELEASE:
2027	      case DHCPV6_DECLINE:
2028	      case DHCPV6_INFORMATION_REQUEST:
2029	      case DHCPV6_LEASEQUERY:
2030	      case DHCPV6_DHCPV4_QUERY:
2031		log_info("Discarding %s to %s port %d down.",
2032			 dhcpv6_type_names[msg->msg_type],
2033			 piaddr(peer),
2034			 ntohs(to.sin6_port));
2035		goto cleanup;
2036
2037	      default:
2038		log_info("Unknown %d type to %s port %d down.",
2039			 msg->msg_type,
2040			 piaddr(peer),
2041			 ntohs(to.sin6_port));
2042		goto cleanup;
2043	}
2044
2045	/* Send the message to the downstream. */
2046	send_packet6(dp->ifp, (unsigned char *) relay_msg.data,
2047		     (size_t) relay_msg.len, &to);
2048
2049      cleanup:
2050	if (relay_msg.data != NULL)
2051		data_string_forget(&relay_msg, MDL);
2052	if (if_id.data != NULL)
2053		data_string_forget(&if_id, MDL);
2054}
2055
2056/*
2057 * Called by the dispatch packet handler with a decoded packet.
2058 */
2059void
2060dhcpv6(struct packet *packet) {
2061	struct stream_list *dp;
2062
2063	/* Try all relay-replies downwards. */
2064	if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) {
2065		process_down6(packet);
2066		return;
2067	}
2068	/* Others are candidates to go up if they come from down. */
2069	for (dp = downstreams; dp; dp = dp->next) {
2070		if (packet->interface != dp->ifp)
2071			continue;
2072		process_up6(packet, dp);
2073		return;
2074	}
2075	/* Relay-forward could work from an unknown interface. */
2076	if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
2077		process_up6(packet, NULL);
2078		return;
2079	}
2080
2081	log_info("Can't process packet from interface '%s'.",
2082		 packet->interface->name);
2083}
2084#endif
2085
2086/* Stub routines needed for linking with DHCP libraries. */
2087void
2088bootp(struct packet *packet) {
2089	return;
2090}
2091
2092void
2093dhcp(struct packet *packet) {
2094	return;
2095}
2096
2097#if defined(DHCPv6) && defined(DHCP4o6)
2098isc_result_t dhcpv4o6_handler(omapi_object_t *h)
2099{
2100	return ISC_R_NOTIMPLEMENTED;
2101}
2102#endif
2103
2104void
2105classify(struct packet *p, struct class *c) {
2106	return;
2107}
2108
2109int
2110check_collection(struct packet *p, struct lease *l, struct collection *c) {
2111	return 0;
2112}
2113
2114isc_result_t
2115find_class(struct class **class, const char *c1, const char *c2, int i) {
2116	return ISC_R_NOTFOUND;
2117}
2118
2119int
2120parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
2121	return 0;
2122}
2123
2124isc_result_t
2125dhcp_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 */
2159void 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#endif /* UNIT_TEST */
2183