Annotation of embedaddon/dhcp/common/dns.c, revision 1.1.1.1

1.1       misho       1: /* dns.c
                      2: 
                      3:    Domain Name Service subroutines. */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2009-2010 by Internet Systems Consortium, Inc. ("ISC")
                      7:  * Copyright (c) 2004-2007 by Internet Systems Consortium, Inc. ("ISC")
                      8:  * Copyright (c) 2001-2003 by Internet Software Consortium
                      9:  *
                     10:  * Permission to use, copy, modify, and distribute this software for any
                     11:  * purpose with or without fee is hereby granted, provided that the above
                     12:  * copyright notice and this permission notice appear in all copies.
                     13:  *
                     14:  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
                     15:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     16:  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
                     17:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     18:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     19:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
                     20:  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     21:  *
                     22:  *   Internet Systems Consortium, Inc.
                     23:  *   950 Charter Street
                     24:  *   Redwood City, CA 94063
                     25:  *   <info@isc.org>
                     26:  *   https://www.isc.org/
                     27:  *
                     28:  * This software has been written for Internet Systems Consortium
                     29:  * by Ted Lemon in cooperation with Nominum, Inc.
                     30:  * To learn more about Internet Systems Consortium, see
                     31:  * ``https://www.isc.org/''.  To learn more about Nominum, Inc., see
                     32:  * ``http://www.nominum.com''.
                     33:  */
                     34: 
                     35: #include "dhcpd.h"
                     36: #include "arpa/nameser.h"
                     37: #include "dst/md5.h"
                     38: 
                     39: /* This file is kind of a crutch for the BIND 8 nsupdate code, which has
                     40:  * itself been cruelly hacked from its original state.   What this code
                     41:  * does is twofold: first, it maintains a database of zone cuts that can
                     42:  * be used to figure out which server should be contacted to update any
                     43:  * given domain name.   Secondly, it maintains a set of named TSIG keys,
                     44:  * and associates those keys with zones.   When an update is requested for
                     45:  * a particular zone, the key associated with that zone is used for the
                     46:  * update.
                     47:  *
                     48:  * The way this works is that you define the domain name to which an
                     49:  * SOA corresponds, and the addresses of some primaries for that domain name:
                     50:  *
                     51:  *     zone FOO.COM {
                     52:  *       primary 10.0.17.1;
                     53:  *       secondary 10.0.22.1, 10.0.23.1;
                     54:  *       key "FOO.COM Key";
                     55:  *     }
                     56:  *
                     57:  * If an update is requested for GAZANGA.TOPANGA.FOO.COM, then the name
                     58:  * server looks in its database for a zone record for "GAZANGA.TOPANGA.FOO.COM",
                     59:  * doesn't find it, looks for one for "TOPANGA.FOO.COM", doesn't find *that*,
                     60:  * looks for "FOO.COM", finds it. So it
                     61:  * attempts the update to the primary for FOO.COM.   If that times out, it
                     62:  * tries the secondaries.   You can list multiple primaries if you have some
                     63:  * kind of magic name server that supports that.   You shouldn't list
                     64:  * secondaries that don't know how to forward updates (e.g., BIND 8 doesn't
                     65:  * support update forwarding, AFAIK).   If no TSIG key is listed, the update
                     66:  * is attempted without TSIG.
                     67:  *
                     68:  * The DHCP server tries to find an existing zone for any given name by
                     69:  * trying to look up a local zone structure for each domain containing
                     70:  * that name, all the way up to '.'.   If it finds one cached, it tries
                     71:  * to use that one to do the update.   That's why it tries to update
                     72:  * "FOO.COM" above, even though theoretically it should try GAZANGA...
                     73:  * and TOPANGA... first.
                     74:  *
                     75:  * If the update fails with a predefined or cached zone (we'll get to
                     76:  * those in a second), then it tries to find a more specific zone.   This
                     77:  * is done by looking first for an SOA for GAZANGA.TOPANGA.FOO.COM.   Then
                     78:  * an SOA for TOPANGA.FOO.COM is sought.   If during this search a predefined
                     79:  * or cached zone is found, the update fails - there's something wrong
                     80:  * somewhere.
                     81:  *
                     82:  * If a more specific zone _is_ found, that zone is cached for the length of
                     83:  * its TTL in the same database as that described above.   TSIG updates are
                     84:  * never done for cached zones - if you want TSIG updates you _must_
                     85:  * write a zone definition linking the key to the zone.   In cases where you
                     86:  * know for sure what the key is but do not want to hardcode the IP addresses
                     87:  * of the primary or secondaries, a zone declaration can be made that doesn't
                     88:  * include any primary or secondary declarations.   When the DHCP server
                     89:  * encounters this while hunting up a matching zone for a name, it looks up
                     90:  * the SOA, fills in the IP addresses, and uses that record for the update.
                     91:  * If the SOA lookup returns NXRRSET, a warning is printed and the zone is
                     92:  * discarded, TSIG key and all.   The search for the zone then continues as if
                     93:  * the zone record hadn't been found.   Zones without IP addresses don't
                     94:  * match when initially hunting for a predefined or cached zone to update.
                     95:  *
                     96:  * When an update is attempted and no predefined or cached zone is found
                     97:  * that matches any enclosing domain of the domain being updated, the DHCP
                     98:  * server goes through the same process that is done when the update to a
                     99:  * predefined or cached zone fails - starting with the most specific domain
                    100:  * name (GAZANGA.TOPANGA.FOO.COM) and moving to the least specific (the root),
                    101:  * it tries to look up an SOA record.   When it finds one, it creates a cached
                    102:  * zone and attempts an update, and gives up if the update fails.
                    103:  *
                    104:  * TSIG keys are defined like this:
                    105:  *
                    106:  *     key "FOO.COM Key" {
                    107:  *             algorithm HMAC-MD5.SIG-ALG.REG.INT;
                    108:  *             secret <Base64>;
                    109:  *     }
                    110:  *
                    111:  * <Base64> is a number expressed in base64 that represents the key.
                    112:  * It's also permissible to use a quoted string here - this will be
                    113:  * translated as the ASCII bytes making up the string, and will not
                    114:  * include any NUL termination.  The key name can be any text string,
                    115:  * and the key type must be one of the key types defined in the draft
                    116:  * or by the IANA.  Currently only the HMAC-MD5... key type is
                    117:  * supported.
                    118:  */
                    119: 
                    120: dns_zone_hash_t *dns_zone_hash;
                    121: 
                    122: #if defined (NSUPDATE)
                    123: isc_result_t find_tsig_key (ns_tsig_key **key, const char *zname,
                    124:                            struct dns_zone *zone)
                    125: {
                    126:        ns_tsig_key *tkey;
                    127: 
                    128:        if (!zone)
                    129:                return ISC_R_NOTFOUND;
                    130: 
                    131:        if (!zone -> key) {
                    132:                return ISC_R_KEY_UNKNOWN;
                    133:        }
                    134:        
                    135:        if ((!zone -> key -> name ||
                    136:             strlen (zone -> key -> name) > NS_MAXDNAME) ||
                    137:            (!zone -> key -> algorithm ||
                    138:             strlen (zone -> key -> algorithm) > NS_MAXDNAME) ||
                    139:            (!zone -> key) ||
                    140:            (!zone -> key -> key) ||
                    141:            (zone -> key -> key -> len == 0)) {
                    142:                return ISC_R_INVALIDKEY;
                    143:        }
                    144:        tkey = dmalloc (sizeof *tkey, MDL);
                    145:        if (!tkey) {
                    146:              nomem:
                    147:                return ISC_R_NOMEMORY;
                    148:        }
                    149:        memset (tkey, 0, sizeof *tkey);
                    150:        tkey -> data = dmalloc (zone -> key -> key -> len, MDL);
                    151:        if (!tkey -> data) {
                    152:                dfree (tkey, MDL);
                    153:                goto nomem;
                    154:        }
                    155:        strcpy (tkey -> name, zone -> key -> name);
                    156:        strcpy (tkey -> alg, zone -> key -> algorithm);
                    157:        memcpy (tkey -> data,
                    158:                zone -> key -> key -> value, zone -> key -> key -> len);
                    159:        tkey -> len = zone -> key -> key -> len;
                    160:        *key = tkey;
                    161:        return ISC_R_SUCCESS;
                    162: }
                    163: 
                    164: void tkey_free (ns_tsig_key **key)
                    165: {
                    166:        if ((*key) -> data)
                    167:                dfree ((*key) -> data, MDL);
                    168:        dfree ((*key), MDL);
                    169:        *key = (ns_tsig_key *)0;
                    170: }
                    171: #endif
                    172: 
                    173: isc_result_t enter_dns_zone (struct dns_zone *zone)
                    174: {
                    175:        struct dns_zone *tz = (struct dns_zone *)0;
                    176: 
                    177:        if (dns_zone_hash) {
                    178:                dns_zone_hash_lookup (&tz,
                    179:                                      dns_zone_hash, zone -> name, 0, MDL);
                    180:                if (tz == zone) {
                    181:                        dns_zone_dereference (&tz, MDL);
                    182:                        return ISC_R_SUCCESS;
                    183:                }
                    184:                if (tz) {
                    185:                        dns_zone_hash_delete (dns_zone_hash,
                    186:                                              zone -> name, 0, MDL);
                    187:                        dns_zone_dereference (&tz, MDL);
                    188:                }
                    189:        } else {
                    190:                if (!dns_zone_new_hash(&dns_zone_hash, DNS_HASH_SIZE, MDL))
                    191:                        return ISC_R_NOMEMORY;
                    192:        }
                    193:        dns_zone_hash_add (dns_zone_hash, zone -> name, 0, zone, MDL);
                    194:        return ISC_R_SUCCESS;
                    195: }
                    196: 
                    197: isc_result_t dns_zone_lookup (struct dns_zone **zone, const char *name)
                    198: {
                    199:        int len;
                    200:        char *tname = (char *)0;
                    201:        isc_result_t status;
                    202: 
                    203:        if (!dns_zone_hash)
                    204:                return ISC_R_NOTFOUND;
                    205: 
                    206:        len = strlen (name);
                    207:        if (name [len - 1] != '.') {
                    208:                tname = dmalloc ((unsigned)len + 2, MDL);
                    209:                if (!tname)
                    210:                        return ISC_R_NOMEMORY;
                    211:                strcpy (tname, name);
                    212:                tname [len] = '.';
                    213:                tname [len + 1] = 0;
                    214:                name = tname;
                    215:        }
                    216:        if (!dns_zone_hash_lookup (zone, dns_zone_hash, name, 0, MDL))
                    217:                status = ISC_R_NOTFOUND;
                    218:        else
                    219:                status = ISC_R_SUCCESS;
                    220: 
                    221:        if (tname)
                    222:                dfree (tname, MDL);
                    223:        return status;
                    224: }
                    225: 
                    226: int dns_zone_dereference (ptr, file, line)
                    227:        struct dns_zone **ptr;
                    228:        const char *file;
                    229:        int line;
                    230: {
                    231:        struct dns_zone *dns_zone;
                    232: 
                    233:        if (!ptr || !*ptr) {
                    234:                log_error ("%s(%d): null pointer", file, line);
                    235: #if defined (POINTER_DEBUG)
                    236:                abort ();
                    237: #else
                    238:                return 0;
                    239: #endif
                    240:        }
                    241: 
                    242:        dns_zone = *ptr;
                    243:        *ptr = (struct dns_zone *)0;
                    244:        --dns_zone -> refcnt;
                    245:        rc_register (file, line, ptr, dns_zone, dns_zone -> refcnt, 1, RC_MISC);
                    246:        if (dns_zone -> refcnt > 0)
                    247:                return 1;
                    248: 
                    249:        if (dns_zone -> refcnt < 0) {
                    250:                log_error ("%s(%d): negative refcnt!", file, line);
                    251: #if defined (DEBUG_RC_HISTORY)
                    252:                dump_rc_history (dns_zone);
                    253: #endif
                    254: #if defined (POINTER_DEBUG)
                    255:                abort ();
                    256: #else
                    257:                return 0;
                    258: #endif
                    259:        }
                    260: 
                    261:        if (dns_zone -> name)
                    262:                dfree (dns_zone -> name, file, line);
                    263:        if (dns_zone -> key)
                    264:                omapi_auth_key_dereference (&dns_zone -> key, file, line);
                    265:        if (dns_zone -> primary)
                    266:                option_cache_dereference (&dns_zone -> primary, file, line);
                    267:        if (dns_zone -> secondary)
                    268:                option_cache_dereference (&dns_zone -> secondary, file, line);
                    269:        dfree (dns_zone, file, line);
                    270:        return 1;
                    271: }
                    272: 
                    273: #if defined (NSUPDATE)
                    274: isc_result_t find_cached_zone (const char *dname, ns_class class,
                    275:                               char *zname, size_t zsize,
                    276:                               struct in_addr *addrs,
                    277:                               int naddrs, int *naddrout,
                    278:                               struct dns_zone **zcookie)
                    279: {
                    280:        isc_result_t status = ISC_R_NOTFOUND;
                    281:        const char *np;
                    282:        struct dns_zone *zone = (struct dns_zone *)0;
                    283:        struct data_string nsaddrs;
                    284:        int ix;
                    285: 
                    286:        /* The absence of the zcookie pointer indicates that we
                    287:           succeeded previously, but the update itself failed, meaning
                    288:           that we shouldn't use the cached zone. */
                    289:        if (!zcookie)
                    290:                return ISC_R_NOTFOUND;
                    291: 
                    292:        /* We can't look up a null zone. */
                    293:        if (!dname || !*dname)
                    294:                return ISC_R_INVALIDARG;
                    295: 
                    296:        /*
                    297:         * For each subzone, try to find a cached zone.
                    298:         */
                    299:        for (np = dname;;) {
                    300:                status = dns_zone_lookup (&zone, np);
                    301:                if (status == ISC_R_SUCCESS)
                    302:                        break;
                    303: 
                    304:                np = strchr(np, '.');
                    305:                if (np == NULL)
                    306:                        break;
                    307:                np++;
                    308:        }
                    309: 
                    310:        if (status != ISC_R_SUCCESS)
                    311:                return status;
                    312: 
                    313:        /* Make sure the zone is valid. */
                    314:        if (zone -> timeout && zone -> timeout < cur_time) {
                    315:                dns_zone_dereference (&zone, MDL);
                    316:                return ISC_R_CANCELED;
                    317:        }
                    318: 
                    319:        /* Make sure the zone name will fit. */
                    320:        if (strlen (zone -> name) > zsize) {
                    321:                dns_zone_dereference (&zone, MDL);
                    322:                return ISC_R_NOSPACE;
                    323:        }
                    324:        strcpy (zname, zone -> name);
                    325: 
                    326:        memset (&nsaddrs, 0, sizeof nsaddrs);
                    327:        ix = 0;
                    328: 
                    329:        if (zone -> primary) {
                    330:                if (evaluate_option_cache (&nsaddrs, (struct packet *)0,
                    331:                                           (struct lease *)0,
                    332:                                           (struct client_state *)0,
                    333:                                           (struct option_state *)0,
                    334:                                           (struct option_state *)0,
                    335:                                           &global_scope,
                    336:                                           zone -> primary, MDL)) {
                    337:                        int ip = 0;
                    338:                        while (ix < naddrs) {
                    339:                                if (ip + 4 > nsaddrs.len)
                    340:                                        break;
                    341:                                memcpy (&addrs [ix], &nsaddrs.data [ip], 4);
                    342:                                ip += 4;
                    343:                                ix++;
                    344:                        }
                    345:                        data_string_forget (&nsaddrs, MDL);
                    346:                }
                    347:        }
                    348:        if (zone -> secondary) {
                    349:                if (evaluate_option_cache (&nsaddrs, (struct packet *)0,
                    350:                                           (struct lease *)0,
                    351:                                           (struct client_state *)0,
                    352:                                           (struct option_state *)0,
                    353:                                           (struct option_state *)0,
                    354:                                           &global_scope,
                    355:                                           zone -> secondary, MDL)) {
                    356:                        int ip = 0;
                    357:                        while (ix < naddrs) {
                    358:                                if (ip + 4 > nsaddrs.len)
                    359:                                        break;
                    360:                                memcpy (&addrs [ix], &nsaddrs.data [ip], 4);
                    361:                                ip += 4;
                    362:                                ix++;
                    363:                        }
                    364:                        data_string_forget (&nsaddrs, MDL);
                    365:                }
                    366:        }
                    367: 
                    368:        /* It's not an error for zcookie to have a value here - actually,
                    369:           it's quite likely, because res_nupdate cycles through all the
                    370:           names in the update looking for their zones. */
                    371:        if (!*zcookie)
                    372:                dns_zone_reference (zcookie, zone, MDL);
                    373:        dns_zone_dereference (&zone, MDL);
                    374:        if (naddrout)
                    375:                *naddrout = ix;
                    376:        return ISC_R_SUCCESS;
                    377: }
                    378: 
                    379: void forget_zone (struct dns_zone **zone)
                    380: {
                    381:        dns_zone_dereference (zone, MDL);
                    382: }
                    383: 
                    384: void repudiate_zone (struct dns_zone **zone)
                    385: {
                    386:        /* XXX Currently we're not differentiating between a cached
                    387:           XXX zone and a zone that's been repudiated, which means
                    388:           XXX that if we reap cached zones, we blow away repudiated
                    389:           XXX zones.   This isn't a big problem since we're not yet
                    390:           XXX caching zones... :'} */
                    391: 
                    392:        (*zone) -> timeout = cur_time - 1;
                    393:        dns_zone_dereference (zone, MDL);
                    394: }
                    395: 
                    396: void cache_found_zone (ns_class class,
                    397:                       char *zname, struct in_addr *addrs, int naddrs)
                    398: {
                    399:        struct dns_zone *zone = (struct dns_zone *)0;
                    400:        int ix = strlen (zname);
                    401: 
                    402:        if (zname [ix - 1] == '.')
                    403:                ix = 0;
                    404: 
                    405:        /* See if there's already such a zone. */
                    406:        if (dns_zone_lookup (&zone, zname) == ISC_R_SUCCESS) {
                    407:                /* If it's not a dynamic zone, leave it alone. */
                    408:                if (!zone -> timeout)
                    409:                        return;
                    410:                /* Address may have changed, so just blow it away. */
                    411:                if (zone -> primary)
                    412:                        option_cache_dereference (&zone -> primary, MDL);
                    413:                if (zone -> secondary)
                    414:                        option_cache_dereference (&zone -> secondary, MDL);
                    415:        } else if (!dns_zone_allocate (&zone, MDL))
                    416:                return;
                    417: 
                    418:        if (!zone -> name) {
                    419:                zone -> name =
                    420:                        dmalloc (strlen (zname) + 1 + (ix != 0), MDL);
                    421:                if (!zone -> name) {
                    422:                        dns_zone_dereference (&zone, MDL);
                    423:                        return;
                    424:                }
                    425:                strcpy (zone -> name, zname);
                    426:                /* Add a trailing '.' if it was missing. */
                    427:                if (ix) {
                    428:                        zone -> name [ix] = '.';
                    429:                        zone -> name [ix + 1] = 0;
                    430:                }
                    431:        }
                    432: 
                    433:        /* XXX Need to get the lower-level code to push the actual zone
                    434:           XXX TTL up to us. */
                    435:        zone -> timeout = cur_time + 1800;
                    436:        
                    437:        if (!option_cache_allocate (&zone -> primary, MDL)) {
                    438:                dns_zone_dereference (&zone, MDL);
                    439:                return;
                    440:        }
                    441:        if (!buffer_allocate (&zone -> primary -> data.buffer,
                    442:                              naddrs * sizeof (struct in_addr), MDL)) {
                    443:                dns_zone_dereference (&zone, MDL);
                    444:                return;
                    445:        }
                    446:        memcpy (zone -> primary -> data.buffer -> data,
                    447:                addrs, naddrs * sizeof *addrs);
                    448:        zone -> primary -> data.data =
                    449:                &zone -> primary -> data.buffer -> data [0];
                    450:        zone -> primary -> data.len = naddrs * sizeof *addrs;
                    451: 
                    452:        enter_dns_zone (zone);
                    453: }
                    454: 
                    455: /* Have to use TXT records for now. */
                    456: #define T_DHCID T_TXT
                    457: 
                    458: int get_dhcid (struct data_string *id,
                    459:               int type, const u_int8_t *data, unsigned len)
                    460: {
                    461:        unsigned char buf[MD5_DIGEST_LENGTH];
                    462:        MD5_CTX md5;
                    463:        int i;
                    464: 
                    465:        /* Types can only be 0..(2^16)-1. */
                    466:        if (type < 0 || type > 65535)
                    467:                return 0;
                    468: 
                    469:        /* Hexadecimal MD5 digest plus two byte type and NUL. */
                    470:        if (!buffer_allocate (&id -> buffer,
                    471:                              (MD5_DIGEST_LENGTH * 2) + 3, MDL))
                    472:                return 0;
                    473:        id -> data = id -> buffer -> data;
                    474: 
                    475:        /*
                    476:         * DHCP clients and servers should use the following forms of client
                    477:         * identification, starting with the most preferable, and finishing
                    478:         * with the least preferable.  If the client does not send any of these
                    479:         * forms of identification, the DHCP/DDNS interaction is not defined by
                    480:         * this specification.  The most preferable form of identification is
                    481:         * the Globally Unique Identifier Option [TBD].  Next is the DHCP
                    482:         * Client Identifier option.  Last is the client's link-layer address,
                    483:         * as conveyed in its DHCPREQUEST message.  Implementors should note
                    484:         * that the link-layer address cannot be used if there are no
                    485:         * significant bytes in the chaddr field of the DHCP client's request,
                    486:         * because this does not constitute a unique identifier.
                    487:         *   -- "Interaction between DHCP and DNS"
                    488:         *      <draft-ietf-dhc-dhcp-dns-12.txt>
                    489:         *      M. Stapp, Y. Rekhter
                    490:         */
                    491: 
                    492:        /* Put the type in the first two bytes. */
                    493:        id->buffer->data[0] = "0123456789abcdef"[(type >> 4) & 0xf];
                    494:        /* This should have been [type & 0xf] but now that
                    495:         * it is in use we need to leave it this way in order
                    496:         * to avoid disturbing customer's lease files
                    497:         */
                    498:        id -> buffer -> data [1] = "0123456789abcdef" [type % 15];
                    499: 
                    500:        /* Mash together an MD5 hash of the identifier. */
                    501:        MD5_Init (&md5);
                    502:        MD5_Update (&md5, data, len);
                    503:        MD5_Final (buf, &md5);
                    504: 
                    505:        /* Convert into ASCII. */
                    506:        for (i = 0; i < MD5_DIGEST_LENGTH; i++) {
                    507:                id -> buffer -> data [i * 2 + 2] =
                    508:                        "0123456789abcdef" [(buf [i] >> 4) & 0xf];
                    509:                id -> buffer -> data [i * 2 + 3] =
                    510:                        "0123456789abcdef" [buf [i] & 0xf];
                    511:        }
                    512:        id -> len = MD5_DIGEST_LENGTH * 2 + 2;
                    513:        id -> buffer -> data [id -> len] = 0;
                    514:        id -> terminated = 1;
                    515: 
                    516:        return 1;
                    517: }
                    518: 
                    519: /* Now for the DDNS update code that is shared between client and
                    520:    server... */
                    521: 
                    522: isc_result_t
                    523: ddns_update_fwd(struct data_string *ddns_fwd_name, struct iaddr ddns_addr,
                    524:                struct data_string *ddns_dhcid, unsigned long ttl,
                    525:                unsigned rrsetp, unsigned conflict) {
                    526:        ns_updque updqueue;
                    527:        ns_updrec *updrec;
                    528:        isc_result_t result;
                    529:        const char *logstr;
                    530:        char ddns_address[
                    531:                sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
                    532:        int ddns_address_type;
                    533: 
                    534:        /* 
                    535:         * We want to delete either A or AAAA records, depending on
                    536:         * whether we have an IPv4 or an IPv6 address.
                    537:         */
                    538:        if (ddns_addr.len == 4) {
                    539:                ddns_address_type = T_A;
                    540:        } else if (ddns_addr.len == 16) {
                    541:                ddns_address_type = T_AAAA;
                    542:        } else {
                    543:                return ISC_R_INVALIDARG;
                    544:        }
                    545:        strcpy(ddns_address, piaddr(ddns_addr));
                    546: 
                    547:        /*
                    548:         * When a DHCP client or server intends to update an A RR, it first
                    549:         * prepares a DNS UPDATE query which includes as a prerequisite the
                    550:         * assertion that the name does not exist.  The update section of the
                    551:         * query attempts to add the new name and its IP address mapping (an A
                    552:         * RR), and the DHCID RR with its unique client-identity.
                    553:         *   -- "Interaction between DHCP and DNS"
                    554:         */
                    555: 
                    556:        ISC_LIST_INIT (updqueue);
                    557: 
                    558:        /*
                    559:         * A RR does not exist.
                    560:         */
                    561:        updrec = minires_mkupdrec (S_PREREQ,
                    562:                                   (const char *)ddns_fwd_name -> data,
                    563:                                   C_IN, ddns_address_type, 0);
                    564:        if (!updrec) {
                    565:                result = ISC_R_NOMEMORY;
                    566:                goto error;
                    567:        }
                    568: 
                    569:        updrec -> r_data = (unsigned char *)0;
                    570:        updrec -> r_size = 0;
                    571:        updrec -> r_opcode = rrsetp ? NXRRSET : NXDOMAIN;
                    572: 
                    573:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    574: 
                    575: 
                    576:        /*
                    577:         * Add A RR.
                    578:         */
                    579:        updrec = minires_mkupdrec (S_UPDATE,
                    580:                                   (const char *)ddns_fwd_name -> data,
                    581:                                   C_IN, ddns_address_type, ttl);
                    582:        if (!updrec) {
                    583:                result = ISC_R_NOMEMORY;
                    584:                goto error;
                    585:        }
                    586: 
                    587:        updrec -> r_data = (unsigned char *)ddns_address;
                    588:        updrec -> r_size = strlen (ddns_address);
                    589:        updrec -> r_opcode = ADD;
                    590: 
                    591:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    592: 
                    593: 
                    594:        /*
                    595:         * Add DHCID RR.
                    596:         */
                    597:        updrec = minires_mkupdrec (S_UPDATE,
                    598:                                   (const char *)ddns_fwd_name -> data,
                    599:                                   C_IN, T_DHCID, ttl);
                    600:        if (!updrec) {
                    601:                result = ISC_R_NOMEMORY;
                    602:                goto error;
                    603:        }
                    604: 
                    605:        updrec -> r_data = ddns_dhcid -> data;
                    606:        updrec -> r_size = ddns_dhcid -> len;
                    607:        updrec -> r_opcode = ADD;
                    608: 
                    609:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    610: 
                    611: 
                    612:        /*
                    613:         * Attempt to perform the update.
                    614:         */
                    615:        result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
                    616: 
                    617: #ifdef DEBUG_DNS_UPDATES
                    618:        print_dns_status ((int)result, &updqueue);
                    619: #endif
                    620: 
                    621:        /*
                    622:         * If this update operation succeeds, the updater can conclude that it
                    623:         * has added a new name whose only RRs are the A and DHCID RR records.
                    624:         * The A RR update is now complete (and a client updater is finished,
                    625:         * while a server might proceed to perform a PTR RR update).
                    626:         *   -- "Interaction between DHCP and DNS"
                    627:         */
                    628: 
                    629:        if (result == ISC_R_SUCCESS) {
                    630:                log_info ("Added new forward map from %.*s to %s",
                    631:                          (int)ddns_fwd_name -> len,
                    632:                          (const char *)ddns_fwd_name -> data, ddns_address);
                    633:                goto error;
                    634:        }
                    635: 
                    636: 
                    637:        /*
                    638:         * If the first update operation fails with YXDOMAIN, the updater can
                    639:         * conclude that the intended name is in use.  The updater then
                    640:         * attempts to confirm that the DNS name is not being used by some
                    641:         * other host. The updater prepares a second UPDATE query in which the
                    642:         * prerequisite is that the desired name has attached to it a DHCID RR
                    643:         * whose contents match the client identity.  The update section of
                    644:         * this query deletes the existing A records on the name, and adds the
                    645:         * A record that matches the DHCP binding and the DHCID RR with the
                    646:         * client identity.
                    647:         *   -- "Interaction between DHCP and DNS"
                    648:         */
                    649: 
                    650:        if (result != (rrsetp ? ISC_R_YXRRSET : ISC_R_YXDOMAIN)) {
                    651:                log_error ("Unable to add forward map from %.*s to %s: %s",
                    652:                           (int)ddns_fwd_name -> len,
                    653:                           (const char *)ddns_fwd_name -> data, ddns_address,
                    654:                           isc_result_totext (result));
                    655:                goto error;
                    656:        }
                    657: 
                    658:        while (!ISC_LIST_EMPTY (updqueue)) {
                    659:                updrec = ISC_LIST_HEAD (updqueue);
                    660:                ISC_LIST_UNLINK (updqueue, updrec, r_link);
                    661:                minires_freeupdrec (updrec);
                    662:        }
                    663: 
                    664:        /* If we're doing conflict resolution, we use a set of prereqs.  If
                    665:         * not, we delete the DHCID in addition to all A rrsets.
                    666:         */
                    667:        if (conflict) {
                    668:                /*
                    669:                 * DHCID RR exists, and matches client identity.
                    670:                 */
                    671:                updrec = minires_mkupdrec (S_PREREQ,
                    672:                                           (const char *)ddns_fwd_name -> data,
                    673:                                           C_IN, T_DHCID, 0);
                    674:                if (!updrec) {
                    675:                        result = ISC_R_NOMEMORY;
                    676:                        goto error;
                    677:                }
                    678:        
                    679:                updrec -> r_data = ddns_dhcid -> data;
                    680:                updrec -> r_size = ddns_dhcid -> len;
                    681:                updrec -> r_opcode = YXRRSET;
                    682: 
                    683:                ISC_LIST_APPEND (updqueue, updrec, r_link);
                    684:        } else {
                    685:                /*
                    686:                 * Conflict detection override: delete DHCID RRs.
                    687:                 */
                    688:                updrec = minires_mkupdrec(S_UPDATE, 
                    689:                                          (const char *)ddns_fwd_name->data,
                    690:                                          C_IN, T_DHCID, 0);
                    691: 
                    692:                if (!updrec) {
                    693:                        result = ISC_R_NOMEMORY;
                    694:                        goto error;
                    695:                }
                    696: 
                    697:                updrec->r_data = NULL;
                    698:                updrec->r_size = 0;
                    699:                updrec->r_opcode = DELETE;
                    700: 
                    701:                ISC_LIST_APPEND(updqueue, updrec, r_link);
                    702: 
                    703: 
                    704:                /*
                    705:                 * With all other DHCID RR's deleted, add this client's
                    706:                 * DHCID unconditionally (as update-conflict-detection is
                    707:                 * disabled).
                    708:                 */
                    709:                updrec = minires_mkupdrec(S_UPDATE,
                    710:                                          (const char *)ddns_fwd_name->data,
                    711:                                          C_IN, T_DHCID, ttl);
                    712:                if (!updrec) {
                    713:                        result = ISC_R_NOMEMORY;
                    714:                        goto error;
                    715:                }
                    716:  
                    717:                updrec->r_data = ddns_dhcid->data;
                    718:                updrec->r_size = ddns_dhcid->len;
                    719:                updrec->r_opcode = ADD;
                    720:  
                    721:                ISC_LIST_APPEND (updqueue, updrec, r_link);
                    722:        }
                    723: 
                    724: 
                    725:        /*
                    726:         * Delete A RRset.
                    727:         */
                    728:        updrec = minires_mkupdrec (S_UPDATE,
                    729:                                   (const char *)ddns_fwd_name -> data,
                    730:                                   C_IN, ddns_address_type, 0);
                    731:        if (!updrec) {
                    732:                result = ISC_R_NOMEMORY;
                    733:                goto error;
                    734:        }
                    735: 
                    736:        updrec -> r_data = (unsigned char *)0;
                    737:        updrec -> r_size = 0;
                    738:        updrec -> r_opcode = DELETE;
                    739: 
                    740:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    741: 
                    742: 
                    743:        /*
                    744:         * Add A RR.
                    745:         */
                    746:        updrec = minires_mkupdrec (S_UPDATE,
                    747:                                   (const char *)ddns_fwd_name -> data,
                    748:                                   C_IN, ddns_address_type, ttl);
                    749:        if (!updrec) {
                    750:                result = ISC_R_NOMEMORY;
                    751:                goto error;
                    752:        }
                    753: 
                    754:        updrec -> r_data = (unsigned char *)ddns_address;
                    755:        updrec -> r_size = strlen (ddns_address);
                    756:        updrec -> r_opcode = ADD;
                    757: 
                    758:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    759: 
                    760: 
                    761:        /*
                    762:         * Attempt to perform the update.
                    763:         */
                    764:        result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
                    765: 
                    766:        switch (result) {
                    767:            case ISC_R_SUCCESS:
                    768:                logstr = NULL;
                    769:                break;
                    770: 
                    771:            case ISC_R_YXRRSET:
                    772:            case ISC_R_YXDOMAIN:
                    773:                logstr = "DHCID mismatch, belongs to another client.";
                    774:                break;
                    775: 
                    776:            case ISC_R_NXRRSET:
                    777:            case ISC_R_NXDOMAIN:
                    778:                logstr = "Has an address record but no DHCID, not mine.";
                    779:                break;
                    780: 
                    781:            default:
                    782:                logstr = isc_result_totext(result);
                    783:                break;
                    784:        }
                    785: 
                    786:        if (logstr != NULL)
                    787:                log_error("Forward map from %.*s to %s FAILED: %s",
                    788:                                   (int)ddns_fwd_name -> len,
                    789:                                   (const char *)ddns_fwd_name -> data,
                    790:                                   ddns_address, logstr);
                    791:        else
                    792:                log_info("Added new forward map from %.*s to %s",
                    793:                          (int)ddns_fwd_name -> len,
                    794:                          (const char *)ddns_fwd_name -> data, ddns_address);
                    795: 
                    796: #if defined (DEBUG_DNS_UPDATES)
                    797:        print_dns_status ((int)result, &updqueue);
                    798: #endif
                    799: 
                    800:        /*
                    801:         * If this query succeeds, the updater can conclude that the current
                    802:         * client was the last client associated with the domain name, and that
                    803:         * the name now contains the updated A RR. The A RR update is now
                    804:         * complete (and a client updater is finished, while a server would
                    805:         * then proceed to perform a PTR RR update).
                    806:         *   -- "Interaction between DHCP and DNS"
                    807:         */
                    808: 
                    809:        /*
                    810:         * If the second query fails with NXRRSET, the updater must conclude
                    811:         * that the client's desired name is in use by another host.  At this
                    812:         * juncture, the updater can decide (based on some administrative
                    813:         * configuration outside of the scope of this document) whether to let
                    814:         * the existing owner of the name keep that name, and to (possibly)
                    815:         * perform some name disambiguation operation on behalf of the current
                    816:         * client, or to replace the RRs on the name with RRs that represent
                    817:         * the current client. If the configured policy allows replacement of
                    818:         * existing records, the updater submits a query that deletes the
                    819:         * existing A RR and the existing DHCID RR, adding A and DHCID RRs that
                    820:         * represent the IP address and client-identity of the new client.
                    821:         *   -- "Interaction between DHCP and DNS"
                    822:         */
                    823: 
                    824:   error:
                    825:        while (!ISC_LIST_EMPTY (updqueue)) {
                    826:                updrec = ISC_LIST_HEAD (updqueue);
                    827:                ISC_LIST_UNLINK (updqueue, updrec, r_link);
                    828:                minires_freeupdrec (updrec);
                    829:        }
                    830: 
                    831:        return result;
                    832: }
                    833: 
                    834: isc_result_t
                    835: ddns_remove_fwd(struct data_string *ddns_fwd_name,
                    836:                struct iaddr ddns_addr, 
                    837:                struct data_string *ddns_dhcid) {
                    838:        ns_updque updqueue;
                    839:        ns_updrec *updrec;
                    840:        isc_result_t result = SERVFAIL;
                    841:        char ddns_address[
                    842:                sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
                    843:        int ddns_address_type;
                    844: 
                    845:        /* 
                    846:         * We want to delete either A or AAAA records, depending on
                    847:         * whether we have an IPv4 or an IPv6 address.
                    848:         */
                    849:        if (ddns_addr.len == 4) {
                    850:                ddns_address_type = T_A;
                    851:        } else if (ddns_addr.len == 16) {
                    852:                ddns_address_type = T_AAAA;
                    853:        } else {
                    854:                return ISC_R_INVALIDARG;
                    855:        }
                    856:        strcpy(ddns_address, piaddr(ddns_addr));
                    857: 
                    858:        /*
                    859:         * The entity chosen to handle the A record for this client (either the
                    860:         * client or the server) SHOULD delete the A record that was added when
                    861:         * the lease was made to the client.
                    862:         *
                    863:         * In order to perform this delete, the updater prepares an UPDATE
                    864:         * query which contains two prerequisites.  The first prerequisite
                    865:         * asserts that the DHCID RR exists whose data is the client identity
                    866:         * described in Section 4.3. The second prerequisite asserts that the
                    867:         * data in the A RR contains the IP address of the lease that has
                    868:         * expired or been released.
                    869:         *   -- "Interaction between DHCP and DNS"
                    870:         */
                    871: 
                    872:        ISC_LIST_INIT (updqueue);
                    873: 
                    874:        /*
                    875:         * DHCID RR exists, and matches client identity.
                    876:         */
                    877:        updrec = minires_mkupdrec (S_PREREQ,
                    878:                                   (const char *)ddns_fwd_name -> data,
                    879:                                   C_IN, T_DHCID,0);
                    880:        if (!updrec) {
                    881:                result = ISC_R_NOMEMORY;
                    882:                goto error;
                    883:        }
                    884: 
                    885:        updrec -> r_data = ddns_dhcid -> data;
                    886:        updrec -> r_size = ddns_dhcid -> len;
                    887:        updrec -> r_opcode = YXRRSET;
                    888: 
                    889:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    890: 
                    891: 
                    892:        /*
                    893:         * Address RR (A/AAAA) matches the expiring lease.
                    894:         */
                    895:        updrec = minires_mkupdrec (S_PREREQ,
                    896:                                   (const char *)ddns_fwd_name -> data,
                    897:                                   C_IN, ddns_address_type, 0);
                    898:        if (!updrec) {
                    899:                result = ISC_R_NOMEMORY;
                    900:                goto error;
                    901:        }
                    902: 
                    903:        updrec -> r_data = (unsigned char *)ddns_address;
                    904:        updrec -> r_size = strlen (ddns_address);
                    905:        updrec -> r_opcode = YXRRSET;
                    906: 
                    907:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    908: 
                    909: 
                    910:        /*
                    911:         * Delete appropriate Address RR (A/AAAA).
                    912:         */
                    913:        updrec = minires_mkupdrec (S_UPDATE,
                    914:                                   (const char *)ddns_fwd_name -> data,
                    915:                                   C_IN, ddns_address_type, 0);
                    916:        if (!updrec) {
                    917:                result = ISC_R_NOMEMORY;
                    918:                goto error;
                    919:        }
                    920: 
                    921:        updrec -> r_data = (unsigned char *)ddns_address;
                    922:        updrec -> r_size = strlen (ddns_address);
                    923:        updrec -> r_opcode = DELETE;
                    924: 
                    925:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    926: 
                    927:        /*
                    928:         * Attempt to perform the update.
                    929:         */
                    930:        result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
                    931:        print_dns_status ((int)result, &updqueue);
                    932: 
                    933:        /*
                    934:         * If the query fails, the updater MUST NOT delete the DNS name.  It
                    935:         * may be that the host whose lease on the server has expired has moved
                    936:         * to another network and obtained a lease from a different server,
                    937:         * which has caused the client's A RR to be replaced. It may also be
                    938:         * that some other client has been configured with a name that matches
                    939:         * the name of the DHCP client, and the policy was that the last client
                    940:         * to specify the name would get the name.  In this case, the DHCID RR
                    941:         * will no longer match the updater's notion of the client-identity of
                    942:         * the host pointed to by the DNS name.
                    943:         *   -- "Interaction between DHCP and DNS"
                    944:         */
                    945: 
                    946:        if (result != ISC_R_SUCCESS) {
                    947:                /* If the rrset isn't there, we didn't need to do the
                    948:                   delete, which is success. */
                    949:                if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN)
                    950:                        result = ISC_R_SUCCESS; 
                    951:                goto error;
                    952:        }
                    953: 
                    954:        while (!ISC_LIST_EMPTY (updqueue)) {
                    955:                updrec = ISC_LIST_HEAD (updqueue);
                    956:                ISC_LIST_UNLINK (updqueue, updrec, r_link);
                    957:                minires_freeupdrec (updrec);
                    958:        }
                    959: 
                    960:        /*
                    961:         * If the deletion of the desired address succeeded (its A or AAAA
                    962:         * RR was removed above), and there are zero other A or AAAA records
                    963:         * left for this domain, then we can delete the DHCID record as well.
                    964:         * We can't delete the DHCID record above because it's possible the
                    965:         * client has more than one valid address added to this domain name,
                    966:         * by this or other DHCP servers.
                    967:         *
                    968:         * Essentially, this final update is a cleanup operation that is only
                    969:         * intended to succeed after the last address has been removed from
                    970:         * DNS (which is only expected to happen after the client is not
                    971:         * reasonably in possession of those addresses).
                    972:         */
                    973:        ISC_LIST_INIT (updqueue);
                    974: 
                    975:        /*
                    976:         * A RR does not exist.
                    977:         */
                    978:        updrec = minires_mkupdrec(S_PREREQ, (const char *)ddns_fwd_name->data,
                    979:                                  C_IN, T_A, 0);
                    980:        if (updrec == NULL) {
                    981:                result = ISC_R_NOMEMORY;
                    982:                goto error;
                    983:        }
                    984: 
                    985:        updrec->r_data = NULL;
                    986:        updrec->r_size = 0;
                    987:        updrec->r_opcode = NXRRSET;
                    988: 
                    989:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    990: 
                    991:        /*
                    992:         * AAAA RR does not exist.
                    993:         */
                    994:        updrec = minires_mkupdrec(S_PREREQ, (const char *)ddns_fwd_name->data,
                    995:                                  C_IN, T_AAAA, 0);
                    996: 
                    997:        if (updrec == NULL) {
                    998:                result = ISC_R_NOMEMORY;
                    999:                goto error;
                   1000:        }
                   1001: 
                   1002:        updrec->r_data = NULL;
                   1003:        updrec->r_size = 0;
                   1004:        updrec->r_opcode = NXRRSET;
                   1005: 
                   1006:        ISC_LIST_APPEND(updqueue, updrec, r_link);
                   1007: 
                   1008:        /*
                   1009:         * Delete appropriate DHCID RR.
                   1010:         */
                   1011:        updrec = minires_mkupdrec (S_UPDATE,
                   1012:                                  (const char *)ddns_fwd_name -> data,
                   1013:                                   C_IN, T_DHCID, 0);
                   1014:        if (!updrec) {
                   1015:                result = ISC_R_NOMEMORY;
                   1016:                goto error;
                   1017:        }
                   1018: 
                   1019:        updrec -> r_data = ddns_dhcid -> data;
                   1020:        updrec -> r_size = ddns_dhcid -> len;
                   1021:        updrec -> r_opcode = DELETE;
                   1022: 
                   1023:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                   1024: 
                   1025:        /*
                   1026:         * Attempt to perform the update.
                   1027:         */
                   1028:        result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
                   1029:        print_dns_status ((int)result, &updqueue);
                   1030: 
                   1031:        /* Fall through. */
                   1032:   error:
                   1033: 
                   1034:        while (!ISC_LIST_EMPTY (updqueue)) {
                   1035:                updrec = ISC_LIST_HEAD (updqueue);
                   1036:                ISC_LIST_UNLINK (updqueue, updrec, r_link);
                   1037:                minires_freeupdrec (updrec);
                   1038:        }
                   1039: 
                   1040:        return result;
                   1041: }
                   1042: 
                   1043: 
                   1044: #endif /* NSUPDATE */
                   1045: 
                   1046: HASH_FUNCTIONS (dns_zone, const char *, struct dns_zone, dns_zone_hash_t,
                   1047:                dns_zone_reference, dns_zone_dereference, do_case_hash)

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