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