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