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