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