3 DHCP/BOOTP Relay Agent. */
6 * Copyright(c) 2004-2016 by Internet Systems Consortium, Inc.("ISC")
7 * Copyright(c) 1997-2003 by Internet Software Consortium
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
13 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Internet Systems Consortium, Inc.
23 * Redwood City, CA 94063
25 * https://www.isc.org/
35 TIME default_lease_time
= 43200; /* 12 hours... */
36 TIME max_lease_time
= 86400; /* 24 hours... */
37 struct tree_cache
*global_options
[256];
39 struct option
*requested_opts
[2];
41 /* Needed to prevent linking against conflex.c. */
47 const char *path_dhcrelay_pid
= _PATH_DHCRELAY_PID
;
48 isc_boolean_t no_dhcrelay_pid
= ISC_FALSE
;
49 /* False (default) => we write and use a pid file */
50 isc_boolean_t no_pid_file
= ISC_FALSE
;
52 int bogus_agent_drops
= 0; /* Packets dropped because agent option
53 field was specified and we're not relaying
54 packets that already have an agent option
56 int bogus_giaddr_drops
= 0; /* Packets sent to us to relay back to a
57 client, but with a bogus giaddr. */
58 int client_packets_relayed
= 0; /* Packets relayed from client to server. */
59 int server_packet_errors
= 0; /* Errors sending packets to servers. */
60 int server_packets_relayed
= 0; /* Packets relayed from server to client. */
61 int client_packet_errors
= 0; /* Errors sending packets to clients. */
63 int add_agent_options
= 0; /* If nonzero, add relay agent options. */
64 int add_rfc3527_suboption
= 0; /* If nonzero, add RFC3527 link selection sub-option. */
66 int agent_option_errors
= 0; /* Number of packets forwarded without
67 agent options because there was no room. */
68 int drop_agent_mismatches
= 0; /* If nonzero, drop server replies that
69 don't have matching circuit-id's. */
70 int corrupt_agent_options
= 0; /* Number of packets dropped because
71 relay agent information option was bad. */
72 int missing_agent_option
= 0; /* Number of packets dropped because no
73 RAI option matching our ID was found. */
74 int bad_circuit_id
= 0; /* Circuit ID option in matching RAI option
75 did not match any known circuit ID. */
76 int missing_circuit_id
= 0; /* Circuit ID option in matching RAI option
78 int max_hop_count
= 10; /* Maximum hop count */
81 /* Force use of DHCPv6 interface-id option. */
82 isc_boolean_t use_if_id
= ISC_FALSE
;
85 /* Maximum size of a packet with agent options added. */
86 int dhcp_max_agent_option_packet_length
= DHCP_MTU_MIN
;
88 /* What to do about packets we're asked to relay that
89 already have a relay option: */
90 enum { forward_and_append
, /* Forward and append our own relay option. */
91 forward_and_replace
, /* Forward, but replace theirs with ours. */
92 forward_untouched
, /* Forward without changes. */
93 discard
} agent_relay_mode
= forward_and_replace
;
96 u_int16_t remote_port
;
98 /* Relay agent server list. */
100 struct server_list
*next
;
101 struct sockaddr_in to
;
104 struct interface_info
*uplink
= NULL
;
108 struct stream_list
*next
;
109 struct interface_info
*ifp
;
110 struct sockaddr_in6 link
;
112 } *downstreams
, *upstreams
;
114 static struct stream_list
*parse_downstream(char *);
115 static struct stream_list
*parse_upstream(char *);
116 static void setup_streams(void);
119 * A pointer to a subscriber id to add to the message we forward.
120 * This is primarily for testing purposes as we only have one id
121 * for the entire relay and don't determine one per client which
122 * would be more useful.
124 char *dhcrelay_sub_id
= NULL
;
127 static void do_relay4(struct interface_info
*, struct dhcp_packet
*,
128 unsigned int, unsigned int, struct iaddr
,
130 static int add_relay_agent_options(struct interface_info
*,
131 struct dhcp_packet
*, unsigned,
133 static int find_interface_by_agent_option(struct dhcp_packet
*,
134 struct interface_info
**, u_int8_t
*, int);
135 static int strip_relay_agent_options(struct interface_info
*,
136 struct interface_info
**,
137 struct dhcp_packet
*, unsigned);
139 static const char copyright
[] =
140 "Copyright 2004-2015 Internet Systems Consortium.";
141 static const char arr
[] = "All rights reserved.";
142 static const char message
[] =
143 "Internet Systems Consortium DHCP Relay Agent";
144 static const char url
[] =
145 "For info, please visit https://www.isc.org/software/dhcp/";
150 #define DHCRELAY_USAGE \
151 "Usage: %s [-4] [-d] [-q] [-a] [-D]\n"\
152 " [-A <length>] [-c <hops>] [-p <port>]\n" \
153 " [-pf <pid-file>] [--no-pid]\n"\
154 " [-m append|replace|forward|discard]\n" \
155 " [-i interface0 [ ... -i interfaceN]\n" \
156 " [-u interface]\n" \
157 " server0 [ ... serverN]\n\n" \
158 " %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
159 " [-pf <pid-file>] [--no-pid]\n" \
160 " [-s <subscriber-id>]\n" \
161 " -l lower0 [ ... -l lowerN]\n" \
162 " -u upper0 [ ... -u upperN]\n" \
163 " lower (client link): [address%%]interface[#index]\n" \
164 " upper (server link): [address%%]interface"
166 #define DHCRELAY_USAGE \
167 "Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
168 " [-pf <pid-file>] [--no-pid]\n" \
169 " [-m append|replace|forward|discard]\n" \
170 " [-i interface0 [ ... -i interfaceN]\n" \
171 " [-u interface]\n" \
172 " server0 [ ... serverN]\n\n"
177 * \brief Print the generic usage message
179 * If the user has provided an incorrect command line print out
180 * the description of the command line. The arguments provide
181 * a way for the caller to request more specific information about
182 * the error be printed as well. Mostly this will be that some
183 * comamnd doesn't include its argument.
185 * \param sfmt - The basic string and format for the specific error
186 * \param sarg - Generally the offending argument from the comamnd line.
190 static const char use_noarg
[] = "No argument for command: %s";
192 static const char use_badproto
[] = "Protocol already set, %s inappropriate";
193 static const char use_v4command
[] = "Command not used for DHCPv6: %s";
194 static const char use_v6command
[] = "Command not used for DHCPv4: %s";
198 usage(const char *sfmt
, const char *sarg
) {
200 /* If desired print out the specific error message */
201 #ifdef PRINT_SPECIFIC_CL_ERRORS
203 log_error(sfmt
, sarg
);
206 log_fatal(DHCRELAY_USAGE
,
208 isc_file_basename(progname
),
210 isc_file_basename(progname
));
214 main(int argc
, char **argv
) {
217 struct server_list
*sp
= NULL
;
218 struct interface_info
*tmp
= NULL
;
219 char *service_local
= NULL
, *service_remote
= NULL
;
220 u_int16_t port_local
= 0, port_remote
= 0;
221 int no_daemon
= 0, quiet
= 0;
225 struct stream_list
*sl
= NULL
;
226 int local_family_set
= 0;
230 progname
= "dhcrelay";
235 /* Make sure that file descriptors 0(stdin), 1,(stdout), and
236 2(stderr) are open. To do this, we assume that when we
237 open a file the lowest available file descriptor is used. */
238 fd
= open("/dev/null", O_RDWR
);
240 fd
= open("/dev/null", O_RDWR
);
242 fd
= open("/dev/null", O_RDWR
);
244 log_perror
= 0; /* No sense logging to /dev/null. */
248 openlog(isc_file_basename(progname
), DHCP_LOG_OPTIONS
, LOG_DAEMON
);
251 setlogmask(LOG_UPTO(LOG_INFO
));
254 /* Set up the isc and dns library managers */
255 status
= dhcp_context_create(DHCP_CONTEXT_PRE_DB
| DHCP_CONTEXT_POST_DB
,
257 if (status
!= ISC_R_SUCCESS
)
258 log_fatal("Can't initialize context: %s",
259 isc_result_totext(status
));
261 /* Set up the OMAPI. */
262 status
= omapi_init();
263 if (status
!= ISC_R_SUCCESS
)
264 log_fatal("Can't initialize OMAPI: %s",
265 isc_result_totext(status
));
267 /* Set up the OMAPI wrappers for the interface object. */
270 for (i
= 1; i
< argc
; i
++) {
271 if (!strcmp(argv
[i
], "-4")) {
273 if (local_family_set
&& (local_family
== AF_INET6
)) {
274 usage(use_badproto
, "-4");
276 local_family_set
= 1;
277 local_family
= AF_INET
;
278 } else if (!strcmp(argv
[i
], "-6")) {
279 if (local_family_set
&& (local_family
== AF_INET
)) {
280 usage(use_badproto
, "-6");
282 local_family_set
= 1;
283 local_family
= AF_INET6
;
285 } else if (!strcmp(argv
[i
], "-d")) {
287 } else if (!strcmp(argv
[i
], "-q")) {
289 quiet_interface_discovery
= 1;
290 } else if (!strcmp(argv
[i
], "-p")) {
292 usage(use_noarg
, argv
[i
-1]);
293 local_port
= validate_port(argv
[i
]);
294 log_debug("binding to user-specified port %d",
296 } else if (!strcmp(argv
[i
], "-c")) {
299 usage(use_noarg
, argv
[i
-1]);
300 hcount
= atoi(argv
[i
]);
302 max_hop_count
= hcount
;
304 usage("Bad hop count to -c: %s", argv
[i
]);
305 } else if (!strcmp(argv
[i
], "-i")) {
307 if (local_family_set
&& (local_family
== AF_INET6
)) {
308 usage(use_v4command
, argv
[i
]);
310 local_family_set
= 1;
311 local_family
= AF_INET
;
314 usage(use_noarg
, argv
[i
-1]);
316 if (strlen(argv
[i
]) >= sizeof(tmp
->name
)) {
317 log_fatal("%s: interface name too long "
319 argv
[i
], (long)strlen(argv
[i
]));
321 status
= interface_allocate(&tmp
, MDL
);
322 if (status
!= ISC_R_SUCCESS
) {
323 log_fatal("%s: interface_allocate: %s",
325 isc_result_totext(status
));
327 strcpy(tmp
->name
, argv
[i
]);
328 interface_snorf(tmp
, INTERFACE_REQUESTED
);
329 interface_dereference(&tmp
, MDL
);
330 } else if (!strcmp(argv
[i
], "-a")) {
332 if (local_family_set
&& (local_family
== AF_INET6
)) {
333 usage(use_v4command
, argv
[i
]);
335 local_family_set
= 1;
336 local_family
= AF_INET
;
338 add_agent_options
= 1;
339 } else if (!strcmp(argv
[i
], "-A")) {
341 if (local_family_set
&& (local_family
== AF_INET6
)) {
342 usage(use_v4command
, argv
[i
]);
344 local_family_set
= 1;
345 local_family
= AF_INET
;
348 usage(use_noarg
, argv
[i
-1]);
350 dhcp_max_agent_option_packet_length
= atoi(argv
[i
]);
352 if (dhcp_max_agent_option_packet_length
> DHCP_MTU_MAX
)
353 log_fatal("%s: packet length exceeds "
354 "longest possible MTU\n",
356 } else if (!strcmp(argv
[i
], "-m")) {
358 if (local_family_set
&& (local_family
== AF_INET6
)) {
359 usage(use_v4command
, argv
[i
]);
361 local_family_set
= 1;
362 local_family
= AF_INET
;
365 usage(use_noarg
, argv
[i
-1]);
366 if (!strcasecmp(argv
[i
], "append")) {
367 agent_relay_mode
= forward_and_append
;
368 } else if (!strcasecmp(argv
[i
], "replace")) {
369 agent_relay_mode
= forward_and_replace
;
370 } else if (!strcasecmp(argv
[i
], "forward")) {
371 agent_relay_mode
= forward_untouched
;
372 } else if (!strcasecmp(argv
[i
], "discard")) {
373 agent_relay_mode
= discard
;
375 usage("Unknown argument to -m: %s", argv
[i
]);
376 } else if (!strcmp(argv
[i
], "-u")) {
378 usage(use_noarg
, argv
[i
-1]);
381 usage("more than one uplink (-u) specified: %s"
385 /* Allocate the uplink interface */
386 status
= interface_allocate(&uplink
, MDL
);
387 if (status
!= ISC_R_SUCCESS
) {
388 log_fatal("%s: uplink interface_allocate: %s",
389 argv
[i
], isc_result_totext(status
));
392 if (strlen(argv
[i
]) >= sizeof(uplink
->name
)) {
393 log_fatal("%s: uplink name too long,"
394 " it cannot exceed: %ld characters",
395 argv
[i
], sizeof(uplink
->name
) - 1);
398 uplink
->name
[sizeof(uplink
->name
) - 1] = 0x00;
399 strncpy(uplink
->name
, argv
[i
],
400 sizeof(uplink
->name
) - 1);
401 interface_snorf(uplink
, INTERFACE_REQUESTED
);
403 /* Turn on -a, in case they don't do so explicitly */
404 add_agent_options
= 1;
405 add_rfc3527_suboption
= 1;
406 } else if (!strcmp(argv
[i
], "-D")) {
408 if (local_family_set
&& (local_family
== AF_INET6
)) {
409 usage(use_v4command
, argv
[i
]);
411 local_family_set
= 1;
412 local_family
= AF_INET
;
414 drop_agent_mismatches
= 1;
416 } else if (!strcmp(argv
[i
], "-I")) {
417 if (local_family_set
&& (local_family
== AF_INET
)) {
418 usage(use_v6command
, argv
[i
]);
420 local_family_set
= 1;
421 local_family
= AF_INET6
;
422 use_if_id
= ISC_TRUE
;
423 } else if (!strcmp(argv
[i
], "-l")) {
424 if (local_family_set
&& (local_family
== AF_INET
)) {
425 usage(use_v6command
, argv
[i
]);
427 local_family_set
= 1;
428 local_family
= AF_INET6
;
429 if (downstreams
!= NULL
)
430 use_if_id
= ISC_TRUE
;
432 usage(use_noarg
, argv
[i
-1]);
433 sl
= parse_downstream(argv
[i
]);
434 sl
->next
= downstreams
;
436 } else if (!strcmp(argv
[i
], "-u")) {
437 if (local_family_set
&& (local_family
== AF_INET
)) {
438 usage(use_v6command
, argv
[i
]);
440 local_family_set
= 1;
441 local_family
= AF_INET6
;
443 usage(use_noarg
, argv
[i
-1]);
444 sl
= parse_upstream(argv
[i
]);
445 sl
->next
= upstreams
;
447 } else if (!strcmp(argv
[i
], "-s")) {
448 if (local_family_set
&& (local_family
== AF_INET
)) {
449 usage(use_v6command
, argv
[i
]);
451 local_family_set
= 1;
452 local_family
= AF_INET6
;
454 usage(use_noarg
, argv
[i
-1]);
455 dhcrelay_sub_id
= argv
[i
];
457 } else if (!strcmp(argv
[i
], "-pf")) {
459 usage(use_noarg
, argv
[i
-1]);
460 path_dhcrelay_pid
= argv
[i
];
461 no_dhcrelay_pid
= ISC_TRUE
;
462 } else if (!strcmp(argv
[i
], "--no-pid")) {
463 no_pid_file
= ISC_TRUE
;
464 } else if (!strcmp(argv
[i
], "--version")) {
465 log_info("isc-dhcrelay-%s", PACKAGE_VERSION
);
467 } else if (!strcmp(argv
[i
], "--help") ||
468 !strcmp(argv
[i
], "-h")) {
469 log_info(DHCRELAY_USAGE
,
471 isc_file_basename(progname
),
473 isc_file_basename(progname
));
475 } else if (argv
[i
][0] == '-') {
476 usage("Unknown command: %s", argv
[i
]);
479 struct in_addr ia
, *iap
= NULL
;
482 if (local_family_set
&& (local_family
== AF_INET6
)) {
483 usage(use_v4command
, argv
[i
]);
485 local_family_set
= 1;
486 local_family
= AF_INET
;
488 if (inet_aton(argv
[i
], &ia
)) {
491 he
= gethostbyname(argv
[i
]);
493 log_error("%s: host unknown", argv
[i
]);
495 iap
= ((struct in_addr
*)
501 sp
= ((struct server_list
*)
502 dmalloc(sizeof *sp
, MDL
));
504 log_fatal("no memory for server.\n");
507 memcpy(&sp
->to
.sin_addr
, iap
, sizeof *iap
);
513 * If the user didn't specify a pid file directly
514 * find one from environment variables or defaults
516 if (no_dhcrelay_pid
== ISC_FALSE
) {
517 if (local_family
== AF_INET
) {
518 path_dhcrelay_pid
= getenv("PATH_DHCRELAY_PID");
519 if (path_dhcrelay_pid
== NULL
)
520 path_dhcrelay_pid
= _PATH_DHCRELAY_PID
;
524 path_dhcrelay_pid
= getenv("PATH_DHCRELAY6_PID");
525 if (path_dhcrelay_pid
== NULL
)
526 path_dhcrelay_pid
= _PATH_DHCRELAY6_PID
;
532 log_info("%s %s", message
, PACKAGE_VERSION
);
539 /* Set default port */
540 if (local_family
== AF_INET
) {
541 service_local
= "bootps";
542 service_remote
= "bootpc";
543 port_local
= htons(67);
544 port_remote
= htons(68);
548 service_local
= "dhcpv6-server";
549 service_remote
= "dhcpv6-client";
550 port_local
= htons(547);
551 port_remote
= htons(546);
556 ent
= getservbyname(service_local
, "udp");
558 local_port
= ent
->s_port
;
560 local_port
= port_local
;
562 ent
= getservbyname(service_remote
, "udp");
564 remote_port
= ent
->s_port
;
566 remote_port
= port_remote
;
571 if (local_family
== AF_INET
) {
572 /* We need at least one server */
573 if (servers
== NULL
) {
574 log_fatal("No servers specified.");
578 /* Set up the server sockaddrs. */
579 for (sp
= servers
; sp
; sp
= sp
->next
) {
580 sp
->to
.sin_port
= local_port
;
581 sp
->to
.sin_family
= AF_INET
;
583 sp
->to
.sin_len
= sizeof sp
->to
;
591 /* We need at least one upstream and one downstream interface */
592 if (upstreams
== NULL
|| downstreams
== NULL
) {
593 log_info("Must specify at least one lower "
594 "and one upper interface.\n");
598 /* Set up the initial dhcp option universe. */
599 initialize_common_option_spaces();
601 /* Check requested options. */
602 code
= D6O_RELAY_MSG
;
603 if (!option_code_hash_lookup(&requested_opts
[0],
604 dhcpv6_universe
.code_hash
,
606 log_fatal("Unable to find the RELAY_MSG "
607 "option definition.");
608 code
= D6O_INTERFACE_ID
;
609 if (!option_code_hash_lookup(&requested_opts
[1],
610 dhcpv6_universe
.code_hash
,
612 log_fatal("Unable to find the INTERFACE_ID "
613 "option definition.");
617 /* Get the current time... */
618 gettimeofday(&cur_tv
, NULL
);
620 /* Discover all the network interfaces. */
621 discover_interfaces(DISCOVER_RELAY
);
624 if (local_family
== AF_INET6
)
628 /* Become a daemon... */
636 if ((pid
= fork()) < 0)
637 log_fatal("Can't fork daemon: %m");
641 if (no_pid_file
== ISC_FALSE
) {
642 pfdesc
= open(path_dhcrelay_pid
,
643 O_CREAT
| O_TRUNC
| O_WRONLY
, 0644);
646 log_error("Can't create %s: %m",
649 pf
= fdopen(pfdesc
, "w");
651 log_error("Can't fdopen %s: %m",
654 fprintf(pf
, "%ld\n",(long)getpid());
665 IGNORE_RET (chdir("/"));
668 /* Set up the packet handler... */
669 if (local_family
== AF_INET
)
670 bootp_packet_handler
= do_relay4
;
673 dhcpv6_packet_handler
= do_packet6
;
676 #if defined(ENABLE_GENTLE_SHUTDOWN)
677 /* no signal handlers until we deal with the side effects */
678 /* install signal handlers */
679 signal(SIGINT
, dhcp_signal_handler
); /* control-c */
680 signal(SIGTERM
, dhcp_signal_handler
); /* kill */
683 /* Start dispatching packets and timeouts... */
686 /* In fact dispatch() never returns. */
691 do_relay4(struct interface_info
*ip
, struct dhcp_packet
*packet
,
692 unsigned int length
, unsigned int from_port
, struct iaddr from
,
693 struct hardware
*hfrom
) {
694 struct server_list
*sp
;
695 struct sockaddr_in to
;
696 struct interface_info
*out
;
697 struct hardware hto
, *htop
;
699 if (packet
->hlen
> sizeof packet
->chaddr
) {
700 log_info("Discarding packet with invalid hlen, received on "
701 "%s interface.", ip
->name
);
704 if (ip
->address_count
< 1 || ip
->addresses
== NULL
) {
705 log_info("Discarding packet received on %s interface that "
706 "has no IPv4 address assigned.", ip
->name
);
710 /* Find the interface that corresponds to the giaddr
712 if (packet
->giaddr
.s_addr
) {
713 for (out
= interfaces
; out
; out
= out
->next
) {
716 for (i
= 0 ; i
< out
->address_count
; i
++ ) {
717 if (out
->addresses
[i
].s_addr
==
718 packet
->giaddr
.s_addr
) {
731 /* If it's a bootreply, forward it to the client. */
732 if (packet
->op
== BOOTREPLY
) {
733 if (!(packet
->flags
& htons(BOOTP_BROADCAST
)) &&
734 can_unicast_without_arp(out
)) {
735 to
.sin_addr
= packet
->yiaddr
;
736 to
.sin_port
= remote_port
;
738 /* and hardware address is not broadcast */
741 to
.sin_addr
.s_addr
= htonl(INADDR_BROADCAST
);
742 to
.sin_port
= remote_port
;
744 /* hardware address is broadcast */
747 to
.sin_family
= AF_INET
;
749 to
.sin_len
= sizeof to
;
752 memcpy(&hto
.hbuf
[1], packet
->chaddr
, packet
->hlen
);
753 hto
.hbuf
[0] = packet
->htype
;
754 hto
.hlen
= packet
->hlen
+ 1;
756 /* Wipe out the agent relay options and, if possible, figure
757 out which interface to use based on the contents of the
758 option that we put on the request to which the server is
761 strip_relay_agent_options(ip
, &out
, packet
, length
)))
765 log_error("Packet to bogus giaddr %s.\n",
766 inet_ntoa(packet
->giaddr
));
767 ++bogus_giaddr_drops
;
771 if (send_packet(out
, NULL
, packet
, length
, out
->addresses
[0],
773 ++server_packet_errors
;
775 log_debug("Forwarded BOOTREPLY for %s to %s",
776 print_hw_addr(packet
->htype
, packet
->hlen
,
778 inet_ntoa(to
.sin_addr
));
780 ++server_packets_relayed
;
785 /* If giaddr matches one of our addresses, ignore the packet -
790 /* Add relay agent options if indicated. If something goes wrong,
791 * drop the packet. Note this may set packet->giaddr if RFC3527
793 if (!(length
= add_relay_agent_options(ip
, packet
, length
,
797 /* If giaddr is not already set, Set it so the server can
798 figure out what net it's from and so that we can later
799 forward the response to the correct net. If it's already
800 set, the response will be sent directly to the relay agent
801 that set giaddr, so we won't see it. */
802 if (!packet
->giaddr
.s_addr
)
803 packet
->giaddr
= ip
->addresses
[0];
804 if (packet
->hops
< max_hop_count
)
805 packet
->hops
= packet
->hops
+ 1;
809 /* Otherwise, it's a BOOTREQUEST, so forward it to all the
811 for (sp
= servers
; sp
; sp
= sp
->next
) {
812 if (send_packet((fallback_interface
813 ? fallback_interface
: interfaces
),
814 NULL
, packet
, length
, ip
->addresses
[0],
815 &sp
->to
, NULL
) < 0) {
816 ++client_packet_errors
;
818 log_debug("Forwarded BOOTREQUEST for %s to %s",
819 print_hw_addr(packet
->htype
, packet
->hlen
,
821 inet_ntoa(sp
->to
.sin_addr
));
822 ++client_packets_relayed
;
828 /* Strip any Relay Agent Information options from the DHCP packet
829 option buffer. If there is a circuit ID suboption, look up the
830 outgoing interface based upon it. */
833 strip_relay_agent_options(struct interface_info
*in
,
834 struct interface_info
**out
,
835 struct dhcp_packet
*packet
,
838 u_int8_t
*op
, *nextop
, *sp
, *max
;
839 int good_agent_option
= 0;
842 /* If we're not adding agent options to packets, we're not taking
844 if (!add_agent_options
)
847 /* If there's no cookie, it's a bootp packet, so we should just
848 forward it unchanged. */
849 if (memcmp(packet
->options
, DHCP_OPTIONS_COOKIE
, 4))
852 max
= ((u_int8_t
*)packet
) + length
;
853 sp
= op
= &packet
->options
[4];
857 /* Skip padding... */
865 /* If we see a message type, it's a DHCP packet. */
866 case DHO_DHCP_MESSAGE_TYPE
:
871 /* Quit immediately if we hit an End option. */
877 case DHO_DHCP_AGENT_OPTIONS
:
878 /* We shouldn't see a relay agent option in a
879 packet before we've seen the DHCP packet type,
880 but if we do, we have to leave it alone. */
884 /* Do not process an agent option if it exceeds the
885 * buffer. Fail this packet.
887 nextop
= op
+ op
[1] + 2;
891 status
= find_interface_by_agent_option(packet
,
894 if (status
== -1 && drop_agent_mismatches
)
897 good_agent_option
= 1;
902 /* Skip over other options. */
904 /* Fail if processing this option will exceed the
905 * buffer(op[1] is malformed).
907 nextop
= op
+ op
[1] + 2;
912 memmove(sp
, op
, op
[1] + 2);
923 /* If it's not a DHCP packet, we're not supposed to touch it. */
927 /* If none of the agent options we found matched, or if we didn't
928 find any agent options, count this packet as not having any
929 matching agent options, and if we're relying on agent options
930 to determine the outgoing interface, drop the packet. */
932 if (!good_agent_option
) {
933 ++missing_agent_option
;
934 if (drop_agent_mismatches
)
938 /* Adjust the length... */
940 length
= sp
-((u_int8_t
*)packet
);
942 /* Make sure the packet isn't short(this is unlikely,
944 if (length
< BOOTP_MIN_LEN
) {
945 memset(sp
, DHO_PAD
, BOOTP_MIN_LEN
- length
);
946 length
= BOOTP_MIN_LEN
;
953 /* Find an interface that matches the circuit ID specified in the
954 Relay Agent Information option. If one is found, store it through
955 the pointer given; otherwise, leave the existing pointer alone.
957 We actually deviate somewhat from the current specification here:
958 if the option buffer is corrupt, we suggest that the caller not
959 respond to this packet. If the circuit ID doesn't match any known
960 interface, we suggest that the caller to drop the packet. Only if
961 we find a circuit ID that matches an existing interface do we tell
962 the caller to go ahead and process the packet. */
965 find_interface_by_agent_option(struct dhcp_packet
*packet
,
966 struct interface_info
**out
,
967 u_int8_t
*buf
, int len
) {
969 u_int8_t
*circuit_id
= 0;
970 unsigned circuit_id_len
= 0;
971 struct interface_info
*ip
;
974 /* If the next agent option overflows the end of the
975 packet, the agent option buffer is corrupt. */
977 i
+ buf
[i
+ 1] + 2 > len
) {
978 ++corrupt_agent_options
;
982 /* Remember where the circuit ID is... */
984 circuit_id
= &buf
[i
+ 2];
985 circuit_id_len
= buf
[i
+ 1];
986 i
+= circuit_id_len
+ 2;
995 /* If there's no circuit ID, it's not really ours, tell the caller
998 ++missing_circuit_id
;
1002 /* Scan the interface list looking for an interface whose
1003 name matches the one specified in circuit_id. */
1005 for (ip
= interfaces
; ip
; ip
= ip
->next
) {
1006 if (ip
->circuit_id
&&
1007 ip
->circuit_id_len
== circuit_id_len
&&
1008 !memcmp(ip
->circuit_id
, circuit_id
, circuit_id_len
))
1012 /* If we got a match, use it. */
1018 /* If we didn't get a match, the circuit ID was bogus. */
1024 * Examine a packet to see if it's a candidate to have a Relay
1025 * Agent Information option tacked onto its tail. If it is, tack
1029 add_relay_agent_options(struct interface_info
*ip
, struct dhcp_packet
*packet
,
1030 unsigned length
, struct in_addr giaddr
) {
1031 int is_dhcp
= 0, mms
;
1033 u_int8_t
*op
, *nextop
, *sp
, *max
, *end_pad
= NULL
;
1034 int adding_link_select
;
1036 /* If we're not adding agent options to packets, we can skip
1038 if (!add_agent_options
)
1041 /* If there's no cookie, it's a bootp packet, so we should just
1042 forward it unchanged. */
1043 if (memcmp(packet
->options
, DHCP_OPTIONS_COOKIE
, 4))
1046 max
= ((u_int8_t
*)packet
) + dhcp_max_agent_option_packet_length
;
1048 /* Add link selection suboption if enabled and we're the first relay */
1049 adding_link_select
= (add_rfc3527_suboption
1050 && (packet
->giaddr
.s_addr
== 0));
1052 /* Commence processing after the cookie. */
1053 sp
= op
= &packet
->options
[4];
1057 /* Skip padding... */
1059 /* Remember the first pad byte so we can commandeer
1062 * XXX: Is this really a good idea? Sure, we can
1063 * seemingly reduce the packet while we're looking,
1064 * but if the packet was signed by the client then
1065 * this padding is part of the checksum(RFC3118),
1066 * and its nonpresence would break authentication.
1068 if (end_pad
== NULL
)
1078 /* If we see a message type, it's a DHCP packet. */
1079 case DHO_DHCP_MESSAGE_TYPE
:
1084 * If there's a maximum message size option, we
1085 * should pay attention to it
1087 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1088 mms
= ntohs(*(op
+ 2));
1089 if (mms
< dhcp_max_agent_option_packet_length
&&
1090 mms
>= DHCP_MTU_MIN
)
1091 max
= ((u_int8_t
*)packet
) + mms
;
1094 /* Quit immediately if we hit an End option. */
1098 case DHO_DHCP_AGENT_OPTIONS
:
1099 /* We shouldn't see a relay agent option in a
1100 packet before we've seen the DHCP packet type,
1101 but if we do, we have to leave it alone. */
1107 /* There's already a Relay Agent Information option
1108 in this packet. How embarrassing. Decide what
1109 to do based on the mode the user specified. */
1111 switch(agent_relay_mode
) {
1112 case forward_and_append
:
1114 case forward_untouched
:
1118 case forward_and_replace
:
1123 /* Skip over the agent option and start copying
1124 if we aren't copying already. */
1129 /* Skip over other options. */
1131 /* Fail if processing this option will exceed the
1132 * buffer(op[1] is malformed).
1134 nextop
= op
+ op
[1] + 2;
1141 memmove(sp
, op
, op
[1] + 2);
1152 /* If it's not a DHCP packet, we're not supposed to touch it. */
1156 /* If the packet was padded out, we can store the agent option
1157 at the beginning of the padding. */
1159 if (end_pad
!= NULL
)
1163 /* Remember where the end of the packet was after parsing
1168 /* Sanity check. Had better not ever happen. */
1169 if ((ip
->circuit_id_len
> 255) ||(ip
->circuit_id_len
< 1))
1170 log_fatal("Circuit ID length %d out of range [1-255] on "
1171 "%s\n", ip
->circuit_id_len
, ip
->name
);
1172 optlen
= ip
->circuit_id_len
+ 2; /* RAI_CIRCUIT_ID + len */
1174 if (ip
->remote_id
) {
1175 if (ip
->remote_id_len
> 255 || ip
->remote_id_len
< 1)
1176 log_fatal("Remote ID length %d out of range [1-255] "
1177 "on %s\n", ip
->circuit_id_len
, ip
->name
);
1178 optlen
+= ip
->remote_id_len
+ 2; /* RAI_REMOTE_ID + len */
1181 if (adding_link_select
) {
1185 /* We do not support relay option fragmenting(multiple options to
1186 * support an option data exceeding 255 bytes).
1188 if ((optlen
< 3) ||(optlen
> 255))
1189 log_fatal("Total agent option length(%u) out of range "
1190 "[3 - 255] on %s\n", optlen
, ip
->name
);
1193 * Is there room for the option, its code+len, and DHO_END?
1194 * If not, forward without adding the option.
1196 if (max
- sp
>= optlen
+ 3) {
1197 log_debug("Adding %d-byte relay agent option", optlen
+ 3);
1199 /* Okay, cons up *our* Relay Agent Information option. */
1200 *sp
++ = DHO_DHCP_AGENT_OPTIONS
;
1203 /* Copy in the circuit id... */
1204 *sp
++ = RAI_CIRCUIT_ID
;
1205 *sp
++ = ip
->circuit_id_len
;
1206 memcpy(sp
, ip
->circuit_id
, ip
->circuit_id_len
);
1207 sp
+= ip
->circuit_id_len
;
1209 /* Copy in remote ID... */
1210 if (ip
->remote_id
) {
1211 *sp
++ = RAI_REMOTE_ID
;
1212 *sp
++ = ip
->remote_id_len
;
1213 memcpy(sp
, ip
->remote_id
, ip
->remote_id_len
);
1214 sp
+= ip
->remote_id_len
;
1217 /* RFC3527: Use the inbound packet's interface address in
1218 * the link selection suboption and set the outbound giaddr
1219 * to the uplink address. */
1220 if (adding_link_select
) {
1221 *sp
++ = RAI_LINK_SELECT
;
1223 memcpy(sp
, &giaddr
.s_addr
, 4);
1225 packet
->giaddr
= uplink
->addresses
[0];
1226 log_debug ("Adding link selection suboption"
1227 " with addr: %s", inet_ntoa(giaddr
));
1230 ++agent_option_errors
;
1231 log_error("No room in packet (used %d of %d) "
1232 "for %d-byte relay agent option: omitted",
1233 (int) (sp
- ((u_int8_t
*) packet
)),
1234 (int) (max
- ((u_int8_t
*) packet
)),
1239 * Deposit an END option unless the packet is full (shouldn't
1245 /* Recalculate total packet length. */
1246 length
= sp
-((u_int8_t
*)packet
);
1248 /* Make sure the packet isn't short(this is unlikely, but WTH) */
1249 if (length
< BOOTP_MIN_LEN
) {
1250 memset(sp
, DHO_PAD
, BOOTP_MIN_LEN
- length
);
1251 return (BOOTP_MIN_LEN
);
1259 * Parse a downstream argument: [address%]interface[#index].
1261 static struct stream_list
*
1262 parse_downstream(char *arg
) {
1263 struct stream_list
*dp
, *up
;
1264 struct interface_info
*ifp
= NULL
;
1265 char *ifname
, *addr
, *iid
;
1266 isc_result_t status
;
1268 if (!supports_multiple_interfaces(ifp
) &&
1269 (downstreams
!= NULL
))
1270 log_fatal("No support for multiple interfaces.");
1272 /* Decode the argument. */
1273 ifname
= strchr(arg
, '%');
1274 if (ifname
== NULL
) {
1281 iid
= strchr(ifname
, '#');
1285 if (strlen(ifname
) >= sizeof(ifp
->name
)) {
1286 usage("Interface name '%s' too long", ifname
);
1289 /* Don't declare twice. */
1290 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1291 if (strcmp(ifname
, dp
->ifp
->name
) == 0)
1292 log_fatal("Down interface '%s' declared twice.",
1296 /* Share with up side? */
1297 for (up
= upstreams
; up
; up
= up
->next
) {
1298 if (strcmp(ifname
, up
->ifp
->name
) == 0) {
1299 log_info("parse_downstream: Interface '%s' is "
1300 "both down and up.", ifname
);
1306 /* New interface. */
1308 status
= interface_allocate(&ifp
, MDL
);
1309 if (status
!= ISC_R_SUCCESS
)
1310 log_fatal("%s: interface_allocate: %s",
1311 arg
, isc_result_totext(status
));
1312 strcpy(ifp
->name
, ifname
);
1314 interface_reference(&ifp
->next
, interfaces
, MDL
);
1315 interface_dereference(&interfaces
, MDL
);
1317 interface_reference(&interfaces
, ifp
, MDL
);
1319 ifp
->flags
|= INTERFACE_REQUESTED
| INTERFACE_DOWNSTREAM
;
1321 /* New downstream. */
1322 dp
= (struct stream_list
*) dmalloc(sizeof(*dp
), MDL
);
1324 log_fatal("No memory for downstream.");
1331 /* !addr case handled by setup. */
1332 if (addr
&& (inet_pton(AF_INET6
, addr
, &dp
->link
.sin6_addr
) <= 0))
1333 log_fatal("Bad link address '%s'", addr
);
1339 * Parse an upstream argument: [address]%interface.
1341 static struct stream_list
*
1342 parse_upstream(char *arg
) {
1343 struct stream_list
*up
, *dp
;
1344 struct interface_info
*ifp
= NULL
;
1345 char *ifname
, *addr
;
1346 isc_result_t status
;
1348 /* Decode the argument. */
1349 ifname
= strchr(arg
, '%');
1350 if (ifname
== NULL
) {
1352 addr
= All_DHCP_Servers
;
1357 if (strlen(ifname
) >= sizeof(ifp
->name
)) {
1358 log_fatal("Interface name '%s' too long", ifname
);
1361 /* Shared up interface? */
1362 for (up
= upstreams
; up
; up
= up
->next
) {
1363 if (strcmp(ifname
, up
->ifp
->name
) == 0) {
1368 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1369 if (strcmp(ifname
, dp
->ifp
->name
) == 0) {
1370 log_info("parse_upstream: Interface '%s' is "
1371 "both down and up.", ifname
);
1377 /* New interface. */
1379 status
= interface_allocate(&ifp
, MDL
);
1380 if (status
!= ISC_R_SUCCESS
)
1381 log_fatal("%s: interface_allocate: %s",
1382 arg
, isc_result_totext(status
));
1383 strcpy(ifp
->name
, ifname
);
1385 interface_reference(&ifp
->next
, interfaces
, MDL
);
1386 interface_dereference(&interfaces
, MDL
);
1388 interface_reference(&interfaces
, ifp
, MDL
);
1390 ifp
->flags
|= INTERFACE_REQUESTED
| INTERFACE_UPSTREAM
;
1393 up
= (struct stream_list
*) dmalloc(sizeof(*up
), MDL
);
1395 log_fatal("No memory for upstream.");
1399 if (inet_pton(AF_INET6
, addr
, &up
->link
.sin6_addr
) <= 0)
1400 log_fatal("Bad address %s", addr
);
1406 * Setup downstream interfaces.
1409 setup_streams(void) {
1410 struct stream_list
*dp
, *up
;
1412 isc_boolean_t link_is_set
;
1414 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1415 /* Check interface */
1416 if (dp
->ifp
->v6address_count
== 0)
1417 log_fatal("Interface '%s' has no IPv6 addresses.",
1420 /* Check/set link. */
1421 if (IN6_IS_ADDR_UNSPECIFIED(&dp
->link
.sin6_addr
))
1422 link_is_set
= ISC_FALSE
;
1424 link_is_set
= ISC_TRUE
;
1425 for (i
= 0; i
< dp
->ifp
->v6address_count
; i
++) {
1426 if (IN6_IS_ADDR_LINKLOCAL(&dp
->ifp
->v6addresses
[i
]))
1430 if (!memcmp(&dp
->ifp
->v6addresses
[i
],
1431 &dp
->link
.sin6_addr
,
1432 sizeof(dp
->link
.sin6_addr
)))
1435 if (i
== dp
->ifp
->v6address_count
)
1436 log_fatal("Interface %s does not have global IPv6 "
1437 "address assigned.", dp
->ifp
->name
);
1439 memcpy(&dp
->link
.sin6_addr
,
1440 &dp
->ifp
->v6addresses
[i
],
1441 sizeof(dp
->link
.sin6_addr
));
1443 /* Set interface-id. */
1445 dp
->id
= dp
->ifp
->index
;
1448 for (up
= upstreams
; up
; up
= up
->next
) {
1449 up
->link
.sin6_port
= local_port
;
1450 up
->link
.sin6_family
= AF_INET6
;
1452 up
->link
.sin6_len
= sizeof(up
->link
);
1455 if (up
->ifp
->v6address_count
== 0)
1456 log_fatal("Interface '%s' has no IPv6 addresses.",
1459 /* RFC 3315 Sec 20 - "If the relay agent relays messages to
1460 * the All_DHCP_Servers address or other multicast addresses,
1461 * it sets the Hop Limit field to 32." */
1462 if (IN6_IS_ADDR_MULTICAST(&up
->link
.sin6_addr
)) {
1463 set_multicast_hop_limit(up
->ifp
, HOP_COUNT_LIMIT
);
1469 * Add DHCPv6 agent options here.
1471 static const int required_forw_opts
[] = {
1479 * Process a packet upwards, i.e., from client to server.
1482 process_up6(struct packet
*packet
, struct stream_list
*dp
) {
1483 char forw_data
[65535];
1485 struct dhcpv6_relay_packet
*relay
;
1486 struct option_state
*opts
;
1487 struct stream_list
*up
;
1489 /* Check if the message should be relayed to the server. */
1490 switch (packet
->dhcpv6_msg_type
) {
1491 case DHCPV6_SOLICIT
:
1492 case DHCPV6_REQUEST
:
1493 case DHCPV6_CONFIRM
:
1496 case DHCPV6_RELEASE
:
1497 case DHCPV6_DECLINE
:
1498 case DHCPV6_INFORMATION_REQUEST
:
1499 case DHCPV6_RELAY_FORW
:
1500 case DHCPV6_LEASEQUERY
:
1501 log_info("Relaying %s from %s port %d going up.",
1502 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1503 piaddr(packet
->client_addr
),
1504 ntohs(packet
->client_port
));
1507 case DHCPV6_ADVERTISE
:
1509 case DHCPV6_RECONFIGURE
:
1510 case DHCPV6_RELAY_REPL
:
1511 case DHCPV6_LEASEQUERY_REPLY
:
1512 log_info("Discarding %s from %s port %d going up.",
1513 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1514 piaddr(packet
->client_addr
),
1515 ntohs(packet
->client_port
));
1519 log_info("Unknown %d type from %s port %d going up.",
1520 packet
->dhcpv6_msg_type
,
1521 piaddr(packet
->client_addr
),
1522 ntohs(packet
->client_port
));
1526 /* Build the relay-forward header. */
1527 relay
= (struct dhcpv6_relay_packet
*) forw_data
;
1528 cursor
= offsetof(struct dhcpv6_relay_packet
, options
);
1529 relay
->msg_type
= DHCPV6_RELAY_FORW
;
1530 if (packet
->dhcpv6_msg_type
== DHCPV6_RELAY_FORW
) {
1531 if (packet
->dhcpv6_hop_count
>= max_hop_count
) {
1532 log_info("Hop count exceeded,");
1535 relay
->hop_count
= packet
->dhcpv6_hop_count
+ 1;
1537 memcpy(&relay
->link_address
, &dp
->link
.sin6_addr
, 16);
1539 /* On smart relay add: && !global. */
1540 if (!use_if_id
&& downstreams
->next
) {
1541 log_info("Shan't get back the interface.");
1544 memset(&relay
->link_address
, 0, 16);
1547 relay
->hop_count
= 0;
1550 memcpy(&relay
->link_address
, &dp
->link
.sin6_addr
, 16);
1552 memcpy(&relay
->peer_address
, packet
->client_addr
.iabuf
, 16);
1554 /* Get an option state. */
1556 if (!option_state_allocate(&opts
, MDL
)) {
1557 log_fatal("No memory for upwards options.");
1560 /* Add an interface-id (if used). */
1566 } else if (!downstreams
->next
) {
1567 if_id
= downstreams
->id
;
1569 log_info("Don't know the interface.");
1570 option_state_dereference(&opts
, MDL
);
1574 if (!save_option_buffer(&dhcpv6_universe
, opts
,
1575 NULL
, (unsigned char *) &if_id
,
1577 D6O_INTERFACE_ID
, 0)) {
1578 log_error("Can't save interface-id.");
1579 option_state_dereference(&opts
, MDL
);
1584 /* Add a subscriber-id if desired. */
1585 /* This is for testing rather than general use */
1586 if (dhcrelay_sub_id
!= NULL
) {
1587 if (!save_option_buffer(&dhcpv6_universe
, opts
, NULL
,
1588 (unsigned char *) dhcrelay_sub_id
,
1589 strlen(dhcrelay_sub_id
),
1590 D6O_SUBSCRIBER_ID
, 0)) {
1591 log_error("Can't save subsriber-id.");
1592 option_state_dereference(&opts
, MDL
);
1598 /* Add the relay-msg carrying the packet. */
1599 if (!save_option_buffer(&dhcpv6_universe
, opts
,
1600 NULL
, (unsigned char *) packet
->raw
,
1601 packet
->packet_length
,
1602 D6O_RELAY_MSG
, 0)) {
1603 log_error("Can't save relay-msg.");
1604 option_state_dereference(&opts
, MDL
);
1608 /* Finish the relay-forward message. */
1609 cursor
+= store_options6(forw_data
+ cursor
,
1610 sizeof(forw_data
) - cursor
,
1612 required_forw_opts
, NULL
);
1613 option_state_dereference(&opts
, MDL
);
1615 /* Send it to all upstreams. */
1616 for (up
= upstreams
; up
; up
= up
->next
) {
1617 send_packet6(up
->ifp
, (unsigned char *) forw_data
,
1618 (size_t) cursor
, &up
->link
);
1623 * Process a packet downwards, i.e., from server to client.
1626 process_down6(struct packet
*packet
) {
1627 struct stream_list
*dp
;
1628 struct option_cache
*oc
;
1629 struct data_string relay_msg
;
1630 const struct dhcpv6_packet
*msg
;
1631 struct data_string if_id
;
1632 struct sockaddr_in6 to
;
1635 /* The packet must be a relay-reply message. */
1636 if (packet
->dhcpv6_msg_type
!= DHCPV6_RELAY_REPL
) {
1637 if (packet
->dhcpv6_msg_type
< dhcpv6_type_name_max
)
1638 log_info("Discarding %s from %s port %d going down.",
1639 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1640 piaddr(packet
->client_addr
),
1641 ntohs(packet
->client_port
));
1643 log_info("Unknown %d type from %s port %d going down.",
1644 packet
->dhcpv6_msg_type
,
1645 piaddr(packet
->client_addr
),
1646 ntohs(packet
->client_port
));
1651 memset(&relay_msg
, 0, sizeof(relay_msg
));
1652 memset(&if_id
, 0, sizeof(if_id
));
1653 memset(&to
, 0, sizeof(to
));
1654 to
.sin6_family
= AF_INET6
;
1656 to
.sin6_len
= sizeof(to
);
1658 to
.sin6_port
= remote_port
;
1661 /* Get the relay-msg option (carrying the message to relay). */
1662 oc
= lookup_option(&dhcpv6_universe
, packet
->options
, D6O_RELAY_MSG
);
1664 log_info("No relay-msg.");
1667 if (!evaluate_option_cache(&relay_msg
, packet
, NULL
, NULL
,
1668 packet
->options
, NULL
,
1669 &global_scope
, oc
, MDL
) ||
1670 (relay_msg
.len
< offsetof(struct dhcpv6_packet
, options
))) {
1671 log_error("Can't evaluate relay-msg.");
1674 msg
= (const struct dhcpv6_packet
*) relay_msg
.data
;
1676 /* Get the interface-id (if exists) and the downstream. */
1677 oc
= lookup_option(&dhcpv6_universe
, packet
->options
,
1682 if (!evaluate_option_cache(&if_id
, packet
, NULL
, NULL
,
1683 packet
->options
, NULL
,
1684 &global_scope
, oc
, MDL
) ||
1685 (if_id
.len
!= sizeof(int))) {
1686 log_info("Can't evaluate interface-id.");
1689 memcpy(&if_index
, if_id
.data
, sizeof(int));
1690 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1691 if (dp
->id
== if_index
)
1696 /* Require an interface-id. */
1697 log_info("No interface-id.");
1700 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1701 /* Get the first matching one. */
1702 if (!memcmp(&dp
->link
.sin6_addr
,
1703 &packet
->dhcpv6_link_address
,
1704 sizeof(struct in6_addr
)))
1708 /* Why bother when there is no choice. */
1709 if (!dp
&& downstreams
&& !downstreams
->next
)
1712 log_info("Can't find the down interface.");
1715 memcpy(peer
.iabuf
, &packet
->dhcpv6_peer_address
, peer
.len
);
1716 to
.sin6_addr
= packet
->dhcpv6_peer_address
;
1718 /* Check if we should relay the carried message. */
1719 switch (msg
->msg_type
) {
1720 /* Relay-Reply of for another relay, not a client. */
1721 case DHCPV6_RELAY_REPL
:
1722 to
.sin6_port
= local_port
;
1725 case DHCPV6_ADVERTISE
:
1727 case DHCPV6_RECONFIGURE
:
1728 case DHCPV6_RELAY_FORW
:
1729 case DHCPV6_LEASEQUERY_REPLY
:
1730 log_info("Relaying %s to %s port %d down.",
1731 dhcpv6_type_names
[msg
->msg_type
],
1733 ntohs(to
.sin6_port
));
1736 case DHCPV6_SOLICIT
:
1737 case DHCPV6_REQUEST
:
1738 case DHCPV6_CONFIRM
:
1741 case DHCPV6_RELEASE
:
1742 case DHCPV6_DECLINE
:
1743 case DHCPV6_INFORMATION_REQUEST
:
1744 case DHCPV6_LEASEQUERY
:
1745 log_info("Discarding %s to %s port %d down.",
1746 dhcpv6_type_names
[msg
->msg_type
],
1748 ntohs(to
.sin6_port
));
1752 log_info("Unknown %d type to %s port %d down.",
1755 ntohs(to
.sin6_port
));
1759 /* Send the message to the downstream. */
1760 send_packet6(dp
->ifp
, (unsigned char *) relay_msg
.data
,
1761 (size_t) relay_msg
.len
, &to
);
1764 if (relay_msg
.data
!= NULL
)
1765 data_string_forget(&relay_msg
, MDL
);
1766 if (if_id
.data
!= NULL
)
1767 data_string_forget(&if_id
, MDL
);
1771 * Called by the dispatch packet handler with a decoded packet.
1774 dhcpv6(struct packet
*packet
) {
1775 struct stream_list
*dp
;
1777 /* Try all relay-replies downwards. */
1778 if (packet
->dhcpv6_msg_type
== DHCPV6_RELAY_REPL
) {
1779 process_down6(packet
);
1782 /* Others are candidates to go up if they come from down. */
1783 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1784 if (packet
->interface
!= dp
->ifp
)
1786 process_up6(packet
, dp
);
1789 /* Relay-forward could work from an unknown interface. */
1790 if (packet
->dhcpv6_msg_type
== DHCPV6_RELAY_FORW
) {
1791 process_up6(packet
, NULL
);
1795 log_info("Can't process packet from interface '%s'.",
1796 packet
->interface
->name
);
1800 /* Stub routines needed for linking with DHCP libraries. */
1802 bootp(struct packet
*packet
) {
1807 dhcp(struct packet
*packet
) {
1812 classify(struct packet
*p
, struct class *c
) {
1817 check_collection(struct packet
*p
, struct lease
*l
, struct collection
*c
) {
1822 find_class(struct class **class, const char *c1
, const char *c2
, int i
) {
1823 return ISC_R_NOTFOUND
;
1827 parse_allow_deny(struct option_cache
**oc
, struct parse
*p
, int i
) {
1832 dhcp_set_control_state(control_object_state_t oldstate
,
1833 control_object_state_t newstate
) {
1834 if (newstate
!= server_shutdown
)
1835 return ISC_R_SUCCESS
;
1837 if (no_pid_file
== ISC_FALSE
)
1838 (void) unlink(path_dhcrelay_pid
);