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