37 int keep_capabilities = 0;
40 #ifdef HAVE_LIBSYSTEMD 41 #include <systemd/sd-daemon.h> 91 isc_boolean_t use_if_id = ISC_FALSE;
110 struct sockaddr_in
to;
117 struct stream_list *
next;
119 struct sockaddr_in6 link;
121 } *downstreams, *upstreams;
123 static struct stream_list *parse_downstream(
char *);
124 static struct stream_list *parse_upstream(
char *);
125 static void setup_streams(
void);
133 char *dhcrelay_sub_id = NULL;
137 unsigned int,
unsigned int,
struct iaddr,
142 static int find_interface_by_agent_option(
struct dhcp_packet *,
148 static void request_v4_interface(
const char* name,
int flags);
150 static const char copyright[] =
151 "Copyright 2004-2016 Internet Systems Consortium.";
152 static const char arr[] =
"All rights reserved.";
153 static const char message[] =
154 "Internet Systems Consortium DHCP Relay Agent";
155 static const char url[] =
156 "For info, please visit https://www.isc.org/software/dhcp/";
161 #define DHCRELAY_USAGE \ 162 "Usage: %s [-4] [-d] [-q] [-a] [-D]\n"\ 163 " [-A <length>] [-c <hops>] [-p <port>]\n" \ 164 " [-pf <pid-file>] [--no-pid]\n"\ 165 " [-m append|replace|forward|discard]\n" \ 166 " [-i interface0 [ ... -i interfaceN]\n" \ 167 " [-iu interface0 [ ... -iu interfaceN]\n" \ 168 " [-id interface0 [ ... -id interfaceN]\n" \ 169 " [-U interface]\n" \ 170 " server0 [ ... serverN]\n\n" \ 171 " %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \ 172 " [-pf <pid-file>] [--no-pid]\n" \ 173 " [-s <subscriber-id>]\n" \ 174 " -l lower0 [ ... -l lowerN]\n" \ 175 " -u upper0 [ ... -u upperN]\n" \ 176 " lower (client link): [address%%]interface[#index]\n" \ 177 " upper (server link): [address%%]interface" 179 #define DHCRELAY_USAGE \ 180 "Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \ 181 " [-pf <pid-file>] [--no-pid]\n" \ 182 " [-m append|replace|forward|discard]\n" \ 183 " [-i interface0 [ ... -i interfaceN]\n" \ 184 " [-iu interface0 [ ... -iu interfaceN]\n" \ 185 " [-id interface0 [ ... -id interfaceN]\n" \ 186 " [-U interface]\n" \ 187 " server0 [ ... serverN]\n\n" 205 static const char use_noarg[] =
"No argument for command: %s";
207 static const char use_badproto[] =
"Protocol already set, %s inappropriate";
208 static const char use_v4command[] =
"Command not used for DHCPv6: %s";
209 static const char use_v6command[] =
"Command not used for DHCPv4: %s";
213 usage(
const char *sfmt,
const char *sarg) {
216 #ifdef PRINT_SPECIFIC_CL_ERRORS 233 char *service_local = NULL, *service_remote = NULL;
234 u_int16_t port_local = 0, port_remote = 0;
239 struct stream_list *sl = NULL;
240 int local_family_set = 0;
252 fd = open(
"/dev/null", O_RDWR | O_CLOEXEC);
254 fd = open(
"/dev/null", O_RDWR | O_CLOEXEC);
256 fd = open(
"/dev/null", O_RDWR | O_CLOEXEC);
265 setlogmask(LOG_UPTO(LOG_INFO));
271 if (status != ISC_R_SUCCESS)
272 log_fatal(
"Can't initialize context: %s",
273 isc_result_totext(status));
277 if (status != ISC_R_SUCCESS)
279 isc_result_totext(status));
284 for (i = 1; i < argc; i++) {
285 if (!strcmp(argv[i],
"-4")) {
288 usage(use_badproto,
"-4");
290 local_family_set = 1;
292 }
else if (!strcmp(argv[i],
"-6")) {
294 usage(use_badproto,
"-6");
296 local_family_set = 1;
299 }
else if (!strcmp(argv[i],
"-d")) {
301 }
else if (!strcmp(argv[i],
"-q")) {
304 }
else if (!strcmp(argv[i],
"-p")) {
306 usage(use_noarg, argv[i-1]);
308 log_debug(
"binding to user-specified port %d",
310 }
else if (!strcmp(argv[i],
"-c")) {
313 usage(use_noarg, argv[i-1]);
314 hcount = atoi(argv[i]);
318 usage(
"Bad hop count to -c: %s", argv[i]);
319 }
else if (!strcmp(argv[i],
"-i")) {
322 usage(use_v4command, argv[i]);
324 local_family_set = 1;
328 usage(use_noarg, argv[i-1]);
332 }
else if (!strcmp(argv[i],
"-iu")) {
335 usage(use_v4command, argv[i]);
337 local_family_set = 1;
341 usage(use_noarg, argv[i-1]);
345 }
else if (!strcmp(argv[i],
"-id")) {
348 usage(use_v4command, argv[i]);
350 local_family_set = 1;
354 usage(use_noarg, argv[i-1]);
358 }
else if (!strcmp(argv[i],
"-a")) {
361 usage(use_v4command, argv[i]);
363 local_family_set = 1;
367 }
else if (!strcmp(argv[i],
"-A")) {
370 usage(use_v4command, argv[i]);
372 local_family_set = 1;
376 usage(use_noarg, argv[i-1]);
382 "longest possible MTU\n",
384 }
else if (!strcmp(argv[i],
"-m")) {
387 usage(use_v4command, argv[i]);
389 local_family_set = 1;
393 usage(use_noarg, argv[i-1]);
394 if (!strcasecmp(argv[i],
"append")) {
396 }
else if (!strcasecmp(argv[i],
"replace")) {
398 }
else if (!strcasecmp(argv[i],
"forward")) {
400 }
else if (!strcasecmp(argv[i],
"discard")) {
403 usage(
"Unknown argument to -m: %s", argv[i]);
404 }
else if (!strcmp(argv [i],
"-U")) {
406 usage(use_noarg, argv[i-1]);
409 usage(
"more than one uplink (-U) specified: %s" 414 status = interface_allocate(&uplink,
MDL);
415 if (status != ISC_R_SUCCESS) {
416 log_fatal(
"%s: uplink interface_allocate: %s",
417 argv[i], isc_result_totext(status));
420 if (strlen(argv[i]) >=
sizeof(uplink->
name)) {
422 " it cannot exceed: %ld characters",
423 argv[i], (
long)(
sizeof(uplink->
name) - 1));
426 uplink->
name[
sizeof(uplink->
name) - 1] = 0x00;
427 strncpy(uplink->
name, argv[i],
428 sizeof(uplink->
name) - 1);
435 }
else if (!strcmp(argv[i],
"-D")) {
438 usage(use_v4command, argv[i]);
440 local_family_set = 1;
445 }
else if (!strcmp(argv[i],
"-I")) {
447 usage(use_v6command, argv[i]);
449 local_family_set = 1;
451 use_if_id = ISC_TRUE;
452 }
else if (!strcmp(argv[i],
"-l")) {
454 usage(use_v6command, argv[i]);
456 local_family_set = 1;
458 if (downstreams != NULL)
459 use_if_id = ISC_TRUE;
461 usage(use_noarg, argv[i-1]);
462 sl = parse_downstream(argv[i]);
463 sl->next = downstreams;
465 }
else if (!strcmp(argv[i],
"-u")) {
467 usage(use_v6command, argv[i]);
469 local_family_set = 1;
472 usage(use_noarg, argv[i-1]);
473 sl = parse_upstream(argv[i]);
474 sl->next = upstreams;
476 }
else if (!strcmp(argv[i],
"-s")) {
478 usage(use_v6command, argv[i]);
480 local_family_set = 1;
483 usage(use_noarg, argv[i-1]);
484 dhcrelay_sub_id = argv[i];
486 }
else if (!strcmp(argv[i],
"-nc")) {
487 #ifdef HAVE_LIBCAP_NG 488 keep_capabilities = 1;
490 }
else if (!strcmp(argv[i],
"-pf")) {
492 usage(use_noarg, argv[i-1]);
495 }
else if (!strcmp(argv[i],
"--no-pid")) {
497 }
else if (!strcmp(argv[i],
"--version")) {
500 }
else if (!strcmp(argv[i],
"--help") ||
501 !strcmp(argv[i],
"-h")) {
508 }
else if (argv[i][0] ==
'-') {
509 usage(
"Unknown command: %s", argv[i]);
512 struct in_addr ia, *iap = NULL;
516 usage(use_v4command, argv[i]);
518 local_family_set = 1;
521 if (inet_aton(argv[i], &ia)) {
524 he = gethostbyname(argv[i]);
528 iap = ((
struct in_addr *)
540 memcpy(&sp->
to.sin_addr, iap,
sizeof *iap);
564 #ifdef HAVE_LIBCAP_NG 566 if (!keep_capabilities) {
567 capng_clear(CAPNG_SELECT_BOTH);
568 capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED,
569 CAP_NET_RAW, CAP_NET_BIND_SERVICE, -1);
570 capng_apply(CAPNG_SELECT_BOTH);
571 log_info (
"Dropped all unnecessary capabilities.");
585 service_local =
"bootps";
586 service_remote =
"bootpc";
587 port_local = htons(67);
588 port_remote = htons(68);
592 service_local =
"dhcpv6-server";
593 service_remote =
"dhcpv6-client";
594 port_local = htons(547);
595 port_remote = htons(546);
600 ent = getservbyname(service_local,
"udp");
606 ent = getservbyname(service_remote,
"udp");
625 sp->
to.sin_family = AF_INET;
627 sp->
to.sin_len =
sizeof sp->
to;
636 if (upstreams == NULL || downstreams == NULL) {
637 log_info(
"Must specify at least one lower " 638 "and one upper interface.\n");
647 if (!option_code_hash_lookup(&requested_opts[0],
650 log_fatal(
"Unable to find the RELAY_MSG " 651 "option definition.");
653 if (!option_code_hash_lookup(&requested_opts[1],
656 log_fatal(
"Unable to find the INTERFACE_ID " 657 "option definition.");
662 gettimeofday(&
cur_tv, NULL);
680 if ((pid = fork()) < 0)
687 O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644);
693 pf = fdopen(pfdesc,
"we");
698 fprintf(pf,
"%ld\n",(
long)getpid());
720 #if defined(ENABLE_GENTLE_SHUTDOWN) 727 #ifdef HAVE_LIBCAP_NG 729 if (!keep_capabilities) {
730 capng_clear(CAPNG_SELECT_BOTH);
731 capng_apply(CAPNG_SELECT_BOTH);
732 log_info (
"Dropped all capabilities.");
736 #ifdef HAVE_LIBSYSTEMD 738 sd_notifyf(0,
"READY=1\n" 739 "STATUS=Dispatching packets...\n" 741 (
unsigned long) getpid());
753 unsigned int length,
unsigned int from_port,
struct iaddr from,
756 struct sockaddr_in to;
761 log_info(
"Discarding packet with invalid hlen, received on " 762 "%s interface.", ip->
name);
766 log_info(
"Discarding packet received on %s interface that " 767 "has no IPv4 address assigned.", ip->
name);
773 if (packet->
giaddr.s_addr) {
801 to.sin_addr = packet->
yiaddr;
807 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
813 to.sin_family = AF_INET;
815 to.sin_len =
sizeof to;
827 strip_relay_agent_options(ip, &out, packet, length)))
831 log_error(
"Packet to bogus giaddr %s.\n",
832 inet_ntoa(packet->
giaddr));
841 log_debug(
"Forwarded BOOTREPLY for %s to %s",
844 inet_ntoa(to.sin_addr));
864 if (!(length = add_relay_agent_options(ip, packet, length,
873 if (!packet->
giaddr.s_addr)
886 &sp->
to, NULL) < 0) {
889 log_debug(
"Forwarded BOOTREQUEST for %s to %s",
892 inet_ntoa(sp->
to.sin_addr));
909 u_int8_t *op, *nextop, *sp, *max;
910 int good_agent_option = 0;
923 max = ((u_int8_t *)packet) + length;
958 nextop = op + op[1] + 2;
962 status = find_interface_by_agent_option(packet,
968 good_agent_option = 1;
978 nextop = op + op[1] + 2;
983 memmove(sp, op, op[1] + 2);
1003 if (!good_agent_option) {
1011 length = sp -((u_int8_t *)packet);
1036 find_interface_by_agent_option(
struct dhcp_packet *packet,
1038 u_int8_t *buf,
int len) {
1040 u_int8_t *circuit_id = 0;
1041 unsigned circuit_id_len = 0;
1048 i + buf[i + 1] + 2 > len) {
1055 circuit_id = &buf[i + 2];
1056 circuit_id_len = buf[i + 1];
1057 i += circuit_id_len + 2;
1061 i += buf[i + 1] + 2;
1079 !memcmp(ip->
circuit_id, circuit_id, circuit_id_len))
1101 unsigned length,
struct in_addr
giaddr) {
1102 int is_dhcp = 0, mms;
1104 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
1105 int adding_link_select;
1121 && (packet->
giaddr.s_addr == 0));
1124 sp = op = &packet->
options[4];
1139 if (end_pad == NULL)
1159 mms = ntohs(*(op + 2));
1162 max = ((u_int8_t *)packet) + mms;
1205 nextop = op + op[1] + 2;
1212 memmove(sp, op, op[1] + 2);
1230 if (end_pad != NULL)
1241 log_fatal(
"Circuit ID length %d out of range [1-255] on " 1247 log_fatal(
"Remote ID length %d out of range [1-255] " 1252 if (adding_link_select) {
1259 if ((optlen < 3) ||(optlen > 255))
1260 log_fatal(
"Total agent option length(%u) out of range " 1261 "[3 - 255] on %s\n", optlen, ip->
name);
1267 if (max - sp >= optlen + 3) {
1268 log_debug(
"Adding %d-byte relay agent option", optlen + 3);
1291 if (adding_link_select) {
1294 memcpy(sp, &giaddr.s_addr, 4);
1297 log_debug (
"Adding link selection suboption" 1298 " with addr: %s", inet_ntoa(giaddr));
1302 log_error(
"No room in packet (used %d of %d) " 1303 "for %d-byte relay agent option: omitted",
1304 (
int) (sp - ((u_int8_t *) packet)),
1305 (
int) (max - ((u_int8_t *) packet)),
1317 length = sp -((u_int8_t *)packet);
1332 static struct stream_list *
1333 parse_downstream(
char *arg) {
1334 struct stream_list *dp, *
up;
1336 char *ifname, *addr, *iid;
1337 isc_result_t status;
1340 (downstreams != NULL))
1341 log_fatal(
"No support for multiple interfaces.");
1344 ifname = strchr(arg,
'%');
1345 if (ifname == NULL) {
1352 iid = strchr(ifname,
'#');
1356 if (strlen(ifname) >=
sizeof(ifp->
name)) {
1357 usage(
"Interface name '%s' too long", ifname);
1361 for (dp = downstreams; dp; dp = dp->next) {
1362 if (strcmp(ifname, dp->ifp->name) == 0)
1363 log_fatal(
"Down interface '%s' declared twice.",
1368 for (up = upstreams;
up; up = up->next) {
1369 if (strcmp(ifname, up->ifp->name) == 0) {
1370 log_info(
"parse_downstream: Interface '%s' is " 1371 "both down and up.", ifname);
1379 status = interface_allocate(&ifp,
MDL);
1380 if (status != ISC_R_SUCCESS)
1382 arg, isc_result_totext(status));
1383 strcpy(ifp->
name, ifname);
1393 dp = (
struct stream_list *)
dmalloc(
sizeof(*dp),
MDL);
1403 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
1404 log_fatal(
"Bad link address '%s'", addr);
1412 static struct stream_list *
1413 parse_upstream(
char *arg) {
1414 struct stream_list *
up, *dp;
1416 char *ifname, *addr;
1417 isc_result_t status;
1420 ifname = strchr(arg,
'%');
1421 if (ifname == NULL) {
1428 if (strlen(ifname) >=
sizeof(ifp->
name)) {
1429 log_fatal(
"Interface name '%s' too long", ifname);
1433 for (up = upstreams;
up; up = up->next) {
1434 if (strcmp(ifname, up->ifp->name) == 0) {
1439 for (dp = downstreams; dp; dp = dp->next) {
1440 if (strcmp(ifname, dp->ifp->name) == 0) {
1441 log_info(
"parse_upstream: Interface '%s' is " 1442 "both down and up.", ifname);
1450 status = interface_allocate(&ifp,
MDL);
1451 if (status != ISC_R_SUCCESS)
1453 arg, isc_result_totext(status));
1454 strcpy(ifp->
name, ifname);
1464 up = (
struct stream_list *)
dmalloc(
sizeof(*up),
MDL);
1470 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
1480 setup_streams(
void) {
1481 struct stream_list *dp, *
up;
1483 isc_boolean_t link_is_set;
1485 for (dp = downstreams; dp; dp = dp->next) {
1487 if (dp->ifp->v6address_count == 0)
1488 log_fatal(
"Interface '%s' has no IPv6 addresses.",
1492 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
1493 link_is_set = ISC_FALSE;
1495 link_is_set = ISC_TRUE;
1496 for (i = 0; i < dp->ifp->v6address_count; i++) {
1497 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
1501 if (!memcmp(&dp->ifp->v6addresses[i],
1502 &dp->link.sin6_addr,
1503 sizeof(dp->link.sin6_addr)))
1506 if (i == dp->ifp->v6address_count)
1507 log_fatal(
"Interface %s does not have global IPv6 " 1508 "address assigned.", dp->ifp->name);
1510 memcpy(&dp->link.sin6_addr,
1511 &dp->ifp->v6addresses[i],
1512 sizeof(dp->link.sin6_addr));
1516 dp->id = dp->ifp->index;
1519 for (up = upstreams;
up; up = up->next) {
1521 up->link.sin6_family = AF_INET6;
1523 up->link.sin6_len =
sizeof(up->link);
1526 if (up->ifp->v6address_count == 0)
1527 log_fatal(
"Interface '%s' has no IPv6 addresses.",
1533 if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) {
1542 static const int required_forw_opts[] = {
1553 process_up6(
struct packet *packet,
struct stream_list *dp) {
1554 char forw_data[65535];
1558 struct stream_list *
up;
1573 log_info(
"Relaying %s from %s port %d going up.",
1585 log_info(
"Discarding %s from %s port %d going up.",
1592 log_info(
"Unknown %d type from %s port %d going up.",
1613 if (!use_if_id && downstreams->next) {
1614 log_info(
"Shan't get back the interface.");
1630 log_fatal(
"No memory for upwards options.");
1639 }
else if (!downstreams->next) {
1640 if_id = downstreams->id;
1642 log_info(
"Don't know the interface.");
1648 NULL, (
unsigned char *) &if_id,
1659 if (dhcrelay_sub_id != NULL) {
1661 (
unsigned char *) dhcrelay_sub_id,
1662 strlen(dhcrelay_sub_id),
1673 NULL, (
unsigned char *) packet->
raw,
1683 sizeof(forw_data) - cursor,
1685 required_forw_opts, NULL);
1689 for (up = upstreams;
up; up = up->next) {
1691 (
size_t) cursor, &up->link);
1699 process_down6(
struct packet *packet) {
1700 struct stream_list *dp;
1705 struct sockaddr_in6 to;
1711 log_info(
"Discarding %s from %s port %d going down.",
1716 log_info(
"Unknown %d type from %s port %d going down.",
1724 memset(&relay_msg, 0,
sizeof(relay_msg));
1725 memset(&if_id, 0,
sizeof(if_id));
1726 memset(&to, 0,
sizeof(to));
1727 to.sin6_family = AF_INET6;
1729 to.sin6_len =
sizeof(
to);
1758 (if_id.
len !=
sizeof(
int))) {
1759 log_info(
"Can't evaluate interface-id.");
1762 memcpy(&if_index, if_id.
data,
sizeof(
int));
1763 for (dp = downstreams; dp; dp = dp->next) {
1764 if (dp->id == if_index)
1773 for (dp = downstreams; dp; dp = dp->next) {
1775 if (!memcmp(&dp->link.sin6_addr,
1777 sizeof(
struct in6_addr)))
1782 if (!dp && downstreams && !downstreams->next)
1785 log_info(
"Can't find the down interface.");
1804 log_info(
"Relaying %s to %s port %d down.",
1807 ntohs(to.sin6_port));
1820 log_info(
"Discarding %s to %s port %d down.",
1823 ntohs(to.sin6_port));
1827 log_info(
"Unknown %d type to %s port %d down.",
1830 ntohs(to.sin6_port));
1836 (
size_t) relay_msg.
len, &to);
1839 if (relay_msg.
data != NULL)
1841 if (if_id.
data != NULL)
1849 dhcpv6(
struct packet *packet) {
1850 struct stream_list *dp;
1854 process_down6(packet);
1858 for (dp = downstreams; dp; dp = dp->next) {
1861 process_up6(packet, dp);
1866 process_up6(packet, NULL);
1870 log_info(
"Can't process packet from interface '%s'.",
1897 find_class(
struct class **
class,
const char *c1,
const char *c2,
int i) {
1898 return ISC_R_NOTFOUND;
1910 return ISC_R_SUCCESS;
1931 void request_v4_interface(
const char* name,
int flags) {
1933 int len = strlen(
name);
1934 isc_result_t status;
1936 if (len >=
sizeof(tmp->
name)) {
1937 log_fatal(
"%s: interface name too long (is %d)",
name, len);
1940 status = interface_allocate(&tmp,
MDL);
1941 if (status != ISC_R_SUCCESS) {
1943 isc_result_totext(status));
1946 log_debug(
"Requesting: %s as upstream: %c downstream: %c",
name,
1952 interface_dereference(&tmp,
MDL);
void do_packet6(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t)
void(* dhcpv6_packet_handler)(struct interface_info *, const char *, int, int, const struct iaddr *, isc_boolean_t)
unsigned char peer_address[16]
#define DHO_DHCP_AGENT_OPTIONS
int drop_agent_mismatches
isc_boolean_t no_dhcrelay_pid
struct tree_cache * global_options[256]
struct binding_scope * global_scope
const char * piaddr(const struct iaddr addr)
void bootp(struct packet *packet)
unsigned char options[FLEXIBLE_ARRAY_MEMBER]
void(* bootp_packet_handler)(struct interface_info *, struct dhcp_packet *, unsigned, unsigned int, struct iaddr, struct hardware *)
int check_collection(struct packet *p, struct lease *l, struct collection *c)
char * print_hw_addr(int htype, const int hlen, const unsigned char *data) const
const char * dhcpv6_type_names[]
int int int log_debug(const char *,...) __attribute__((__format__(__printf__
#define DHCPV6_RECONFIGURE
const char * path_dhcrelay_pid
isc_result_t dhcp_set_control_state(control_object_state_t oldstate, control_object_state_t newstate)
#define DHCP_CONTEXT_PRE_DB
struct in_addr * addresses
void data_string_forget(struct data_string *data, const char *file, int line)
int log_error(const char *,...) __attribute__((__format__(__printf__
#define DHCPV6_DHCPV4_QUERY
int dhcp_max_agent_option_packet_length
struct option_state * options
unsigned char dhcpv6_hop_count
unsigned char link_address[16]
unsigned char dhcpv6_msg_type
void log_fatal(const char *,...) __attribute__((__format__(__printf__
#define DHCPV6_RELAY_REPL
#define DHCPV6_LEASEQUERY
#define DHCP_CONTEXT_POST_DB
isc_boolean_t no_pid_file
struct option * requested_opts[2]
u_int16_t validate_port(char *port)
void dhcp_signal_handler(int signal)
struct server_list * next
struct interface_info * fallback_interface
int option_state_allocate(struct option_state **ptr, const char *file, int line)
isc_result_t dhcp_context_create(int flags, struct in_addr *local4, struct in6_addr *local6)
int evaluate_option_cache(struct data_string *result, struct packet *packet, struct lease *lease, struct client_state *client_state, struct option_state *in_options, struct option_state *cfg_options, struct binding_scope **scope, struct option_cache *oc, const char *file, int line)
#define DHCPV6_DHCPV4_RESPONSE
enum @28 agent_relay_mode
#define _PATH_DHCRELAY6_PID
struct interface_info * interface
ssize_t send_packet6(struct interface_info *, const unsigned char *, size_t, struct sockaddr_in6 *)
#define D6O_SUBSCRIBER_ID
int parse_allow_deny(struct option_cache **oc, struct parse *p, int i)
ssize_t send_packet(struct interface_info *, struct packet *, struct dhcp_packet *, size_t, struct in_addr, struct sockaddr_in *, struct hardware *)
#define DHCPV6_RELAY_FORW
int save_option_buffer(struct universe *universe, struct option_state *options, struct buffer *bp, unsigned char *buffer, unsigned length, unsigned code, int terminatep)
struct interface_info * uplink
struct option_cache * lookup_option(struct universe *universe, struct option_state *options, unsigned code)
int int log_info(const char *,...) __attribute__((__format__(__printf__
void * dmalloc(size_t, const char *, int)
int server_packets_relayed
struct interface_info * interfaces
void interface_snorf(struct interface_info *tmp, int ir)
void dhcp(struct packet *packet)
#define DHO_DHCP_MAX_MESSAGE_SIZE
#define DHCPV6_LEASEQUERY_REPLY
int store_options6(char *buf, int buflen, struct option_state *opt_state, struct packet *packet, const int *required_opts, struct data_string *oro)
int quiet_interface_discovery
int option_state_dereference(struct option_state **ptr, const char *file, int line)
void initialize_common_option_spaces()
void dhcpv6(struct packet *)
const int dhcpv6_type_name_max
struct interface_info * next
struct universe dhcpv6_universe
void classify(struct packet *p, struct class *c)
int supports_multiple_interfaces(struct interface_info *)
isc_result_t interface_setup()
u_int8_t hbuf[HARDWARE_ADDR_LEN+1]
#define INTERFACE_UPSTREAM
struct server_list * servers
void set_multicast_hop_limit(struct interface_info *info, int hop_limit)
#define INTERFACE_DOWNSTREAM
option_code_hash_t * code_hash
#define _PATH_DHCRELAY_PID
struct in6_addr dhcpv6_peer_address
int can_unicast_without_arp(struct interface_info *)
int add_rfc3527_suboption
const unsigned char * data
#define DHO_DHCP_MESSAGE_TYPE
int corrupt_agent_options
#define DHCPV6_INFORMATION_REQUEST
#define INTERFACE_STREAMS
struct in6_addr dhcpv6_link_address
int main(int argc, char **argv)
void discover_interfaces(int state)
#define DHCP_OPTIONS_COOKIE
#define INTERFACE_REQUESTED
int client_packets_relayed
isc_result_t omapi_init(void)
unsigned char options[DHCP_MAX_OPTION_LEN]
isc_result_t find_class(struct class **class, const char *c1, const char *c2, int i)