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