00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include "dhcpd.h"
00030 #include <syslog.h>
00031 #include <signal.h>
00032 #include <sys/time.h>
00033
00034 #ifdef HAVE_LIBCAP_NG
00035 # include <cap-ng.h>
00036 int keep_capabilities = 0;
00037 #endif
00038
00039 TIME default_lease_time = 43200;
00040 TIME max_lease_time = 86400;
00041 struct tree_cache *global_options[256];
00042
00043 struct option *requested_opts[2];
00044
00045
00046 int lexline;
00047 int lexchar;
00048 char *token_line;
00049 char *tlname;
00050
00051 const char *path_dhcrelay_pid = _PATH_DHCRELAY_PID;
00052 isc_boolean_t no_dhcrelay_pid = ISC_FALSE;
00053
00054 isc_boolean_t no_pid_file = ISC_FALSE;
00055
00056 int bogus_agent_drops = 0;
00057
00058
00059
00060 int bogus_giaddr_drops = 0;
00061
00062 int client_packets_relayed = 0;
00063 int server_packet_errors = 0;
00064 int server_packets_relayed = 0;
00065 int client_packet_errors = 0;
00066
00067 int add_agent_options = 0;
00068
00069 int agent_option_errors = 0;
00070
00071 int drop_agent_mismatches = 0;
00072
00073 int corrupt_agent_options = 0;
00074
00075 int missing_agent_option = 0;
00076
00077 int bad_circuit_id = 0;
00078
00079 int missing_circuit_id = 0;
00080
00081 int max_hop_count = 10;
00082
00083 #ifdef DHCPv6
00084
00085 isc_boolean_t use_if_id = ISC_FALSE;
00086 #endif
00087
00088
00089 int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
00090
00091
00092
00093 enum { forward_and_append,
00094 forward_and_replace,
00095 forward_untouched,
00096 discard } agent_relay_mode = forward_and_replace;
00097
00098 u_int16_t local_port;
00099 u_int16_t remote_port;
00100
00101
00102 struct server_list {
00103 struct server_list *next;
00104 struct sockaddr_in to;
00105 } *servers;
00106
00107 #ifdef DHCPv6
00108 struct stream_list {
00109 struct stream_list *next;
00110 struct interface_info *ifp;
00111 struct sockaddr_in6 link;
00112 int id;
00113 } *downstreams, *upstreams;
00114
00115 static struct stream_list *parse_downstream(char *);
00116 static struct stream_list *parse_upstream(char *);
00117 static void setup_streams(void);
00118
00119
00120
00121
00122
00123
00124
00125 char *dhcrelay_sub_id = NULL;
00126 #endif
00127
00128 static void do_relay4(struct interface_info *, struct dhcp_packet *,
00129 unsigned int, unsigned int, struct iaddr,
00130 struct hardware *);
00131 static int add_relay_agent_options(struct interface_info *,
00132 struct dhcp_packet *, unsigned,
00133 struct in_addr);
00134 static int find_interface_by_agent_option(struct dhcp_packet *,
00135 struct interface_info **, u_int8_t *, int);
00136 static int strip_relay_agent_options(struct interface_info *,
00137 struct interface_info **,
00138 struct dhcp_packet *, unsigned);
00139
00140 static const char copyright[] =
00141 "Copyright 2004-2014 Internet Systems Consortium.";
00142 static const char arr[] = "All rights reserved.";
00143 static const char message[] =
00144 "Internet Systems Consortium DHCP Relay Agent";
00145 static const char url[] =
00146 "For info, please visit https://www.isc.org/software/dhcp/";
00147
00148 #ifdef DHCPv6
00149 #define DHCRELAY_USAGE \
00150 "Usage: dhcrelay [-4] [-d] [-q] [-a] [-D]\n"\
00151 " [-A <length>] [-c <hops>] [-p <port>]\n" \
00152 " [-pf <pid-file>] [--no-pid]\n"\
00153 " [-m append|replace|forward|discard]\n" \
00154 " [-i interface0 [ ... -i interfaceN]\n" \
00155 " server0 [ ... serverN]\n\n" \
00156 " dhcrelay -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
00157 " [-pf <pid-file>] [--no-pid]\n" \
00158 " [-s <subscriber-id>]\n" \
00159 " -l lower0 [ ... -l lowerN]\n" \
00160 " -u upper0 [ ... -u upperN]\n" \
00161 " lower (client link): [address%%]interface[#index]\n" \
00162 " upper (server link): [address%%]interface"
00163 #else
00164 #define DHCRELAY_USAGE \
00165 "Usage: dhcrelay [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
00166 " [-pf <pid-file>] [--no-pid]\n" \
00167 " [-m append|replace|forward|discard]\n" \
00168 " [-i interface0 [ ... -i interfaceN]\n" \
00169 " server0 [ ... serverN]\n\n"
00170 #endif
00171
00172 static void usage() {
00173 log_fatal(DHCRELAY_USAGE);
00174 }
00175
00176 int
00177 main(int argc, char **argv) {
00178 isc_result_t status;
00179 struct servent *ent;
00180 struct server_list *sp = NULL;
00181 struct interface_info *tmp = NULL;
00182 char *service_local = NULL, *service_remote = NULL;
00183 u_int16_t port_local = 0, port_remote = 0;
00184 int no_daemon = 0, quiet = 0;
00185 int fd;
00186 int i;
00187 #ifdef DHCPv6
00188 struct stream_list *sl = NULL;
00189 int local_family_set = 0;
00190 #endif
00191
00192
00193
00194
00195 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
00196 if (fd == 0)
00197 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
00198 if (fd == 1)
00199 fd = open("/dev/null", O_RDWR | O_CLOEXEC);
00200 if (fd == 2)
00201 log_perror = 0;
00202 else if (fd != -1)
00203 close(fd);
00204
00205 openlog("dhcrelay", LOG_NDELAY, LOG_DAEMON);
00206
00207 #if !defined(DEBUG)
00208 setlogmask(LOG_UPTO(LOG_INFO));
00209 #endif
00210
00211
00212 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
00213 NULL, NULL);
00214 if (status != ISC_R_SUCCESS)
00215 log_fatal("Can't initialize context: %s",
00216 isc_result_totext(status));
00217
00218
00219 status = omapi_init();
00220 if (status != ISC_R_SUCCESS)
00221 log_fatal("Can't initialize OMAPI: %s",
00222 isc_result_totext(status));
00223
00224
00225 interface_setup();
00226
00227 for (i = 1; i < argc; i++) {
00228 if (!strcmp(argv[i], "-4")) {
00229 #ifdef DHCPv6
00230 if (local_family_set && (local_family == AF_INET6)) {
00231 usage();
00232 }
00233 local_family_set = 1;
00234 local_family = AF_INET;
00235 } else if (!strcmp(argv[i], "-6")) {
00236 if (local_family_set && (local_family == AF_INET)) {
00237 usage();
00238 }
00239 local_family_set = 1;
00240 local_family = AF_INET6;
00241 #endif
00242 } else if (!strcmp(argv[i], "-d")) {
00243 no_daemon = 1;
00244 } else if (!strcmp(argv[i], "-q")) {
00245 quiet = 1;
00246 quiet_interface_discovery = 1;
00247 } else if (!strcmp(argv[i], "-p")) {
00248 if (++i == argc)
00249 usage();
00250 local_port = validate_port(argv[i]);
00251 log_debug("binding to user-specified port %d",
00252 ntohs(local_port));
00253 } else if (!strcmp(argv[i], "-c")) {
00254 int hcount;
00255 if (++i == argc)
00256 usage();
00257 hcount = atoi(argv[i]);
00258 if (hcount <= 255)
00259 max_hop_count= hcount;
00260 else
00261 usage();
00262 } else if (!strcmp(argv[i], "-i")) {
00263 #ifdef DHCPv6
00264 if (local_family_set && (local_family == AF_INET6)) {
00265 usage();
00266 }
00267 local_family_set = 1;
00268 local_family = AF_INET;
00269 #endif
00270 if (++i == argc) {
00271 usage();
00272 }
00273 if (strlen(argv[i]) >= sizeof(tmp->name)) {
00274 log_fatal("%s: interface name too long "
00275 "(is %ld)",
00276 argv[i], (long)strlen(argv[i]));
00277 }
00278 status = interface_allocate(&tmp, MDL);
00279 if (status != ISC_R_SUCCESS) {
00280 log_fatal("%s: interface_allocate: %s",
00281 argv[i],
00282 isc_result_totext(status));
00283 }
00284 strcpy(tmp->name, argv[i]);
00285 interface_snorf(tmp, INTERFACE_REQUESTED);
00286 interface_dereference(&tmp, MDL);
00287 } else if (!strcmp(argv[i], "-a")) {
00288 #ifdef DHCPv6
00289 if (local_family_set && (local_family == AF_INET6)) {
00290 usage();
00291 }
00292 local_family_set = 1;
00293 local_family = AF_INET;
00294 #endif
00295 add_agent_options = 1;
00296 } else if (!strcmp(argv[i], "-A")) {
00297 #ifdef DHCPv6
00298 if (local_family_set && (local_family == AF_INET6)) {
00299 usage();
00300 }
00301 local_family_set = 1;
00302 local_family = AF_INET;
00303 #endif
00304 if (++i == argc)
00305 usage();
00306
00307 dhcp_max_agent_option_packet_length = atoi(argv[i]);
00308
00309 if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX)
00310 log_fatal("%s: packet length exceeds "
00311 "longest possible MTU\n",
00312 argv[i]);
00313 } else if (!strcmp(argv[i], "-m")) {
00314 #ifdef DHCPv6
00315 if (local_family_set && (local_family == AF_INET6)) {
00316 usage();
00317 }
00318 local_family_set = 1;
00319 local_family = AF_INET;
00320 #endif
00321 if (++i == argc)
00322 usage();
00323 if (!strcasecmp(argv[i], "append")) {
00324 agent_relay_mode = forward_and_append;
00325 } else if (!strcasecmp(argv[i], "replace")) {
00326 agent_relay_mode = forward_and_replace;
00327 } else if (!strcasecmp(argv[i], "forward")) {
00328 agent_relay_mode = forward_untouched;
00329 } else if (!strcasecmp(argv[i], "discard")) {
00330 agent_relay_mode = discard;
00331 } else
00332 usage();
00333 } else if (!strcmp(argv[i], "-D")) {
00334 #ifdef DHCPv6
00335 if (local_family_set && (local_family == AF_INET6)) {
00336 usage();
00337 }
00338 local_family_set = 1;
00339 local_family = AF_INET;
00340 #endif
00341 drop_agent_mismatches = 1;
00342 #ifdef DHCPv6
00343 } else if (!strcmp(argv[i], "-I")) {
00344 if (local_family_set && (local_family == AF_INET)) {
00345 usage();
00346 }
00347 local_family_set = 1;
00348 local_family = AF_INET6;
00349 use_if_id = ISC_TRUE;
00350 } else if (!strcmp(argv[i], "-l")) {
00351 if (local_family_set && (local_family == AF_INET)) {
00352 usage();
00353 }
00354 local_family_set = 1;
00355 local_family = AF_INET6;
00356 if (downstreams != NULL)
00357 use_if_id = ISC_TRUE;
00358 if (++i == argc)
00359 usage();
00360 sl = parse_downstream(argv[i]);
00361 sl->next = downstreams;
00362 downstreams = sl;
00363 } else if (!strcmp(argv[i], "-u")) {
00364 if (local_family_set && (local_family == AF_INET)) {
00365 usage();
00366 }
00367 local_family_set = 1;
00368 local_family = AF_INET6;
00369 if (++i == argc)
00370 usage();
00371 sl = parse_upstream(argv[i]);
00372 sl->next = upstreams;
00373 upstreams = sl;
00374 } else if (!strcmp(argv[i], "-s")) {
00375 if (local_family_set && (local_family == AF_INET)) {
00376 usage();
00377 }
00378 local_family_set = 1;
00379 local_family = AF_INET6;
00380 if (++i == argc)
00381 usage();
00382 dhcrelay_sub_id = argv[i];
00383 #endif
00384 } else if (!strcmp(argv[i], "-nc")) {
00385 #ifdef HAVE_LIBCAP_NG
00386 keep_capabilities = 1;
00387 #endif
00388 } else if (!strcmp(argv[i], "-pf")) {
00389 if (++i == argc)
00390 usage();
00391 path_dhcrelay_pid = argv[i];
00392 no_dhcrelay_pid = ISC_TRUE;
00393 } else if (!strcmp(argv[i], "--no-pid")) {
00394 no_pid_file = ISC_TRUE;
00395 } else if (!strcmp(argv[i], "--version")) {
00396 log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
00397 exit(0);
00398 } else if (!strcmp(argv[i], "--help") ||
00399 !strcmp(argv[i], "-h")) {
00400 log_info(DHCRELAY_USAGE);
00401 exit(0);
00402 } else if (argv[i][0] == '-') {
00403 usage();
00404 } else {
00405 struct hostent *he;
00406 struct in_addr ia, *iap = NULL;
00407
00408 #ifdef DHCPv6
00409 if (local_family_set && (local_family == AF_INET6)) {
00410 usage();
00411 }
00412 local_family_set = 1;
00413 local_family = AF_INET;
00414 #endif
00415 if (inet_aton(argv[i], &ia)) {
00416 iap = &ia;
00417 } else {
00418 he = gethostbyname(argv[i]);
00419 if (!he) {
00420 log_error("%s: host unknown", argv[i]);
00421 } else {
00422 iap = ((struct in_addr *)
00423 he->h_addr_list[0]);
00424 }
00425 }
00426
00427 if (iap) {
00428 sp = ((struct server_list *)
00429 dmalloc(sizeof *sp, MDL));
00430 if (!sp)
00431 log_fatal("no memory for server.\n");
00432 sp->next = servers;
00433 servers = sp;
00434 memcpy(&sp->to.sin_addr, iap, sizeof *iap);
00435 }
00436 }
00437 }
00438
00439
00440
00441
00442
00443 if (no_dhcrelay_pid == ISC_FALSE) {
00444 if (local_family == AF_INET) {
00445 path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID");
00446 if (path_dhcrelay_pid == NULL)
00447 path_dhcrelay_pid = _PATH_DHCRELAY_PID;
00448 }
00449 #ifdef DHCPv6
00450 else {
00451 path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID");
00452 if (path_dhcrelay_pid == NULL)
00453 path_dhcrelay_pid = _PATH_DHCRELAY6_PID;
00454 }
00455 #endif
00456 }
00457
00458 #ifdef HAVE_LIBCAP_NG
00459
00460 if (!keep_capabilities) {
00461 capng_clear(CAPNG_SELECT_BOTH);
00462 capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
00463 CAP_NET_RAW, CAP_NET_BIND_SERVICE, -1);
00464 capng_apply(CAPNG_SELECT_BOTH);
00465 log_info ("Dropped all unnecessary capabilities.");
00466 }
00467 #endif
00468
00469 if (!quiet) {
00470 log_info("%s %s", message, PACKAGE_VERSION);
00471 log_info(copyright);
00472 log_info(arr);
00473 log_info(url);
00474 } else
00475 log_perror = 0;
00476
00477
00478 if (local_family == AF_INET) {
00479 service_local = "bootps";
00480 service_remote = "bootpc";
00481 port_local = htons(67);
00482 port_remote = htons(68);
00483 }
00484 #ifdef DHCPv6
00485 else {
00486 service_local = "dhcpv6-server";
00487 service_remote = "dhcpv6-client";
00488 port_local = htons(547);
00489 port_remote = htons(546);
00490 }
00491 #endif
00492
00493 if (!local_port) {
00494 ent = getservbyname(service_local, "udp");
00495 if (ent)
00496 local_port = ent->s_port;
00497 else
00498 local_port = port_local;
00499
00500 ent = getservbyname(service_remote, "udp");
00501 if (ent)
00502 remote_port = ent->s_port;
00503 else
00504 remote_port = port_remote;
00505
00506 endservent();
00507 }
00508
00509 if (local_family == AF_INET) {
00510
00511 if (servers == NULL) {
00512 log_fatal("No servers specified.");
00513 }
00514
00515
00516
00517 for (sp = servers; sp; sp = sp->next) {
00518 sp->to.sin_port = local_port;
00519 sp->to.sin_family = AF_INET;
00520 #ifdef HAVE_SA_LEN
00521 sp->to.sin_len = sizeof sp->to;
00522 #endif
00523 }
00524 }
00525 #ifdef DHCPv6
00526 else {
00527 unsigned code;
00528
00529
00530 if (upstreams == NULL || downstreams == NULL) {
00531 log_info("Must specify at least one lower "
00532 "and one upper interface.\n");
00533 usage();
00534 }
00535
00536
00537 initialize_common_option_spaces();
00538
00539
00540 code = D6O_RELAY_MSG;
00541 if (!option_code_hash_lookup(&requested_opts[0],
00542 dhcpv6_universe.code_hash,
00543 &code, 0, MDL))
00544 log_fatal("Unable to find the RELAY_MSG "
00545 "option definition.");
00546 code = D6O_INTERFACE_ID;
00547 if (!option_code_hash_lookup(&requested_opts[1],
00548 dhcpv6_universe.code_hash,
00549 &code, 0, MDL))
00550 log_fatal("Unable to find the INTERFACE_ID "
00551 "option definition.");
00552 }
00553 #endif
00554
00555
00556 gettimeofday(&cur_tv, NULL);
00557
00558
00559 discover_interfaces(DISCOVER_RELAY);
00560
00561 #ifdef DHCPv6
00562 if (local_family == AF_INET6)
00563 setup_streams();
00564 #endif
00565
00566
00567 if (!no_daemon) {
00568 int pid;
00569 FILE *pf;
00570 int pfdesc;
00571
00572 log_perror = 0;
00573
00574 if ((pid = fork()) < 0)
00575 log_fatal("Can't fork daemon: %m");
00576 else if (pid)
00577 exit(0);
00578
00579 if (no_pid_file == ISC_FALSE) {
00580 pfdesc = open(path_dhcrelay_pid,
00581 O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
00582
00583 if (pfdesc < 0) {
00584 log_error("Can't create %s: %m",
00585 path_dhcrelay_pid);
00586 } else {
00587 pf = fdopen(pfdesc, "we");
00588 if (!pf)
00589 log_error("Can't fdopen %s: %m",
00590 path_dhcrelay_pid);
00591 else {
00592 fprintf(pf, "%ld\n",(long)getpid());
00593 fclose(pf);
00594 }
00595 }
00596 }
00597
00598 (void) close(0);
00599 (void) close(1);
00600 (void) close(2);
00601 (void) setsid();
00602
00603 IGNORE_RET (chdir("/"));
00604 }
00605
00606
00607 if (local_family == AF_INET)
00608 bootp_packet_handler = do_relay4;
00609 #ifdef DHCPv6
00610 else
00611 dhcpv6_packet_handler = do_packet6;
00612 #endif
00613
00614
00615 signal(SIGINT, dhcp_signal_handler);
00616 signal(SIGTERM, dhcp_signal_handler);
00617
00618 #ifdef HAVE_LIBCAP_NG
00619
00620 if (!keep_capabilities) {
00621 capng_clear(CAPNG_SELECT_BOTH);
00622 capng_apply(CAPNG_SELECT_BOTH);
00623 log_info ("Dropped all capabilities.");
00624 }
00625 #endif
00626
00627
00628 dispatch();
00629
00630
00631 return (0);
00632 }
00633
00634 static void
00635 do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
00636 unsigned int length, unsigned int from_port, struct iaddr from,
00637 struct hardware *hfrom) {
00638 struct server_list *sp;
00639 struct sockaddr_in to;
00640 struct interface_info *out;
00641 struct hardware hto, *htop;
00642
00643 if (packet->hlen > sizeof packet->chaddr) {
00644 log_info("Discarding packet with invalid hlen, received on "
00645 "%s interface.", ip->name);
00646 return;
00647 }
00648 if (ip->address_count < 1 || ip->addresses == NULL) {
00649 log_info("Discarding packet received on %s interface that "
00650 "has no IPv4 address assigned.", ip->name);
00651 return;
00652 }
00653
00654
00655
00656 if (packet->giaddr.s_addr) {
00657 for (out = interfaces; out; out = out->next) {
00658 int i;
00659
00660 for (i = 0 ; i < out->address_count ; i++ ) {
00661 if (out->addresses[i].s_addr ==
00662 packet->giaddr.s_addr) {
00663 i = -1;
00664 break;
00665 }
00666 }
00667
00668 if (i == -1)
00669 break;
00670 }
00671 } else {
00672 out = NULL;
00673 }
00674
00675
00676 if (packet->op == BOOTREPLY) {
00677 if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
00678 can_unicast_without_arp(out)) {
00679 to.sin_addr = packet->yiaddr;
00680 to.sin_port = remote_port;
00681
00682
00683 htop = &hto;
00684 } else {
00685 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
00686 to.sin_port = remote_port;
00687
00688
00689 htop = NULL;
00690 }
00691 to.sin_family = AF_INET;
00692 #ifdef HAVE_SA_LEN
00693 to.sin_len = sizeof to;
00694 #endif
00695
00696 memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen);
00697 hto.hbuf[0] = packet->htype;
00698 hto.hlen = packet->hlen + 1;
00699
00700
00701
00702
00703
00704 if (!(length =
00705 strip_relay_agent_options(ip, &out, packet, length)))
00706 return;
00707
00708 if (!out) {
00709 log_error("Packet to bogus giaddr %s.\n",
00710 inet_ntoa(packet->giaddr));
00711 ++bogus_giaddr_drops;
00712 return;
00713 }
00714
00715 if (send_packet(out, NULL, packet, length, out->addresses[0],
00716 &to, htop) < 0) {
00717 ++server_packet_errors;
00718 } else {
00719 log_debug("Forwarded BOOTREPLY for %s to %s",
00720 print_hw_addr(packet->htype, packet->hlen,
00721 packet->chaddr),
00722 inet_ntoa(to.sin_addr));
00723
00724 ++server_packets_relayed;
00725 }
00726 return;
00727 }
00728
00729
00730
00731 if (out)
00732 return;
00733
00734
00735
00736 if (!(length = add_relay_agent_options(ip, packet, length,
00737 ip->addresses[0])))
00738 return;
00739
00740
00741
00742
00743
00744
00745 if (!packet->giaddr.s_addr)
00746 packet->giaddr = ip->addresses[0];
00747 if (packet->hops < max_hop_count)
00748 packet->hops = packet->hops + 1;
00749 else
00750 return;
00751
00752
00753
00754 for (sp = servers; sp; sp = sp->next) {
00755 if (send_packet((fallback_interface
00756 ? fallback_interface : interfaces),
00757 NULL, packet, length, ip->addresses[0],
00758 &sp->to, NULL) < 0) {
00759 ++client_packet_errors;
00760 } else {
00761 log_debug("Forwarded BOOTREQUEST for %s to %s",
00762 print_hw_addr(packet->htype, packet->hlen,
00763 packet->chaddr),
00764 inet_ntoa(sp->to.sin_addr));
00765 ++client_packets_relayed;
00766 }
00767 }
00768
00769 }
00770
00771
00772
00773
00774
00775 static int
00776 strip_relay_agent_options(struct interface_info *in,
00777 struct interface_info **out,
00778 struct dhcp_packet *packet,
00779 unsigned length) {
00780 int is_dhcp = 0;
00781 u_int8_t *op, *nextop, *sp, *max;
00782 int good_agent_option = 0;
00783 int status;
00784
00785
00786
00787 if (!add_agent_options)
00788 return (length);
00789
00790
00791
00792 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
00793 return (length);
00794
00795 max = ((u_int8_t *)packet) + length;
00796 sp = op = &packet->options[4];
00797
00798 while (op < max) {
00799 switch(*op) {
00800
00801 case DHO_PAD:
00802 if (sp != op)
00803 *sp = *op;
00804 ++op;
00805 ++sp;
00806 continue;
00807
00808
00809 case DHO_DHCP_MESSAGE_TYPE:
00810 is_dhcp = 1;
00811 goto skip;
00812 break;
00813
00814
00815 case DHO_END:
00816 if (sp != op)
00817 *sp++ = *op++;
00818 goto out;
00819
00820 case DHO_DHCP_AGENT_OPTIONS:
00821
00822
00823
00824 if (!is_dhcp)
00825 goto skip;
00826
00827
00828
00829
00830 nextop = op + op[1] + 2;
00831 if (nextop > max)
00832 return (0);
00833
00834 status = find_interface_by_agent_option(packet,
00835 out, op + 2,
00836 op[1]);
00837 if (status == -1 && drop_agent_mismatches)
00838 return (0);
00839 if (status)
00840 good_agent_option = 1;
00841 op = nextop;
00842 break;
00843
00844 skip:
00845
00846 default:
00847
00848
00849
00850 nextop = op + op[1] + 2;
00851 if (nextop > max)
00852 return (0);
00853
00854 if (sp != op) {
00855 memmove(sp, op, op[1] + 2);
00856 sp += op[1] + 2;
00857 op = nextop;
00858 } else
00859 op = sp = nextop;
00860
00861 break;
00862 }
00863 }
00864 out:
00865
00866
00867 if (!is_dhcp)
00868 return (length);
00869
00870
00871
00872
00873
00874
00875 if (!good_agent_option) {
00876 ++missing_agent_option;
00877 if (drop_agent_mismatches)
00878 return (0);
00879 }
00880
00881
00882 if (sp != op) {
00883 length = sp -((u_int8_t *)packet);
00884
00885
00886
00887 if (length < BOOTP_MIN_LEN) {
00888 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
00889 length = BOOTP_MIN_LEN;
00890 }
00891 }
00892 return (length);
00893 }
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906
00907 static int
00908 find_interface_by_agent_option(struct dhcp_packet *packet,
00909 struct interface_info **out,
00910 u_int8_t *buf, int len) {
00911 int i = 0;
00912 u_int8_t *circuit_id = 0;
00913 unsigned circuit_id_len = 0;
00914 struct interface_info *ip;
00915
00916 while (i < len) {
00917
00918
00919 if (i + 1 == len ||
00920 i + buf[i + 1] + 2 > len) {
00921 ++corrupt_agent_options;
00922 return (-1);
00923 }
00924 switch(buf[i]) {
00925
00926 case RAI_CIRCUIT_ID:
00927 circuit_id = &buf[i + 2];
00928 circuit_id_len = buf[i + 1];
00929 i += circuit_id_len + 2;
00930 continue;
00931
00932 default:
00933 i += buf[i + 1] + 2;
00934 break;
00935 }
00936 }
00937
00938
00939
00940 if (!circuit_id) {
00941 ++missing_circuit_id;
00942 return (-1);
00943 }
00944
00945
00946
00947
00948 for (ip = interfaces; ip; ip = ip->next) {
00949 if (ip->circuit_id &&
00950 ip->circuit_id_len == circuit_id_len &&
00951 !memcmp(ip->circuit_id, circuit_id, circuit_id_len))
00952 break;
00953 }
00954
00955
00956 if (ip) {
00957 *out = ip;
00958 return (1);
00959 }
00960
00961
00962 ++bad_circuit_id;
00963 return (-1);
00964 }
00965
00966
00967
00968
00969
00970
00971 static int
00972 add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
00973 unsigned length, struct in_addr giaddr) {
00974 int is_dhcp = 0, mms;
00975 unsigned optlen;
00976 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
00977
00978
00979
00980 if (!add_agent_options)
00981 return (length);
00982
00983
00984
00985 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
00986 return (length);
00987
00988 max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length;
00989
00990
00991 sp = op = &packet->options[4];
00992
00993 while (op < max) {
00994 switch(*op) {
00995
00996 case DHO_PAD:
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006 if (end_pad == NULL)
01007 end_pad = sp;
01008
01009 if (sp != op)
01010 *sp++ = *op++;
01011 else
01012 sp = ++op;
01013
01014 continue;
01015
01016
01017 case DHO_DHCP_MESSAGE_TYPE:
01018 is_dhcp = 1;
01019 goto skip;
01020
01021
01022
01023
01024
01025 case DHO_DHCP_MAX_MESSAGE_SIZE:
01026 mms = ntohs(*(op + 2));
01027 if (mms < dhcp_max_agent_option_packet_length &&
01028 mms >= DHCP_MTU_MIN)
01029 max = ((u_int8_t *)packet) + mms;
01030 goto skip;
01031
01032
01033 case DHO_END:
01034 goto out;
01035
01036 case DHO_DHCP_AGENT_OPTIONS:
01037
01038
01039
01040 if (!is_dhcp)
01041 goto skip;
01042
01043 end_pad = NULL;
01044
01045
01046
01047
01048
01049 switch(agent_relay_mode) {
01050 case forward_and_append:
01051 goto skip;
01052 case forward_untouched:
01053 return (length);
01054 case discard:
01055 return (0);
01056 case forward_and_replace:
01057 default:
01058 break;
01059 }
01060
01061
01062
01063 op += op[1] + 2;
01064 break;
01065
01066 skip:
01067
01068 default:
01069
01070
01071
01072 nextop = op + op[1] + 2;
01073 if (nextop > max)
01074 return (0);
01075
01076 end_pad = NULL;
01077
01078 if (sp != op) {
01079 memmove(sp, op, op[1] + 2);
01080 sp += op[1] + 2;
01081 op = nextop;
01082 } else
01083 op = sp = nextop;
01084
01085 break;
01086 }
01087 }
01088 out:
01089
01090
01091 if (!is_dhcp)
01092 return (length);
01093
01094
01095
01096
01097 if (end_pad != NULL)
01098 sp = end_pad;
01099
01100 #if 0
01101
01102
01103 op = sp;
01104 #endif
01105
01106
01107 if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
01108 log_fatal("Circuit ID length %d out of range [1-255] on "
01109 "%s\n", ip->circuit_id_len, ip->name);
01110 optlen = ip->circuit_id_len + 2;
01111
01112 if (ip->remote_id) {
01113 if (ip->remote_id_len > 255 || ip->remote_id_len < 1)
01114 log_fatal("Remote ID length %d out of range [1-255] "
01115 "on %s\n", ip->circuit_id_len, ip->name);
01116 optlen += ip->remote_id_len + 2;
01117 }
01118
01119
01120
01121
01122 if ((optlen < 3) ||(optlen > 255))
01123 log_fatal("Total agent option length(%u) out of range "
01124 "[3 - 255] on %s\n", optlen, ip->name);
01125
01126
01127
01128
01129
01130 if (max - sp >= optlen + 3) {
01131 log_debug("Adding %d-byte relay agent option", optlen + 3);
01132
01133
01134 *sp++ = DHO_DHCP_AGENT_OPTIONS;
01135 *sp++ = optlen;
01136
01137
01138 *sp++ = RAI_CIRCUIT_ID;
01139 *sp++ = ip->circuit_id_len;
01140 memcpy(sp, ip->circuit_id, ip->circuit_id_len);
01141 sp += ip->circuit_id_len;
01142
01143
01144 if (ip->remote_id) {
01145 *sp++ = RAI_REMOTE_ID;
01146 *sp++ = ip->remote_id_len;
01147 memcpy(sp, ip->remote_id, ip->remote_id_len);
01148 sp += ip->remote_id_len;
01149 }
01150 } else {
01151 ++agent_option_errors;
01152 log_error("No room in packet (used %d of %d) "
01153 "for %d-byte relay agent option: omitted",
01154 (int) (sp - ((u_int8_t *) packet)),
01155 (int) (max - ((u_int8_t *) packet)),
01156 optlen + 3);
01157 }
01158
01159
01160
01161
01162
01163 if (sp < max)
01164 *sp++ = DHO_END;
01165
01166
01167 length = sp -((u_int8_t *)packet);
01168
01169
01170 if (length < BOOTP_MIN_LEN) {
01171 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
01172 return (BOOTP_MIN_LEN);
01173 }
01174
01175 return (length);
01176 }
01177
01178 #ifdef DHCPv6
01179
01180
01181
01182 static struct stream_list *
01183 parse_downstream(char *arg) {
01184 struct stream_list *dp, *up;
01185 struct interface_info *ifp = NULL;
01186 char *ifname, *addr, *iid;
01187 isc_result_t status;
01188
01189 if (!supports_multiple_interfaces(ifp) &&
01190 (downstreams != NULL))
01191 log_fatal("No support for multiple interfaces.");
01192
01193
01194 ifname = strchr(arg, '%');
01195 if (ifname == NULL) {
01196 ifname = arg;
01197 addr = NULL;
01198 } else {
01199 *ifname++ = '\0';
01200 addr = arg;
01201 }
01202 iid = strchr(ifname, '#');
01203 if (iid != NULL) {
01204 *iid++ = '\0';
01205 }
01206 if (strlen(ifname) >= sizeof(ifp->name)) {
01207 log_error("Interface name '%s' too long", ifname);
01208 usage();
01209 }
01210
01211
01212 for (dp = downstreams; dp; dp = dp->next) {
01213 if (strcmp(ifname, dp->ifp->name) == 0)
01214 log_fatal("Down interface '%s' declared twice.",
01215 ifname);
01216 }
01217
01218
01219 for (up = upstreams; up; up = up->next) {
01220 if (strcmp(ifname, up->ifp->name) == 0) {
01221 log_info("Interface '%s' is both down and up.",
01222 ifname);
01223 ifp = up->ifp;
01224 break;
01225 }
01226 }
01227
01228
01229 if (ifp == NULL) {
01230 status = interface_allocate(&ifp, MDL);
01231 if (status != ISC_R_SUCCESS)
01232 log_fatal("%s: interface_allocate: %s",
01233 arg, isc_result_totext(status));
01234 strcpy(ifp->name, ifname);
01235 if (interfaces) {
01236 interface_reference(&ifp->next, interfaces, MDL);
01237 interface_dereference(&interfaces, MDL);
01238 }
01239 interface_reference(&interfaces, ifp, MDL);
01240 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM;
01241 }
01242
01243
01244 dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL);
01245 if (!dp)
01246 log_fatal("No memory for downstream.");
01247 dp->ifp = ifp;
01248 if (iid != NULL) {
01249 dp->id = atoi(iid);
01250 } else {
01251 dp->id = -1;
01252 }
01253
01254 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
01255 log_fatal("Bad link address '%s'", addr);
01256
01257 return dp;
01258 }
01259
01260
01261
01262
01263 static struct stream_list *
01264 parse_upstream(char *arg) {
01265 struct stream_list *up, *dp;
01266 struct interface_info *ifp = NULL;
01267 char *ifname, *addr;
01268 isc_result_t status;
01269
01270
01271 ifname = strchr(arg, '%');
01272 if (ifname == NULL) {
01273 ifname = arg;
01274 addr = All_DHCP_Servers;
01275 } else {
01276 *ifname++ = '\0';
01277 addr = arg;
01278 }
01279 if (strlen(ifname) >= sizeof(ifp->name)) {
01280 log_fatal("Interface name '%s' too long", ifname);
01281 }
01282
01283
01284 for (up = upstreams; up; up = up->next) {
01285 if (strcmp(ifname, up->ifp->name) == 0) {
01286 ifp = up->ifp;
01287 break;
01288 }
01289 }
01290 for (dp = downstreams; dp; dp = dp->next) {
01291 if (strcmp(ifname, dp->ifp->name) == 0) {
01292 ifp = dp->ifp;
01293 break;
01294 }
01295 }
01296
01297
01298 if (ifp == NULL) {
01299 status = interface_allocate(&ifp, MDL);
01300 if (status != ISC_R_SUCCESS)
01301 log_fatal("%s: interface_allocate: %s",
01302 arg, isc_result_totext(status));
01303 strcpy(ifp->name, ifname);
01304 if (interfaces) {
01305 interface_reference(&ifp->next, interfaces, MDL);
01306 interface_dereference(&interfaces, MDL);
01307 }
01308 interface_reference(&interfaces, ifp, MDL);
01309 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM;
01310 }
01311
01312
01313 up = (struct stream_list *) dmalloc(sizeof(*up), MDL);
01314 if (up == NULL)
01315 log_fatal("No memory for upstream.");
01316
01317 up->ifp = ifp;
01318
01319 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
01320 log_fatal("Bad address %s", addr);
01321
01322 return up;
01323 }
01324
01325
01326
01327
01328 static void
01329 setup_streams(void) {
01330 struct stream_list *dp, *up;
01331 int i;
01332 isc_boolean_t link_is_set;
01333
01334 for (dp = downstreams; dp; dp = dp->next) {
01335
01336 if (dp->ifp->v6address_count == 0)
01337 log_fatal("Interface '%s' has no IPv6 addresses.",
01338 dp->ifp->name);
01339
01340
01341 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
01342 link_is_set = ISC_FALSE;
01343 else
01344 link_is_set = ISC_TRUE;
01345 for (i = 0; i < dp->ifp->v6address_count; i++) {
01346 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
01347 continue;
01348 if (!link_is_set)
01349 break;
01350 if (!memcmp(&dp->ifp->v6addresses[i],
01351 &dp->link.sin6_addr,
01352 sizeof(dp->link.sin6_addr)))
01353 break;
01354 }
01355 if (i == dp->ifp->v6address_count)
01356 log_fatal("Interface %s does not have global IPv6 "
01357 "address assigned.", dp->ifp->name);
01358 if (!link_is_set)
01359 memcpy(&dp->link.sin6_addr,
01360 &dp->ifp->v6addresses[i],
01361 sizeof(dp->link.sin6_addr));
01362
01363
01364 if (dp->id == -1)
01365 dp->id = dp->ifp->index;
01366 }
01367
01368 for (up = upstreams; up; up = up->next) {
01369 up->link.sin6_port = local_port;
01370 up->link.sin6_family = AF_INET6;
01371 #ifdef HAVE_SA_LEN
01372 up->link.sin6_len = sizeof(up->link);
01373 #endif
01374
01375 if (up->ifp->v6address_count == 0)
01376 log_fatal("Interface '%s' has no IPv6 addresses.",
01377 up->ifp->name);
01378 }
01379 }
01380
01381
01382
01383
01384 static const int required_forw_opts[] = {
01385 D6O_INTERFACE_ID,
01386 D6O_SUBSCRIBER_ID,
01387 D6O_RELAY_MSG,
01388 0
01389 };
01390
01391
01392
01393
01394 static void
01395 process_up6(struct packet *packet, struct stream_list *dp) {
01396 char forw_data[65535];
01397 unsigned cursor;
01398 struct dhcpv6_relay_packet *relay;
01399 struct option_state *opts;
01400 struct stream_list *up;
01401
01402
01403 switch (packet->dhcpv6_msg_type) {
01404 case DHCPV6_SOLICIT:
01405 case DHCPV6_REQUEST:
01406 case DHCPV6_CONFIRM:
01407 case DHCPV6_RENEW:
01408 case DHCPV6_REBIND:
01409 case DHCPV6_RELEASE:
01410 case DHCPV6_DECLINE:
01411 case DHCPV6_INFORMATION_REQUEST:
01412 case DHCPV6_RELAY_FORW:
01413 case DHCPV6_LEASEQUERY:
01414 log_info("Relaying %s from %s port %d going up.",
01415 dhcpv6_type_names[packet->dhcpv6_msg_type],
01416 piaddr(packet->client_addr),
01417 ntohs(packet->client_port));
01418 break;
01419
01420 case DHCPV6_ADVERTISE:
01421 case DHCPV6_REPLY:
01422 case DHCPV6_RECONFIGURE:
01423 case DHCPV6_RELAY_REPL:
01424 case DHCPV6_LEASEQUERY_REPLY:
01425 log_info("Discarding %s from %s port %d going up.",
01426 dhcpv6_type_names[packet->dhcpv6_msg_type],
01427 piaddr(packet->client_addr),
01428 ntohs(packet->client_port));
01429 return;
01430
01431 default:
01432 log_info("Unknown %d type from %s port %d going up.",
01433 packet->dhcpv6_msg_type,
01434 piaddr(packet->client_addr),
01435 ntohs(packet->client_port));
01436 return;
01437 }
01438
01439
01440 relay = (struct dhcpv6_relay_packet *) forw_data;
01441 cursor = offsetof(struct dhcpv6_relay_packet, options);
01442 relay->msg_type = DHCPV6_RELAY_FORW;
01443 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
01444 if (packet->dhcpv6_hop_count >= max_hop_count) {
01445 log_info("Hop count exceeded,");
01446 return;
01447 }
01448 relay->hop_count = packet->dhcpv6_hop_count + 1;
01449 if (dp) {
01450 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
01451 } else {
01452
01453 if (!use_if_id && downstreams->next) {
01454 log_info("Shan't get back the interface.");
01455 return;
01456 }
01457 memset(&relay->link_address, 0, 16);
01458 }
01459 } else {
01460 relay->hop_count = 0;
01461 if (!dp)
01462 return;
01463 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
01464 }
01465 memcpy(&relay->peer_address, packet->client_addr.iabuf, 16);
01466
01467
01468 opts = NULL;
01469 if (!option_state_allocate(&opts, MDL)) {
01470 log_fatal("No memory for upwards options.");
01471 }
01472
01473
01474 if (use_if_id) {
01475 int if_id;
01476
01477 if (dp) {
01478 if_id = dp->id;
01479 } else if (!downstreams->next) {
01480 if_id = downstreams->id;
01481 } else {
01482 log_info("Don't know the interface.");
01483 option_state_dereference(&opts, MDL);
01484 return;
01485 }
01486
01487 if (!save_option_buffer(&dhcpv6_universe, opts,
01488 NULL, (unsigned char *) &if_id,
01489 sizeof(int),
01490 D6O_INTERFACE_ID, 0)) {
01491 log_error("Can't save interface-id.");
01492 option_state_dereference(&opts, MDL);
01493 return;
01494 }
01495 }
01496
01497
01498
01499 if (dhcrelay_sub_id != NULL) {
01500 if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
01501 (unsigned char *) dhcrelay_sub_id,
01502 strlen(dhcrelay_sub_id),
01503 D6O_SUBSCRIBER_ID, 0)) {
01504 log_error("Can't save subsriber-id.");
01505 option_state_dereference(&opts, MDL);
01506 return;
01507 }
01508 }
01509
01510
01511
01512 if (!save_option_buffer(&dhcpv6_universe, opts,
01513 NULL, (unsigned char *) packet->raw,
01514 packet->packet_length,
01515 D6O_RELAY_MSG, 0)) {
01516 log_error("Can't save relay-msg.");
01517 option_state_dereference(&opts, MDL);
01518 return;
01519 }
01520
01521
01522 cursor += store_options6(forw_data + cursor,
01523 sizeof(forw_data) - cursor,
01524 opts, packet,
01525 required_forw_opts, NULL);
01526 option_state_dereference(&opts, MDL);
01527
01528
01529 for (up = upstreams; up; up = up->next) {
01530 send_packet6(up->ifp, (unsigned char *) forw_data,
01531 (size_t) cursor, &up->link);
01532 }
01533 }
01534
01535
01536
01537
01538 static void
01539 process_down6(struct packet *packet) {
01540 struct stream_list *dp;
01541 struct option_cache *oc;
01542 struct data_string relay_msg;
01543 const struct dhcpv6_packet *msg;
01544 struct data_string if_id;
01545 struct sockaddr_in6 to;
01546 struct iaddr peer;
01547
01548
01549 if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) {
01550 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max)
01551 log_info("Discarding %s from %s port %d going down.",
01552 dhcpv6_type_names[packet->dhcpv6_msg_type],
01553 piaddr(packet->client_addr),
01554 ntohs(packet->client_port));
01555 else
01556 log_info("Unknown %d type from %s port %d going down.",
01557 packet->dhcpv6_msg_type,
01558 piaddr(packet->client_addr),
01559 ntohs(packet->client_port));
01560 return;
01561 }
01562
01563
01564 memset(&relay_msg, 0, sizeof(relay_msg));
01565 memset(&if_id, 0, sizeof(if_id));
01566 memset(&to, 0, sizeof(to));
01567 to.sin6_family = AF_INET6;
01568 #ifdef HAVE_SA_LEN
01569 to.sin6_len = sizeof(to);
01570 #endif
01571 to.sin6_port = remote_port;
01572 peer.len = 16;
01573
01574
01575 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
01576 if (oc == NULL) {
01577 log_info("No relay-msg.");
01578 return;
01579 }
01580 if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL,
01581 packet->options, NULL,
01582 &global_scope, oc, MDL) ||
01583 (relay_msg.len < offsetof(struct dhcpv6_packet, options))) {
01584 log_error("Can't evaluate relay-msg.");
01585 return;
01586 }
01587 msg = (const struct dhcpv6_packet *) relay_msg.data;
01588
01589
01590 oc = lookup_option(&dhcpv6_universe, packet->options,
01591 D6O_INTERFACE_ID);
01592 if (oc != NULL) {
01593 int if_index;
01594
01595 if (!evaluate_option_cache(&if_id, packet, NULL, NULL,
01596 packet->options, NULL,
01597 &global_scope, oc, MDL) ||
01598 (if_id.len != sizeof(int))) {
01599 log_info("Can't evaluate interface-id.");
01600 goto cleanup;
01601 }
01602 memcpy(&if_index, if_id.data, sizeof(int));
01603 for (dp = downstreams; dp; dp = dp->next) {
01604 if (dp->id == if_index)
01605 break;
01606 }
01607 } else {
01608 if (use_if_id) {
01609
01610 log_info("No interface-id.");
01611 goto cleanup;
01612 }
01613 for (dp = downstreams; dp; dp = dp->next) {
01614
01615 if (!memcmp(&dp->link.sin6_addr,
01616 &packet->dhcpv6_link_address,
01617 sizeof(struct in6_addr)))
01618 break;
01619 }
01620 }
01621
01622 if (!dp && downstreams && !downstreams->next)
01623 dp = downstreams;
01624 if (!dp) {
01625 log_info("Can't find the down interface.");
01626 goto cleanup;
01627 }
01628 memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len);
01629 to.sin6_addr = packet->dhcpv6_peer_address;
01630
01631
01632 switch (msg->msg_type) {
01633
01634 case DHCPV6_RELAY_REPL:
01635 to.sin6_port = local_port;
01636
01637
01638 case DHCPV6_ADVERTISE:
01639 case DHCPV6_REPLY:
01640 case DHCPV6_RECONFIGURE:
01641 case DHCPV6_RELAY_FORW:
01642 case DHCPV6_LEASEQUERY_REPLY:
01643 log_info("Relaying %s to %s port %d down.",
01644 dhcpv6_type_names[msg->msg_type],
01645 piaddr(peer),
01646 ntohs(to.sin6_port));
01647 break;
01648
01649 case DHCPV6_SOLICIT:
01650 case DHCPV6_REQUEST:
01651 case DHCPV6_CONFIRM:
01652 case DHCPV6_RENEW:
01653 case DHCPV6_REBIND:
01654 case DHCPV6_RELEASE:
01655 case DHCPV6_DECLINE:
01656 case DHCPV6_INFORMATION_REQUEST:
01657 case DHCPV6_LEASEQUERY:
01658 log_info("Discarding %s to %s port %d down.",
01659 dhcpv6_type_names[msg->msg_type],
01660 piaddr(peer),
01661 ntohs(to.sin6_port));
01662 goto cleanup;
01663
01664 default:
01665 log_info("Unknown %d type to %s port %d down.",
01666 msg->msg_type,
01667 piaddr(peer),
01668 ntohs(to.sin6_port));
01669 goto cleanup;
01670 }
01671
01672
01673 send_packet6(dp->ifp, (unsigned char *) relay_msg.data,
01674 (size_t) relay_msg.len, &to);
01675
01676 cleanup:
01677 if (relay_msg.data != NULL)
01678 data_string_forget(&relay_msg, MDL);
01679 if (if_id.data != NULL)
01680 data_string_forget(&if_id, MDL);
01681 }
01682
01683
01684
01685
01686 void
01687 dhcpv6(struct packet *packet) {
01688 struct stream_list *dp;
01689
01690
01691 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) {
01692 process_down6(packet);
01693 return;
01694 }
01695
01696 for (dp = downstreams; dp; dp = dp->next) {
01697 if (packet->interface != dp->ifp)
01698 continue;
01699 process_up6(packet, dp);
01700 return;
01701 }
01702
01703 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
01704 process_up6(packet, NULL);
01705 return;
01706 }
01707
01708 log_info("Can't process packet from interface '%s'.",
01709 packet->interface->name);
01710 }
01711 #endif
01712
01713
01714 void
01715 bootp(struct packet *packet) {
01716 return;
01717 }
01718
01719 void
01720 dhcp(struct packet *packet) {
01721 return;
01722 }
01723
01724 void
01725 classify(struct packet *p, struct class *c) {
01726 return;
01727 }
01728
01729 int
01730 check_collection(struct packet *p, struct lease *l, struct collection *c) {
01731 return 0;
01732 }
01733
01734 isc_result_t
01735 find_class(struct class **class, const char *c1, const char *c2, int i) {
01736 return ISC_R_NOTFOUND;
01737 }
01738
01739 int
01740 parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
01741 return 0;
01742 }
01743
01744 isc_result_t
01745 dhcp_set_control_state(control_object_state_t oldstate,
01746 control_object_state_t newstate) {
01747 if (newstate != server_shutdown)
01748 return ISC_R_SUCCESS;
01749 exit(0);
01750 }