Annotation of embedaddon/dhcp/relay/dhcrelay.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>