~ubuntu-branches/ubuntu/oneiric/isc-dhcp/oneiric-security

« back to all changes in this revision

Viewing changes to relay/dhcrelay.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Pollock
  • Date: 2009-09-02 22:34:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090902223425-nypo7bkftxffq41m
Tags: upstream-4.1.0
ImportĀ upstreamĀ versionĀ 4.1.0

Show diffs side-by-side

added added

removed removed

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