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