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