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