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