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