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