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