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