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