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