Annotation of embedaddon/dhcp/server/dhcpleasequery.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (C) 2006-2007 by Internet Systems Consortium, Inc. ("ISC")
        !             3:  *
        !             4:  * Permission to use, copy, modify, and distribute this software for any
        !             5:  * purpose with or without fee is hereby granted, provided that the above
        !             6:  * copyright notice and this permission notice appear in all copies.
        !             7:  *
        !             8:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
        !             9:  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
        !            10:  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
        !            11:  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
        !            12:  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
        !            13:  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
        !            14:  * PERFORMANCE OF THIS SOFTWARE.
        !            15:  */
        !            16: 
        !            17: #include "dhcpd.h"
        !            18: 
        !            19: /*
        !            20:  * TODO: RFC4388 specifies that the server SHOULD return the same
        !            21:  *       options it would for a DHCREQUEST message, if no Parameter
        !            22:  *       Request List option (option 55) is passed. We do not do that.
        !            23:  *
        !            24:  * TODO: RFC4388 specifies the creation of a "non-sensitive options"
        !            25:  *       configuration list, and that these SHOULD be returned. We
        !            26:  *       have no such list.
        !            27:  *
        !            28:  * TODO: RFC4388 says the server SHOULD use RFC3118, "Authentication
        !            29:  *       for DHCP Messages".
        !            30:  *
        !            31:  * TODO: RFC4388 specifies that you SHOULD insure that you cannot be
        !            32:  *       DoS'ed by DHCPLEASEQUERY message.
        !            33:  */
        !            34: 
        !            35: /* 
        !            36:  * If you query by hardware address or by client ID, then you may have
        !            37:  * more than one IP address for your query argument. We need to do two
        !            38:  * things:
        !            39:  *
        !            40:  *   1. Find the most recent lease.
        !            41:  *   2. Find all additional IP addresses for the query argument.
        !            42:  *
        !            43:  * We do this by looking through all of the leases associated with a
        !            44:  * given hardware address or client ID. We use the cltt (client last
        !            45:  * transaction time) of the lease, which only has a resolution of one
        !            46:  * second, so we might not actually give the very latest IP.
        !            47:  */
        !            48: 
        !            49: static struct lease*
        !            50: next_hw(const struct lease *lease) {
        !            51:        /* INSIST(lease != NULL); */
        !            52:        return lease->n_hw;
        !            53: }
        !            54: 
        !            55: static struct lease*
        !            56: next_uid(const struct lease *lease) {
        !            57:        /* INSIST(lease != NULL); */
        !            58:        return lease->n_uid;
        !            59: }
        !            60: 
        !            61: void
        !            62: get_newest_lease(struct lease **retval,
        !            63:                 struct lease *lease,
        !            64:                 struct lease *(*next)(const struct lease *)) {
        !            65: 
        !            66:        struct lease *p;
        !            67:        struct lease *newest;
        !            68: 
        !            69:        /* INSIST(newest != NULL); */
        !            70:        /* INSIST(next != NULL); */
        !            71: 
        !            72:        *retval = NULL;
        !            73: 
        !            74:        if (lease == NULL) {
        !            75:                return;
        !            76:        }
        !            77: 
        !            78:        newest = lease;
        !            79:        for (p=next(lease); p != NULL; p=next(p)) {
        !            80:                if (newest->binding_state == FTS_ACTIVE) {
        !            81:                        if ((p->binding_state == FTS_ACTIVE) && 
        !            82:                        (p->cltt > newest->cltt)) {
        !            83:                                newest = p;
        !            84:                        }
        !            85:                } else {
        !            86:                        if (p->ends > newest->ends) {
        !            87:                                newest = p;
        !            88:                        }
        !            89:                }
        !            90:        }
        !            91: 
        !            92:        lease_reference(retval, newest, MDL);
        !            93: }
        !            94: 
        !            95: static int
        !            96: get_associated_ips(const struct lease *lease,
        !            97:                   struct lease *(*next)(const struct lease *), 
        !            98:                   const struct lease *newest,
        !            99:                   u_int32_t *associated_ips,
        !           100:                   unsigned int associated_ips_size) {
        !           101: 
        !           102:        const struct lease *p;
        !           103:        int cnt;
        !           104: 
        !           105:        /* INSIST(next != NULL); */
        !           106:        /* INSIST(associated_ips != NULL); */
        !           107: 
        !           108:        if (lease == NULL) {
        !           109:                return 0;
        !           110:        }
        !           111: 
        !           112:        cnt = 0;
        !           113:        for (p=lease; p != NULL; p=next(p)) {
        !           114:                if ((p->binding_state == FTS_ACTIVE) && (p != newest)) {
        !           115:                        if (cnt < associated_ips_size) {
        !           116:                                memcpy(&associated_ips[cnt],
        !           117:                                       p->ip_addr.iabuf,
        !           118:                                       sizeof(associated_ips[cnt]));
        !           119:                        }
        !           120:                        cnt++;
        !           121:                }
        !           122:        }
        !           123:        return cnt;
        !           124: }
        !           125: 
        !           126: 
        !           127: void 
        !           128: dhcpleasequery(struct packet *packet, int ms_nulltp) {
        !           129:        char msgbuf[256];
        !           130:        char dbg_info[128];
        !           131:        struct iaddr cip;
        !           132:        struct iaddr gip;
        !           133:        struct data_string uid;
        !           134:        struct hardware h;
        !           135:        struct lease *tmp_lease;
        !           136:        struct lease *lease;
        !           137:        int want_associated_ip;
        !           138:        int assoc_ip_cnt;
        !           139:        u_int32_t assoc_ips[40];  /* XXXSK: arbitrary maximum number of IPs */
        !           140:        const int nassoc_ips = sizeof(assoc_ips) / sizeof(assoc_ips[0]);
        !           141: 
        !           142:        unsigned char dhcpMsgType;
        !           143:        const char *dhcp_msg_type_name;
        !           144:        struct subnet *subnet;
        !           145:        struct group *relay_group;
        !           146:        struct option_state *options;
        !           147:        struct option_cache *oc;
        !           148:        int allow_leasequery;
        !           149:        int ignorep;
        !           150:        u_int32_t lease_duration;
        !           151:        u_int32_t time_renewal;
        !           152:        u_int32_t time_rebinding;
        !           153:        u_int32_t time_expiry;
        !           154:        u_int32_t client_last_transaction_time;
        !           155:        struct sockaddr_in to;
        !           156:        struct in_addr siaddr;
        !           157:        struct data_string prl;
        !           158:        struct data_string *prl_ptr;
        !           159: 
        !           160:        int i;
        !           161:        struct interface_info *interface;
        !           162: 
        !           163:        /* INSIST(packet != NULL); */
        !           164: 
        !           165:        /*
        !           166:         * Prepare log information.
        !           167:         */
        !           168:        snprintf(msgbuf, sizeof(msgbuf), 
        !           169:                "DHCPLEASEQUERY from %s", inet_ntoa(packet->raw->giaddr));
        !           170: 
        !           171:        /* 
        !           172:         * We can't reply if there is no giaddr field.
        !           173:         */
        !           174:        if (!packet->raw->giaddr.s_addr) {
        !           175:                log_info("%s: missing giaddr, ciaddr is %s, no reply sent", 
        !           176:                         msgbuf, inet_ntoa(packet->raw->ciaddr));
        !           177:                return;
        !           178:        }
        !           179: 
        !           180:        /* 
        !           181:         * Initially we use the 'giaddr' subnet options scope to determine if
        !           182:         * the giaddr-identified relay agent is permitted to perform a
        !           183:         * leasequery.  The subnet is not required, and may be omitted, in
        !           184:         * which case we are essentially interrogating the root options class
        !           185:         * to find a globally permit.
        !           186:         */
        !           187:        gip.len = sizeof(packet->raw->giaddr);
        !           188:        memcpy(gip.iabuf, &packet->raw->giaddr, sizeof(packet->raw->giaddr));
        !           189: 
        !           190:        subnet = NULL;
        !           191:        find_subnet(&subnet, gip, MDL);
        !           192:        if (subnet != NULL)
        !           193:                relay_group = subnet->group;
        !           194:        else
        !           195:                relay_group = root_group;
        !           196: 
        !           197:        subnet_dereference(&subnet, MDL);
        !           198: 
        !           199:        options = NULL;
        !           200:        if (!option_state_allocate(&options, MDL)) {
        !           201:                log_error("No memory for option state.");
        !           202:                log_info("%s: out of memory, no reply sent", msgbuf);
        !           203:                return;
        !           204:        }
        !           205: 
        !           206:        execute_statements_in_scope(NULL,
        !           207:                                    packet,
        !           208:                                    NULL,
        !           209:                                    NULL,
        !           210:                                    packet->options,
        !           211:                                    options,
        !           212:                                    &global_scope,
        !           213:                                    relay_group,
        !           214:                                    NULL);
        !           215: 
        !           216:        for (i=packet->class_count-1; i>=0; i--) {
        !           217:                execute_statements_in_scope(NULL,
        !           218:                                            packet,
        !           219:                                            NULL,
        !           220:                                            NULL,
        !           221:                                            packet->options,
        !           222:                                            options,
        !           223:                                            &global_scope,
        !           224:                                            packet->classes[i]->group,
        !           225:                                            relay_group);
        !           226:        }
        !           227: 
        !           228:        /* 
        !           229:         * Because LEASEQUERY has some privacy concerns, default to deny.
        !           230:         */
        !           231:        allow_leasequery = 0;
        !           232: 
        !           233:        /*
        !           234:         * See if we are authorized to do LEASEQUERY.
        !           235:         */
        !           236:        oc = lookup_option(&server_universe, options, SV_LEASEQUERY);
        !           237:        if (oc != NULL) {
        !           238:                allow_leasequery = evaluate_boolean_option_cache(&ignorep,
        !           239:                                         packet, NULL, NULL, packet->options,
        !           240:                                         options, &global_scope, oc, MDL);
        !           241:        }
        !           242: 
        !           243:        if (!allow_leasequery) {
        !           244:                log_info("%s: LEASEQUERY not allowed, query ignored", msgbuf);
        !           245:                option_state_dereference(&options, MDL);
        !           246:                return;
        !           247:        }
        !           248: 
        !           249: 
        !           250:        /* 
        !           251:         * Copy out the client IP address.
        !           252:         */
        !           253:        cip.len = sizeof(packet->raw->ciaddr);
        !           254:        memcpy(cip.iabuf, &packet->raw->ciaddr, sizeof(packet->raw->ciaddr));
        !           255: 
        !           256:        /* 
        !           257:         * If the client IP address is valid (not all zero), then we 
        !           258:         * are looking for information about that IP address.
        !           259:         */
        !           260:        assoc_ip_cnt = 0;
        !           261:        lease = tmp_lease = NULL;
        !           262:        if (memcmp(cip.iabuf, "\0\0\0", 4)) {
        !           263: 
        !           264:                want_associated_ip = 0;
        !           265: 
        !           266:                snprintf(dbg_info, sizeof(dbg_info), "IP %s", piaddr(cip));
        !           267:                find_lease_by_ip_addr(&lease, cip, MDL);
        !           268: 
        !           269: 
        !           270:        } else {
        !           271: 
        !           272:                want_associated_ip = 1;
        !           273: 
        !           274:                /*
        !           275:                 * If the client IP address is all zero, then we will
        !           276:                 * either look up by the client identifier (if we have
        !           277:                 * one), or by the MAC address.
        !           278:                 */
        !           279: 
        !           280:                memset(&uid, 0, sizeof(uid));
        !           281:                if (get_option(&uid, 
        !           282:                               &dhcp_universe,
        !           283:                               packet,
        !           284:                               NULL,
        !           285:                               NULL,
        !           286:                               packet->options,
        !           287:                               NULL,
        !           288:                               packet->options, 
        !           289:                               &global_scope,
        !           290:                               DHO_DHCP_CLIENT_IDENTIFIER,
        !           291:                               MDL)) {
        !           292: 
        !           293:                        snprintf(dbg_info, 
        !           294:                                 sizeof(dbg_info), 
        !           295:                                 "client-id %s",
        !           296:                                 print_hex_1(uid.len, uid.data, 60));
        !           297: 
        !           298:                        find_lease_by_uid(&tmp_lease, uid.data, uid.len, MDL);
        !           299:                        data_string_forget(&uid, MDL);
        !           300:                        get_newest_lease(&lease, tmp_lease, next_uid);
        !           301:                        assoc_ip_cnt = get_associated_ips(tmp_lease,
        !           302:                                                          next_uid, 
        !           303:                                                          lease,
        !           304:                                                          assoc_ips, 
        !           305:                                                          nassoc_ips);
        !           306: 
        !           307:                } else {
        !           308: 
        !           309:                        if (packet->raw->hlen+1 > sizeof(h.hbuf)) {
        !           310:                                log_info("%s: hardware length too long, "
        !           311:                                         "no reply sent", msgbuf);
        !           312:                                option_state_dereference(&options, MDL);
        !           313:                                return;
        !           314:                        }
        !           315: 
        !           316:                        h.hlen = packet->raw->hlen + 1;
        !           317:                        h.hbuf[0] = packet->raw->htype;
        !           318:                        memcpy(&h.hbuf[1], 
        !           319:                               packet->raw->chaddr, 
        !           320:                               packet->raw->hlen);
        !           321: 
        !           322:                        snprintf(dbg_info, 
        !           323:                                 sizeof(dbg_info), 
        !           324:                                 "MAC address %s",
        !           325:                                 print_hw_addr(h.hbuf[0], 
        !           326:                                               h.hlen - 1, 
        !           327:                                               &h.hbuf[1]));
        !           328: 
        !           329:                        find_lease_by_hw_addr(&tmp_lease, h.hbuf, h.hlen, MDL);
        !           330:                        get_newest_lease(&lease, tmp_lease, next_hw);
        !           331:                        assoc_ip_cnt = get_associated_ips(tmp_lease,
        !           332:                                                          next_hw, 
        !           333:                                                          lease,
        !           334:                                                          assoc_ips, 
        !           335:                                                          nassoc_ips);
        !           336: 
        !           337:                }
        !           338: 
        !           339:                lease_dereference(&tmp_lease, MDL);
        !           340: 
        !           341:                if (lease != NULL) {
        !           342:                        memcpy(&packet->raw->ciaddr, 
        !           343:                               lease->ip_addr.iabuf,
        !           344:                               sizeof(packet->raw->ciaddr));
        !           345:                }
        !           346: 
        !           347:                /*
        !           348:                 * Log if we have too many IP addresses associated
        !           349:                 * with this client.
        !           350:                 */
        !           351:                if (want_associated_ip && (assoc_ip_cnt > nassoc_ips)) {
        !           352:                        log_info("%d IP addresses associated with %s, "
        !           353:                                 "only %d sent in reply.",
        !           354:                                 assoc_ip_cnt, dbg_info, nassoc_ips);
        !           355:                }
        !           356:        }
        !           357: 
        !           358:        /*
        !           359:         * We now know the query target too, so can report this in 
        !           360:         * our log message.
        !           361:         */
        !           362:        snprintf(msgbuf, sizeof(msgbuf), 
        !           363:                "DHCPLEASEQUERY from %s for %s",
        !           364:                inet_ntoa(packet->raw->giaddr), dbg_info);
        !           365: 
        !           366:        /*
        !           367:         * Figure our our return type.
        !           368:         */
        !           369:        if (lease == NULL) {
        !           370:                dhcpMsgType = DHCPLEASEUNKNOWN;
        !           371:                dhcp_msg_type_name = "DHCPLEASEUNKNOWN";
        !           372:        } else {
        !           373:                if (lease->binding_state == FTS_ACTIVE) {
        !           374:                        dhcpMsgType = DHCPLEASEACTIVE;
        !           375:                        dhcp_msg_type_name = "DHCPLEASEACTIVE";
        !           376:                } else {
        !           377:                        dhcpMsgType = DHCPLEASEUNASSIGNED;
        !           378:                        dhcp_msg_type_name = "DHCPLEASEUNASSIGNED";
        !           379:                }
        !           380:        }
        !           381: 
        !           382:        /* 
        !           383:         * Set options that only make sense if we have an active lease.
        !           384:         */
        !           385: 
        !           386:        if (dhcpMsgType == DHCPLEASEACTIVE)
        !           387:        {
        !           388:                /*
        !           389:                 * RFC 4388 uses the PRL to request options for the agent to
        !           390:                 * receive that are "about" the client.  It is confusing
        !           391:                 * because in some cases it wants to know what was sent to
        !           392:                 * the client (lease times, adjusted), and in others it wants
        !           393:                 * to know information the client sent.  You're supposed to
        !           394:                 * know this on a case-by-case basis.
        !           395:                 *
        !           396:                 * "Name servers", "domain name", and the like from the relay
        !           397:                 * agent's scope seems less than useful.  Our options are to
        !           398:                 * restart the option cache from the lease's best point of view
        !           399:                 * (execute statements from the lease pool's group), or to
        !           400:                 * simply restart the option cache from empty.
        !           401:                 *
        !           402:                 * I think restarting the option cache from empty best
        !           403:                 * approaches RFC 4388's intent; specific options are included.
        !           404:                 */
        !           405:                option_state_dereference(&options, MDL);
        !           406: 
        !           407:                if (!option_state_allocate(&options, MDL)) {
        !           408:                        log_error("%s: out of memory, no reply sent", msgbuf);
        !           409:                        lease_dereference(&lease, MDL);
        !           410:                        return;
        !           411:                }
        !           412: 
        !           413:                /* 
        !           414:                 * Set the hardware address fields.
        !           415:                 */
        !           416: 
        !           417:                packet->raw->hlen = lease->hardware_addr.hlen - 1;
        !           418:                packet->raw->htype = lease->hardware_addr.hbuf[0];
        !           419:                memcpy(packet->raw->chaddr, 
        !           420:                       &lease->hardware_addr.hbuf[1], 
        !           421:                       sizeof(packet->raw->chaddr));
        !           422: 
        !           423:                /*
        !           424:                 * Set client identifier option.
        !           425:                 */
        !           426:                if (lease->uid_len > 0) {
        !           427:                        if (!add_option(options,
        !           428:                                        DHO_DHCP_CLIENT_IDENTIFIER,
        !           429:                                        lease->uid,
        !           430:                                        lease->uid_len)) {
        !           431:                                option_state_dereference(&options, MDL);
        !           432:                                lease_dereference(&lease, MDL);
        !           433:                                log_info("%s: out of memory, no reply sent",
        !           434:                                         msgbuf);
        !           435:                                return;
        !           436:                        }
        !           437:                }
        !           438: 
        !           439: 
        !           440:                /*
        !           441:                 * Calculate T1 and T2, the times when the client
        !           442:                 * tries to extend its lease on its networking
        !           443:                 * address.
        !           444:                 * These seem to be hard-coded in ISC DHCP, to 0.5 and
        !           445:                 * 0.875 of the lease time.
        !           446:                 */
        !           447: 
        !           448:                lease_duration = lease->ends - lease->starts;
        !           449:                time_renewal = lease->starts + 
        !           450:                        (lease_duration / 2);
        !           451:                time_rebinding = lease->starts + 
        !           452:                        (lease_duration / 2) +
        !           453:                        (lease_duration / 4) +
        !           454:                        (lease_duration / 8);
        !           455: 
        !           456:                if (time_renewal > cur_time) {
        !           457:                        if (time_renewal < cur_time)
        !           458:                                time_renewal = 0;
        !           459:                        else
        !           460:                                time_renewal = htonl(time_renewal - cur_time);
        !           461: 
        !           462:                        if (!add_option(options, 
        !           463:                                        DHO_DHCP_RENEWAL_TIME,
        !           464:                                        &time_renewal, 
        !           465:                                        sizeof(time_renewal))) {
        !           466:                                option_state_dereference(&options, MDL);
        !           467:                                lease_dereference(&lease, MDL);
        !           468:                                log_info("%s: out of memory, no reply sent",
        !           469:                                         msgbuf);
        !           470:                                return;
        !           471:                        }
        !           472:                }
        !           473: 
        !           474:                if (time_rebinding > cur_time) {
        !           475:                        time_rebinding = htonl(time_rebinding - cur_time);
        !           476: 
        !           477:                        if (!add_option(options, 
        !           478:                                        DHO_DHCP_REBINDING_TIME,
        !           479:                                        &time_rebinding, 
        !           480:                                        sizeof(time_rebinding))) {
        !           481:                                option_state_dereference(&options, MDL);
        !           482:                                lease_dereference(&lease, MDL);
        !           483:                                log_info("%s: out of memory, no reply sent",
        !           484:                                         msgbuf);
        !           485:                                return;
        !           486:                        }
        !           487:                }
        !           488: 
        !           489:                if (lease->ends > cur_time) {
        !           490:                        if (time_expiry < cur_time) {
        !           491:                                log_error("Impossible condition at %s:%d.",
        !           492:                                          MDL);
        !           493: 
        !           494:                                option_state_dereference(&options, MDL);
        !           495:                                lease_dereference(&lease, MDL);
        !           496:                                return;
        !           497:                        }
        !           498:                        time_expiry = htonl(lease->ends - cur_time);
        !           499:                        if (!add_option(options, 
        !           500:                                        DHO_DHCP_LEASE_TIME,
        !           501:                                        &time_expiry, 
        !           502:                                        sizeof(time_expiry))) {
        !           503:                                option_state_dereference(&options, MDL);
        !           504:                                lease_dereference(&lease, MDL);
        !           505:                                log_info("%s: out of memory, no reply sent",
        !           506:                                         msgbuf);
        !           507:                                return;
        !           508:                        }
        !           509:                }
        !           510: 
        !           511:                /* Supply the Vendor-Class-Identifier. */
        !           512:                if (lease->scope != NULL) {
        !           513:                        struct data_string vendor_class;
        !           514: 
        !           515:                        memset(&vendor_class, 0, sizeof(vendor_class));
        !           516: 
        !           517:                        if (find_bound_string(&vendor_class, lease->scope,
        !           518:                                              "vendor-class-identifier")) {
        !           519:                                if (!add_option(options,
        !           520:                                                DHO_VENDOR_CLASS_IDENTIFIER,
        !           521:                                                (void *)vendor_class.data,
        !           522:                                                vendor_class.len)) {
        !           523:                                        option_state_dereference(&options,
        !           524:                                                                 MDL);
        !           525:                                        lease_dereference(&lease, MDL);
        !           526:                                        log_error("%s: error adding vendor "
        !           527:                                                  "class identifier, no reply "
        !           528:                                                  "sent", msgbuf);
        !           529:                                        data_string_forget(&vendor_class, MDL);
        !           530:                                        return;
        !           531:                                }
        !           532:                                data_string_forget(&vendor_class, MDL);
        !           533:                        }
        !           534:                }
        !           535: 
        !           536:                /*
        !           537:                 * Set the relay agent info.
        !           538:                 *
        !           539:                 * Note that because agent info is appended without regard
        !           540:                 * to the PRL in cons_options(), this will be sent as the
        !           541:                 * last option in the packet whether it is listed on PRL or
        !           542:                 * not.
        !           543:                 */
        !           544: 
        !           545:                if (lease->agent_options != NULL) {
        !           546:                        int idx = agent_universe.index;
        !           547:                        struct option_chain_head **tmp1 = 
        !           548:                                (struct option_chain_head **)
        !           549:                                &(options->universes[idx]);
        !           550:                                struct option_chain_head *tmp2 = 
        !           551:                                (struct option_chain_head *)
        !           552:                                lease->agent_options;
        !           553: 
        !           554:                        option_chain_head_reference(tmp1, tmp2, MDL);
        !           555:                }
        !           556: 
        !           557:                /* 
        !           558:                 * Set the client last transaction time.
        !           559:                 * We check to make sure we have a timestamp. For
        !           560:                 * lease files that were saved before running a 
        !           561:                 * timestamp-aware version of the server, this may
        !           562:                 * not be set.
        !           563:                 */
        !           564: 
        !           565:                if (lease->cltt != MIN_TIME) {
        !           566:                        if (cur_time > lease->cltt) {
        !           567:                                client_last_transaction_time = 
        !           568:                                        htonl(cur_time - lease->cltt);
        !           569:                        } else {
        !           570:                                client_last_transaction_time = htonl(0);
        !           571:                        }
        !           572:                        if (!add_option(options, 
        !           573:                                        DHO_CLIENT_LAST_TRANSACTION_TIME,
        !           574:                                        &client_last_transaction_time,
        !           575:                                        sizeof(client_last_transaction_time))) {
        !           576:                                option_state_dereference(&options, MDL);
        !           577:                                lease_dereference(&lease, MDL);
        !           578:                                log_info("%s: out of memory, no reply sent",
        !           579:                                         msgbuf);
        !           580:                                return;
        !           581:                        }
        !           582:                }
        !           583: 
        !           584:                /*
        !           585:                 * Set associated IPs, if requested and there are some.
        !           586:                 */
        !           587:                if (want_associated_ip && (assoc_ip_cnt > 0)) {
        !           588:                        if (!add_option(options, 
        !           589:                                        DHO_ASSOCIATED_IP,
        !           590:                                        assoc_ips,
        !           591:                                        assoc_ip_cnt * sizeof(assoc_ips[0]))) {
        !           592:                                option_state_dereference(&options, MDL);
        !           593:                                lease_dereference(&lease, MDL);
        !           594:                                log_info("%s: out of memory, no reply sent",
        !           595:                                         msgbuf);
        !           596:                                return;
        !           597:                        }
        !           598:                }
        !           599:        }
        !           600: 
        !           601:        /* 
        !           602:         * Set the message type.
        !           603:         */
        !           604: 
        !           605:        packet->raw->op = BOOTREPLY;
        !           606: 
        !           607:        /*
        !           608:         * Set DHCP message type.
        !           609:         */
        !           610:        if (!add_option(options, 
        !           611:                        DHO_DHCP_MESSAGE_TYPE,
        !           612:                        &dhcpMsgType, 
        !           613:                        sizeof(dhcpMsgType))) {
        !           614:                option_state_dereference(&options, MDL);
        !           615:                lease_dereference(&lease, MDL);
        !           616:                log_info("%s: error adding option, no reply sent", msgbuf);
        !           617:                return;
        !           618:        }
        !           619: 
        !           620:        /*
        !           621:         * Log the message we've received.
        !           622:         */
        !           623:        log_info("%s", msgbuf);
        !           624: 
        !           625:        /*
        !           626:         * Figure out which address to use to send from.
        !           627:         */
        !           628:        get_server_source_address(&siaddr, options, packet);
        !           629: 
        !           630:        /* 
        !           631:         * Set up the option buffer.
        !           632:         */
        !           633: 
        !           634:        memset(&prl, 0, sizeof(prl));
        !           635:        oc = lookup_option(&dhcp_universe, options, 
        !           636:                           DHO_DHCP_PARAMETER_REQUEST_LIST);
        !           637:        if (oc != NULL) {
        !           638:                evaluate_option_cache(&prl, 
        !           639:                                      packet, 
        !           640:                                      NULL,
        !           641:                                      NULL,
        !           642:                                      packet->options,
        !           643:                                      options,
        !           644:                                      &global_scope,
        !           645:                                      oc,
        !           646:                                      MDL);
        !           647:        }
        !           648:        if (prl.len > 0) {
        !           649:                prl_ptr = &prl;
        !           650:        } else {
        !           651:                prl_ptr = NULL;
        !           652:        }
        !           653: 
        !           654:        packet->packet_length = cons_options(packet, 
        !           655:                                             packet->raw, 
        !           656:                                             lease,
        !           657:                                             NULL,
        !           658:                                             0,
        !           659:                                             packet->options,
        !           660:                                             options,
        !           661:                                             &global_scope,
        !           662:                                             0,
        !           663:                                             0,
        !           664:                                             0, 
        !           665:                                             prl_ptr,
        !           666:                                             NULL);
        !           667: 
        !           668:        data_string_forget(&prl, MDL);  /* SK: safe, even if empty */
        !           669:        option_state_dereference(&options, MDL);
        !           670:        lease_dereference(&lease, MDL);
        !           671: 
        !           672:        to.sin_family = AF_INET;
        !           673: #ifdef HAVE_SA_LEN
        !           674:        to.sin_len = sizeof(to);
        !           675: #endif
        !           676:        memset(to.sin_zero, 0, sizeof(to.sin_zero));
        !           677: 
        !           678:        /* 
        !           679:         * Leasequery packets are be sent to the gateway address.
        !           680:         */
        !           681:        to.sin_addr = packet->raw->giaddr;
        !           682:        if (packet->raw->giaddr.s_addr != htonl(INADDR_LOOPBACK)) {
        !           683:                to.sin_port = local_port;
        !           684:        } else {
        !           685:                to.sin_port = remote_port; /* XXXSK: For debugging. */
        !           686:        }
        !           687: 
        !           688:        /* 
        !           689:         * The fallback_interface lets us send with a real IP
        !           690:         * address. The packet interface sends from all-zeros.
        !           691:         */
        !           692:        if (fallback_interface != NULL) {
        !           693:                interface = fallback_interface;
        !           694:        } else {
        !           695:                interface = packet->interface;
        !           696:        }
        !           697: 
        !           698:        /*
        !           699:         * Report what we're sending.
        !           700:         */
        !           701:        log_info("%s to %s for %s (%d associated IPs)",
        !           702:                dhcp_msg_type_name, 
        !           703:                inet_ntoa(to.sin_addr), dbg_info, assoc_ip_cnt);
        !           704: 
        !           705:        send_packet(interface,
        !           706:                    NULL,
        !           707:                    packet->raw, 
        !           708:                    packet->packet_length,
        !           709:                    siaddr,
        !           710:                    &to,
        !           711:                    NULL);
        !           712: }
        !           713: 
        !           714: #ifdef DHCPv6
        !           715: 
        !           716: /*
        !           717:  * TODO: RFC5007 query-by-clientid.
        !           718:  *
        !           719:  * TODO: RFC5007 look at the pools according to the link-address.
        !           720:  *
        !           721:  * TODO: get fixed leases too.
        !           722:  *
        !           723:  * TODO: RFC5007 ORO in query-options.
        !           724:  *
        !           725:  * TODO: RFC5007 lq-relay-data.
        !           726:  *
        !           727:  * TODO: RFC5007 lq-client-link.
        !           728:  *
        !           729:  * Note: the code is still nearly compliant and usable for the target
        !           730:  * case with these missing features!
        !           731:  */
        !           732: 
        !           733: /*
        !           734:  * The structure to handle a leasequery.
        !           735:  */
        !           736: struct lq6_state {
        !           737:        struct packet *packet;
        !           738:        struct data_string client_id;
        !           739:        struct data_string server_id;
        !           740:        struct data_string lq_query;
        !           741:        uint8_t query_type;
        !           742:        struct in6_addr link_addr;
        !           743:        struct option_state *query_opts;
        !           744: 
        !           745:        struct option_state *reply_opts;
        !           746:        unsigned cursor;
        !           747:        union reply_buffer {
        !           748:                unsigned char data[65536];
        !           749:                struct dhcpv6_packet reply;
        !           750:        } buf;
        !           751: };
        !           752: 
        !           753: /*
        !           754:  * Options that we want to send.
        !           755:  */
        !           756: static const int required_opts_lq[] = {
        !           757:        D6O_CLIENTID,
        !           758:        D6O_SERVERID,
        !           759:        D6O_STATUS_CODE,
        !           760:        D6O_CLIENT_DATA,
        !           761:        D6O_LQ_RELAY_DATA,
        !           762:        D6O_LQ_CLIENT_LINK,
        !           763:        0
        !           764: };
        !           765: static const int required_opt_CLIENT_DATA[] = {
        !           766:        D6O_CLIENTID,
        !           767:        D6O_IAADDR,
        !           768:        D6O_IAPREFIX,
        !           769:        D6O_CLT_TIME,
        !           770:        0
        !           771: };
        !           772: 
        !           773: /*
        !           774:  * Get the lq-query option from the packet.
        !           775:  */
        !           776: static isc_result_t
        !           777: get_lq_query(struct lq6_state *lq)
        !           778: {
        !           779:        struct data_string *lq_query = &lq->lq_query;
        !           780:        struct packet *packet = lq->packet;
        !           781:        struct option_cache *oc;
        !           782: 
        !           783:        /*
        !           784:         * Verify our lq_query structure is empty.
        !           785:         */
        !           786:        if ((lq_query->data != NULL) || (lq_query->len != 0)) {
        !           787:                return ISC_R_INVALIDARG;
        !           788:        }
        !           789: 
        !           790:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_LQ_QUERY);
        !           791:        if (oc == NULL) {
        !           792:                return ISC_R_NOTFOUND;
        !           793:        }
        !           794: 
        !           795:        if (!evaluate_option_cache(lq_query, packet, NULL, NULL,
        !           796:                                   packet->options, NULL,
        !           797:                                   &global_scope, oc, MDL)) {
        !           798:                return ISC_R_FAILURE;
        !           799:        }
        !           800: 
        !           801:        return ISC_R_SUCCESS;
        !           802: }
        !           803: 
        !           804: /*
        !           805:  * Message validation, RFC 5007 section 4.2.1:
        !           806:  *  dhcpv6.c:valid_client_msg() - unicast + lq-query option.
        !           807:  */
        !           808: static int
        !           809: valid_query_msg(struct lq6_state *lq) {
        !           810:        struct packet *packet = lq->packet;
        !           811:        int ret_val = 0;
        !           812:        struct option_cache *oc;
        !           813: 
        !           814:        /* INSIST((lq != NULL) || (packet != NULL)); */
        !           815: 
        !           816:        switch (get_client_id(packet, &lq->client_id)) {
        !           817:                case ISC_R_SUCCESS:
        !           818:                        break;
        !           819:                case ISC_R_NOTFOUND:
        !           820:                        log_debug("Discarding %s from %s; "
        !           821:                                  "client identifier missing", 
        !           822:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           823:                                  piaddr(packet->client_addr));
        !           824:                        goto exit;
        !           825:                default:
        !           826:                        log_error("Error processing %s from %s; "
        !           827:                                  "unable to evaluate Client Identifier",
        !           828:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           829:                                  piaddr(packet->client_addr));
        !           830:                        goto exit;
        !           831:        }
        !           832: 
        !           833:        oc = lookup_option(&dhcpv6_universe, packet->options, D6O_SERVERID);
        !           834:        if (oc != NULL) {
        !           835:                if (evaluate_option_cache(&lq->server_id, packet, NULL, NULL,
        !           836:                                          packet->options, NULL, 
        !           837:                                          &global_scope, oc, MDL)) {
        !           838:                        log_debug("Discarding %s from %s; " 
        !           839:                                  "server identifier found "
        !           840:                                  "(CLIENTID %s, SERVERID %s)", 
        !           841:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           842:                                  piaddr(packet->client_addr),
        !           843:                                  print_hex_1(lq->client_id.len, 
        !           844:                                              lq->client_id.data, 60),
        !           845:                                  print_hex_2(lq->server_id.len,
        !           846:                                              lq->server_id.data, 60));
        !           847:                } else {
        !           848:                        log_debug("Discarding %s from %s; " 
        !           849:                                  "server identifier found "
        !           850:                                  "(CLIENTID %s)", 
        !           851:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           852:                                  print_hex_1(lq->client_id.len, 
        !           853:                                              lq->client_id.data, 60),
        !           854:                                  piaddr(packet->client_addr));
        !           855:                }
        !           856:                goto exit;
        !           857:        }
        !           858: 
        !           859:        switch (get_lq_query(lq)) {
        !           860:                case ISC_R_SUCCESS:
        !           861:                        break;
        !           862:                case ISC_R_NOTFOUND:
        !           863:                        log_debug("Discarding %s from %s; lq-query missing",
        !           864:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           865:                                  piaddr(packet->client_addr));
        !           866:                        goto exit;
        !           867:                default:
        !           868:                        log_error("Error processing %s from %s; "
        !           869:                                  "unable to evaluate LQ-Query",
        !           870:                                  dhcpv6_type_names[packet->dhcpv6_msg_type],
        !           871:                                  piaddr(packet->client_addr));
        !           872:                        goto exit;
        !           873:        }
        !           874: 
        !           875:        /* looks good */
        !           876:        ret_val = 1;
        !           877: 
        !           878: exit:
        !           879:        if (!ret_val) {
        !           880:                if (lq->client_id.len > 0) {
        !           881:                        data_string_forget(&lq->client_id, MDL);
        !           882:                }
        !           883:                if (lq->server_id.len > 0) {
        !           884:                        data_string_forget(&lq->server_id, MDL);
        !           885:                }
        !           886:                if (lq->lq_query.len > 0) {
        !           887:                        data_string_forget(&lq->lq_query, MDL);
        !           888:                }
        !           889:        }
        !           890:        return ret_val;
        !           891: }
        !           892: 
        !           893: /*
        !           894:  * Set an error in a status-code option (from set_status_code).
        !           895:  */
        !           896: static int
        !           897: set_error(struct lq6_state *lq, u_int16_t code, const char *message) {
        !           898:        struct data_string d;
        !           899:        int ret_val;
        !           900: 
        !           901:        memset(&d, 0, sizeof(d));
        !           902:        d.len = sizeof(code) + strlen(message);
        !           903:        if (!buffer_allocate(&d.buffer, d.len, MDL)) {
        !           904:                log_fatal("set_error: no memory for status code.");
        !           905:        }
        !           906:        d.data = d.buffer->data;
        !           907:        putUShort(d.buffer->data, code);
        !           908:        memcpy(d.buffer->data + sizeof(code), message, d.len - sizeof(code));
        !           909:        if (!save_option_buffer(&dhcpv6_universe, lq->reply_opts,
        !           910:                                d.buffer, (unsigned char *)d.data, d.len, 
        !           911:                                D6O_STATUS_CODE, 0)) {
        !           912:                log_error("set_error: error saving status code.");
        !           913:                ret_val = 0;
        !           914:        } else {
        !           915:                ret_val = 1;
        !           916:        }
        !           917:        data_string_forget(&d, MDL);
        !           918:        return ret_val;
        !           919: }
        !           920: 
        !           921: /*
        !           922:  * Process a by-address lease query.
        !           923:  */
        !           924: static int
        !           925: process_lq_by_address(struct lq6_state *lq) {
        !           926:        struct packet *packet = lq->packet;
        !           927:        struct option_cache *oc;
        !           928:        struct ipv6_pool *pool = NULL;
        !           929:        struct data_string data;
        !           930:        struct in6_addr addr;
        !           931:        struct iasubopt *iaaddr = NULL;
        !           932:        struct option_state *opt_state = NULL;
        !           933:        u_int32_t lifetime;
        !           934:        unsigned opt_cursor;
        !           935:        int ret_val = 0;
        !           936: 
        !           937:        /*
        !           938:         * Get the IAADDR.
        !           939:         */
        !           940:        oc = lookup_option(&dhcpv6_universe, lq->query_opts, D6O_IAADDR);
        !           941:        if (oc == NULL) {
        !           942:                if (!set_error(lq, STATUS_MalformedQuery,
        !           943:                               "No OPTION_IAADDR.")) {
        !           944:                        log_error("process_lq_by_address: unable "
        !           945:                                  "to set MalformedQuery status code.");
        !           946:                        return 0;
        !           947:                }
        !           948:                return 1;
        !           949:        }
        !           950:        memset(&data, 0, sizeof(data));
        !           951:        if (!evaluate_option_cache(&data, packet,
        !           952:                                   NULL, NULL,
        !           953:                                   lq->query_opts, NULL,
        !           954:                                   &global_scope, oc, MDL) ||
        !           955:            (data.len < IAADDR_OFFSET)) {
        !           956:                log_error("process_lq_by_address: error evaluating IAADDR.");
        !           957:                goto exit;
        !           958:        }
        !           959:        memcpy(&addr, data.data, sizeof(addr));
        !           960:        data_string_forget(&data, MDL);
        !           961: 
        !           962:        /*
        !           963:         * Find the lease.
        !           964:         * Note the RFC 5007 says to use the link-address to find the link
        !           965:         * or the ia-aadr when it is :: but in any case the ia-addr has
        !           966:         * to be on the link, so we ignore the link-address here.
        !           967:         */
        !           968:        if (find_ipv6_pool(&pool, D6O_IA_NA, &addr) != ISC_R_SUCCESS) {
        !           969:                if (!set_error(lq, STATUS_NotConfigured,
        !           970:                               "Address not in a pool.")) {
        !           971:                        log_error("process_lq_by_address: unable "
        !           972:                                  "to set NotConfigured status code.");
        !           973:                        goto exit;
        !           974:                }
        !           975:                ret_val = 1;
        !           976:                goto exit;
        !           977:        }
        !           978:        if (iasubopt_hash_lookup(&iaaddr, pool->leases, &addr,
        !           979:                                 sizeof(addr), MDL) == 0) {
        !           980:                ret_val = 1;
        !           981:                goto exit;
        !           982:        }
        !           983:        if ((iaaddr == NULL) || (iaaddr->state != FTS_ACTIVE) ||
        !           984:            (iaaddr->ia == NULL) || (iaaddr->ia->iaid_duid.len <= 4)) {
        !           985:                ret_val = 1;
        !           986:                goto exit;
        !           987:        }
        !           988: 
        !           989:        /*
        !           990:         * Build the client-data option (with client-id, ia-addr and clt-time).
        !           991:         */
        !           992:        if (!option_state_allocate(&opt_state, MDL)) {
        !           993:                log_error("process_lq_by_address: "
        !           994:                          "no memory for option state.");
        !           995:                goto exit;
        !           996:        }
        !           997: 
        !           998:        data_string_copy(&data, &iaaddr->ia->iaid_duid, MDL);
        !           999:        data.data += 4;
        !          1000:        data.len -= 4;
        !          1001:        if (!save_option_buffer(&dhcpv6_universe, opt_state,
        !          1002:                                NULL, (unsigned char *)data.data, data.len,
        !          1003:                                D6O_CLIENTID, 0)) {
        !          1004:                log_error("process_lq_by_address: error saving client ID.");
        !          1005:                goto exit;
        !          1006:        }
        !          1007:        data_string_forget(&data, MDL);
        !          1008: 
        !          1009:        data.len = IAADDR_OFFSET;
        !          1010:        if (!buffer_allocate(&data.buffer, data.len, MDL)) {
        !          1011:                log_error("process_lq_by_address: no memory for ia-addr.");
        !          1012:                goto exit;
        !          1013:        }
        !          1014:        data.data = data.buffer->data;
        !          1015:        memcpy(data.buffer->data, &iaaddr->addr, 16);
        !          1016:        lifetime = iaaddr->prefer;
        !          1017:        putULong(data.buffer->data + 16, lifetime);
        !          1018:        lifetime = iaaddr->valid;
        !          1019:        putULong(data.buffer->data + 20, lifetime);
        !          1020:        if (!save_option_buffer(&dhcpv6_universe, opt_state,
        !          1021:                                NULL, (unsigned char *)data.data, data.len,
        !          1022:                                D6O_IAADDR, 0)) {
        !          1023:                log_error("process_lq_by_address: error saving ia-addr.");
        !          1024:                goto exit;
        !          1025:        }
        !          1026:        data_string_forget(&data, MDL);
        !          1027: 
        !          1028:        lifetime = htonl(iaaddr->ia->cltt);
        !          1029:        if (!save_option_buffer(&dhcpv6_universe, opt_state,
        !          1030:                                NULL, (unsigned char *)&lifetime, 4,
        !          1031:                                D6O_CLT_TIME, 0)) {
        !          1032:                log_error("process_lq_by_address: error saving clt time.");
        !          1033:                goto exit;
        !          1034:        }
        !          1035: 
        !          1036:        /*
        !          1037:         * Store the client-data option.
        !          1038:         */
        !          1039:        opt_cursor = lq->cursor;
        !          1040:        putUShort(lq->buf.data + lq->cursor, (unsigned)D6O_CLIENT_DATA);
        !          1041:        lq->cursor += 2;
        !          1042:        /* Skip option length. */
        !          1043:        lq->cursor += 2;
        !          1044: 
        !          1045:        lq->cursor += store_options6((char *)lq->buf.data + lq->cursor,
        !          1046:                                     sizeof(lq->buf) - lq->cursor,
        !          1047:                                     opt_state, lq->packet,
        !          1048:                                     required_opt_CLIENT_DATA, NULL);
        !          1049:        /* Reset the length. */
        !          1050:        putUShort(lq->buf.data + opt_cursor + 2,
        !          1051:                  lq->cursor - (opt_cursor + 4));
        !          1052: 
        !          1053:        /* Done. */
        !          1054:        ret_val = 1;
        !          1055: 
        !          1056:      exit:
        !          1057:        if (data.data != NULL)
        !          1058:                data_string_forget(&data, MDL);
        !          1059:        if (pool != NULL)
        !          1060:                ipv6_pool_dereference(&pool, MDL);
        !          1061:        if (iaaddr != NULL)
        !          1062:                iasubopt_dereference(&iaaddr, MDL);
        !          1063:        if (opt_state != NULL)
        !          1064:                option_state_dereference(&opt_state, MDL);
        !          1065:        return ret_val;
        !          1066: }
        !          1067: 
        !          1068: 
        !          1069: /*
        !          1070:  * Process a lease query.
        !          1071:  */
        !          1072: void
        !          1073: dhcpv6_leasequery(struct data_string *reply_ret, struct packet *packet) {
        !          1074:        static struct lq6_state lq;
        !          1075:        struct option_cache *oc;
        !          1076:        int allow_lq;
        !          1077: 
        !          1078:        /*
        !          1079:         * Initialize the lease query state.
        !          1080:         */
        !          1081:        lq.packet = NULL;
        !          1082:        memset(&lq.client_id, 0, sizeof(lq.client_id));
        !          1083:        memset(&lq.server_id, 0, sizeof(lq.server_id));
        !          1084:        memset(&lq.lq_query, 0, sizeof(lq.lq_query));
        !          1085:        lq.query_opts = NULL;
        !          1086:        lq.reply_opts = NULL;
        !          1087:        packet_reference(&lq.packet, packet, MDL);
        !          1088: 
        !          1089:        /*
        !          1090:         * Validate our input.
        !          1091:         */
        !          1092:        if (!valid_query_msg(&lq)) {
        !          1093:                goto exit;
        !          1094:        }
        !          1095: 
        !          1096:        /*
        !          1097:         * Prepare our reply.
        !          1098:         */
        !          1099:        if (!option_state_allocate(&lq.reply_opts, MDL)) {
        !          1100:                log_error("dhcpv6_leasequery: no memory for option state.");
        !          1101:                goto exit;
        !          1102:        }
        !          1103:        execute_statements_in_scope(NULL, lq.packet, NULL, NULL,
        !          1104:                                    lq.packet->options, lq.reply_opts,
        !          1105:                                    &global_scope, root_group, NULL);
        !          1106: 
        !          1107:        lq.buf.reply.msg_type = DHCPV6_LEASEQUERY_REPLY;
        !          1108: 
        !          1109:        memcpy(lq.buf.reply.transaction_id,
        !          1110:               lq.packet->dhcpv6_transaction_id,
        !          1111:               sizeof(lq.buf.reply.transaction_id));
        !          1112: 
        !          1113:        /* 
        !          1114:         * Because LEASEQUERY has some privacy concerns, default to deny.
        !          1115:         */
        !          1116:        allow_lq = 0;
        !          1117: 
        !          1118:        /*
        !          1119:         * See if we are authorized to do LEASEQUERY.
        !          1120:         */
        !          1121:        oc = lookup_option(&server_universe, lq.reply_opts, SV_LEASEQUERY);
        !          1122:        if (oc != NULL) {
        !          1123:                allow_lq = evaluate_boolean_option_cache(NULL,
        !          1124:                                                         lq.packet,
        !          1125:                                                         NULL, NULL,
        !          1126:                                                         lq.packet->options,
        !          1127:                                                         lq.reply_opts,
        !          1128:                                                         &global_scope,
        !          1129:                                                         oc, MDL);
        !          1130:        }
        !          1131: 
        !          1132:        if (!allow_lq) {
        !          1133:                log_info("dhcpv6_leasequery: not allowed, query ignored.");
        !          1134:                goto exit;
        !          1135:        }
        !          1136:            
        !          1137:        /*
        !          1138:         * Same than transmission of REPLY message in RFC 3315:
        !          1139:         *  server-id
        !          1140:         *  client-id
        !          1141:         */
        !          1142: 
        !          1143:        oc = lookup_option(&dhcpv6_universe, lq.reply_opts, D6O_SERVERID);
        !          1144:        if (oc == NULL) {
        !          1145:                /* If not already in options, get from query then global. */
        !          1146:                if (lq.server_id.data == NULL)
        !          1147:                        copy_server_duid(&lq.server_id, MDL);
        !          1148:                if (!save_option_buffer(&dhcpv6_universe,
        !          1149:                                        lq.reply_opts,
        !          1150:                                        NULL,
        !          1151:                                        (unsigned char *)lq.server_id.data,
        !          1152:                                        lq.server_id.len, 
        !          1153:                                        D6O_SERVERID,
        !          1154:                                        0)) {
        !          1155:                        log_error("dhcpv6_leasequery: "
        !          1156:                                  "error saving server identifier.");
        !          1157:                        goto exit;
        !          1158:                }
        !          1159:        }
        !          1160: 
        !          1161:        if (!save_option_buffer(&dhcpv6_universe,
        !          1162:                                lq.reply_opts,
        !          1163:                                lq.client_id.buffer,
        !          1164:                                (unsigned char *)lq.client_id.data,
        !          1165:                                lq.client_id.len,
        !          1166:                                D6O_CLIENTID,
        !          1167:                                0)) {
        !          1168:                log_error("dhcpv6_leasequery: "
        !          1169:                          "error saving client identifier.");
        !          1170:                goto exit;
        !          1171:        }
        !          1172: 
        !          1173:        lq.cursor = 4;
        !          1174: 
        !          1175:        /*
        !          1176:         * Decode the lq-query option.
        !          1177:         */
        !          1178: 
        !          1179:        if (lq.lq_query.len <= LQ_QUERY_OFFSET) {
        !          1180:                if (!set_error(&lq, STATUS_MalformedQuery,
        !          1181:                               "OPTION_LQ_QUERY too short.")) {
        !          1182:                        log_error("dhcpv6_leasequery: unable "
        !          1183:                                  "to set MalformedQuery status code.");
        !          1184:                        goto exit;
        !          1185:                }
        !          1186:                goto done;
        !          1187:        }
        !          1188: 
        !          1189:        lq.query_type = lq.lq_query.data [0];
        !          1190:        memcpy(&lq.link_addr, lq.lq_query.data + 1, sizeof(lq.link_addr));
        !          1191:        switch (lq.query_type) {
        !          1192:                case LQ6QT_BY_ADDRESS:
        !          1193:                        break;
        !          1194:                case LQ6QT_BY_CLIENTID:
        !          1195:                        if (!set_error(&lq, STATUS_UnknownQueryType,
        !          1196:                                       "QUERY_BY_CLIENTID not supported.")) {
        !          1197:                                log_error("dhcpv6_leasequery: unable to "
        !          1198:                                          "set UnknownQueryType status code.");
        !          1199:                                goto exit;
        !          1200:                        }
        !          1201:                        goto done;
        !          1202:                default:
        !          1203:                        if (!set_error(&lq, STATUS_UnknownQueryType,
        !          1204:                                       "Unknown query-type.")) {
        !          1205:                                log_error("dhcpv6_leasequery: unable to "
        !          1206:                                          "set UnknownQueryType status code.");
        !          1207:                                goto exit;
        !          1208:                        }
        !          1209:                        goto done;
        !          1210:        }
        !          1211: 
        !          1212:        if (!option_state_allocate(&lq.query_opts, MDL)) {
        !          1213:                log_error("dhcpv6_leasequery: no memory for option state.");
        !          1214:                goto exit;
        !          1215:        }
        !          1216:        if (!parse_option_buffer(lq.query_opts,
        !          1217:                                 lq.lq_query.data + LQ_QUERY_OFFSET,
        !          1218:                                 lq.lq_query.len - LQ_QUERY_OFFSET,
        !          1219:                                 &dhcpv6_universe)) {
        !          1220:                log_error("dhcpv6_leasequery: error parsing query-options.");
        !          1221:                if (!set_error(&lq, STATUS_MalformedQuery,
        !          1222:                               "Bad query-options.")) {
        !          1223:                        log_error("dhcpv6_leasequery: unable "
        !          1224:                                  "to set MalformedQuery status code.");
        !          1225:                        goto exit;
        !          1226:                }
        !          1227:                goto done;
        !          1228:        }
        !          1229: 
        !          1230:        /* Do it. */
        !          1231:        if (!process_lq_by_address(&lq))
        !          1232:                goto exit;
        !          1233: 
        !          1234:       done:
        !          1235:        /* Store the options. */
        !          1236:        lq.cursor += store_options6((char *)lq.buf.data + lq.cursor,
        !          1237:                                    sizeof(lq.buf) - lq.cursor,
        !          1238:                                    lq.reply_opts,
        !          1239:                                    lq.packet,
        !          1240:                                    required_opts_lq,
        !          1241:                                    NULL);
        !          1242: 
        !          1243:        /* Return our reply to the caller. */
        !          1244:        reply_ret->len = lq.cursor;
        !          1245:        reply_ret->buffer = NULL;
        !          1246:        if (!buffer_allocate(&reply_ret->buffer, lq.cursor, MDL)) {
        !          1247:                log_fatal("dhcpv6_leasequery: no memory to store Reply.");
        !          1248:        }
        !          1249:        memcpy(reply_ret->buffer->data, lq.buf.data, lq.cursor);
        !          1250:        reply_ret->data = reply_ret->buffer->data;
        !          1251: 
        !          1252:       exit:
        !          1253:        /* Cleanup. */
        !          1254:        if (lq.packet != NULL)
        !          1255:                packet_dereference(&lq.packet, MDL);
        !          1256:        if (lq.client_id.data != NULL)
        !          1257:                data_string_forget(&lq.client_id, MDL);
        !          1258:        if (lq.server_id.data != NULL)
        !          1259:                data_string_forget(&lq.server_id, MDL);
        !          1260:        if (lq.lq_query.data != NULL)
        !          1261:                data_string_forget(&lq.lq_query, MDL);
        !          1262:        if (lq.query_opts != NULL)
        !          1263:                option_state_dereference(&lq.query_opts, MDL);
        !          1264:        if (lq.reply_opts != NULL)
        !          1265:                option_state_dereference(&lq.reply_opts, MDL);
        !          1266: }
        !          1267: 
        !          1268: #endif /* DHCPv6 */

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