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