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