]> git.ipfire.org Git - thirdparty/dhcp.git/blame - relay/dhcrelay.c
Remerged #38692
[thirdparty/dhcp.git] / relay / dhcrelay.c
CommitLineData
747ec13b
TL
1/* dhcrelay.c
2
3 DHCP/BOOTP Relay Agent. */
4
5/*
2794167d 6 * Copyright(c) 2004-2015 by Internet Systems Consortium, Inc.("ISC")
7de20a95 7 * Copyright(c) 1997-2003 by Internet Software Consortium
747ec13b 8 *
98311e4b
DH
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.
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
DH
21 * Internet Systems Consortium, Inc.
22 * 950 Charter Street
23 * Redwood City, CA 94063
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. */
d352732e
EH
64
65int agent_option_errors = 0; /* Number of packets forwarded without
66 agent options because there was no room. */
866428dd 67int drop_agent_mismatches = 0; /* If nonzero, drop server replies that
98311e4b 68 don't have matching circuit-id's. */
866428dd
TL
69int corrupt_agent_options = 0; /* Number of packets dropped because
70 relay agent information option was bad. */
71int missing_agent_option = 0; /* Number of packets dropped because no
72 RAI option matching our ID was found. */
73int bad_circuit_id = 0; /* Circuit ID option in matching RAI option
74 did not match any known circuit ID. */
75int missing_circuit_id = 0; /* Circuit ID option in matching RAI option
76 was missing. */
98311e4b
DH
77int max_hop_count = 10; /* Maximum hop count */
78
7de20a95
EH
79#ifdef DHCPv6
80 /* Force use of DHCPv6 interface-id option. */
81isc_boolean_t use_if_id = ISC_FALSE;
82#endif
866428dd
TL
83
84 /* Maximum size of a packet with agent options added. */
d352732e 85int dhcp_max_agent_option_packet_length = DHCP_MTU_MIN;
866428dd
TL
86
87 /* What to do about packets we're asked to relay that
88 already have a relay option: */
89enum { forward_and_append, /* Forward and append our own relay option. */
90 forward_and_replace, /* Forward, but replace theirs with ours. */
91 forward_untouched, /* Forward without changes. */
92 discard } agent_relay_mode = forward_and_replace;
93
747ec13b
TL
94u_int16_t local_port;
95u_int16_t remote_port;
747ec13b 96
78c553c4
DH
97/* Relay agent server list. */
98struct server_list {
99 struct server_list *next;
100 struct sockaddr_in to;
101} *servers;
102
7de20a95
EH
103#ifdef DHCPv6
104struct stream_list {
105 struct stream_list *next;
106 struct interface_info *ifp;
107 struct sockaddr_in6 link;
108 int id;
109} *downstreams, *upstreams;
110
111static struct stream_list *parse_downstream(char *);
112static struct stream_list *parse_upstream(char *);
113static void setup_streams(void);
619304cd
SR
114
115/*
116 * A pointer to a subscriber id to add to the message we forward.
117 * This is primarily for testing purposes as we only have one id
118 * for the entire relay and don't determine one per client which
119 * would be more useful.
120 */
121char *dhcrelay_sub_id = NULL;
7de20a95
EH
122#endif
123
124static void do_relay4(struct interface_info *, struct dhcp_packet *,
125 unsigned int, unsigned int, struct iaddr,
d352732e 126 struct hardware *);
7de20a95 127static int add_relay_agent_options(struct interface_info *,
d352732e
EH
128 struct dhcp_packet *, unsigned,
129 struct in_addr);
7de20a95 130static int find_interface_by_agent_option(struct dhcp_packet *,
d352732e 131 struct interface_info **, u_int8_t *, int);
7de20a95 132static int strip_relay_agent_options(struct interface_info *,
d352732e
EH
133 struct interface_info **,
134 struct dhcp_packet *, unsigned);
7de20a95 135
ae566556 136static const char copyright[] =
4d9b81fc 137"Copyright 2004-2015 Internet Systems Consortium.";
ae566556
SR
138static const char arr[] = "All rights reserved.";
139static const char message[] =
140"Internet Systems Consortium DHCP Relay Agent";
141static const char url[] =
2c85ac9b 142"For info, please visit https://www.isc.org/software/dhcp/";
7de20a95 143
7acd8753
FD
144char *progname;
145
7de20a95
EH
146#ifdef DHCPv6
147#define DHCRELAY_USAGE \
7acd8753 148"Usage: %s [-4] [-d] [-q] [-a] [-D]\n"\
7de20a95 149" [-A <length>] [-c <hops>] [-p <port>]\n" \
4a5bfeac 150" [-pf <pid-file>] [--no-pid]\n"\
7de20a95
EH
151" [-m append|replace|forward|discard]\n" \
152" [-i interface0 [ ... -i interfaceN]\n" \
153" server0 [ ... serverN]\n\n" \
7acd8753 154" %s -6 [-d] [-q] [-I] [-c <hops>] [-p <port>]\n" \
619304cd
SR
155" [-pf <pid-file>] [--no-pid]\n" \
156" [-s <subscriber-id>]\n" \
7de20a95
EH
157" -l lower0 [ ... -l lowerN]\n" \
158" -u upper0 [ ... -u upperN]\n" \
159" lower (client link): [address%%]interface[#index]\n" \
160" upper (server link): [address%%]interface"
161#else
162#define DHCRELAY_USAGE \
7acd8753 163"Usage: %s [-d] [-q] [-a] [-D] [-A <length>] [-c <hops>] [-p <port>]\n" \
619304cd 164" [-pf <pid-file>] [--no-pid]\n" \
7de20a95
EH
165" [-m append|replace|forward|discard]\n" \
166" [-i interface0 [ ... -i interfaceN]\n" \
167" server0 [ ... serverN]\n\n"
168#endif
169
170static void usage() {
7acd8753
FD
171 log_fatal(DHCRELAY_USAGE,
172#ifdef DHCPv6
173 isc_file_basename(progname),
174#endif
175 isc_file_basename(progname));
7de20a95 176}
d2bc90bd 177
98bd7ca0
DH
178int
179main(int argc, char **argv) {
7de20a95 180 isc_result_t status;
747ec13b 181 struct servent *ent;
78c553c4 182 struct server_list *sp = NULL;
d352732e 183 struct interface_info *tmp = NULL;
4c750c58
PS
184 char *service_local = NULL, *service_remote = NULL;
185 u_int16_t port_local = 0, port_remote = 0;
7de20a95
EH
186 int no_daemon = 0, quiet = 0;
187 int fd;
188 int i;
189#ifdef DHCPv6
d352732e 190 struct stream_list *sl = NULL;
7de20a95
EH
191 int local_family_set = 0;
192#endif
747ec13b 193
7acd8753
FD
194#ifdef OLD_LOG_NAME
195 progname = "dhcrelay";
196#else
197 progname = argv[0];
198#endif
199
d352732e
EH
200 /* Make sure that file descriptors 0(stdin), 1,(stdout), and
201 2(stderr) are open. To do this, we assume that when we
202 open a file the lowest available file descriptor is used. */
203 fd = open("/dev/null", O_RDWR);
204 if (fd == 0)
205 fd = open("/dev/null", O_RDWR);
206 if (fd == 1)
207 fd = open("/dev/null", O_RDWR);
208 if (fd == 2)
209 log_perror = 0; /* No sense logging to /dev/null. */
210 else if (fd != -1)
211 close(fd);
dfb6c5aa 212
7acd8753 213 openlog(isc_file_basename(progname), DHCP_LOG_OPTIONS, LOG_DAEMON);
747ec13b 214
fe5b0fdd 215#if !defined(DEBUG)
7de20a95 216 setlogmask(LOG_UPTO(LOG_INFO));
747ec13b
TL
217#endif
218
98bf1607 219 /* Set up the isc and dns library managers */
61ef216b
SR
220 status = dhcp_context_create(DHCP_CONTEXT_PRE_DB | DHCP_CONTEXT_POST_DB,
221 NULL, NULL);
98bf1607
SR
222 if (status != ISC_R_SUCCESS)
223 log_fatal("Can't initialize context: %s",
224 isc_result_totext(status));
225
6cecb7c5 226 /* Set up the OMAPI. */
7de20a95 227 status = omapi_init();
6cecb7c5 228 if (status != ISC_R_SUCCESS)
7de20a95
EH
229 log_fatal("Can't initialize OMAPI: %s",
230 isc_result_totext(status));
6cecb7c5
TL
231
232 /* Set up the OMAPI wrappers for the interface object. */
7de20a95 233 interface_setup();
6cecb7c5 234
747ec13b 235 for (i = 1; i < argc; i++) {
7de20a95
EH
236 if (!strcmp(argv[i], "-4")) {
237#ifdef DHCPv6
238 if (local_family_set && (local_family == AF_INET6)) {
239 usage();
e7012e3f 240 }
7de20a95
EH
241 local_family_set = 1;
242 local_family = AF_INET;
243 } else if (!strcmp(argv[i], "-6")) {
244 if (local_family_set && (local_family == AF_INET)) {
245 usage();
246 }
247 local_family_set = 1;
248 local_family = AF_INET6;
249#endif
250 } else if (!strcmp(argv[i], "-d")) {
251 no_daemon = 1;
252 } else if (!strcmp(argv[i], "-q")) {
e7012e3f
TL
253 quiet = 1;
254 quiet_interface_discovery = 1;
7de20a95
EH
255 } else if (!strcmp(argv[i], "-p")) {
256 if (++i == argc)
257 usage();
59112e84 258 local_port = validate_port(argv[i]);
7de20a95
EH
259 log_debug("binding to user-specified port %d",
260 ntohs(local_port));
261 } else if (!strcmp(argv[i], "-c")) {
98311e4b
DH
262 int hcount;
263 if (++i == argc)
7de20a95 264 usage();
98311e4b
DH
265 hcount = atoi(argv[i]);
266 if (hcount <= 255)
267 max_hop_count= hcount;
268 else
7de20a95
EH
269 usage();
270 } else if (!strcmp(argv[i], "-i")) {
271#ifdef DHCPv6
272 if (local_family_set && (local_family == AF_INET6)) {
273 usage();
274 }
275 local_family_set = 1;
276 local_family = AF_INET;
277#endif
0f750c4f
SR
278 if (++i == argc) {
279 usage();
280 }
281 if (strlen(argv[i]) >= sizeof(tmp->name)) {
282 log_fatal("%s: interface name too long "
283 "(is %ld)",
284 argv[i], (long)strlen(argv[i]));
285 }
7de20a95 286 status = interface_allocate(&tmp, MDL);
0f750c4f 287 if (status != ISC_R_SUCCESS) {
7de20a95
EH
288 log_fatal("%s: interface_allocate: %s",
289 argv[i],
290 isc_result_totext(status));
7de20a95
EH
291 }
292 strcpy(tmp->name, argv[i]);
293 interface_snorf(tmp, INTERFACE_REQUESTED);
294 interface_dereference(&tmp, MDL);
295 } else if (!strcmp(argv[i], "-a")) {
296#ifdef DHCPv6
297 if (local_family_set && (local_family == AF_INET6)) {
298 usage();
299 }
300 local_family_set = 1;
301 local_family = AF_INET;
302#endif
303 add_agent_options = 1;
304 } else if (!strcmp(argv[i], "-A")) {
305#ifdef DHCPv6
306 if (local_family_set && (local_family == AF_INET6)) {
307 usage();
308 }
309 local_family_set = 1;
310 local_family = AF_INET;
311#endif
866428dd 312 if (++i == argc)
7de20a95 313 usage();
d352732e 314
7de20a95 315 dhcp_max_agent_option_packet_length = atoi(argv[i]);
d352732e
EH
316
317 if (dhcp_max_agent_option_packet_length > DHCP_MTU_MAX)
318 log_fatal("%s: packet length exceeds "
319 "longest possible MTU\n",
320 argv[i]);
7de20a95
EH
321 } else if (!strcmp(argv[i], "-m")) {
322#ifdef DHCPv6
323 if (local_family_set && (local_family == AF_INET6)) {
324 usage();
325 }
326 local_family_set = 1;
327 local_family = AF_INET;
328#endif
866428dd 329 if (++i == argc)
7de20a95
EH
330 usage();
331 if (!strcasecmp(argv[i], "append")) {
866428dd 332 agent_relay_mode = forward_and_append;
7de20a95 333 } else if (!strcasecmp(argv[i], "replace")) {
866428dd 334 agent_relay_mode = forward_and_replace;
7de20a95 335 } else if (!strcasecmp(argv[i], "forward")) {
866428dd 336 agent_relay_mode = forward_untouched;
7de20a95 337 } else if (!strcasecmp(argv[i], "discard")) {
866428dd
TL
338 agent_relay_mode = discard;
339 } else
7de20a95
EH
340 usage();
341 } else if (!strcmp(argv[i], "-D")) {
342#ifdef DHCPv6
343 if (local_family_set && (local_family == AF_INET6)) {
344 usage();
345 }
346 local_family_set = 1;
347 local_family = AF_INET;
348#endif
866428dd 349 drop_agent_mismatches = 1;
7de20a95
EH
350#ifdef DHCPv6
351 } else if (!strcmp(argv[i], "-I")) {
352 if (local_family_set && (local_family == AF_INET)) {
353 usage();
354 }
355 local_family_set = 1;
356 local_family = AF_INET6;
357 use_if_id = ISC_TRUE;
358 } else if (!strcmp(argv[i], "-l")) {
359 if (local_family_set && (local_family == AF_INET)) {
360 usage();
361 }
362 local_family_set = 1;
363 local_family = AF_INET6;
d352732e
EH
364 if (downstreams != NULL)
365 use_if_id = ISC_TRUE;
7de20a95
EH
366 if (++i == argc)
367 usage();
d352732e
EH
368 sl = parse_downstream(argv[i]);
369 sl->next = downstreams;
370 downstreams = sl;
7de20a95
EH
371 } else if (!strcmp(argv[i], "-u")) {
372 if (local_family_set && (local_family == AF_INET)) {
373 usage();
374 }
375 local_family_set = 1;
376 local_family = AF_INET6;
377 if (++i == argc)
378 usage();
d352732e
EH
379 sl = parse_upstream(argv[i]);
380 sl->next = upstreams;
381 upstreams = sl;
619304cd
SR
382 } else if (!strcmp(argv[i], "-s")) {
383 if (local_family_set && (local_family == AF_INET)) {
384 usage();
385 }
386 local_family_set = 1;
387 local_family = AF_INET6;
388 if (++i == argc)
389 usage();
390 dhcrelay_sub_id = argv[i];
7de20a95 391#endif
4a5bfeac
SR
392 } else if (!strcmp(argv[i], "-pf")) {
393 if (++i == argc)
394 usage();
395 path_dhcrelay_pid = argv[i];
396 no_dhcrelay_pid = ISC_TRUE;
397 } else if (!strcmp(argv[i], "--no-pid")) {
398 no_pid_file = ISC_TRUE;
7de20a95
EH
399 } else if (!strcmp(argv[i], "--version")) {
400 log_info("isc-dhcrelay-%s", PACKAGE_VERSION);
401 exit(0);
402 } else if (!strcmp(argv[i], "--help") ||
403 !strcmp(argv[i], "-h")) {
7acd8753
FD
404 log_info(DHCRELAY_USAGE,
405#ifdef DHCPv6
406 isc_file_basename(progname),
407#endif
408 isc_file_basename(progname));
7de20a95
EH
409 exit(0);
410 } else if (argv[i][0] == '-') {
411 usage();
747ec13b 412 } else {
78c553c4 413 struct hostent *he;
7de20a95
EH
414 struct in_addr ia, *iap = NULL;
415
416#ifdef DHCPv6
417 if (local_family_set && (local_family == AF_INET6)) {
418 usage();
419 }
420 local_family_set = 1;
421 local_family = AF_INET;
422#endif
423 if (inet_aton(argv[i], &ia)) {
78c553c4
DH
424 iap = &ia;
425 } else {
7de20a95 426 he = gethostbyname(argv[i]);
78c553c4 427 if (!he) {
7de20a95 428 log_error("%s: host unknown", argv[i]);
78c553c4
DH
429 } else {
430 iap = ((struct in_addr *)
7de20a95 431 he->h_addr_list[0]);
78c553c4
DH
432 }
433 }
7de20a95 434
78c553c4
DH
435 if (iap) {
436 sp = ((struct server_list *)
7de20a95 437 dmalloc(sizeof *sp, MDL));
78c553c4 438 if (!sp)
7de20a95
EH
439 log_fatal("no memory for server.\n");
440 sp->next = servers;
78c553c4 441 servers = sp;
7de20a95 442 memcpy(&sp->to.sin_addr, iap, sizeof *iap);
78c553c4 443 }
747ec13b
TL
444 }
445 }
e7012e3f 446
4a5bfeac
SR
447 /*
448 * If the user didn't specify a pid file directly
449 * find one from environment variables or defaults
450 */
451 if (no_dhcrelay_pid == ISC_FALSE) {
452 if (local_family == AF_INET) {
453 path_dhcrelay_pid = getenv("PATH_DHCRELAY_PID");
454 if (path_dhcrelay_pid == NULL)
455 path_dhcrelay_pid = _PATH_DHCRELAY_PID;
456 }
7de20a95 457#ifdef DHCPv6
4a5bfeac
SR
458 else {
459 path_dhcrelay_pid = getenv("PATH_DHCRELAY6_PID");
460 if (path_dhcrelay_pid == NULL)
461 path_dhcrelay_pid = _PATH_DHCRELAY6_PID;
462 }
7de20a95 463#endif
4a5bfeac 464 }
cfa7212d 465
d2bc90bd 466 if (!quiet) {
7de20a95
EH
467 log_info("%s %s", message, PACKAGE_VERSION);
468 log_info(copyright);
469 log_info(arr);
470 log_info(url);
dc9d7b08 471 } else
bc62fb2a 472 log_perror = 0;
d2bc90bd 473
7de20a95 474 /* Set default port */
d352732e 475 if (local_family == AF_INET) {
9733358a
EH
476 service_local = "bootps";
477 service_remote = "bootpc";
d352732e 478 port_local = htons(67);
9733358a 479 port_remote = htons(68);
d352732e 480 }
7de20a95 481#ifdef DHCPv6
d352732e
EH
482 else {
483 service_local = "dhcpv6-server";
484 service_remote = "dhcpv6-client";
485 port_local = htons(547);
486 port_remote = htons(546);
487 }
7de20a95 488#endif
747ec13b 489
7de20a95 490 if (!local_port) {
d352732e
EH
491 ent = getservbyname(service_local, "udp");
492 if (ent)
493 local_port = ent->s_port;
494 else
495 local_port = port_local;
496
497 ent = getservbyname(service_remote, "udp");
498 if (ent)
499 remote_port = ent->s_port;
500 else
501 remote_port = port_remote;
502
503 endservent();
504 }
505
506 if (local_family == AF_INET) {
507 /* We need at least one server */
508 if (servers == NULL) {
509 log_fatal("No servers specified.");
510 }
511
512
513 /* Set up the server sockaddrs. */
514 for (sp = servers; sp; sp = sp->next) {
515 sp->to.sin_port = local_port;
516 sp->to.sin_family = AF_INET;
747ec13b 517#ifdef HAVE_SA_LEN
d352732e 518 sp->to.sin_len = sizeof sp->to;
7de20a95 519#endif
d352732e
EH
520 }
521 }
7de20a95 522#ifdef DHCPv6
d352732e 523 else {
7de20a95
EH
524 unsigned code;
525
d352732e
EH
526 /* We need at least one upstream and one downstream interface */
527 if (upstreams == NULL || downstreams == NULL) {
528 log_info("Must specify at least one lower "
529 "and one upper interface.\n");
530 usage();
531 }
7de20a95
EH
532
533 /* Set up the initial dhcp option universe. */
534 initialize_common_option_spaces();
535
536 /* Check requested options. */
537 code = D6O_RELAY_MSG;
538 if (!option_code_hash_lookup(&requested_opts[0],
539 dhcpv6_universe.code_hash,
540 &code, 0, MDL))
541 log_fatal("Unable to find the RELAY_MSG "
542 "option definition.");
543 code = D6O_INTERFACE_ID;
544 if (!option_code_hash_lookup(&requested_opts[1],
545 dhcpv6_universe.code_hash,
546 &code, 0, MDL))
547 log_fatal("Unable to find the INTERFACE_ID "
548 "option definition.");
d352732e 549 }
747ec13b 550#endif
747ec13b
TL
551
552 /* Get the current time... */
be62cf06 553 gettimeofday(&cur_tv, NULL);
747ec13b
TL
554
555 /* Discover all the network interfaces. */
7de20a95 556 discover_interfaces(DISCOVER_RELAY);
747ec13b 557
7de20a95
EH
558#ifdef DHCPv6
559 if (local_family == AF_INET6)
d352732e 560 setup_streams();
7de20a95 561#endif
84228fed 562
e7012e3f
TL
563 /* Become a daemon... */
564 if (!no_daemon) {
565 int pid;
566 FILE *pf;
567 int pfdesc;
568
569 log_perror = 0;
570
571 if ((pid = fork()) < 0)
7de20a95 572 log_fatal("Can't fork daemon: %m");
e7012e3f 573 else if (pid)
7de20a95 574 exit(0);
e7012e3f 575
4a5bfeac
SR
576 if (no_pid_file == ISC_FALSE) {
577 pfdesc = open(path_dhcrelay_pid,
578 O_CREAT | O_TRUNC | O_WRONLY, 0644);
579
580 if (pfdesc < 0) {
581 log_error("Can't create %s: %m",
582 path_dhcrelay_pid);
583 } else {
584 pf = fdopen(pfdesc, "w");
585 if (!pf)
586 log_error("Can't fdopen %s: %m",
587 path_dhcrelay_pid);
588 else {
589 fprintf(pf, "%ld\n",(long)getpid());
590 fclose(pf);
591 }
592 }
e7012e3f
TL
593 }
594
dc9d7b08
MA
595 (void) close(0);
596 (void) close(1);
597 (void) close(2);
598 (void) setsid();
a546f2a7 599
ae566556 600 IGNORE_RET (chdir("/"));
e7012e3f
TL
601 }
602
7de20a95 603 /* Set up the packet handler... */
d352732e
EH
604 if (local_family == AF_INET)
605 bootp_packet_handler = do_relay4;
7de20a95 606#ifdef DHCPv6
d352732e
EH
607 else
608 dhcpv6_packet_handler = do_packet6;
7de20a95
EH
609#endif
610
e9326fd0
SR
611#if defined(ENABLE_GENTLE_SHUTDOWN)
612 /* no signal handlers until we deal with the side effects */
47e8308d
SR
613 /* install signal handlers */
614 signal(SIGINT, dhcp_signal_handler); /* control-c */
615 signal(SIGTERM, dhcp_signal_handler); /* kill */
e9326fd0 616#endif
47e8308d 617
747ec13b 618 /* Start dispatching packets and timeouts... */
7de20a95 619 dispatch();
84228fed 620
0895c955 621 /* In fact dispatch() never returns. */
7de20a95 622 return (0);
747ec13b
TL
623}
624
7de20a95
EH
625static void
626do_relay4(struct interface_info *ip, struct dhcp_packet *packet,
627 unsigned int length, unsigned int from_port, struct iaddr from,
628 struct hardware *hfrom) {
747ec13b
TL
629 struct server_list *sp;
630 struct sockaddr_in to;
631 struct interface_info *out;
98311e4b 632 struct hardware hto, *htop;
747ec13b 633
7de20a95 634 if (packet->hlen > sizeof packet->chaddr) {
1185c766
TM
635 log_info("Discarding packet with invalid hlen, received on "
636 "%s interface.", ip->name);
637 return;
638 }
639 if (ip->address_count < 1 || ip->addresses == NULL) {
640 log_info("Discarding packet received on %s interface that "
641 "has no IPv4 address assigned.", ip->name);
60dab809
TL
642 return;
643 }
644
866428dd
TL
645 /* Find the interface that corresponds to the giaddr
646 in the packet. */
7de20a95
EH
647 if (packet->giaddr.s_addr) {
648 for (out = interfaces; out; out = out->next) {
98bd7ca0
DH
649 int i;
650
651 for (i = 0 ; i < out->address_count ; i++ ) {
652 if (out->addresses[i].s_addr ==
0f750c4f 653 packet->giaddr.s_addr) {
98bd7ca0
DH
654 i = -1;
655 break;
0f750c4f 656 }
98bd7ca0
DH
657 }
658
659 if (i == -1)
78c553c4 660 break;
866428dd
TL
661 }
662 } else {
7de20a95 663 out = NULL;
866428dd
TL
664 }
665
747ec13b 666 /* If it's a bootreply, forward it to the client. */
7de20a95
EH
667 if (packet->op == BOOTREPLY) {
668 if (!(packet->flags & htons(BOOTP_BROADCAST)) &&
669 can_unicast_without_arp(out)) {
670 to.sin_addr = packet->yiaddr;
75661c60 671 to.sin_port = remote_port;
98311e4b
DH
672
673 /* and hardware address is not broadcast */
674 htop = &hto;
d2bc90bd 675 } else {
7de20a95 676 to.sin_addr.s_addr = htonl(INADDR_BROADCAST);
75661c60 677 to.sin_port = remote_port;
98311e4b
DH
678
679 /* hardware address is broadcast */
680 htop = NULL;
747ec13b
TL
681 }
682 to.sin_family = AF_INET;
683#ifdef HAVE_SA_LEN
684 to.sin_len = sizeof to;
685#endif
686
7de20a95
EH
687 memcpy(&hto.hbuf[1], packet->chaddr, packet->hlen);
688 hto.hbuf[0] = packet->htype;
689 hto.hlen = packet->hlen + 1;
747ec13b 690
866428dd
TL
691 /* Wipe out the agent relay options and, if possible, figure
692 out which interface to use based on the contents of the
693 option that we put on the request to which the server is
694 replying. */
695 if (!(length =
7de20a95 696 strip_relay_agent_options(ip, &out, packet, length)))
866428dd
TL
697 return;
698
747ec13b 699 if (!out) {
7de20a95
EH
700 log_error("Packet to bogus giaddr %s.\n",
701 inet_ntoa(packet->giaddr));
866428dd 702 ++bogus_giaddr_drops;
747ec13b
TL
703 return;
704 }
705
98bd7ca0
DH
706 if (send_packet(out, NULL, packet, length, out->addresses[0],
707 &to, htop) < 0) {
866428dd
TL
708 ++server_packet_errors;
709 } else {
7de20a95
EH
710 log_debug("Forwarded BOOTREPLY for %s to %s",
711 print_hw_addr(packet->htype, packet->hlen,
712 packet->chaddr),
713 inet_ntoa(to.sin_addr));
75661c60 714
866428dd
TL
715 ++server_packets_relayed;
716 }
747ec13b
TL
717 return;
718 }
719
866428dd
TL
720 /* If giaddr matches one of our addresses, ignore the packet -
721 we just sent it. */
722 if (out)
723 return;
724
725 /* Add relay agent options if indicated. If something goes wrong,
726 drop the packet. */
98bd7ca0
DH
727 if (!(length = add_relay_agent_options(ip, packet, length,
728 ip->addresses[0])))
75661c60 729 return;
75661c60 730
866428dd
TL
731 /* If giaddr is not already set, Set it so the server can
732 figure out what net it's from and so that we can later
733 forward the response to the correct net. If it's already
734 set, the response will be sent directly to the relay agent
735 that set giaddr, so we won't see it. */
7de20a95 736 if (!packet->giaddr.s_addr)
98bd7ca0 737 packet->giaddr = ip->addresses[0];
7de20a95
EH
738 if (packet->hops < max_hop_count)
739 packet->hops = packet->hops + 1;
98311e4b
DH
740 else
741 return;
75661c60 742
747ec13b
TL
743 /* Otherwise, it's a BOOTREQUEST, so forward it to all the
744 servers. */
7de20a95 745 for (sp = servers; sp; sp = sp->next) {
98bd7ca0
DH
746 if (send_packet((fallback_interface
747 ? fallback_interface : interfaces),
748 NULL, packet, length, ip->addresses[0],
749 &sp->to, NULL) < 0) {
866428dd 750 ++client_packet_errors;
747ec13b 751 } else {
7de20a95
EH
752 log_debug("Forwarded BOOTREQUEST for %s to %s",
753 print_hw_addr(packet->htype, packet->hlen,
754 packet->chaddr),
755 inet_ntoa(sp->to.sin_addr));
866428dd 756 ++client_packets_relayed;
747ec13b
TL
757 }
758 }
78c553c4 759
747ec13b
TL
760}
761
866428dd 762/* Strip any Relay Agent Information options from the DHCP packet
98311e4b
DH
763 option buffer. If there is a circuit ID suboption, look up the
764 outgoing interface based upon it. */
866428dd 765
7de20a95
EH
766static int
767strip_relay_agent_options(struct interface_info *in,
d352732e
EH
768 struct interface_info **out,
769 struct dhcp_packet *packet,
770 unsigned length) {
866428dd 771 int is_dhcp = 0;
88cd8aca 772 u_int8_t *op, *nextop, *sp, *max;
866428dd
TL
773 int good_agent_option = 0;
774 int status;
775
776 /* If we're not adding agent options to packets, we're not taking
777 them out either. */
778 if (!add_agent_options)
7de20a95 779 return (length);
866428dd
TL
780
781 /* If there's no cookie, it's a bootp packet, so we should just
782 forward it unchanged. */
7de20a95
EH
783 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
784 return (length);
866428dd
TL
785
786 max = ((u_int8_t *)packet) + length;
7de20a95 787 sp = op = &packet->options[4];
866428dd
TL
788
789 while (op < max) {
7de20a95 790 switch(*op) {
866428dd
TL
791 /* Skip padding... */
792 case DHO_PAD:
793 if (sp != op)
794 *sp = *op;
795 ++op;
796 ++sp;
797 continue;
798
799 /* If we see a message type, it's a DHCP packet. */
800 case DHO_DHCP_MESSAGE_TYPE:
801 is_dhcp = 1;
802 goto skip;
803 break;
804
805 /* Quit immediately if we hit an End option. */
806 case DHO_END:
807 if (sp != op)
808 *sp++ = *op++;
809 goto out;
810
811 case DHO_DHCP_AGENT_OPTIONS:
812 /* We shouldn't see a relay agent option in a
813 packet before we've seen the DHCP packet type,
814 but if we do, we have to leave it alone. */
815 if (!is_dhcp)
816 goto skip;
817
88cd8aca
DH
818 /* Do not process an agent option if it exceeds the
819 * buffer. Fail this packet.
820 */
821 nextop = op + op[1] + 2;
822 if (nextop > max)
7de20a95 823 return (0);
88cd8aca 824
7de20a95
EH
825 status = find_interface_by_agent_option(packet,
826 out, op + 2,
827 op[1]);
866428dd 828 if (status == -1 && drop_agent_mismatches)
7de20a95 829 return (0);
866428dd
TL
830 if (status)
831 good_agent_option = 1;
88cd8aca 832 op = nextop;
866428dd
TL
833 break;
834
835 skip:
836 /* Skip over other options. */
837 default:
88cd8aca 838 /* Fail if processing this option will exceed the
7de20a95 839 * buffer(op[1] is malformed).
88cd8aca
DH
840 */
841 nextop = op + op[1] + 2;
842 if (nextop > max)
7de20a95 843 return (0);
88cd8aca
DH
844
845 if (sp != op) {
846 memmove(sp, op, op[1] + 2);
847 sp += op[1] + 2;
848 op = nextop;
849 } else
850 op = sp = nextop;
851
866428dd
TL
852 break;
853 }
854 }
855 out:
856
857 /* If it's not a DHCP packet, we're not supposed to touch it. */
858 if (!is_dhcp)
7de20a95 859 return (length);
866428dd
TL
860
861 /* If none of the agent options we found matched, or if we didn't
862 find any agent options, count this packet as not having any
863 matching agent options, and if we're relying on agent options
864 to determine the outgoing interface, drop the packet. */
865
866 if (!good_agent_option) {
867 ++missing_agent_option;
868 if (drop_agent_mismatches)
7de20a95 869 return (0);
866428dd
TL
870 }
871
872 /* Adjust the length... */
873 if (sp != op) {
7de20a95 874 length = sp -((u_int8_t *)packet);
866428dd 875
7de20a95 876 /* Make sure the packet isn't short(this is unlikely,
d352732e 877 but WTH) */
866428dd 878 if (length < BOOTP_MIN_LEN) {
7de20a95 879 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
866428dd
TL
880 length = BOOTP_MIN_LEN;
881 }
882 }
7de20a95 883 return (length);
866428dd
TL
884}
885
886
887/* Find an interface that matches the circuit ID specified in the
888 Relay Agent Information option. If one is found, store it through
889 the pointer given; otherwise, leave the existing pointer alone.
890
891 We actually deviate somewhat from the current specification here:
892 if the option buffer is corrupt, we suggest that the caller not
893 respond to this packet. If the circuit ID doesn't match any known
894 interface, we suggest that the caller to drop the packet. Only if
895 we find a circuit ID that matches an existing interface do we tell
896 the caller to go ahead and process the packet. */
897
7de20a95
EH
898static int
899find_interface_by_agent_option(struct dhcp_packet *packet,
d352732e
EH
900 struct interface_info **out,
901 u_int8_t *buf, int len) {
639b70fa 902 int i = 0;
866428dd 903 u_int8_t *circuit_id = 0;
98311e4b 904 unsigned circuit_id_len = 0;
866428dd
TL
905 struct interface_info *ip;
906
907 while (i < len) {
908 /* If the next agent option overflows the end of the
909 packet, the agent option buffer is corrupt. */
910 if (i + 1 == len ||
7de20a95 911 i + buf[i + 1] + 2 > len) {
866428dd 912 ++corrupt_agent_options;
7de20a95 913 return (-1);
866428dd 914 }
7de20a95 915 switch(buf[i]) {
866428dd
TL
916 /* Remember where the circuit ID is... */
917 case RAI_CIRCUIT_ID:
7de20a95
EH
918 circuit_id = &buf[i + 2];
919 circuit_id_len = buf[i + 1];
866428dd
TL
920 i += circuit_id_len + 2;
921 continue;
922
923 default:
7de20a95 924 i += buf[i + 1] + 2;
866428dd
TL
925 break;
926 }
927 }
928
929 /* If there's no circuit ID, it's not really ours, tell the caller
930 it's no good. */
931 if (!circuit_id) {
932 ++missing_circuit_id;
7de20a95 933 return (-1);
866428dd
TL
934 }
935
936 /* Scan the interface list looking for an interface whose
937 name matches the one specified in circuit_id. */
938
7de20a95
EH
939 for (ip = interfaces; ip; ip = ip->next) {
940 if (ip->circuit_id &&
941 ip->circuit_id_len == circuit_id_len &&
942 !memcmp(ip->circuit_id, circuit_id, circuit_id_len))
866428dd
TL
943 break;
944 }
945
946 /* If we got a match, use it. */
947 if (ip) {
948 *out = ip;
7de20a95 949 return (1);
866428dd
TL
950 }
951
952 /* If we didn't get a match, the circuit ID was bogus. */
953 ++bad_circuit_id;
7de20a95 954 return (-1);
866428dd
TL
955}
956
7de20a95
EH
957/*
958 * Examine a packet to see if it's a candidate to have a Relay
959 * Agent Information option tacked onto its tail. If it is, tack
960 * the option on.
961 */
962static int
963add_relay_agent_options(struct interface_info *ip, struct dhcp_packet *packet,
d352732e
EH
964 unsigned length, struct in_addr giaddr) {
965 int is_dhcp = 0, mms;
88cd8aca
DH
966 unsigned optlen;
967 u_int8_t *op, *nextop, *sp, *max, *end_pad = NULL;
866428dd
TL
968
969 /* If we're not adding agent options to packets, we can skip
970 this. */
971 if (!add_agent_options)
7de20a95 972 return (length);
866428dd
TL
973
974 /* If there's no cookie, it's a bootp packet, so we should just
975 forward it unchanged. */
88cd8aca 976 if (memcmp(packet->options, DHCP_OPTIONS_COOKIE, 4))
7de20a95 977 return (length);
866428dd 978
d352732e 979 max = ((u_int8_t *)packet) + dhcp_max_agent_option_packet_length;
88cd8aca
DH
980
981 /* Commence processing after the cookie. */
982 sp = op = &packet->options[4];
866428dd
TL
983
984 while (op < max) {
7de20a95 985 switch(*op) {
866428dd
TL
986 /* Skip padding... */
987 case DHO_PAD:
88cd8aca
DH
988 /* Remember the first pad byte so we can commandeer
989 * padded space.
990 *
991 * XXX: Is this really a good idea? Sure, we can
992 * seemingly reduce the packet while we're looking,
993 * but if the packet was signed by the client then
7de20a95 994 * this padding is part of the checksum(RFC3118),
88cd8aca
DH
995 * and its nonpresence would break authentication.
996 */
997 if (end_pad == NULL)
998 end_pad = sp;
999
866428dd 1000 if (sp != op)
88cd8aca
DH
1001 *sp++ = *op++;
1002 else
1003 sp = ++op;
1004
866428dd
TL
1005 continue;
1006
1007 /* If we see a message type, it's a DHCP packet. */
1008 case DHO_DHCP_MESSAGE_TYPE:
1009 is_dhcp = 1;
1010 goto skip;
d352732e
EH
1011
1012 /*
1013 * If there's a maximum message size option, we
1014 * should pay attention to it
1015 */
1016 case DHO_DHCP_MAX_MESSAGE_SIZE:
1017 mms = ntohs(*(op + 2));
1018 if (mms < dhcp_max_agent_option_packet_length &&
1019 mms >= DHCP_MTU_MIN)
1020 max = ((u_int8_t *)packet) + mms;
1021 goto skip;
866428dd
TL
1022
1023 /* Quit immediately if we hit an End option. */
1024 case DHO_END:
1025 goto out;
1026
1027 case DHO_DHCP_AGENT_OPTIONS:
1028 /* We shouldn't see a relay agent option in a
1029 packet before we've seen the DHCP packet type,
1030 but if we do, we have to leave it alone. */
1031 if (!is_dhcp)
1032 goto skip;
88cd8aca
DH
1033
1034 end_pad = NULL;
866428dd
TL
1035
1036 /* There's already a Relay Agent Information option
1037 in this packet. How embarrassing. Decide what
1038 to do based on the mode the user specified. */
1039
7de20a95 1040 switch(agent_relay_mode) {
866428dd
TL
1041 case forward_and_append:
1042 goto skip;
1043 case forward_untouched:
7de20a95 1044 return (length);
866428dd 1045 case discard:
7de20a95 1046 return (0);
866428dd
TL
1047 case forward_and_replace:
1048 default:
1049 break;
1050 }
1051
1052 /* Skip over the agent option and start copying
1053 if we aren't copying already. */
88cd8aca 1054 op += op[1] + 2;
866428dd
TL
1055 break;
1056
1057 skip:
1058 /* Skip over other options. */
1059 default:
88cd8aca 1060 /* Fail if processing this option will exceed the
7de20a95 1061 * buffer(op[1] is malformed).
88cd8aca
DH
1062 */
1063 nextop = op + op[1] + 2;
1064 if (nextop > max)
7de20a95 1065 return (0);
88cd8aca
DH
1066
1067 end_pad = NULL;
1068
1069 if (sp != op) {
1070 memmove(sp, op, op[1] + 2);
1071 sp += op[1] + 2;
1072 op = nextop;
1073 } else
1074 op = sp = nextop;
1075
866428dd
TL
1076 break;
1077 }
1078 }
1079 out:
1080
1081 /* If it's not a DHCP packet, we're not supposed to touch it. */
1082 if (!is_dhcp)
7de20a95 1083 return (length);
866428dd
TL
1084
1085 /* If the packet was padded out, we can store the agent option
1086 at the beginning of the padding. */
1087
88cd8aca 1088 if (end_pad != NULL)
866428dd
TL
1089 sp = end_pad;
1090
dc9d7b08 1091#if 0
866428dd
TL
1092 /* Remember where the end of the packet was after parsing
1093 it. */
1094 op = sp;
dc9d7b08 1095#endif
866428dd 1096
88cd8aca 1097 /* Sanity check. Had better not ever happen. */
7de20a95
EH
1098 if ((ip->circuit_id_len > 255) ||(ip->circuit_id_len < 1))
1099 log_fatal("Circuit ID length %d out of range [1-255] on "
88cd8aca
DH
1100 "%s\n", ip->circuit_id_len, ip->name);
1101 optlen = ip->circuit_id_len + 2; /* RAI_CIRCUIT_ID + len */
1102
1103 if (ip->remote_id) {
1104 if (ip->remote_id_len > 255 || ip->remote_id_len < 1)
7de20a95 1105 log_fatal("Remote ID length %d out of range [1-255] "
88cd8aca
DH
1106 "on %s\n", ip->circuit_id_len, ip->name);
1107 optlen += ip->remote_id_len + 2; /* RAI_REMOTE_ID + len */
1108 }
1109
7de20a95 1110 /* We do not support relay option fragmenting(multiple options to
88cd8aca
DH
1111 * support an option data exceeding 255 bytes).
1112 */
7de20a95
EH
1113 if ((optlen < 3) ||(optlen > 255))
1114 log_fatal("Total agent option length(%u) out of range "
88cd8aca
DH
1115 "[3 - 255] on %s\n", optlen, ip->name);
1116
d352732e
EH
1117 /*
1118 * Is there room for the option, its code+len, and DHO_END?
1119 * If not, forward without adding the option.
1120 */
1121 if (max - sp >= optlen + 3) {
1122 log_debug("Adding %d-byte relay agent option", optlen + 3);
1123
1124 /* Okay, cons up *our* Relay Agent Information option. */
1125 *sp++ = DHO_DHCP_AGENT_OPTIONS;
1126 *sp++ = optlen;
1127
1128 /* Copy in the circuit id... */
1129 *sp++ = RAI_CIRCUIT_ID;
1130 *sp++ = ip->circuit_id_len;
1131 memcpy(sp, ip->circuit_id, ip->circuit_id_len);
1132 sp += ip->circuit_id_len;
1133
1134 /* Copy in remote ID... */
1135 if (ip->remote_id) {
1136 *sp++ = RAI_REMOTE_ID;
1137 *sp++ = ip->remote_id_len;
1138 memcpy(sp, ip->remote_id, ip->remote_id_len);
1139 sp += ip->remote_id_len;
1140 }
1141 } else {
1142 ++agent_option_errors;
1143 log_error("No room in packet (used %d of %d) "
1144 "for %d-byte relay agent option: omitted",
1145 (int) (sp - ((u_int8_t *) packet)),
1146 (int) (max - ((u_int8_t *) packet)),
1147 optlen + 3);
866428dd
TL
1148 }
1149
d352732e
EH
1150 /*
1151 * Deposit an END option unless the packet is full (shouldn't
1152 * be possible).
1153 */
1154 if (sp < max)
1155 *sp++ = DHO_END;
866428dd
TL
1156
1157 /* Recalculate total packet length. */
7de20a95 1158 length = sp -((u_int8_t *)packet);
866428dd 1159
7de20a95 1160 /* Make sure the packet isn't short(this is unlikely, but WTH) */
866428dd 1161 if (length < BOOTP_MIN_LEN) {
88cd8aca 1162 memset(sp, DHO_PAD, BOOTP_MIN_LEN - length);
7de20a95
EH
1163 return (BOOTP_MIN_LEN);
1164 }
1165
1166 return (length);
1167}
1168
1169#ifdef DHCPv6
1170/*
1171 * Parse a downstream argument: [address%]interface[#index].
1172 */
1173static struct stream_list *
1174parse_downstream(char *arg) {
1175 struct stream_list *dp, *up;
1176 struct interface_info *ifp = NULL;
1177 char *ifname, *addr, *iid;
1178 isc_result_t status;
1179
1180 if (!supports_multiple_interfaces(ifp) &&
1181 (downstreams != NULL))
1182 log_fatal("No support for multiple interfaces.");
1183
1184 /* Decode the argument. */
1185 ifname = strchr(arg, '%');
1186 if (ifname == NULL) {
1187 ifname = arg;
1188 addr = NULL;
1189 } else {
1190 *ifname++ = '\0';
1191 addr = arg;
1192 }
1193 iid = strchr(ifname, '#');
1194 if (iid != NULL) {
1195 *iid++ = '\0';
1196 }
1197 if (strlen(ifname) >= sizeof(ifp->name)) {
1198 log_error("Interface name '%s' too long", ifname);
1199 usage();
1200 }
1201
1202 /* Don't declare twice. */
1203 for (dp = downstreams; dp; dp = dp->next) {
1204 if (strcmp(ifname, dp->ifp->name) == 0)
1205 log_fatal("Down interface '%s' declared twice.",
1206 ifname);
1207 }
1208
1209 /* Share with up side? */
1210 for (up = upstreams; up; up = up->next) {
1211 if (strcmp(ifname, up->ifp->name) == 0) {
c2b5b5e8
TM
1212 log_info("parse_downstream: Interface '%s' is "
1213 "both down and up.", ifname);
7de20a95
EH
1214 ifp = up->ifp;
1215 break;
1216 }
1217 }
1218
1219 /* New interface. */
1220 if (ifp == NULL) {
1221 status = interface_allocate(&ifp, MDL);
1222 if (status != ISC_R_SUCCESS)
1223 log_fatal("%s: interface_allocate: %s",
1224 arg, isc_result_totext(status));
1225 strcpy(ifp->name, ifname);
1226 if (interfaces) {
1227 interface_reference(&ifp->next, interfaces, MDL);
1228 interface_dereference(&interfaces, MDL);
1229 }
1230 interface_reference(&interfaces, ifp, MDL);
7de20a95 1231 }
c2b5b5e8 1232 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_DOWNSTREAM;
7de20a95
EH
1233
1234 /* New downstream. */
1235 dp = (struct stream_list *) dmalloc(sizeof(*dp), MDL);
1236 if (!dp)
1237 log_fatal("No memory for downstream.");
1238 dp->ifp = ifp;
1239 if (iid != NULL) {
1240 dp->id = atoi(iid);
1241 } else {
1242 dp->id = -1;
1243 }
1244 /* !addr case handled by setup. */
1245 if (addr && (inet_pton(AF_INET6, addr, &dp->link.sin6_addr) <= 0))
1246 log_fatal("Bad link address '%s'", addr);
1247
1248 return dp;
1249}
1250
1251/*
1252 * Parse an upstream argument: [address]%interface.
1253 */
1254static struct stream_list *
1255parse_upstream(char *arg) {
1256 struct stream_list *up, *dp;
1257 struct interface_info *ifp = NULL;
1258 char *ifname, *addr;
1259 isc_result_t status;
1260
1261 /* Decode the argument. */
1262 ifname = strchr(arg, '%');
1263 if (ifname == NULL) {
1264 ifname = arg;
1265 addr = All_DHCP_Servers;
1266 } else {
1267 *ifname++ = '\0';
1268 addr = arg;
1269 }
1270 if (strlen(ifname) >= sizeof(ifp->name)) {
1271 log_fatal("Interface name '%s' too long", ifname);
1272 }
1273
1274 /* Shared up interface? */
1275 for (up = upstreams; up; up = up->next) {
1276 if (strcmp(ifname, up->ifp->name) == 0) {
1277 ifp = up->ifp;
1278 break;
1279 }
1280 }
1281 for (dp = downstreams; dp; dp = dp->next) {
1282 if (strcmp(ifname, dp->ifp->name) == 0) {
c2b5b5e8
TM
1283 log_info("parse_upstream: Interface '%s' is "
1284 "both down and up.", ifname);
7de20a95
EH
1285 ifp = dp->ifp;
1286 break;
1287 }
1288 }
1289
1290 /* New interface. */
1291 if (ifp == NULL) {
1292 status = interface_allocate(&ifp, MDL);
1293 if (status != ISC_R_SUCCESS)
1294 log_fatal("%s: interface_allocate: %s",
1295 arg, isc_result_totext(status));
1296 strcpy(ifp->name, ifname);
1297 if (interfaces) {
1298 interface_reference(&ifp->next, interfaces, MDL);
1299 interface_dereference(&interfaces, MDL);
1300 }
1301 interface_reference(&interfaces, ifp, MDL);
7de20a95 1302 }
c2b5b5e8 1303 ifp->flags |= INTERFACE_REQUESTED | INTERFACE_UPSTREAM;
7de20a95
EH
1304
1305 /* New upstream. */
1306 up = (struct stream_list *) dmalloc(sizeof(*up), MDL);
1307 if (up == NULL)
1308 log_fatal("No memory for upstream.");
1309
1310 up->ifp = ifp;
1311
1312 if (inet_pton(AF_INET6, addr, &up->link.sin6_addr) <= 0)
1313 log_fatal("Bad address %s", addr);
1314
1315 return up;
1316}
1317
1318/*
1319 * Setup downstream interfaces.
1320 */
1321static void
1322setup_streams(void) {
1323 struct stream_list *dp, *up;
1324 int i;
1325 isc_boolean_t link_is_set;
1326
1327 for (dp = downstreams; dp; dp = dp->next) {
1328 /* Check interface */
1329 if (dp->ifp->v6address_count == 0)
d352732e
EH
1330 log_fatal("Interface '%s' has no IPv6 addresses.",
1331 dp->ifp->name);
7de20a95
EH
1332
1333 /* Check/set link. */
1334 if (IN6_IS_ADDR_UNSPECIFIED(&dp->link.sin6_addr))
1335 link_is_set = ISC_FALSE;
1336 else
1337 link_is_set = ISC_TRUE;
1338 for (i = 0; i < dp->ifp->v6address_count; i++) {
1339 if (IN6_IS_ADDR_LINKLOCAL(&dp->ifp->v6addresses[i]))
1340 continue;
1341 if (!link_is_set)
1342 break;
1343 if (!memcmp(&dp->ifp->v6addresses[i],
d352732e
EH
1344 &dp->link.sin6_addr,
1345 sizeof(dp->link.sin6_addr)))
7de20a95
EH
1346 break;
1347 }
1348 if (i == dp->ifp->v6address_count)
c6455252
TM
1349 log_fatal("Interface %s does not have global IPv6 "
1350 "address assigned.", dp->ifp->name);
7de20a95
EH
1351 if (!link_is_set)
1352 memcpy(&dp->link.sin6_addr,
1353 &dp->ifp->v6addresses[i],
1354 sizeof(dp->link.sin6_addr));
1355
1356 /* Set interface-id. */
1357 if (dp->id == -1)
1358 dp->id = dp->ifp->index;
1359 }
1360
1361 for (up = upstreams; up; up = up->next) {
1362 up->link.sin6_port = local_port;
1363 up->link.sin6_family = AF_INET6;
1364#ifdef HAVE_SA_LEN
1365 up->link.sin6_len = sizeof(up->link);
1366#endif
1367
1368 if (up->ifp->v6address_count == 0)
1369 log_fatal("Interface '%s' has no IPv6 addresses.",
1370 up->ifp->name);
c2b5b5e8
TM
1371
1372 /* RFC 3315 Sec 20 - "If the relay agent relays messages to
1373 * the All_DHCP_Servers address or other multicast addresses,
1374 * it sets the Hop Limit field to 32." */
1375 if (IN6_IS_ADDR_MULTICAST(&up->link.sin6_addr)) {
1376 set_multicast_hop_limit(up->ifp, HOP_COUNT_LIMIT);
1377 }
7de20a95
EH
1378 }
1379}
1380
1381/*
1382 * Add DHCPv6 agent options here.
1383 */
1384static const int required_forw_opts[] = {
1385 D6O_INTERFACE_ID,
619304cd 1386 D6O_SUBSCRIBER_ID,
7de20a95
EH
1387 D6O_RELAY_MSG,
1388 0
1389};
1390
1391/*
1392 * Process a packet upwards, i.e., from client to server.
1393 */
1394static void
1395process_up6(struct packet *packet, struct stream_list *dp) {
1396 char forw_data[65535];
1397 unsigned cursor;
1398 struct dhcpv6_relay_packet *relay;
1399 struct option_state *opts;
1400 struct stream_list *up;
1401
1402 /* Check if the message should be relayed to the server. */
1403 switch (packet->dhcpv6_msg_type) {
1404 case DHCPV6_SOLICIT:
1405 case DHCPV6_REQUEST:
1406 case DHCPV6_CONFIRM:
1407 case DHCPV6_RENEW:
1408 case DHCPV6_REBIND:
1409 case DHCPV6_RELEASE:
1410 case DHCPV6_DECLINE:
1411 case DHCPV6_INFORMATION_REQUEST:
1412 case DHCPV6_RELAY_FORW:
1413 case DHCPV6_LEASEQUERY:
1414 log_info("Relaying %s from %s port %d going up.",
1415 dhcpv6_type_names[packet->dhcpv6_msg_type],
1416 piaddr(packet->client_addr),
1417 ntohs(packet->client_port));
1418 break;
1419
1420 case DHCPV6_ADVERTISE:
1421 case DHCPV6_REPLY:
1422 case DHCPV6_RECONFIGURE:
1423 case DHCPV6_RELAY_REPL:
1424 case DHCPV6_LEASEQUERY_REPLY:
1425 log_info("Discarding %s from %s port %d going up.",
1426 dhcpv6_type_names[packet->dhcpv6_msg_type],
1427 piaddr(packet->client_addr),
1428 ntohs(packet->client_port));
1429 return;
1430
1431 default:
1432 log_info("Unknown %d type from %s port %d going up.",
1433 packet->dhcpv6_msg_type,
1434 piaddr(packet->client_addr),
1435 ntohs(packet->client_port));
1436 return;
1437 }
1438
1439 /* Build the relay-forward header. */
1440 relay = (struct dhcpv6_relay_packet *) forw_data;
a3528574 1441 cursor = offsetof(struct dhcpv6_relay_packet, options);
7de20a95
EH
1442 relay->msg_type = DHCPV6_RELAY_FORW;
1443 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
1444 if (packet->dhcpv6_hop_count >= max_hop_count) {
1445 log_info("Hop count exceeded,");
1446 return;
1447 }
1448 relay->hop_count = packet->dhcpv6_hop_count + 1;
1449 if (dp) {
1450 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1451 } else {
1452 /* On smart relay add: && !global. */
1453 if (!use_if_id && downstreams->next) {
1454 log_info("Shan't get back the interface.");
1455 return;
1456 }
1457 memset(&relay->link_address, 0, 16);
1458 }
1459 } else {
1460 relay->hop_count = 0;
1461 if (!dp)
1462 return;
1463 memcpy(&relay->link_address, &dp->link.sin6_addr, 16);
1464 }
1465 memcpy(&relay->peer_address, packet->client_addr.iabuf, 16);
1466
1467 /* Get an option state. */
1468 opts = NULL;
1469 if (!option_state_allocate(&opts, MDL)) {
1470 log_fatal("No memory for upwards options.");
1471 }
1472
1473 /* Add an interface-id (if used). */
1474 if (use_if_id) {
1475 int if_id;
1476
1477 if (dp) {
1478 if_id = dp->id;
ebf076fe 1479 } else if (!downstreams->next) {
7de20a95
EH
1480 if_id = downstreams->id;
1481 } else {
1482 log_info("Don't know the interface.");
1483 option_state_dereference(&opts, MDL);
1484 return;
1485 }
1486
1487 if (!save_option_buffer(&dhcpv6_universe, opts,
1488 NULL, (unsigned char *) &if_id,
1489 sizeof(int),
1490 D6O_INTERFACE_ID, 0)) {
1491 log_error("Can't save interface-id.");
1492 option_state_dereference(&opts, MDL);
1493 return;
1494 }
1495 }
1496
619304cd
SR
1497 /* Add a subscriber-id if desired. */
1498 /* This is for testing rather than general use */
1499 if (dhcrelay_sub_id != NULL) {
1500 if (!save_option_buffer(&dhcpv6_universe, opts, NULL,
1501 (unsigned char *) dhcrelay_sub_id,
1502 strlen(dhcrelay_sub_id),
1503 D6O_SUBSCRIBER_ID, 0)) {
1504 log_error("Can't save subsriber-id.");
1505 option_state_dereference(&opts, MDL);
1506 return;
1507 }
1508 }
1509
1510
7de20a95
EH
1511 /* Add the relay-msg carrying the packet. */
1512 if (!save_option_buffer(&dhcpv6_universe, opts,
1513 NULL, (unsigned char *) packet->raw,
1514 packet->packet_length,
1515 D6O_RELAY_MSG, 0)) {
1516 log_error("Can't save relay-msg.");
1517 option_state_dereference(&opts, MDL);
1518 return;
1519 }
1520
1521 /* Finish the relay-forward message. */
1522 cursor += store_options6(forw_data + cursor,
1523 sizeof(forw_data) - cursor,
1524 opts, packet,
1525 required_forw_opts, NULL);
1526 option_state_dereference(&opts, MDL);
1527
1528 /* Send it to all upstreams. */
1529 for (up = upstreams; up; up = up->next) {
1530 send_packet6(up->ifp, (unsigned char *) forw_data,
1531 (size_t) cursor, &up->link);
1532 }
1533}
1534
1535/*
1536 * Process a packet downwards, i.e., from server to client.
1537 */
1538static void
1539process_down6(struct packet *packet) {
1540 struct stream_list *dp;
1541 struct option_cache *oc;
1542 struct data_string relay_msg;
1543 const struct dhcpv6_packet *msg;
1544 struct data_string if_id;
1545 struct sockaddr_in6 to;
1546 struct iaddr peer;
1547
1548 /* The packet must be a relay-reply message. */
1549 if (packet->dhcpv6_msg_type != DHCPV6_RELAY_REPL) {
1550 if (packet->dhcpv6_msg_type < dhcpv6_type_name_max)
1551 log_info("Discarding %s from %s port %d going down.",
1552 dhcpv6_type_names[packet->dhcpv6_msg_type],
1553 piaddr(packet->client_addr),
1554 ntohs(packet->client_port));
1555 else
1556 log_info("Unknown %d type from %s port %d going down.",
1557 packet->dhcpv6_msg_type,
1558 piaddr(packet->client_addr),
1559 ntohs(packet->client_port));
1560 return;
1561 }
1562
1563 /* Inits. */
1564 memset(&relay_msg, 0, sizeof(relay_msg));
1565 memset(&if_id, 0, sizeof(if_id));
1566 memset(&to, 0, sizeof(to));
1567 to.sin6_family = AF_INET6;
1568#ifdef HAVE_SA_LEN
1569 to.sin6_len = sizeof(to);
1570#endif
1571 to.sin6_port = remote_port;
1572 peer.len = 16;
1573
1574 /* Get the relay-msg option (carrying the message to relay). */
1575 oc = lookup_option(&dhcpv6_universe, packet->options, D6O_RELAY_MSG);
1576 if (oc == NULL) {
1577 log_info("No relay-msg.");
1578 return;
1579 }
1580 if (!evaluate_option_cache(&relay_msg, packet, NULL, NULL,
1581 packet->options, NULL,
1582 &global_scope, oc, MDL) ||
69c1bf48 1583 (relay_msg.len < offsetof(struct dhcpv6_packet, options))) {
7de20a95
EH
1584 log_error("Can't evaluate relay-msg.");
1585 return;
1586 }
1587 msg = (const struct dhcpv6_packet *) relay_msg.data;
1588
1589 /* Get the interface-id (if exists) and the downstream. */
1590 oc = lookup_option(&dhcpv6_universe, packet->options,
1591 D6O_INTERFACE_ID);
1592 if (oc != NULL) {
1593 int if_index;
1594
1595 if (!evaluate_option_cache(&if_id, packet, NULL, NULL,
1596 packet->options, NULL,
1597 &global_scope, oc, MDL) ||
1598 (if_id.len != sizeof(int))) {
1599 log_info("Can't evaluate interface-id.");
1600 goto cleanup;
1601 }
1602 memcpy(&if_index, if_id.data, sizeof(int));
1603 for (dp = downstreams; dp; dp = dp->next) {
1604 if (dp->id == if_index)
1605 break;
1606 }
1607 } else {
1608 if (use_if_id) {
1609 /* Require an interface-id. */
1610 log_info("No interface-id.");
1611 goto cleanup;
1612 }
1613 for (dp = downstreams; dp; dp = dp->next) {
1614 /* Get the first matching one. */
1615 if (!memcmp(&dp->link.sin6_addr,
d352732e 1616 &packet->dhcpv6_link_address,
7de20a95
EH
1617 sizeof(struct in6_addr)))
1618 break;
1619 }
1620 }
1621 /* Why bother when there is no choice. */
dc9d7b08 1622 if (!dp && downstreams && !downstreams->next)
7de20a95
EH
1623 dp = downstreams;
1624 if (!dp) {
1625 log_info("Can't find the down interface.");
1626 goto cleanup;
1627 }
1628 memcpy(peer.iabuf, &packet->dhcpv6_peer_address, peer.len);
1629 to.sin6_addr = packet->dhcpv6_peer_address;
1630
1631 /* Check if we should relay the carried message. */
1632 switch (msg->msg_type) {
1633 /* Relay-Reply of for another relay, not a client. */
1634 case DHCPV6_RELAY_REPL:
1635 to.sin6_port = local_port;
1636 /* Fall into: */
1637
1638 case DHCPV6_ADVERTISE:
1639 case DHCPV6_REPLY:
1640 case DHCPV6_RECONFIGURE:
1641 case DHCPV6_RELAY_FORW:
1642 case DHCPV6_LEASEQUERY_REPLY:
1643 log_info("Relaying %s to %s port %d down.",
1644 dhcpv6_type_names[msg->msg_type],
1645 piaddr(peer),
1646 ntohs(to.sin6_port));
1647 break;
1648
1649 case DHCPV6_SOLICIT:
1650 case DHCPV6_REQUEST:
1651 case DHCPV6_CONFIRM:
1652 case DHCPV6_RENEW:
1653 case DHCPV6_REBIND:
1654 case DHCPV6_RELEASE:
1655 case DHCPV6_DECLINE:
1656 case DHCPV6_INFORMATION_REQUEST:
1657 case DHCPV6_LEASEQUERY:
1658 log_info("Discarding %s to %s port %d down.",
1659 dhcpv6_type_names[msg->msg_type],
1660 piaddr(peer),
1661 ntohs(to.sin6_port));
1662 goto cleanup;
1663
1664 default:
1665 log_info("Unknown %d type to %s port %d down.",
1666 msg->msg_type,
1667 piaddr(peer),
1668 ntohs(to.sin6_port));
1669 goto cleanup;
1670 }
1671
1672 /* Send the message to the downstream. */
1673 send_packet6(dp->ifp, (unsigned char *) relay_msg.data,
1674 (size_t) relay_msg.len, &to);
1675
1676 cleanup:
1677 if (relay_msg.data != NULL)
1678 data_string_forget(&relay_msg, MDL);
1679 if (if_id.data != NULL)
1680 data_string_forget(&if_id, MDL);
1681}
1682
1683/*
1684 * Called by the dispatch packet handler with a decoded packet.
1685 */
1686void
1687dhcpv6(struct packet *packet) {
1688 struct stream_list *dp;
1689
1690 /* Try all relay-replies downwards. */
1691 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_REPL) {
1692 process_down6(packet);
1693 return;
1694 }
1695 /* Others are candidates to go up if they come from down. */
1696 for (dp = downstreams; dp; dp = dp->next) {
1697 if (packet->interface != dp->ifp)
1698 continue;
1699 process_up6(packet, dp);
1700 return;
1701 }
1702 /* Relay-forward could work from an unknown interface. */
1703 if (packet->dhcpv6_msg_type == DHCPV6_RELAY_FORW) {
1704 process_up6(packet, NULL);
1705 return;
866428dd
TL
1706 }
1707
7de20a95 1708 log_info("Can't process packet from interface '%s'.",
d352732e 1709 packet->interface->name);
7de20a95
EH
1710}
1711#endif
1712
1713/* Stub routines needed for linking with DHCP libraries. */
1714void
1715bootp(struct packet *packet) {
d352732e 1716 return;
7de20a95
EH
1717}
1718
1719void
1720dhcp(struct packet *packet) {
d352732e 1721 return;
7de20a95
EH
1722}
1723
1724void
1725classify(struct packet *p, struct class *c) {
d352732e 1726 return;
7de20a95
EH
1727}
1728
1729int
1730check_collection(struct packet *p, struct lease *l, struct collection *c) {
1731 return 0;
1732}
1733
1734isc_result_t
1735find_class(struct class **class, const char *c1, const char *c2, int i) {
1736 return ISC_R_NOTFOUND;
1737}
1738
1739int
1740parse_allow_deny(struct option_cache **oc, struct parse *p, int i) {
1741 return 0;
1742}
1743
1744isc_result_t
1745dhcp_set_control_state(control_object_state_t oldstate,
1746 control_object_state_t newstate) {
0895c955
SR
1747 if (newstate != server_shutdown)
1748 return ISC_R_SUCCESS;
f950de77
SR
1749
1750 if (no_pid_file == ISC_FALSE)
1751 (void) unlink(path_dhcrelay_pid);
1752
0895c955 1753 exit(0);
866428dd 1754}