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 void request_v4_interface(const char* name
, int flags
);
141 static const char copyright
[] =
142 "Copyright 2004-2016 Internet Systems Consortium.";
143 static const char arr
[] = "All rights reserved.";
144 static const char message
[] =
145 "Internet Systems Consortium DHCP Relay Agent";
146 static const char url
[] =
147 "For info, please visit https://www.isc.org/software/dhcp/";
152 #define DHCRELAY_USAGE \
153 "Usage: %s [-4] [-d] [-q] [-a] [-D]\n"\
154 " [-A <length>] [-c <hops>] [-p <port>]\n" \
155 " [-pf <pid-file>] [--no-pid]\n"\
156 " [-m append|replace|forward|discard]\n" \
157 " [-i interface0 [ ... -i interfaceN]\n" \
158 " [-iu interface0 [ ... -iu interfaceN]\n" \
159 " [-id interface0 [ ... -id interfaceN]\n" \
160 " [-U interface]\n" \
161 " server0 [ ... serverN]\n\n" \
162 " %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
163 " [-pf <pid-file>] [--no-pid]\n" \
164 " [-s <subscriber-id>]\n" \
165 " -l lower0 [ ... -l lowerN]\n" \
166 " -u upper0 [ ... -u upperN]\n" \
167 " lower (client link): [address%%]interface[#index]\n" \
168 " upper (server link): [address%%]interface"
170 #define DHCRELAY_USAGE \
171 "Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
172 " [-pf <pid-file>] [--no-pid]\n" \
173 " [-m append|replace|forward|discard]\n" \
174 " [-i interface0 [ ... -i interfaceN]\n" \
175 " [-iu interface0 [ ... -iu interfaceN]\n" \
176 " [-id interface0 [ ... -id interfaceN]\n" \
177 " [-U interface]\n" \
178 " server0 [ ... serverN]\n\n"
183 * \brief Print the generic usage message
185 * If the user has provided an incorrect command line print out
186 * the description of the command line. The arguments provide
187 * a way for the caller to request more specific information about
188 * the error be printed as well. Mostly this will be that some
189 * comamnd doesn't include its argument.
191 * \param sfmt - The basic string and format for the specific error
192 * \param sarg - Generally the offending argument from the comamnd line.
196 static const char use_noarg
[] = "No argument for command: %s";
198 static const char use_badproto
[] = "Protocol already set, %s inappropriate";
199 static const char use_v4command
[] = "Command not used for DHCPv6: %s";
200 static const char use_v6command
[] = "Command not used for DHCPv4: %s";
204 usage(const char *sfmt
, const char *sarg
) {
206 /* If desired print out the specific error message */
207 #ifdef PRINT_SPECIFIC_CL_ERRORS
209 log_error(sfmt
, sarg
);
212 log_fatal(DHCRELAY_USAGE
,
214 isc_file_basename(progname
),
216 isc_file_basename(progname
));
220 main(int argc
, char **argv
) {
223 struct server_list
*sp
= NULL
;
224 char *service_local
= NULL
, *service_remote
= NULL
;
225 u_int16_t port_local
= 0, port_remote
= 0;
226 int no_daemon
= 0, quiet
= 0;
230 struct stream_list
*sl
= NULL
;
231 int local_family_set
= 0;
235 progname
= "dhcrelay";
240 /* Make sure that file descriptors 0(stdin), 1,(stdout), and
241 2(stderr) are open. To do this, we assume that when we
242 open a file the lowest available file descriptor is used. */
243 fd
= open("/dev/null", O_RDWR
);
245 fd
= open("/dev/null", O_RDWR
);
247 fd
= open("/dev/null", O_RDWR
);
249 log_perror
= 0; /* No sense logging to /dev/null. */
253 openlog(isc_file_basename(progname
), DHCP_LOG_OPTIONS
, LOG_DAEMON
);
256 setlogmask(LOG_UPTO(LOG_INFO
));
259 /* Set up the isc and dns library managers */
260 status
= dhcp_context_create(DHCP_CONTEXT_PRE_DB
| DHCP_CONTEXT_POST_DB
,
262 if (status
!= ISC_R_SUCCESS
)
263 log_fatal("Can't initialize context: %s",
264 isc_result_totext(status
));
266 /* Set up the OMAPI. */
267 status
= omapi_init();
268 if (status
!= ISC_R_SUCCESS
)
269 log_fatal("Can't initialize OMAPI: %s",
270 isc_result_totext(status
));
272 /* Set up the OMAPI wrappers for the interface object. */
275 for (i
= 1; i
< argc
; i
++) {
276 if (!strcmp(argv
[i
], "-4")) {
278 if (local_family_set
&& (local_family
== AF_INET6
)) {
279 usage(use_badproto
, "-4");
281 local_family_set
= 1;
282 local_family
= AF_INET
;
283 } else if (!strcmp(argv
[i
], "-6")) {
284 if (local_family_set
&& (local_family
== AF_INET
)) {
285 usage(use_badproto
, "-6");
287 local_family_set
= 1;
288 local_family
= AF_INET6
;
290 } else if (!strcmp(argv
[i
], "-d")) {
292 } else if (!strcmp(argv
[i
], "-q")) {
294 quiet_interface_discovery
= 1;
295 } else if (!strcmp(argv
[i
], "-p")) {
297 usage(use_noarg
, argv
[i
-1]);
298 local_port
= validate_port(argv
[i
]);
299 log_debug("binding to user-specified port %d",
301 } else if (!strcmp(argv
[i
], "-c")) {
304 usage(use_noarg
, argv
[i
-1]);
305 hcount
= atoi(argv
[i
]);
307 max_hop_count
= hcount
;
309 usage("Bad hop count to -c: %s", argv
[i
]);
310 } else if (!strcmp(argv
[i
], "-i")) {
312 if (local_family_set
&& (local_family
== AF_INET6
)) {
313 usage(use_v4command
, argv
[i
]);
315 local_family_set
= 1;
316 local_family
= AF_INET
;
319 usage(use_noarg
, argv
[i
-1]);
322 request_v4_interface(argv
[i
], INTERFACE_STREAMS
);
323 } else if (!strcmp(argv
[i
], "-iu")) {
325 if (local_family_set
&& (local_family
== AF_INET6
)) {
326 usage(use_v4command
, argv
[i
]);
328 local_family_set
= 1;
329 local_family
= AF_INET
;
332 usage(use_noarg
, argv
[i
-1]);
335 request_v4_interface(argv
[i
], INTERFACE_UPSTREAM
);
336 } else if (!strcmp(argv
[i
], "-id")) {
338 if (local_family_set
&& (local_family
== AF_INET6
)) {
339 usage(use_v4command
, argv
[i
]);
341 local_family_set
= 1;
342 local_family
= AF_INET
;
345 usage(use_noarg
, argv
[i
-1]);
348 request_v4_interface(argv
[i
], INTERFACE_DOWNSTREAM
);
349 } else if (!strcmp(argv
[i
], "-a")) {
351 if (local_family_set
&& (local_family
== AF_INET6
)) {
352 usage(use_v4command
, argv
[i
]);
354 local_family_set
= 1;
355 local_family
= AF_INET
;
357 add_agent_options
= 1;
358 } else if (!strcmp(argv
[i
], "-A")) {
360 if (local_family_set
&& (local_family
== AF_INET6
)) {
361 usage(use_v4command
, argv
[i
]);
363 local_family_set
= 1;
364 local_family
= AF_INET
;
367 usage(use_noarg
, argv
[i
-1]);
369 dhcp_max_agent_option_packet_length
= atoi(argv
[i
]);
371 if (dhcp_max_agent_option_packet_length
> DHCP_MTU_MAX
)
372 log_fatal("%s: packet length exceeds "
373 "longest possible MTU\n",
375 } else if (!strcmp(argv
[i
], "-m")) {
377 if (local_family_set
&& (local_family
== AF_INET6
)) {
378 usage(use_v4command
, argv
[i
]);
380 local_family_set
= 1;
381 local_family
= AF_INET
;
384 usage(use_noarg
, argv
[i
-1]);
385 if (!strcasecmp(argv
[i
], "append")) {
386 agent_relay_mode
= forward_and_append
;
387 } else if (!strcasecmp(argv
[i
], "replace")) {
388 agent_relay_mode
= forward_and_replace
;
389 } else if (!strcasecmp(argv
[i
], "forward")) {
390 agent_relay_mode
= forward_untouched
;
391 } else if (!strcasecmp(argv
[i
], "discard")) {
392 agent_relay_mode
= discard
;
394 usage("Unknown argument to -m: %s", argv
[i
]);
395 } else if (!strcmp(argv
[i
], "-U")) {
397 usage(use_noarg
, argv
[i
-1]);
400 usage("more than one uplink (-U) specified: %s"
404 /* Allocate the uplink interface */
405 status
= interface_allocate(&uplink
, MDL
);
406 if (status
!= ISC_R_SUCCESS
) {
407 log_fatal("%s: uplink interface_allocate: %s",
408 argv
[i
], isc_result_totext(status
));
411 if (strlen(argv
[i
]) >= sizeof(uplink
->name
)) {
412 log_fatal("%s: uplink name too long,"
413 " it cannot exceed: %ld characters",
414 argv
[i
], (long)(sizeof(uplink
->name
) - 1));
417 uplink
->name
[sizeof(uplink
->name
) - 1] = 0x00;
418 strncpy(uplink
->name
, argv
[i
],
419 sizeof(uplink
->name
) - 1);
420 interface_snorf(uplink
, (INTERFACE_REQUESTED
|
423 /* Turn on -a, in case they don't do so explicitly */
424 add_agent_options
= 1;
425 add_rfc3527_suboption
= 1;
426 } else if (!strcmp(argv
[i
], "-D")) {
428 if (local_family_set
&& (local_family
== AF_INET6
)) {
429 usage(use_v4command
, argv
[i
]);
431 local_family_set
= 1;
432 local_family
= AF_INET
;
434 drop_agent_mismatches
= 1;
436 } else if (!strcmp(argv
[i
], "-I")) {
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
;
442 use_if_id
= ISC_TRUE
;
443 } else if (!strcmp(argv
[i
], "-l")) {
444 if (local_family_set
&& (local_family
== AF_INET
)) {
445 usage(use_v6command
, argv
[i
]);
447 local_family_set
= 1;
448 local_family
= AF_INET6
;
449 if (downstreams
!= NULL
)
450 use_if_id
= ISC_TRUE
;
452 usage(use_noarg
, argv
[i
-1]);
453 sl
= parse_downstream(argv
[i
]);
454 sl
->next
= downstreams
;
456 } else if (!strcmp(argv
[i
], "-u")) {
457 if (local_family_set
&& (local_family
== AF_INET
)) {
458 usage(use_v6command
, argv
[i
]);
460 local_family_set
= 1;
461 local_family
= AF_INET6
;
463 usage(use_noarg
, argv
[i
-1]);
464 sl
= parse_upstream(argv
[i
]);
465 sl
->next
= upstreams
;
467 } else if (!strcmp(argv
[i
], "-s")) {
468 if (local_family_set
&& (local_family
== AF_INET
)) {
469 usage(use_v6command
, argv
[i
]);
471 local_family_set
= 1;
472 local_family
= AF_INET6
;
474 usage(use_noarg
, argv
[i
-1]);
475 dhcrelay_sub_id
= argv
[i
];
477 } else if (!strcmp(argv
[i
], "-pf")) {
479 usage(use_noarg
, argv
[i
-1]);
480 path_dhcrelay_pid
= argv
[i
];
481 no_dhcrelay_pid
= ISC_TRUE
;
482 } else if (!strcmp(argv
[i
], "--no-pid")) {
483 no_pid_file
= ISC_TRUE
;
484 } else if (!strcmp(argv
[i
], "--version")) {
485 log_info("isc-dhcrelay-%s", PACKAGE_VERSION
);
487 } else if (!strcmp(argv
[i
], "--help") ||
488 !strcmp(argv
[i
], "-h")) {
489 log_info(DHCRELAY_USAGE
,
491 isc_file_basename(progname
),
493 isc_file_basename(progname
));
495 } else if (argv
[i
][0] == '-') {
496 usage("Unknown command: %s", argv
[i
]);
499 struct in_addr ia
, *iap
= NULL
;
502 if (local_family_set
&& (local_family
== AF_INET6
)) {
503 usage(use_v4command
, argv
[i
]);
505 local_family_set
= 1;
506 local_family
= AF_INET
;
508 if (inet_aton(argv
[i
], &ia
)) {
511 he
= gethostbyname(argv
[i
]);
513 log_error("%s: host unknown", argv
[i
]);
515 iap
= ((struct in_addr
*)
521 sp
= ((struct server_list
*)
522 dmalloc(sizeof *sp
, MDL
));
524 log_fatal("no memory for server.\n");
527 memcpy(&sp
->to
.sin_addr
, iap
, sizeof *iap
);
533 * If the user didn't specify a pid file directly
534 * find one from environment variables or defaults
536 if (no_dhcrelay_pid
== ISC_FALSE
) {
537 if (local_family
== AF_INET
) {
538 path_dhcrelay_pid
= getenv("PATH_DHCRELAY_PID");
539 if (path_dhcrelay_pid
== NULL
)
540 path_dhcrelay_pid
= _PATH_DHCRELAY_PID
;
544 path_dhcrelay_pid
= getenv("PATH_DHCRELAY6_PID");
545 if (path_dhcrelay_pid
== NULL
)
546 path_dhcrelay_pid
= _PATH_DHCRELAY6_PID
;
552 log_info("%s %s", message
, PACKAGE_VERSION
);
559 /* Set default port */
560 if (local_family
== AF_INET
) {
561 service_local
= "bootps";
562 service_remote
= "bootpc";
563 port_local
= htons(67);
564 port_remote
= htons(68);
568 service_local
= "dhcpv6-server";
569 service_remote
= "dhcpv6-client";
570 port_local
= htons(547);
571 port_remote
= htons(546);
576 ent
= getservbyname(service_local
, "udp");
578 local_port
= ent
->s_port
;
580 local_port
= port_local
;
582 ent
= getservbyname(service_remote
, "udp");
584 remote_port
= ent
->s_port
;
586 remote_port
= port_remote
;
591 if (local_family
== AF_INET
) {
592 /* We need at least one server */
593 if (servers
== NULL
) {
594 log_fatal("No servers specified.");
598 /* Set up the server sockaddrs. */
599 for (sp
= servers
; sp
; sp
= sp
->next
) {
600 sp
->to
.sin_port
= local_port
;
601 sp
->to
.sin_family
= AF_INET
;
603 sp
->to
.sin_len
= sizeof sp
->to
;
611 /* We need at least one upstream and one downstream interface */
612 if (upstreams
== NULL
|| downstreams
== NULL
) {
613 log_info("Must specify at least one lower "
614 "and one upper interface.\n");
618 /* Set up the initial dhcp option universe. */
619 initialize_common_option_spaces();
621 /* Check requested options. */
622 code
= D6O_RELAY_MSG
;
623 if (!option_code_hash_lookup(&requested_opts
[0],
624 dhcpv6_universe
.code_hash
,
626 log_fatal("Unable to find the RELAY_MSG "
627 "option definition.");
628 code
= D6O_INTERFACE_ID
;
629 if (!option_code_hash_lookup(&requested_opts
[1],
630 dhcpv6_universe
.code_hash
,
632 log_fatal("Unable to find the INTERFACE_ID "
633 "option definition.");
637 /* Get the current time... */
638 gettimeofday(&cur_tv
, NULL
);
640 /* Discover all the network interfaces. */
641 discover_interfaces(DISCOVER_RELAY
);
644 if (local_family
== AF_INET6
)
648 /* Become a daemon... */
656 if ((pid
= fork()) < 0)
657 log_fatal("Can't fork daemon: %m");
661 if (no_pid_file
== ISC_FALSE
) {
662 pfdesc
= open(path_dhcrelay_pid
,
663 O_CREAT
| O_TRUNC
| O_WRONLY
, 0644);
666 log_error("Can't create %s: %m",
669 pf
= fdopen(pfdesc
, "w");
671 log_error("Can't fdopen %s: %m",
674 fprintf(pf
, "%ld\n",(long)getpid());
685 IGNORE_RET (chdir("/"));
688 /* Set up the packet handler... */
689 if (local_family
== AF_INET
)
690 bootp_packet_handler
= do_relay4
;
693 dhcpv6_packet_handler
= do_packet6
;
696 #if defined(ENABLE_GENTLE_SHUTDOWN)
697 /* no signal handlers until we deal with the side effects */
698 /* install signal handlers */
699 signal(SIGINT
, dhcp_signal_handler
); /* control-c */
700 signal(SIGTERM
, dhcp_signal_handler
); /* kill */
703 /* Start dispatching packets and timeouts... */
706 /* In fact dispatch() never returns. */
711 do_relay4(struct interface_info
*ip
, struct dhcp_packet
*packet
,
712 unsigned int length
, unsigned int from_port
, struct iaddr from
,
713 struct hardware
*hfrom
) {
714 struct server_list
*sp
;
715 struct sockaddr_in to
;
716 struct interface_info
*out
;
717 struct hardware hto
, *htop
;
719 if (packet
->hlen
> sizeof packet
->chaddr
) {
720 log_info("Discarding packet with invalid hlen, received on "
721 "%s interface.", ip
->name
);
724 if (ip
->address_count
< 1 || ip
->addresses
== NULL
) {
725 log_info("Discarding packet received on %s interface that "
726 "has no IPv4 address assigned.", ip
->name
);
730 /* Find the interface that corresponds to the giaddr
732 if (packet
->giaddr
.s_addr
) {
733 for (out
= interfaces
; out
; out
= out
->next
) {
736 for (i
= 0 ; i
< out
->address_count
; i
++ ) {
737 if (out
->addresses
[i
].s_addr
==
738 packet
->giaddr
.s_addr
) {
751 /* If it's a bootreply, forward it to the client. */
752 if (packet
->op
== BOOTREPLY
) {
753 if (!(ip
->flags
& INTERFACE_UPSTREAM
)) {
754 log_debug("Dropping reply received on %s", ip
->name
);
758 if (!(packet
->flags
& htons(BOOTP_BROADCAST
)) &&
759 can_unicast_without_arp(out
)) {
760 to
.sin_addr
= packet
->yiaddr
;
761 to
.sin_port
= remote_port
;
763 /* and hardware address is not broadcast */
766 to
.sin_addr
.s_addr
= htonl(INADDR_BROADCAST
);
767 to
.sin_port
= remote_port
;
769 /* hardware address is broadcast */
772 to
.sin_family
= AF_INET
;
774 to
.sin_len
= sizeof to
;
777 memcpy(&hto
.hbuf
[1], packet
->chaddr
, packet
->hlen
);
778 hto
.hbuf
[0] = packet
->htype
;
779 hto
.hlen
= packet
->hlen
+ 1;
781 /* Wipe out the agent relay options and, if possible, figure
782 out which interface to use based on the contents of the
783 option that we put on the request to which the server is
786 strip_relay_agent_options(ip
, &out
, packet
, length
)))
790 log_error("Packet to bogus giaddr %s.\n",
791 inet_ntoa(packet
->giaddr
));
792 ++bogus_giaddr_drops
;
796 if (send_packet(out
, NULL
, packet
, length
, out
->addresses
[0],
798 ++server_packet_errors
;
800 log_debug("Forwarded BOOTREPLY for %s to %s",
801 print_hw_addr(packet
->htype
, packet
->hlen
,
803 inet_ntoa(to
.sin_addr
));
805 ++server_packets_relayed
;
810 /* If giaddr matches one of our addresses, ignore the packet -
815 if (!(ip
->flags
& INTERFACE_DOWNSTREAM
)) {
816 log_debug("Dropping request received on %s", ip
->name
);
820 /* Add relay agent options if indicated. If something goes wrong,
821 * drop the packet. Note this may set packet->giaddr if RFC3527
823 if (!(length
= add_relay_agent_options(ip
, packet
, length
,
827 /* If giaddr is not already set, Set it so the server can
828 figure out what net it's from and so that we can later
829 forward the response to the correct net. If it's already
830 set, the response will be sent directly to the relay agent
831 that set giaddr, so we won't see it. */
832 if (!packet
->giaddr
.s_addr
)
833 packet
->giaddr
= ip
->addresses
[0];
834 if (packet
->hops
< max_hop_count
)
835 packet
->hops
= packet
->hops
+ 1;
839 /* Otherwise, it's a BOOTREQUEST, so forward it to all the
841 for (sp
= servers
; sp
; sp
= sp
->next
) {
842 if (send_packet((fallback_interface
843 ? fallback_interface
: interfaces
),
844 NULL
, packet
, length
, ip
->addresses
[0],
845 &sp
->to
, NULL
) < 0) {
846 ++client_packet_errors
;
848 log_debug("Forwarded BOOTREQUEST for %s to %s",
849 print_hw_addr(packet
->htype
, packet
->hlen
,
851 inet_ntoa(sp
->to
.sin_addr
));
852 ++client_packets_relayed
;
858 /* Strip any Relay Agent Information options from the DHCP packet
859 option buffer. If there is a circuit ID suboption, look up the
860 outgoing interface based upon it. */
863 strip_relay_agent_options(struct interface_info
*in
,
864 struct interface_info
**out
,
865 struct dhcp_packet
*packet
,
868 u_int8_t
*op
, *nextop
, *sp
, *max
;
869 int good_agent_option
= 0;
872 /* If we're not adding agent options to packets, we're not taking
874 if (!add_agent_options
)
877 /* If there's no cookie, it's a bootp packet, so we should just
878 forward it unchanged. */
879 if (memcmp(packet
->options
, DHCP_OPTIONS_COOKIE
, 4))
882 max
= ((u_int8_t
*)packet
) + length
;
883 sp
= op
= &packet
->options
[4];
887 /* Skip padding... */
895 /* If we see a message type, it's a DHCP packet. */
896 case DHO_DHCP_MESSAGE_TYPE
:
901 /* Quit immediately if we hit an End option. */
907 case DHO_DHCP_AGENT_OPTIONS
:
908 /* We shouldn't see a relay agent option in a
909 packet before we've seen the DHCP packet type,
910 but if we do, we have to leave it alone. */
914 /* Do not process an agent option if it exceeds the
915 * buffer. Fail this packet.
917 nextop
= op
+ op
[1] + 2;
921 status
= find_interface_by_agent_option(packet
,
924 if (status
== -1 && drop_agent_mismatches
)
927 good_agent_option
= 1;
932 /* Skip over other options. */
934 /* Fail if processing this option will exceed the
935 * buffer(op[1] is malformed).
937 nextop
= op
+ op
[1] + 2;
942 memmove(sp
, op
, op
[1] + 2);
953 /* If it's not a DHCP packet, we're not supposed to touch it. */
957 /* If none of the agent options we found matched, or if we didn't
958 find any agent options, count this packet as not having any
959 matching agent options, and if we're relying on agent options
960 to determine the outgoing interface, drop the packet. */
962 if (!good_agent_option
) {
963 ++missing_agent_option
;
964 if (drop_agent_mismatches
)
968 /* Adjust the length... */
970 length
= sp
-((u_int8_t
*)packet
);
972 /* Make sure the packet isn't short(this is unlikely,
974 if (length
< BOOTP_MIN_LEN
) {
975 memset(sp
, DHO_PAD
, BOOTP_MIN_LEN
- length
);
976 length
= BOOTP_MIN_LEN
;
983 /* Find an interface that matches the circuit ID specified in the
984 Relay Agent Information option. If one is found, store it through
985 the pointer given; otherwise, leave the existing pointer alone.
987 We actually deviate somewhat from the current specification here:
988 if the option buffer is corrupt, we suggest that the caller not
989 respond to this packet. If the circuit ID doesn't match any known
990 interface, we suggest that the caller to drop the packet. Only if
991 we find a circuit ID that matches an existing interface do we tell
992 the caller to go ahead and process the packet. */
995 find_interface_by_agent_option(struct dhcp_packet
*packet
,
996 struct interface_info
**out
,
997 u_int8_t
*buf
, int len
) {
999 u_int8_t
*circuit_id
= 0;
1000 unsigned circuit_id_len
= 0;
1001 struct interface_info
*ip
;
1004 /* If the next agent option overflows the end of the
1005 packet, the agent option buffer is corrupt. */
1007 i
+ buf
[i
+ 1] + 2 > len
) {
1008 ++corrupt_agent_options
;
1012 /* Remember where the circuit ID is... */
1013 case RAI_CIRCUIT_ID
:
1014 circuit_id
= &buf
[i
+ 2];
1015 circuit_id_len
= buf
[i
+ 1];
1016 i
+= circuit_id_len
+ 2;
1020 i
+= buf
[i
+ 1] + 2;
1025 /* If there's no circuit ID, it's not really ours, tell the caller
1028 ++missing_circuit_id
;
1032 /* Scan the interface list looking for an interface whose
1033 name matches the one specified in circuit_id. */
1035 for (ip
= interfaces
; ip
; ip
= ip
->next
) {
1036 if (ip
->circuit_id
&&
1037 ip
->circuit_id_len
== circuit_id_len
&&
1038 !memcmp(ip
->circuit_id
, circuit_id
, circuit_id_len
))
1042 /* If we got a match, use it. */
1048 /* If we didn't get a match, the circuit ID was bogus. */
1054 * Examine a packet to see if it's a candidate to have a Relay
1055 * Agent Information option tacked onto its tail. If it is, tack
1059 add_relay_agent_options(struct interface_info
*ip
, struct dhcp_packet
*packet
,
1060 unsigned length
, struct in_addr giaddr
) {
1061 int is_dhcp
= 0, mms
;
1063 u_int8_t
*op
, *nextop
, *sp
, *max
, *end_pad
= NULL
;
1064 int adding_link_select
;
1066 /* If we're not adding agent options to packets, we can skip
1068 if (!add_agent_options
)
1071 /* If there's no cookie, it's a bootp packet, so we should just
1072 forward it unchanged. */
1073 if (memcmp(packet
->options
, DHCP_OPTIONS_COOKIE
, 4))
1076 max
= ((u_int8_t
*)packet
) + dhcp_max_agent_option_packet_length
;
1078 /* Add link selection suboption if enabled and we're the first relay */
1079 adding_link_select
= (add_rfc3527_suboption
1080 && (packet
->giaddr
.s_addr
== 0));
1082 /* Commence processing after the cookie. */
1083 sp
= op
= &packet
->options
[4];
1087 /* Skip padding... */
1089 /* Remember the first pad byte so we can commandeer
1092 * XXX: Is this really a good idea? Sure, we can
1093 * seemingly reduce the packet while we're looking,
1094 * but if the packet was signed by the client then
1095 * this padding is part of the checksum(RFC3118),
1096 * and its nonpresence would break authentication.
1098 if (end_pad
== NULL
)
1108 /* If we see a message type, it's a DHCP packet. */
1109 case DHO_DHCP_MESSAGE_TYPE
:
1114 * If there's a maximum message size option, we
1115 * should pay attention to it
1117 case DHO_DHCP_MAX_MESSAGE_SIZE
:
1118 mms
= ntohs(*(op
+ 2));
1119 if (mms
< dhcp_max_agent_option_packet_length
&&
1120 mms
>= DHCP_MTU_MIN
)
1121 max
= ((u_int8_t
*)packet
) + mms
;
1124 /* Quit immediately if we hit an End option. */
1128 case DHO_DHCP_AGENT_OPTIONS
:
1129 /* We shouldn't see a relay agent option in a
1130 packet before we've seen the DHCP packet type,
1131 but if we do, we have to leave it alone. */
1137 /* There's already a Relay Agent Information option
1138 in this packet. How embarrassing. Decide what
1139 to do based on the mode the user specified. */
1141 switch(agent_relay_mode
) {
1142 case forward_and_append
:
1144 case forward_untouched
:
1148 case forward_and_replace
:
1153 /* Skip over the agent option and start copying
1154 if we aren't copying already. */
1159 /* Skip over other options. */
1161 /* Fail if processing this option will exceed the
1162 * buffer(op[1] is malformed).
1164 nextop
= op
+ op
[1] + 2;
1171 memmove(sp
, op
, op
[1] + 2);
1182 /* If it's not a DHCP packet, we're not supposed to touch it. */
1186 /* If the packet was padded out, we can store the agent option
1187 at the beginning of the padding. */
1189 if (end_pad
!= NULL
)
1193 /* Remember where the end of the packet was after parsing
1198 /* Sanity check. Had better not ever happen. */
1199 if ((ip
->circuit_id_len
> 255) ||(ip
->circuit_id_len
< 1))
1200 log_fatal("Circuit ID length %d out of range [1-255] on "
1201 "%s\n", ip
->circuit_id_len
, ip
->name
);
1202 optlen
= ip
->circuit_id_len
+ 2; /* RAI_CIRCUIT_ID + len */
1204 if (ip
->remote_id
) {
1205 if (ip
->remote_id_len
> 255 || ip
->remote_id_len
< 1)
1206 log_fatal("Remote ID length %d out of range [1-255] "
1207 "on %s\n", ip
->remote_id_len
, ip
->name
);
1208 optlen
+= ip
->remote_id_len
+ 2; /* RAI_REMOTE_ID + len */
1211 if (adding_link_select
) {
1215 /* We do not support relay option fragmenting(multiple options to
1216 * support an option data exceeding 255 bytes).
1218 if ((optlen
< 3) ||(optlen
> 255))
1219 log_fatal("Total agent option length(%u) out of range "
1220 "[3 - 255] on %s\n", optlen
, ip
->name
);
1223 * Is there room for the option, its code+len, and DHO_END?
1224 * If not, forward without adding the option.
1226 if (max
- sp
>= optlen
+ 3) {
1227 log_debug("Adding %d-byte relay agent option", optlen
+ 3);
1229 /* Okay, cons up *our* Relay Agent Information option. */
1230 *sp
++ = DHO_DHCP_AGENT_OPTIONS
;
1233 /* Copy in the circuit id... */
1234 *sp
++ = RAI_CIRCUIT_ID
;
1235 *sp
++ = ip
->circuit_id_len
;
1236 memcpy(sp
, ip
->circuit_id
, ip
->circuit_id_len
);
1237 sp
+= ip
->circuit_id_len
;
1239 /* Copy in remote ID... */
1240 if (ip
->remote_id
) {
1241 *sp
++ = RAI_REMOTE_ID
;
1242 *sp
++ = ip
->remote_id_len
;
1243 memcpy(sp
, ip
->remote_id
, ip
->remote_id_len
);
1244 sp
+= ip
->remote_id_len
;
1247 /* RFC3527: Use the inbound packet's interface address in
1248 * the link selection suboption and set the outbound giaddr
1249 * to the uplink address. */
1250 if (adding_link_select
) {
1251 *sp
++ = RAI_LINK_SELECT
;
1253 memcpy(sp
, &giaddr
.s_addr
, 4);
1255 packet
->giaddr
= uplink
->addresses
[0];
1256 log_debug ("Adding link selection suboption"
1257 " with addr: %s", inet_ntoa(giaddr
));
1260 ++agent_option_errors
;
1261 log_error("No room in packet (used %d of %d) "
1262 "for %d-byte relay agent option: omitted",
1263 (int) (sp
- ((u_int8_t
*) packet
)),
1264 (int) (max
- ((u_int8_t
*) packet
)),
1269 * Deposit an END option unless the packet is full (shouldn't
1275 /* Recalculate total packet length. */
1276 length
= sp
-((u_int8_t
*)packet
);
1278 /* Make sure the packet isn't short(this is unlikely, but WTH) */
1279 if (length
< BOOTP_MIN_LEN
) {
1280 memset(sp
, DHO_PAD
, BOOTP_MIN_LEN
- length
);
1281 return (BOOTP_MIN_LEN
);
1289 * Parse a downstream argument: [address%]interface[#index].
1291 static struct stream_list
*
1292 parse_downstream(char *arg
) {
1293 struct stream_list
*dp
, *up
;
1294 struct interface_info
*ifp
= NULL
;
1295 char *ifname
, *addr
, *iid
;
1296 isc_result_t status
;
1298 if (!supports_multiple_interfaces(ifp
) &&
1299 (downstreams
!= NULL
))
1300 log_fatal("No support for multiple interfaces.");
1302 /* Decode the argument. */
1303 ifname
= strchr(arg
, '%');
1304 if (ifname
== NULL
) {
1311 iid
= strchr(ifname
, '#');
1315 if (strlen(ifname
) >= sizeof(ifp
->name
)) {
1316 usage("Interface name '%s' too long", ifname
);
1319 /* Don't declare twice. */
1320 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1321 if (strcmp(ifname
, dp
->ifp
->name
) == 0)
1322 log_fatal("Down interface '%s' declared twice.",
1326 /* Share with up side? */
1327 for (up
= upstreams
; up
; up
= up
->next
) {
1328 if (strcmp(ifname
, up
->ifp
->name
) == 0) {
1329 log_info("parse_downstream: Interface '%s' is "
1330 "both down and up.", ifname
);
1336 /* New interface. */
1338 status
= interface_allocate(&ifp
, MDL
);
1339 if (status
!= ISC_R_SUCCESS
)
1340 log_fatal("%s: interface_allocate: %s",
1341 arg
, isc_result_totext(status
));
1342 strcpy(ifp
->name
, ifname
);
1344 interface_reference(&ifp
->next
, interfaces
, MDL
);
1345 interface_dereference(&interfaces
, MDL
);
1347 interface_reference(&interfaces
, ifp
, MDL
);
1349 ifp
->flags
|= INTERFACE_REQUESTED
| INTERFACE_DOWNSTREAM
;
1351 /* New downstream. */
1352 dp
= (struct stream_list
*) dmalloc(sizeof(*dp
), MDL
);
1354 log_fatal("No memory for downstream.");
1361 /* !addr case handled by setup. */
1362 if (addr
&& (inet_pton(AF_INET6
, addr
, &dp
->link
.sin6_addr
) <= 0))
1363 log_fatal("Bad link address '%s'", addr
);
1369 * Parse an upstream argument: [address]%interface.
1371 static struct stream_list
*
1372 parse_upstream(char *arg
) {
1373 struct stream_list
*up
, *dp
;
1374 struct interface_info
*ifp
= NULL
;
1375 char *ifname
, *addr
;
1376 isc_result_t status
;
1378 /* Decode the argument. */
1379 ifname
= strchr(arg
, '%');
1380 if (ifname
== NULL
) {
1382 addr
= All_DHCP_Servers
;
1387 if (strlen(ifname
) >= sizeof(ifp
->name
)) {
1388 log_fatal("Interface name '%s' too long", ifname
);
1391 /* Shared up interface? */
1392 for (up
= upstreams
; up
; up
= up
->next
) {
1393 if (strcmp(ifname
, up
->ifp
->name
) == 0) {
1398 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1399 if (strcmp(ifname
, dp
->ifp
->name
) == 0) {
1400 log_info("parse_upstream: Interface '%s' is "
1401 "both down and up.", ifname
);
1407 /* New interface. */
1409 status
= interface_allocate(&ifp
, MDL
);
1410 if (status
!= ISC_R_SUCCESS
)
1411 log_fatal("%s: interface_allocate: %s",
1412 arg
, isc_result_totext(status
));
1413 strcpy(ifp
->name
, ifname
);
1415 interface_reference(&ifp
->next
, interfaces
, MDL
);
1416 interface_dereference(&interfaces
, MDL
);
1418 interface_reference(&interfaces
, ifp
, MDL
);
1420 ifp
->flags
|= INTERFACE_REQUESTED
| INTERFACE_UPSTREAM
;
1423 up
= (struct stream_list
*) dmalloc(sizeof(*up
), MDL
);
1425 log_fatal("No memory for upstream.");
1429 if (inet_pton(AF_INET6
, addr
, &up
->link
.sin6_addr
) <= 0)
1430 log_fatal("Bad address %s", addr
);
1436 * Setup downstream interfaces.
1439 setup_streams(void) {
1440 struct stream_list
*dp
, *up
;
1442 isc_boolean_t link_is_set
;
1444 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1445 /* Check interface */
1446 if (dp
->ifp
->v6address_count
== 0)
1447 log_fatal("Interface '%s' has no IPv6 addresses.",
1450 /* Check/set link. */
1451 if (IN6_IS_ADDR_UNSPECIFIED(&dp
->link
.sin6_addr
))
1452 link_is_set
= ISC_FALSE
;
1454 link_is_set
= ISC_TRUE
;
1455 for (i
= 0; i
< dp
->ifp
->v6address_count
; i
++) {
1456 if (IN6_IS_ADDR_LINKLOCAL(&dp
->ifp
->v6addresses
[i
]))
1460 if (!memcmp(&dp
->ifp
->v6addresses
[i
],
1461 &dp
->link
.sin6_addr
,
1462 sizeof(dp
->link
.sin6_addr
)))
1465 if (i
== dp
->ifp
->v6address_count
)
1466 log_fatal("Interface %s does not have global IPv6 "
1467 "address assigned.", dp
->ifp
->name
);
1469 memcpy(&dp
->link
.sin6_addr
,
1470 &dp
->ifp
->v6addresses
[i
],
1471 sizeof(dp
->link
.sin6_addr
));
1473 /* Set interface-id. */
1475 dp
->id
= dp
->ifp
->index
;
1478 for (up
= upstreams
; up
; up
= up
->next
) {
1479 up
->link
.sin6_port
= local_port
;
1480 up
->link
.sin6_family
= AF_INET6
;
1482 up
->link
.sin6_len
= sizeof(up
->link
);
1485 if (up
->ifp
->v6address_count
== 0)
1486 log_fatal("Interface '%s' has no IPv6 addresses.",
1489 /* RFC 3315 Sec 20 - "If the relay agent relays messages to
1490 * the All_DHCP_Servers address or other multicast addresses,
1491 * it sets the Hop Limit field to 32." */
1492 if (IN6_IS_ADDR_MULTICAST(&up
->link
.sin6_addr
)) {
1493 set_multicast_hop_limit(up
->ifp
, HOP_COUNT_LIMIT
);
1499 * Add DHCPv6 agent options here.
1501 static const int required_forw_opts
[] = {
1509 * Process a packet upwards, i.e., from client to server.
1512 process_up6(struct packet
*packet
, struct stream_list
*dp
) {
1513 char forw_data
[65535];
1515 struct dhcpv6_relay_packet
*relay
;
1516 struct option_state
*opts
;
1517 struct stream_list
*up
;
1519 /* Check if the message should be relayed to the server. */
1520 switch (packet
->dhcpv6_msg_type
) {
1521 case DHCPV6_SOLICIT
:
1522 case DHCPV6_REQUEST
:
1523 case DHCPV6_CONFIRM
:
1526 case DHCPV6_RELEASE
:
1527 case DHCPV6_DECLINE
:
1528 case DHCPV6_INFORMATION_REQUEST
:
1529 case DHCPV6_RELAY_FORW
:
1530 case DHCPV6_LEASEQUERY
:
1531 case DHCPV6_DHCPV4_QUERY
:
1532 log_info("Relaying %s from %s port %d going up.",
1533 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1534 piaddr(packet
->client_addr
),
1535 ntohs(packet
->client_port
));
1538 case DHCPV6_ADVERTISE
:
1540 case DHCPV6_RECONFIGURE
:
1541 case DHCPV6_RELAY_REPL
:
1542 case DHCPV6_LEASEQUERY_REPLY
:
1543 case DHCPV6_DHCPV4_RESPONSE
:
1544 log_info("Discarding %s from %s port %d going up.",
1545 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1546 piaddr(packet
->client_addr
),
1547 ntohs(packet
->client_port
));
1551 log_info("Unknown %d type from %s port %d going up.",
1552 packet
->dhcpv6_msg_type
,
1553 piaddr(packet
->client_addr
),
1554 ntohs(packet
->client_port
));
1558 /* Build the relay-forward header. */
1559 relay
= (struct dhcpv6_relay_packet
*) forw_data
;
1560 cursor
= offsetof(struct dhcpv6_relay_packet
, options
);
1561 relay
->msg_type
= DHCPV6_RELAY_FORW
;
1562 if (packet
->dhcpv6_msg_type
== DHCPV6_RELAY_FORW
) {
1563 if (packet
->dhcpv6_hop_count
>= max_hop_count
) {
1564 log_info("Hop count exceeded,");
1567 relay
->hop_count
= packet
->dhcpv6_hop_count
+ 1;
1569 memcpy(&relay
->link_address
, &dp
->link
.sin6_addr
, 16);
1571 /* On smart relay add: && !global. */
1572 if (!use_if_id
&& downstreams
->next
) {
1573 log_info("Shan't get back the interface.");
1576 memset(&relay
->link_address
, 0, 16);
1579 relay
->hop_count
= 0;
1582 memcpy(&relay
->link_address
, &dp
->link
.sin6_addr
, 16);
1584 memcpy(&relay
->peer_address
, packet
->client_addr
.iabuf
, 16);
1586 /* Get an option state. */
1588 if (!option_state_allocate(&opts
, MDL
)) {
1589 log_fatal("No memory for upwards options.");
1592 /* Add an interface-id (if used). */
1598 } else if (!downstreams
->next
) {
1599 if_id
= downstreams
->id
;
1601 log_info("Don't know the interface.");
1602 option_state_dereference(&opts
, MDL
);
1606 if (!save_option_buffer(&dhcpv6_universe
, opts
,
1607 NULL
, (unsigned char *) &if_id
,
1609 D6O_INTERFACE_ID
, 0)) {
1610 log_error("Can't save interface-id.");
1611 option_state_dereference(&opts
, MDL
);
1616 /* Add a subscriber-id if desired. */
1617 /* This is for testing rather than general use */
1618 if (dhcrelay_sub_id
!= NULL
) {
1619 if (!save_option_buffer(&dhcpv6_universe
, opts
, NULL
,
1620 (unsigned char *) dhcrelay_sub_id
,
1621 strlen(dhcrelay_sub_id
),
1622 D6O_SUBSCRIBER_ID
, 0)) {
1623 log_error("Can't save subsriber-id.");
1624 option_state_dereference(&opts
, MDL
);
1630 /* Add the relay-msg carrying the packet. */
1631 if (!save_option_buffer(&dhcpv6_universe
, opts
,
1632 NULL
, (unsigned char *) packet
->raw
,
1633 packet
->packet_length
,
1634 D6O_RELAY_MSG
, 0)) {
1635 log_error("Can't save relay-msg.");
1636 option_state_dereference(&opts
, MDL
);
1640 /* Finish the relay-forward message. */
1641 cursor
+= store_options6(forw_data
+ cursor
,
1642 sizeof(forw_data
) - cursor
,
1644 required_forw_opts
, NULL
);
1645 option_state_dereference(&opts
, MDL
);
1647 /* Send it to all upstreams. */
1648 for (up
= upstreams
; up
; up
= up
->next
) {
1649 send_packet6(up
->ifp
, (unsigned char *) forw_data
,
1650 (size_t) cursor
, &up
->link
);
1655 * Process a packet downwards, i.e., from server to client.
1658 process_down6(struct packet
*packet
) {
1659 struct stream_list
*dp
;
1660 struct option_cache
*oc
;
1661 struct data_string relay_msg
;
1662 const struct dhcpv6_packet
*msg
;
1663 struct data_string if_id
;
1664 struct sockaddr_in6 to
;
1667 /* The packet must be a relay-reply message. */
1668 if (packet
->dhcpv6_msg_type
!= DHCPV6_RELAY_REPL
) {
1669 if (packet
->dhcpv6_msg_type
< dhcpv6_type_name_max
)
1670 log_info("Discarding %s from %s port %d going down.",
1671 dhcpv6_type_names
[packet
->dhcpv6_msg_type
],
1672 piaddr(packet
->client_addr
),
1673 ntohs(packet
->client_port
));
1675 log_info("Unknown %d type from %s port %d going down.",
1676 packet
->dhcpv6_msg_type
,
1677 piaddr(packet
->client_addr
),
1678 ntohs(packet
->client_port
));
1683 memset(&relay_msg
, 0, sizeof(relay_msg
));
1684 memset(&if_id
, 0, sizeof(if_id
));
1685 memset(&to
, 0, sizeof(to
));
1686 to
.sin6_family
= AF_INET6
;
1688 to
.sin6_len
= sizeof(to
);
1690 to
.sin6_port
= remote_port
;
1693 /* Get the relay-msg option (carrying the message to relay). */
1694 oc
= lookup_option(&dhcpv6_universe
, packet
->options
, D6O_RELAY_MSG
);
1696 log_info("No relay-msg.");
1699 if (!evaluate_option_cache(&relay_msg
, packet
, NULL
, NULL
,
1700 packet
->options
, NULL
,
1701 &global_scope
, oc
, MDL
) ||
1702 (relay_msg
.len
< offsetof(struct dhcpv6_packet
, options
))) {
1703 log_error("Can't evaluate relay-msg.");
1706 msg
= (const struct dhcpv6_packet
*) relay_msg
.data
;
1708 /* Get the interface-id (if exists) and the downstream. */
1709 oc
= lookup_option(&dhcpv6_universe
, packet
->options
,
1714 if (!evaluate_option_cache(&if_id
, packet
, NULL
, NULL
,
1715 packet
->options
, NULL
,
1716 &global_scope
, oc
, MDL
) ||
1717 (if_id
.len
!= sizeof(int))) {
1718 log_info("Can't evaluate interface-id.");
1721 memcpy(&if_index
, if_id
.data
, sizeof(int));
1722 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1723 if (dp
->id
== if_index
)
1728 /* Require an interface-id. */
1729 log_info("No interface-id.");
1732 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1733 /* Get the first matching one. */
1734 if (!memcmp(&dp
->link
.sin6_addr
,
1735 &packet
->dhcpv6_link_address
,
1736 sizeof(struct in6_addr
)))
1740 /* Why bother when there is no choice. */
1741 if (!dp
&& downstreams
&& !downstreams
->next
)
1744 log_info("Can't find the down interface.");
1747 memcpy(peer
.iabuf
, &packet
->dhcpv6_peer_address
, peer
.len
);
1748 to
.sin6_addr
= packet
->dhcpv6_peer_address
;
1750 /* Check if we should relay the carried message. */
1751 switch (msg
->msg_type
) {
1752 /* Relay-Reply of for another relay, not a client. */
1753 case DHCPV6_RELAY_REPL
:
1754 to
.sin6_port
= local_port
;
1757 case DHCPV6_ADVERTISE
:
1759 case DHCPV6_RECONFIGURE
:
1760 case DHCPV6_RELAY_FORW
:
1761 case DHCPV6_LEASEQUERY_REPLY
:
1762 case DHCPV6_DHCPV4_RESPONSE
:
1763 log_info("Relaying %s to %s port %d down.",
1764 dhcpv6_type_names
[msg
->msg_type
],
1766 ntohs(to
.sin6_port
));
1769 case DHCPV6_SOLICIT
:
1770 case DHCPV6_REQUEST
:
1771 case DHCPV6_CONFIRM
:
1774 case DHCPV6_RELEASE
:
1775 case DHCPV6_DECLINE
:
1776 case DHCPV6_INFORMATION_REQUEST
:
1777 case DHCPV6_LEASEQUERY
:
1778 case DHCPV6_DHCPV4_QUERY
:
1779 log_info("Discarding %s to %s port %d down.",
1780 dhcpv6_type_names
[msg
->msg_type
],
1782 ntohs(to
.sin6_port
));
1786 log_info("Unknown %d type to %s port %d down.",
1789 ntohs(to
.sin6_port
));
1793 /* Send the message to the downstream. */
1794 send_packet6(dp
->ifp
, (unsigned char *) relay_msg
.data
,
1795 (size_t) relay_msg
.len
, &to
);
1798 if (relay_msg
.data
!= NULL
)
1799 data_string_forget(&relay_msg
, MDL
);
1800 if (if_id
.data
!= NULL
)
1801 data_string_forget(&if_id
, MDL
);
1805 * Called by the dispatch packet handler with a decoded packet.
1808 dhcpv6(struct packet
*packet
) {
1809 struct stream_list
*dp
;
1811 /* Try all relay-replies downwards. */
1812 if (packet
->dhcpv6_msg_type
== DHCPV6_RELAY_REPL
) {
1813 process_down6(packet
);
1816 /* Others are candidates to go up if they come from down. */
1817 for (dp
= downstreams
; dp
; dp
= dp
->next
) {
1818 if (packet
->interface
!= dp
->ifp
)
1820 process_up6(packet
, dp
);
1823 /* Relay-forward could work from an unknown interface. */
1824 if (packet
->dhcpv6_msg_type
== DHCPV6_RELAY_FORW
) {
1825 process_up6(packet
, NULL
);
1829 log_info("Can't process packet from interface '%s'.",
1830 packet
->interface
->name
);
1834 /* Stub routines needed for linking with DHCP libraries. */
1836 bootp(struct packet
*packet
) {
1841 dhcp(struct packet
*packet
) {
1846 classify(struct packet
*p
, struct class *c
) {
1851 check_collection(struct packet
*p
, struct lease
*l
, struct collection
*c
) {
1856 find_class(struct class **class, const char *c1
, const char *c2
, int i
) {
1857 return ISC_R_NOTFOUND
;
1861 parse_allow_deny(struct option_cache
**oc
, struct parse
*p
, int i
) {
1866 dhcp_set_control_state(control_object_state_t oldstate
,
1867 control_object_state_t newstate
) {
1868 if (newstate
!= server_shutdown
)
1869 return ISC_R_SUCCESS
;
1871 if (no_pid_file
== ISC_FALSE
)
1872 (void) unlink(path_dhcrelay_pid
);
1879 * \brief Allocate an interface as requested with a given set of flags
1881 * The requested interface is allocated, its flags field is set to
1882 * INTERFACE_REQUESTED OR'd with the given flags, and then added to
1883 * the list of interfaces.
1885 * \param name - name of the requested interface
1886 * \param flags - additional flags for the interface
1890 void request_v4_interface(const char* name
, int flags
) {
1891 struct interface_info
*tmp
= NULL
;
1892 int len
= strlen(name
);
1893 isc_result_t status
;
1895 if (len
>= sizeof(tmp
->name
)) {
1896 log_fatal("%s: interface name too long (is %d)", name
, len
);
1899 status
= interface_allocate(&tmp
, MDL
);
1900 if (status
!= ISC_R_SUCCESS
) {
1901 log_fatal("%s: interface_allocate: %s", name
,
1902 isc_result_totext(status
));
1905 log_debug("Requesting: %s as upstream: %c downstream: %c", name
,
1906 (flags
& INTERFACE_UPSTREAM
? 'Y' : 'N'),
1907 (flags
& INTERFACE_DOWNSTREAM
? 'Y' : 'N'));
1909 strncpy(tmp
->name
, name
, len
);
1910 interface_snorf(tmp
, (INTERFACE_REQUESTED
| flags
));
1911 interface_dereference(&tmp
, MDL
);