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