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