Annotation of embedaddon/dhcp/server/ddns.c, revision 1.1.1.1

1.1       misho       1: /* ddns.c
                      2: 
                      3:    Dynamic DNS updates. */
                      4: 
                      5: /*
                      6:  * Copyright (c) 2004-2007,2009-2010 by
                      7:  *                                 Internet Systems Consortium, Inc. ("ISC")
                      8:  * Copyright (c) 2000-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 donated to Internet Systems Consortium
                     29:  * by Damien Neil of Nominum, Inc.
                     30:  *
                     31:  * To learn more about Internet Systems Consortium, see
                     32:  * ``https://www.isc.org/''.   To learn more about Nominum, Inc., see
                     33:  * ``http://www.nominum.com''.
                     34:  */
                     35: 
                     36: #include "dhcpd.h"
                     37: #include "dst/md5.h"
                     38: #include "minires/minires.h"
                     39: 
                     40: #ifdef NSUPDATE
                     41: 
                     42: /* DN: No way of checking that there is enough space in a data_string's
                     43:    buffer.  Be certain to allocate enough!
                     44:    TL: This is why the expression evaluation code allocates a *new*
                     45:    data_string.   :') */
                     46: static void data_string_append (struct data_string *ds1,
                     47:                                struct data_string *ds2)
                     48: {
                     49:        memcpy (ds1 -> buffer -> data + ds1 -> len,
                     50:                ds2 -> data,
                     51:                ds2 -> len);
                     52:        ds1 -> len += ds2 -> len;
                     53: }
                     54: 
                     55: static isc_result_t ddns_update_ptr (struct data_string *ddns_fwd_name,
                     56:                                     struct data_string *ddns_rev_name,
                     57:                                     unsigned long ttl)
                     58: {
                     59:        ns_updque updqueue;
                     60:        ns_updrec *updrec;
                     61:        isc_result_t result = ISC_R_UNEXPECTED;
                     62: 
                     63:        /*
                     64:         * The DHCP server submits a DNS query which deletes all of the PTR RRs
                     65:         * associated with the lease IP address, and adds a PTR RR whose data
                     66:         * is the client's (possibly disambiguated) host name. The server also
                     67:         * adds a DHCID RR specified in Section 4.3.
                     68:         *   -- "Interaction between DHCP and DNS"
                     69:         */
                     70: 
                     71:        ISC_LIST_INIT (updqueue);
                     72: 
                     73:        /*
                     74:         * Delete all PTR RRs.
                     75:         */
                     76:        updrec = minires_mkupdrec (S_UPDATE,
                     77:                                   (const char *)ddns_rev_name -> data,
                     78:                                   C_IN, T_PTR, 0);
                     79:        if (!updrec) {
                     80:                result = ISC_R_NOMEMORY;
                     81:                goto error;
                     82:        }
                     83: 
                     84:        updrec -> r_data = (unsigned char *)0;
                     85:        updrec -> r_size = 0;
                     86:        updrec -> r_opcode = DELETE;
                     87: 
                     88:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                     89: 
                     90:        /*
                     91:         * Add PTR RR.
                     92:         */
                     93:        updrec = minires_mkupdrec (S_UPDATE,
                     94:                                   (const char *)ddns_rev_name -> data,
                     95:                                   C_IN, T_PTR, ttl);
                     96:        if (!updrec) {
                     97:                result = ISC_R_NOMEMORY;
                     98:                goto error;
                     99:        }
                    100: 
                    101:        updrec -> r_data = ddns_fwd_name -> data;
                    102:        updrec -> r_size = ddns_fwd_name -> len;
                    103:        updrec -> r_opcode = ADD;
                    104: 
                    105:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    106: 
                    107:        /*
                    108:         * Attempt to perform the update.
                    109:         */
                    110:        result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
                    111: #if defined (DEBUG)
                    112:        print_dns_status ((int)result, &updqueue);
                    113: #endif
                    114:        if (result == ISC_R_SUCCESS) {
                    115:                log_info ("added reverse map from %.*s to %.*s",
                    116:                          (int)ddns_rev_name -> len,
                    117:                          (const char *)ddns_rev_name -> data,
                    118:                          (int)ddns_fwd_name -> len,
                    119:                          (const char *)ddns_fwd_name -> data);
                    120:        } else {
                    121:                log_error ("unable to add reverse map from %.*s to %.*s: %s",
                    122:                           (int)ddns_rev_name -> len,
                    123:                           (const char *)ddns_rev_name -> data,
                    124:                           (int)ddns_fwd_name -> len,
                    125:                           (const char *)ddns_fwd_name -> data,
                    126:                           isc_result_totext (result));
                    127:        }
                    128: 
                    129:        /* Fall through. */
                    130:       error:
                    131: 
                    132:        while (!ISC_LIST_EMPTY (updqueue)) {
                    133:                updrec = ISC_LIST_HEAD (updqueue);
                    134:                ISC_LIST_UNLINK (updqueue, updrec, r_link);
                    135:                minires_freeupdrec (updrec);
                    136:        }
                    137: 
                    138:        return result;
                    139: }
                    140: 
                    141: 
                    142: static isc_result_t ddns_remove_ptr (struct data_string *ddns_rev_name)
                    143: {
                    144:        ns_updque updqueue;
                    145:        ns_updrec *updrec;
                    146:        isc_result_t result;
                    147: 
                    148:        /*
                    149:         * When a lease expires or a DHCP client issues a DHCPRELEASE request,
                    150:         * the DHCP server SHOULD delete the PTR RR that matches the DHCP
                    151:         * binding, if one was successfully added. The server's update query
                    152:         * SHOULD assert that the name in the PTR record matches the name of
                    153:         * the client whose lease has expired or been released.
                    154:         *   -- "Interaction between DHCP and DNS"
                    155:         */
                    156: 
                    157:        ISC_LIST_INIT (updqueue);
                    158: 
                    159:        /*
                    160:         * Delete the PTR RRset for the leased address.
                    161:         */
                    162:        updrec = minires_mkupdrec (S_UPDATE,
                    163:                                   (const char *)ddns_rev_name -> data,
                    164:                                   C_IN, T_PTR, 0);
                    165:        if (!updrec) {
                    166:                result = ISC_R_NOMEMORY;
                    167:                goto error;
                    168:        }
                    169: 
                    170:        updrec -> r_data = (unsigned char *)0;
                    171:        updrec -> r_size = 0;
                    172:        updrec -> r_opcode = DELETE;
                    173: 
                    174:        ISC_LIST_APPEND (updqueue, updrec, r_link);
                    175: 
                    176:        /*
                    177:         * Attempt to perform the update.
                    178:         */
                    179:        result = minires_nupdate (&resolver_state, ISC_LIST_HEAD (updqueue));
                    180: #if defined (DEBUG)
                    181:        print_dns_status ((int)result, &updqueue);
                    182: #endif
                    183:        if (result == ISC_R_SUCCESS) {
                    184:                log_info ("removed reverse map on %.*s",
                    185:                          (int)ddns_rev_name -> len,
                    186:                          (const char *)ddns_rev_name -> data);
                    187:        } else {
                    188:                if (result != ISC_R_NXRRSET && result != ISC_R_NXDOMAIN)
                    189:                        log_error ("can't remove reverse map on %.*s: %s",
                    190:                                   (int)ddns_rev_name -> len,
                    191:                                   (const char *)ddns_rev_name -> data,
                    192:                                   isc_result_totext (result));
                    193:        }
                    194: 
                    195:        /* Not there is success. */
                    196:        if (result == ISC_R_NXRRSET || result == ISC_R_NXDOMAIN)
                    197:                result = ISC_R_SUCCESS;
                    198: 
                    199:        /* Fall through. */
                    200:       error:
                    201: 
                    202:        while (!ISC_LIST_EMPTY (updqueue)) {
                    203:                updrec = ISC_LIST_HEAD (updqueue);
                    204:                ISC_LIST_UNLINK (updqueue, updrec, r_link);
                    205:                minires_freeupdrec (updrec);
                    206:        }
                    207: 
                    208:        return result;
                    209: }
                    210: 
                    211: 
                    212: /* Determine what, if any, forward and reverse updates need to be
                    213:  * performed, and carry them through.
                    214:  */
                    215: int
                    216: ddns_updates(struct packet *packet, struct lease *lease, struct lease *old,
                    217:             struct iasubopt *lease6, struct iasubopt *old6,
                    218:             struct option_state *options)
                    219: {
                    220:        unsigned long ddns_ttl = DEFAULT_DDNS_TTL;
                    221:        struct data_string ddns_hostname;
                    222:        struct data_string ddns_domainname;
                    223:        struct data_string old_ddns_fwd_name;
                    224:        struct data_string ddns_fwd_name;
                    225:        struct data_string ddns_rev_name;
                    226:        struct data_string ddns_dhcid;
                    227:        struct binding_scope **scope;
                    228:        struct iaddr addr;
                    229:        struct data_string d1;
                    230:        struct option_cache *oc;
                    231:        int s1, s2;
                    232:        int result = 0;
                    233:        isc_result_t rcode1 = ISC_R_SUCCESS, rcode2 = ISC_R_SUCCESS;
                    234:        int server_updates_a = 1;
                    235:        int server_updates_ptr = 1;
                    236:        struct buffer *bp = (struct buffer *)0;
                    237:        int ignorep = 0, client_ignorep = 0;
                    238:        int rev_name_len;
                    239:        int i;
                    240: 
                    241:        if (ddns_update_style != 2)
                    242:                return 0;
                    243: 
                    244:        if (lease != NULL) {
                    245:                scope = &(lease->scope);
                    246:                addr = lease->ip_addr;
                    247:        } else if (lease6 != NULL) {
                    248:                scope = &(lease6->scope);
                    249:                memcpy(addr.iabuf, lease6->addr.s6_addr, 16);
                    250:                addr.len = 16;
                    251:        } else {
                    252:                log_fatal("Impossible condition at %s:%d.", MDL);
                    253:                /* Silence compiler warnings. */
                    254:                return 0;
                    255:        }
                    256: 
                    257:        memset(&d1, 0, sizeof(d1));
                    258:        memset (&ddns_hostname, 0, sizeof (ddns_hostname));
                    259:        memset (&ddns_domainname, 0, sizeof (ddns_domainname));
                    260:        memset (&old_ddns_fwd_name, 0, sizeof (ddns_fwd_name));
                    261:        memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
                    262:        memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
                    263:        memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
                    264: 
                    265:        /* If we are allowed to accept the client's update of its own A
                    266:           record, see if the client wants to update its own A record. */
                    267:        if (!(oc = lookup_option(&server_universe, options,
                    268:                                 SV_CLIENT_UPDATES)) ||
                    269:            evaluate_boolean_option_cache(&client_ignorep, packet, lease, NULL,
                    270:                                          packet->options, options, scope,
                    271:                                          oc, MDL)) {
                    272:                /* If there's no fqdn.no-client-update or if it's
                    273:                   nonzero, don't try to use the client-supplied
                    274:                   XXX */
                    275:                if (!(oc = lookup_option (&fqdn_universe, packet -> options,
                    276:                                          FQDN_SERVER_UPDATE)) ||
                    277:                    evaluate_boolean_option_cache(&ignorep, packet, lease,
                    278:                                                  NULL, packet->options,
                    279:                                                  options, scope, oc, MDL))
                    280:                        goto noclient;
                    281:                /* Win98 and Win2k will happily claim to be willing to
                    282:                   update an unqualified domain name. */
                    283:                if (!(oc = lookup_option (&fqdn_universe, packet -> options,
                    284:                                          FQDN_DOMAINNAME)))
                    285:                        goto noclient;
                    286:                if (!(oc = lookup_option (&fqdn_universe, packet -> options,
                    287:                                          FQDN_FQDN)) ||
                    288:                    !evaluate_option_cache(&ddns_fwd_name, packet, lease,
                    289:                                           NULL, packet->options,
                    290:                                           options, scope, oc, MDL))
                    291:                        goto noclient;
                    292:                server_updates_a = 0;
                    293:                goto client_updates;
                    294:        }
                    295:       noclient:
                    296:        /* If do-forward-updates is disabled, this basically means don't
                    297:           do an update unless the client is participating, so if we get
                    298:           here and do-forward-updates is disabled, we can stop. */
                    299:        if ((oc = lookup_option (&server_universe, options,
                    300:                                 SV_DO_FORWARD_UPDATES)) &&
                    301:            !evaluate_boolean_option_cache(&ignorep, packet, lease,
                    302:                                           NULL, packet->options,
                    303:                                           options, scope, oc, MDL)) {
                    304:                return 0;
                    305:        }
                    306: 
                    307:        /* If it's a static lease, then don't do the DNS update unless we're
                    308:           specifically configured to do so.   If the client asked to do its
                    309:           own update and we allowed that, we don't do this test. */
                    310:        /* XXX: note that we cannot detect static DHCPv6 leases. */
                    311:        if ((lease != NULL) && (lease->flags & STATIC_LEASE)) {
                    312:                if (!(oc = lookup_option(&server_universe, options,
                    313:                                         SV_UPDATE_STATIC_LEASES)) ||
                    314:                    !evaluate_boolean_option_cache(&ignorep, packet, lease,
                    315:                                                   NULL, packet->options,
                    316:                                                   options, scope, oc, MDL))
                    317:                        return 0;
                    318:        }
                    319: 
                    320:        /*
                    321:         * Compute the name for the A record.
                    322:         */
                    323:        oc = lookup_option(&server_universe, options, SV_DDNS_HOST_NAME);
                    324:        if (oc)
                    325:                s1 = evaluate_option_cache(&ddns_hostname, packet, lease,
                    326:                                           NULL, packet->options,
                    327:                                           options, scope, oc, MDL);
                    328:        else
                    329:                s1 = 0;
                    330: 
                    331:        oc = lookup_option(&server_universe, options, SV_DDNS_DOMAIN_NAME);
                    332:        if (oc)
                    333:                s2 = evaluate_option_cache(&ddns_domainname, packet, lease,
                    334:                                           NULL, packet->options,
                    335:                                           options, scope, oc, MDL);
                    336:        else
                    337:                s2 = 0;
                    338: 
                    339:        if (s1 && s2) {
                    340:                if (ddns_hostname.len + ddns_domainname.len > 253) {
                    341:                        log_error ("ddns_update: host.domain name too long");
                    342: 
                    343:                        goto out;
                    344:                }
                    345: 
                    346:                buffer_allocate (&ddns_fwd_name.buffer,
                    347:                                 ddns_hostname.len + ddns_domainname.len + 2,
                    348:                                 MDL);
                    349:                if (ddns_fwd_name.buffer) {
                    350:                        ddns_fwd_name.data = ddns_fwd_name.buffer -> data;
                    351:                        data_string_append (&ddns_fwd_name, &ddns_hostname);
                    352:                        ddns_fwd_name.buffer -> data [ddns_fwd_name.len] = '.';
                    353:                        ddns_fwd_name.len++;
                    354:                        data_string_append (&ddns_fwd_name, &ddns_domainname);
                    355:                        ddns_fwd_name.buffer -> data [ddns_fwd_name.len] ='\0';
                    356:                        ddns_fwd_name.terminated = 1;
                    357:                }
                    358:        }
                    359:       client_updates:
                    360: 
                    361:        /* See if there's a name already stored on the lease. */
                    362:        if (find_bound_string(&old_ddns_fwd_name, *scope, "ddns-fwd-name")) {
                    363:                /* If there is, see if it's different. */
                    364:                if (old_ddns_fwd_name.len != ddns_fwd_name.len ||
                    365:                    memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
                    366:                            old_ddns_fwd_name.len)) {
                    367:                        /* If the name is different, try to delete
                    368:                           the old A record. */
                    369:                        if (!ddns_removals(lease, lease6))
                    370:                                goto out;
                    371:                        /* If the delete succeeded, go install the new
                    372:                           record. */
                    373:                        goto in;
                    374:                }
                    375: 
                    376:                /* See if there's a DHCID on the lease, and if not
                    377:                 * then potentially look for 'on events' for ad-hoc ddns.
                    378:                 */
                    379:                if (!find_bound_string(&ddns_dhcid, *scope, "ddns-txt") &&
                    380:                    (old != NULL)) {
                    381:                        /* If there's no DHCID, the update was probably
                    382:                           done with the old-style ad-hoc DDNS updates.
                    383:                           So if the expiry and release events look like
                    384:                           they're the same, run them.   This should delete
                    385:                           the old DDNS data. */
                    386:                        if (old -> on_expiry == old -> on_release) {
                    387:                                execute_statements(NULL, NULL, lease, NULL,
                    388:                                                   NULL, NULL, scope,
                    389:                                                   old->on_expiry);
                    390:                                if (old -> on_expiry)
                    391:                                        executable_statement_dereference
                    392:                                                (&old -> on_expiry, MDL);
                    393:                                if (old -> on_release)
                    394:                                        executable_statement_dereference
                    395:                                                (&old -> on_release, MDL);
                    396:                                /* Now, install the DDNS data the new way. */
                    397:                                goto in;
                    398:                        }
                    399:                } else
                    400:                        data_string_forget(&ddns_dhcid, MDL);
                    401: 
                    402:                /* See if the administrator wants to do updates even
                    403:                   in cases where the update already appears to have been
                    404:                   done. */
                    405:                if (!(oc = lookup_option(&server_universe, options,
                    406:                                         SV_UPDATE_OPTIMIZATION)) ||
                    407:                    evaluate_boolean_option_cache(&ignorep, packet, lease,
                    408:                                                  NULL, packet->options,
                    409:                                                  options, scope, oc, MDL)) {
                    410:                        result = 1;
                    411:                        goto noerror;
                    412:                }
                    413:        /* If there's no "ddns-fwd-name" on the lease record, see if
                    414:         * there's a ddns-client-fqdn indicating a previous client
                    415:         * update (if it changes, we need to adjust the PTR).
                    416:         */
                    417:        } else if (find_bound_string(&old_ddns_fwd_name, *scope,
                    418:                                     "ddns-client-fqdn")) {
                    419:                /* If the name is not different, no need to update
                    420:                   the PTR record. */
                    421:                if (old_ddns_fwd_name.len == ddns_fwd_name.len &&
                    422:                    !memcmp (old_ddns_fwd_name.data, ddns_fwd_name.data,
                    423:                             old_ddns_fwd_name.len) &&
                    424:                    (!(oc = lookup_option(&server_universe, options,
                    425:                                          SV_UPDATE_OPTIMIZATION)) ||
                    426:                     evaluate_boolean_option_cache(&ignorep, packet, lease,
                    427:                                                   NULL, packet->options,
                    428:                                                   options, scope, oc, MDL))) {
                    429:                        goto noerror;
                    430:                }
                    431:        }
                    432:       in:
                    433:                
                    434:        /* If we don't have a name that the client has been assigned, we
                    435:           can just skip all this. */
                    436:        if (!ddns_fwd_name.len)
                    437:                goto out;
                    438: 
                    439:        if (ddns_fwd_name.len > 255) {
                    440:                log_error ("client provided fqdn: too long");
                    441:                goto out;
                    442:        }
                    443: 
                    444:        /*
                    445:         * Compute the RR TTL.
                    446:         */
                    447:        ddns_ttl = DEFAULT_DDNS_TTL;
                    448:        if ((oc = lookup_option(&server_universe, options, SV_DDNS_TTL))) {
                    449:                if (evaluate_option_cache(&d1, packet, lease, NULL,
                    450:                                          packet->options, options, scope,
                    451:                                          oc, MDL)) {
                    452:                        if (d1.len == sizeof (u_int32_t))
                    453:                                ddns_ttl = getULong (d1.data);
                    454:                        data_string_forget (&d1, MDL);
                    455:                }
                    456:        }
                    457: 
                    458:        /*
                    459:         * Compute the reverse IP name, starting with the domain name.
                    460:         */
                    461:        oc = lookup_option(&server_universe, options, SV_DDNS_REV_DOMAIN_NAME);
                    462:        if (oc)
                    463:                s1 = evaluate_option_cache(&d1, packet, lease, NULL,
                    464:                                           packet->options, options,
                    465:                                           scope, oc, MDL);
                    466:        else
                    467:                s1 = 0;
                    468: 
                    469:        /* 
                    470:         * Figure out the length of the part of the name that depends 
                    471:         * on the address.
                    472:         */
                    473:        if (addr.len == 4) {
                    474:                char buf[17];
                    475:                /* XXX: WOW this is gross. */
                    476:                rev_name_len = snprintf(buf, sizeof(buf), "%u.%u.%u.%u.",
                    477:                                        addr.iabuf[3] & 0xff,
                    478:                                        addr.iabuf[2] & 0xff,
                    479:                                        addr.iabuf[1] & 0xff,
                    480:                                        addr.iabuf[0] & 0xff) + 1;
                    481: 
                    482:                if (s1) {
                    483:                        rev_name_len += d1.len;
                    484: 
                    485:                        if (rev_name_len > 255) {
                    486:                                log_error("ddns_update: Calculated rev domain "
                    487:                                          "name too long.");
                    488:                                s1 = 0;
                    489:                                data_string_forget(&d1, MDL);
                    490:                        }
                    491:                }
                    492:        } else if (addr.len == 16) {
                    493:                /* 
                    494:                 * IPv6 reverse names are always the same length, with 
                    495:                 * 32 hex characters separated by dots.
                    496:                 */
                    497:                rev_name_len = sizeof("0.1.2.3.4.5.6.7."
                    498:                                      "8.9.a.b.c.d.e.f."
                    499:                                      "0.1.2.3.4.5.6.7."
                    500:                                      "8.9.a.b.c.d.e.f."
                    501:                                      "ip6.arpa.");
                    502: 
                    503:                /* Set s1 to make sure we gate into updates. */
                    504:                s1 = 1;
                    505:        } else {
                    506:                log_fatal("invalid address length %d", addr.len);
                    507:                /* Silence compiler warnings. */
                    508:                return 0;
                    509:        }
                    510: 
                    511:        /* See if we are configured NOT to do reverse ptr updates */
                    512:        if ((oc = lookup_option(&server_universe, options,
                    513:                                SV_DO_REVERSE_UPDATES)) &&
                    514:            !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
                    515:                                           packet->options, options,
                    516:                                           scope, oc, MDL)) {
                    517:                server_updates_ptr = 0;
                    518:        }
                    519: 
                    520:        if (s1) {
                    521:                buffer_allocate(&ddns_rev_name.buffer, rev_name_len, MDL);
                    522:                if (ddns_rev_name.buffer != NULL) {
                    523:                        ddns_rev_name.data = ddns_rev_name.buffer->data;
                    524: 
                    525:                        if (addr.len == 4) {
                    526:                                ddns_rev_name.len =
                    527:                                    sprintf((char *)ddns_rev_name.buffer->data,
                    528:                                            "%u.%u.%u.%u.", 
                    529:                                            addr.iabuf[3] & 0xff,
                    530:                                            addr.iabuf[2] & 0xff,
                    531:                                            addr.iabuf[1] & 0xff,
                    532:                                            addr.iabuf[0] & 0xff);
                    533: 
                    534:                                /*
                    535:                                 * d1.data may be opaque, garbage bytes, from
                    536:                                 * user (mis)configuration.
                    537:                                 */
                    538:                                data_string_append(&ddns_rev_name, &d1);
                    539:                                ddns_rev_name.buffer->data[ddns_rev_name.len] =
                    540:                                        '\0';
                    541:                        } else if (addr.len == 16) {
                    542:                                char *p = (char *)&ddns_rev_name.buffer->data;
                    543:                                unsigned char *a = addr.iabuf + 15;
                    544:                                for (i=0; i<16; i++) {
                    545:                                        sprintf(p, "%x.%x.", 
                    546:                                                (*a & 0xF), ((*a >> 4) & 0xF));
                    547:                                        p += 4;
                    548:                                        a -= 1;
                    549:                                }
                    550:                                strcat(p, "ip6.arpa.");
                    551:                                ddns_rev_name.len =
                    552:                                    strlen((const char *)ddns_rev_name.data);
                    553:                        }
                    554: 
                    555:                        ddns_rev_name.terminated = 1;
                    556:                }
                    557: 
                    558:                if (d1.data != NULL)
                    559:                        data_string_forget(&d1, MDL);
                    560:        }
                    561: 
                    562:        /*
                    563:         * If we are updating the A record, compute the DHCID value.
                    564:         */
                    565:        if (server_updates_a) {
                    566:                memset (&ddns_dhcid, 0, sizeof ddns_dhcid);
                    567:                if (lease6 != NULL)
                    568:                        result = get_dhcid(&ddns_dhcid, 2,
                    569:                                           lease6->ia->iaid_duid.data,
                    570:                                           lease6->ia->iaid_duid.len);
                    571:                else if ((lease != NULL) && (lease->uid != NULL) &&
                    572:                         (lease->uid_len != 0))
                    573:                        result = get_dhcid (&ddns_dhcid,
                    574:                                            DHO_DHCP_CLIENT_IDENTIFIER,
                    575:                                            lease -> uid, lease -> uid_len);
                    576:                else if (lease != NULL)
                    577:                        result = get_dhcid (&ddns_dhcid, 0,
                    578:                                            lease -> hardware_addr.hbuf,
                    579:                                            lease -> hardware_addr.hlen);
                    580:                else
                    581:                        log_fatal("Impossible condition at %s:%d.", MDL);
                    582: 
                    583:                if (!result)
                    584:                        goto badfqdn;
                    585:        }
                    586: 
                    587:        /*
                    588:         * Start the resolver, if necessary.
                    589:         */
                    590:        if (!resolver_inited) {
                    591:                minires_ninit (&resolver_state);
                    592:                resolver_inited = 1;
                    593:                resolver_state.retrans = 1;
                    594:                resolver_state.retry = 1;
                    595:        }
                    596: 
                    597:        /*
                    598:         * Perform updates.
                    599:         */
                    600:        if (ddns_fwd_name.len && ddns_dhcid.len) {
                    601:                unsigned conflict;
                    602: 
                    603:                oc = lookup_option(&server_universe, options,
                    604:                                   SV_DDNS_CONFLICT_DETECT);
                    605:                if (!oc ||
                    606:                    evaluate_boolean_option_cache(&ignorep, packet, lease,
                    607:                                                  NULL, packet->options,
                    608:                                                  options, scope, oc, MDL))
                    609:                        conflict = 1;
                    610:                else
                    611:                        conflict = 0;
                    612: 
                    613:                rcode1 = ddns_update_fwd(&ddns_fwd_name, addr, &ddns_dhcid,
                    614:                                         ddns_ttl, 0, conflict);
                    615:        }
                    616: 
                    617:        if (rcode1 == ISC_R_SUCCESS && server_updates_ptr) {
                    618:                if (ddns_fwd_name.len && ddns_rev_name.len)
                    619:                        rcode2 = ddns_update_ptr (&ddns_fwd_name,
                    620:                                                  &ddns_rev_name, ddns_ttl);
                    621:        } else
                    622:                rcode2 = rcode1;
                    623: 
                    624:        if (rcode1 == ISC_R_SUCCESS &&
                    625:            (server_updates_a || rcode2 == ISC_R_SUCCESS)) {
                    626:                bind_ds_value(scope, server_updates_a ? "ddns-fwd-name"
                    627:                                                       : "ddns-client-fqdn",
                    628:                              &ddns_fwd_name);
                    629:                if (server_updates_a)
                    630:                        bind_ds_value(scope, "ddns-txt", &ddns_dhcid);
                    631:        }
                    632: 
                    633:        if (rcode2 == ISC_R_SUCCESS && server_updates_ptr) {
                    634:                bind_ds_value(scope, "ddns-rev-name", &ddns_rev_name);
                    635:        }
                    636: 
                    637:       noerror:
                    638:        /*
                    639:         * If fqdn-reply option is disabled in dhcpd.conf, then don't
                    640:         * send the client an FQDN option at all, even if one was requested.
                    641:         * (WinXP clients allegedly misbehave if the option is present,
                    642:         * refusing to handle PTR updates themselves).
                    643:         */
                    644:        if ((oc = lookup_option (&server_universe, options, SV_FQDN_REPLY)) &&
                    645:            !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
                    646:                                           packet->options, options,
                    647:                                           scope, oc, MDL)) {
                    648:                goto badfqdn;
                    649: 
                    650:        /* If we're ignoring client updates, then we tell a sort of 'white
                    651:         * lie'.  We've already updated the name the server wants (per the
                    652:         * config written by the server admin).  Now let the client do as
                    653:         * it pleases with the name they supplied (if any).
                    654:         *
                    655:         * We only form an FQDN option this way if the client supplied an
                    656:         * FQDN option that had FQDN_SERVER_UPDATE set false.
                    657:         */
                    658:        } else if (client_ignorep &&
                    659:            (oc = lookup_option(&fqdn_universe, packet->options,
                    660:                                FQDN_SERVER_UPDATE)) &&
                    661:            !evaluate_boolean_option_cache(&ignorep, packet, lease, NULL,
                    662:                                           packet->options, options,
                    663:                                           scope, oc, MDL)) {
                    664:                oc = lookup_option(&fqdn_universe, packet->options, FQDN_FQDN);
                    665:                if (oc && evaluate_option_cache(&d1, packet, lease, NULL,
                    666:                                                packet->options, options,
                    667:                                                scope, oc, MDL)) {
                    668:                        if (d1.len == 0 ||
                    669:                            !buffer_allocate(&bp, d1.len + 5, MDL))
                    670:                                goto badfqdn;
                    671: 
                    672:                        /* Server pretends it is not updating. */
                    673:                        bp->data[0] = 0;
                    674:                        if (!save_option_buffer(&fqdn_universe, options,
                    675:                                                bp, &bp->data[0], 1,
                    676:                                                FQDN_SERVER_UPDATE, 0))
                    677:                                goto badfqdn;
                    678: 
                    679:                        /* Client is encouraged to update. */
                    680:                        bp->data[1] = 0;
                    681:                        if (!save_option_buffer(&fqdn_universe, options,
                    682:                                                bp, &bp->data[1], 1,
                    683:                                                FQDN_NO_CLIENT_UPDATE, 0))
                    684:                                goto badfqdn;
                    685: 
                    686:                        /* Use the encoding of client's FQDN option. */
                    687:                        oc = lookup_option(&fqdn_universe, packet->options,
                    688:                                           FQDN_ENCODED);
                    689:                        if (oc &&
                    690:                            evaluate_boolean_option_cache(&ignorep, packet,
                    691:                                                          lease, NULL,
                    692:                                                          packet->options,
                    693:                                                          options, scope,
                    694:                                                          oc, MDL))
                    695:                                bp->data[2] = 1; /* FQDN is encoded. */
                    696:                        else
                    697:                                bp->data[2] = 0; /* FQDN is not encoded. */
                    698: 
                    699:                        if (!save_option_buffer(&fqdn_universe, options,
                    700:                                                bp, &bp->data[2], 1,
                    701:                                                FQDN_ENCODED, 0))
                    702:                                goto badfqdn;
                    703: 
                    704:                        /* Current FQDN drafts indicate 255 is mandatory. */
                    705:                        bp->data[3] = 255;
                    706:                        if (!save_option_buffer(&fqdn_universe, options,
                    707:                                                bp, &bp->data[3], 1,
                    708:                                                FQDN_RCODE1, 0))
                    709:                                goto badfqdn;
                    710: 
                    711:                        bp->data[4] = 255;
                    712:                        if (!save_option_buffer(&fqdn_universe, options,
                    713:                                                bp, &bp->data[4], 1,
                    714:                                                FQDN_RCODE2, 0))
                    715:                                goto badfqdn;
                    716: 
                    717:                        /* Copy in the FQDN supplied by the client.  Note well
                    718:                         * that the format of this option in the cache is going
                    719:                         * to be in text format.  If the fqdn supplied by the
                    720:                         * client is encoded, it is decoded into the option
                    721:                         * cache when parsed out of the packet.  It will be
                    722:                         * re-encoded when the option is assembled to be
                    723:                         * transmitted if the client elects that encoding.
                    724:                         */
                    725:                        memcpy(&bp->data[5], d1.data, d1.len);
                    726:                        if (!save_option_buffer(&fqdn_universe, options,
                    727:                                                bp, &bp->data[5], d1.len,
                    728:                                                FQDN_FQDN, 0))
                    729:                                goto badfqdn;
                    730: 
                    731:                        data_string_forget(&d1, MDL);
                    732:                }
                    733:        /* Set up the outgoing FQDN option if there was an incoming
                    734:         * FQDN option.  If there's a valid FQDN option, there MUST
                    735:         * be an FQDN_SERVER_UPDATES suboption, it's part of the fixed
                    736:         * length head of the option contents, so we test the latter
                    737:         * to detect the presence of the former.
                    738:         */
                    739:        } else if ((oc = lookup_option(&fqdn_universe, packet->options,
                    740:                                       FQDN_ENCODED)) &&
                    741:                   buffer_allocate(&bp, ddns_fwd_name.len + 5, MDL)) {
                    742:                bp -> data [0] = server_updates_a;
                    743:                if (!save_option_buffer(&fqdn_universe, options,
                    744:                                        bp, &bp->data [0], 1,
                    745:                                        FQDN_SERVER_UPDATE, 0))
                    746:                        goto badfqdn;
                    747:                bp -> data [1] = server_updates_a;
                    748:                if (!save_option_buffer(&fqdn_universe, options,
                    749:                                         bp, &bp->data [1], 1,
                    750:                                         FQDN_NO_CLIENT_UPDATE, 0))
                    751:                        goto badfqdn;
                    752: 
                    753:                /* Do the same encoding the client did. */
                    754:                if (evaluate_boolean_option_cache(&ignorep, packet, lease,
                    755:                                                  NULL, packet->options,
                    756:                                                  options, scope, oc, MDL))
                    757:                        bp -> data [2] = 1;
                    758:                else
                    759:                        bp -> data [2] = 0;
                    760:                if (!save_option_buffer(&fqdn_universe, options,
                    761:                                        bp, &bp->data [2], 1,
                    762:                                        FQDN_ENCODED, 0))
                    763:                        goto badfqdn;
                    764:                bp -> data [3] = isc_rcode_to_ns (rcode1);
                    765:                if (!save_option_buffer(&fqdn_universe, options,
                    766:                                        bp, &bp->data [3], 1,
                    767:                                        FQDN_RCODE1, 0))
                    768:                        goto badfqdn;
                    769:                bp -> data [4] = isc_rcode_to_ns (rcode2);
                    770:                if (!save_option_buffer(&fqdn_universe, options,
                    771:                                        bp, &bp->data [4], 1,
                    772:                                        FQDN_RCODE2, 0))
                    773:                        goto badfqdn;
                    774:                if (ddns_fwd_name.len) {
                    775:                    memcpy (&bp -> data [5],
                    776:                            ddns_fwd_name.data, ddns_fwd_name.len);
                    777:                    if (!save_option_buffer(&fqdn_universe, options,
                    778:                                             bp, &bp->data [5],
                    779:                                             ddns_fwd_name.len,
                    780:                                             FQDN_FQDN, 0))
                    781:                        goto badfqdn;
                    782:                }
                    783:        }
                    784: 
                    785:       badfqdn:
                    786:       out:
                    787:        /*
                    788:         * Final cleanup.
                    789:         */
                    790:        data_string_forget(&d1, MDL);
                    791:        data_string_forget(&ddns_hostname, MDL);
                    792:        data_string_forget(&ddns_domainname, MDL);
                    793:        data_string_forget(&old_ddns_fwd_name, MDL);
                    794:        data_string_forget(&ddns_fwd_name, MDL);
                    795:        data_string_forget(&ddns_rev_name, MDL);
                    796:        data_string_forget(&ddns_dhcid, MDL);
                    797:        if (bp)
                    798:                buffer_dereference(&bp, MDL);
                    799: 
                    800:        return result;
                    801: }
                    802: 
                    803: /* Remove relevant entries from DNS. */
                    804: int
                    805: ddns_removals(struct lease *lease, struct iasubopt *lease6)
                    806: {
                    807:        struct data_string ddns_fwd_name;
                    808:        struct data_string ddns_rev_name;
                    809:        struct data_string ddns_dhcid;
                    810:        isc_result_t rcode;
                    811:        struct binding_scope **scope;
                    812:        struct iaddr addr;
                    813:        int result = 0;
                    814:        int client_updated = 0;
                    815: 
                    816:        if (lease != NULL) {
                    817:                scope = &(lease->scope);
                    818:                addr = lease->ip_addr;
                    819:        } else if (lease6 != NULL) {
                    820:                scope = &(lease6->scope);
                    821:                memcpy(addr.iabuf, lease6->addr.s6_addr, 16);
                    822:                addr.len = 16;
                    823:        } else
                    824:                return 0;
                    825: 
                    826:        /* No scope implies that DDNS has not been performed for this lease. */
                    827:        if (*scope == NULL)
                    828:                return 0;
                    829: 
                    830:        if (ddns_update_style != 2)
                    831:                return 0;
                    832: 
                    833:        /*
                    834:         * Look up stored names.
                    835:         */
                    836:        memset (&ddns_fwd_name, 0, sizeof (ddns_fwd_name));
                    837:        memset (&ddns_rev_name, 0, sizeof (ddns_rev_name));
                    838:        memset (&ddns_dhcid, 0, sizeof (ddns_dhcid));
                    839: 
                    840:        /*
                    841:         * Start the resolver, if necessary.
                    842:         */
                    843:        if (!resolver_inited) {
                    844:                minires_ninit (&resolver_state);
                    845:                resolver_inited = 1;
                    846:                resolver_state.retrans = 1;
                    847:                resolver_state.retry = 1;
                    848:        }
                    849: 
                    850:        /* We need the fwd name whether we are deleting both records or just
                    851:           the PTR record, so if it's not there, we can't proceed. */
                    852:        if (!find_bound_string(&ddns_fwd_name, *scope, "ddns-fwd-name")) {
                    853:                /* If there's no ddns-fwd-name, look for the client fqdn,
                    854:                   in case the client did the update. */
                    855:                if (find_bound_string(&ddns_fwd_name, *scope,
                    856:                                       "ddns-client-fqdn"))
                    857:                        client_updated = 1;
                    858:                goto try_rev;
                    859:        }
                    860: 
                    861:        /* If the ddns-txt binding isn't there, this isn't an interim
                    862:           or rfc3??? record, so we can't delete the A record using
                    863:           this mechanism, but we can delete the PTR record. */
                    864:        if (!find_bound_string (&ddns_dhcid, *scope, "ddns-txt")) {
                    865:                result = 1;
                    866:                goto try_rev;
                    867:        }
                    868: 
                    869:        /*
                    870:         * Perform removals.
                    871:         */
                    872:        if (ddns_fwd_name.len)
                    873:                rcode = ddns_remove_fwd(&ddns_fwd_name, addr, &ddns_dhcid);
                    874:        else
                    875:                rcode = ISC_R_SUCCESS;
                    876: 
                    877:        if (rcode == ISC_R_SUCCESS) {
                    878:                result = 1;
                    879:                unset(*scope, "ddns-fwd-name");
                    880:                unset(*scope, "ddns-txt");
                    881:              try_rev:
                    882:                if (find_bound_string(&ddns_rev_name, *scope,
                    883:                                      "ddns-rev-name")) {
                    884:                        if (ddns_remove_ptr(&ddns_rev_name) == ISC_R_SUCCESS) {
                    885:                                unset(*scope, "ddns-rev-name");
                    886:                                if (client_updated)
                    887:                                        unset(*scope, "ddns-client-fqdn");
                    888:                                /* XXX this is to compensate for a bug in
                    889:                                   XXX 3.0rc8, and should be removed before
                    890:                                   XXX 3.0pl1. */
                    891:                                else if (!ddns_fwd_name.len)
                    892:                                        unset(*scope, "ddns-text");
                    893:                        } else
                    894:                                result = 0;
                    895:                }
                    896:        }
                    897: 
                    898:        data_string_forget (&ddns_fwd_name, MDL);
                    899:        data_string_forget (&ddns_rev_name, MDL);
                    900:        data_string_forget (&ddns_dhcid, MDL);
                    901: 
                    902:        return result;
                    903: }
                    904: 
                    905: #endif /* NSUPDATE */

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