1beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin/** @file
2beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
3beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  This program and the accompanying materials are licensed and made available
4beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  under the terms and conditions of the BSD License which accompanies this
5beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  distribution.  The full text of the license may be found at
6beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  http://opensource.org/licenses/bsd-license.php.
7beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin
8beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
10beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin**/
11d7ce700605e1af0e455e31ec11f19ff21d26b525darylm/*
12d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Copyright (c) 1996 by Internet Software Consortium.
13d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
14d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Permission to use, copy, modify, and distribute this software for any
15d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * purpose with or without fee is hereby granted, provided that the above
16d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * copyright notice and this permission notice appear in all copies.
17d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
18d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
19d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
20d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
21d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
22d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
23d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
24d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * SOFTWARE.
26d7ce700605e1af0e455e31ec11f19ff21d26b525darylm */
27d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
28d7ce700605e1af0e455e31ec11f19ff21d26b525darylm/*
29d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Portions copyright (c) 1999, 2000
30d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Intel Corporation.
31d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * All rights reserved.
32d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
33d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Redistribution and use in source and binary forms, with or without
34d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * modification, are permitted provided that the following conditions
35d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * are met:
36d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
37d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * 1. Redistributions of source code must retain the above copyright
38d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    notice, this list of conditions and the following disclaimer.
39d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
40d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * 2. Redistributions in binary form must reproduce the above copyright
41d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    notice, this list of conditions and the following disclaimer in the
42d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    documentation and/or other materials provided with the distribution.
43d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
44d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * 3. All advertising materials mentioning features or use of this software
45d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    must display the following acknowledgement:
46d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
47d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    This product includes software developed by Intel Corporation and
48d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    its contributors.
49d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
50d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * 4. Neither the name of Intel Corporation or its contributors may be
51d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    used to endorse or promote products derived from this software
52d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *    without specific prior written permission.
53d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
54d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
55d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * ARE DISCLAIMED.  IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
58d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
64d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * THE POSSIBILITY OF SUCH DAMAGE.
65d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
66d7ce700605e1af0e455e31ec11f19ff21d26b525darylm */
67d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
68d7ce700605e1af0e455e31ec11f19ff21d26b525darylm/*
69d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Based on the Dynamic DNS reference implementation by Viraj Bais
70d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * <viraj_bais@ccm.fm.intel.com>
71d7ce700605e1af0e455e31ec11f19ff21d26b525darylm */
72d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
73d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <sys/param.h>
74d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <sys/socket.h>
75d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <sys/time.h>
76d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <netinet/in.h>
77d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <arpa/inet.h>
78d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <arpa/nameser.h>
79d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <errno.h>
80d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <limits.h>
81d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <netdb.h>
82d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <resolv.h>
83d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <stdio.h>
84d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <stdlib.h>
85d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#include <string.h>
86d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
87d7ce700605e1af0e455e31ec11f19ff21d26b525darylm/*
88d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Separate a linked list of records into groups so that all records
89d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * in a group will belong to a single zone on the nameserver.
90d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Create a dynamic update packet for each zone and send it to the
91d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * nameservers for that zone, and await answer.
92d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Abort if error occurs in updating any zone.
93d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * Return the number of zones updated on success, < 0 on error.
94d7ce700605e1af0e455e31ec11f19ff21d26b525darylm *
95d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * On error, caller must deal with the unsynchronized zones
96d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * eg. an A record might have been successfully added to the forward
97d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * zone but the corresponding PTR record would be missing if error
98d7ce700605e1af0e455e31ec11f19ff21d26b525darylm * was encountered while updating the reverse zone.
99d7ce700605e1af0e455e31ec11f19ff21d26b525darylm */
100d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
101d7ce700605e1af0e455e31ec11f19ff21d26b525darylm#define NSMAX 16
102d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
103d7ce700605e1af0e455e31ec11f19ff21d26b525darylmstruct ns1 {
104d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    char nsname[MAXDNAME];
105d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    struct in_addr nsaddr1;
106d7ce700605e1af0e455e31ec11f19ff21d26b525darylm};
107d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
108d7ce700605e1af0e455e31ec11f19ff21d26b525darylmstruct zonegrp {
109d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    char        z_origin[MAXDNAME];
110d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    int16_t     z_class;
111d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    char        z_soardata[MAXDNAME + 5 * INT32SZ];
112d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    struct ns1  z_ns[NSMAX];
113d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    int     z_nscount;
114d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    ns_updrec * z_rr;
115d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    struct zonegrp *z_next;
116d7ce700605e1af0e455e31ec11f19ff21d26b525darylm};
117d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
118d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
119d7ce700605e1af0e455e31ec11f19ff21d26b525darylmint
120d7ce700605e1af0e455e31ec11f19ff21d26b525darylmres_update(ns_updrec *rrecp_in) {
121d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    ns_updrec *rrecp, *tmprrecp;
122d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    u_char buf[PACKETSZ], answer[PACKETSZ], packet[2*PACKETSZ];
123d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    char name[MAXDNAME], zname[MAXDNAME], primary[MAXDNAME],
124d7ce700605e1af0e455e31ec11f19ff21d26b525darylm         mailaddr[MAXDNAME];
125d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    u_char soardata[2*MAXCDNAME+5*INT32SZ];
126d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    char *dname, *svdname, *cp1, *target;
127d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    u_char *cp, *eom;
128d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    HEADER *hp = (HEADER *) answer;
129d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    struct zonegrp *zptr = NULL, *tmpzptr, *prevzptr, *zgrp_start = NULL;
130d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    int i, j, k = 0, n, ancount, nscount, arcount, rcode, rdatasize,
131d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        newgroup, done, myzone, seen_before, numzones = 0;
132d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    u_int16_t dlen, class, qclass, type, qtype;
133d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    u_int32_t ttl;
134d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
135d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
136d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        h_errno = NETDB_INTERNAL;
137d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        return (-1);
138d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    }
139d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
140d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    for (rrecp = rrecp_in; rrecp; rrecp = rrecp->r_next) {
141d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        dname = rrecp->r_dname;
142d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        n = (int)strlen(dname);
143d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (dname[n-1] == '.')
144d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            dname[n-1] = '\0';
145d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        qtype = T_SOA;
146d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        qclass = rrecp->r_class;
147d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        done = 0;
148d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        seen_before = 0;
149d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
150d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        while (!done && dname) {
151d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (qtype == T_SOA) {
152d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            for (tmpzptr = zgrp_start;
153d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 tmpzptr && !seen_before;
154d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 tmpzptr = tmpzptr->z_next) {
155d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (strcasecmp(dname,
156d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           tmpzptr->z_origin) == 0 &&
157d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    tmpzptr->z_class == qclass)
158d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    seen_before++;
159d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                for (tmprrecp = tmpzptr->z_rr;
160d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     tmprrecp && !seen_before;
161d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     tmprrecp = tmprrecp->r_grpnext)
162d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (strcasecmp(dname, tmprrecp->r_dname) == 0
163d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    && tmprrecp->r_class == qclass) {
164d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    seen_before++;
165d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    break;
166d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                }
167d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (seen_before) {
168d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    /*
169d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     * Append to the end of
170d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     * current group.
171d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     */
172d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    for (tmprrecp = tmpzptr->z_rr;
173d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                         tmprrecp->r_grpnext;
174d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                         tmprrecp = tmprrecp->r_grpnext)
175d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                        (void)NULL;
176d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    tmprrecp->r_grpnext = rrecp;
177d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    rrecp->r_grpnext = NULL;
178d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    done = 1;
179d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    break;
180d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                }
181d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
182d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        } else if (qtype == T_A) {
183d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            for (tmpzptr = zgrp_start;
184d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             tmpzptr && !done;
185d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             tmpzptr = tmpzptr->z_next)
186d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                for (i = 0; i < tmpzptr->z_nscount; i++)
187d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (tmpzptr->z_class == qclass &&
188d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    strcasecmp(tmpzptr->z_ns[i].nsname,
189d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           dname) == 0 &&
190d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    tmpzptr->z_ns[i].nsaddr1.s_addr != 0) {
191d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    zptr->z_ns[k].nsaddr1.s_addr =
192d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     tmpzptr->z_ns[i].nsaddr1.s_addr;
193d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    done = 1;
194d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    break;
195d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                }
196d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
197d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (done)
198d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            break;
199d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        n = res_mkquery(QUERY, dname, qclass, qtype, NULL,
200d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                0, NULL, buf, sizeof buf);
201d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (n <= 0) {
202d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "res_update: mkquery failed\n");
203d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (n);
204d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
205d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        n = res_send(buf, n, answer, sizeof answer);
206d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (n < 0) {
207d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "res_update: send error for %s\n",
208d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                rrecp->r_dname);
209d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (n);
210d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
211d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (n < HFIXEDSZ)
212d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
213d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        ancount = ntohs(hp->ancount);
214d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        nscount = ntohs(hp->nscount);
215d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        arcount = ntohs(hp->arcount);
216d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        rcode = hp->rcode;
217d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        cp = answer + HFIXEDSZ;
218d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        eom = answer + n;
219d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        /* skip the question section */
220d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        n = dn_skipname(cp, eom);
221d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (n < 0 || cp + n + 2 * INT16SZ > eom)
222d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
223d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        cp += n + 2 * INT16SZ;
224d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
225d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (qtype == T_SOA) {
226d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (ancount == 0 && nscount == 0 && arcount == 0) {
227d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /*
228d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * if (rcode == NOERROR) then the dname exists but
229d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * has no soa record associated with it.
230d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * if (rcode == NXDOMAIN) then the dname does not
231d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * exist and the server is replying out of NCACHE.
232d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * in either case, proceed with the next try
233d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             */
234d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            dname = strchr(dname, '.');
235d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (dname != NULL)
236d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname++;
237d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            continue;
238d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else if ((rcode == NOERROR || rcode == NXDOMAIN) &&
239d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                   ancount == 0 &&
240d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                   nscount == 1 && arcount == 0) {
241d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /*
242d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * name/data does not exist, soa record supplied in the
243d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * authority section
244d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             */
245d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* authority section must contain the soa record */
246d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if ((n = dn_expand(answer, eom, cp, zname,
247d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    sizeof zname)) < 0)
248d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (n);
249d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += n;
250d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + 2 * INT16SZ > eom)
251d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
252d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(type, cp);
253d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(class, cp);
254d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (type != T_SOA || class != qclass) {
255d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                fprintf(stderr, "unknown answer\n");
256d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
257d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
258d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            myzone = 0;
259d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            svdname = dname;
260d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            while (dname)
261d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (strcasecmp(dname, zname) == 0) {
262d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                myzone = 1;
263d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                break;
264d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                } else if ((dname = strchr(dname, '.')) != NULL)
265d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname++;
266d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (!myzone) {
267d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname = strchr(svdname, '.');
268d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (dname != NULL)
269d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname++;
270d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                continue;
271d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
272d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            nscount = 0;
273d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* fallthrough */
274d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else if (rcode == NOERROR && ancount == 1) {
275d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /*
276d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * found the zone name
277d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * new servers will supply NS records for the zone
278d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * in authority section and A records for those
279d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * nameservers in the additional section
280d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * older servers have to be explicitly queried for
281d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * NS records for the zone
282d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             */
283d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* answer section must contain the soa record */
284d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if ((n = dn_expand(answer, eom, cp, zname,
285d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           sizeof zname)) < 0)
286d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (n);
287d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            else
288d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                cp += n;
289d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + 2 * INT16SZ > eom)
290d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
291d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(type, cp);
292d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(class, cp);
293d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (type == T_CNAME) {
294d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname = strchr(dname, '.');
295d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (dname != NULL)
296d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    dname++;
297d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                continue;
298d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
299d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (strcasecmp(dname, zname) != 0 ||
300d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                type != T_SOA ||
301d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                class != rrecp->r_class) {
302d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                fprintf(stderr, "unknown answer\n");
303d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
304d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
305d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* FALLTHROUGH */
306d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else {
307d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr,
308d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
309d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                ancount, nscount, arcount, hp->rcode);
310d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
311d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
312d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + INT32SZ + INT16SZ > eom)
313d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
314d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* continue processing the soa record */
315d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETLONG(ttl, cp);
316d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(dlen, cp);
317d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + dlen > eom)
318d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
319d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            newgroup = 1;
320d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            zptr = zgrp_start;
321d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            prevzptr = NULL;
322d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            while (zptr) {
323d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (strcasecmp(zname, zptr->z_origin) == 0 &&
324d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                type == T_SOA && class == qclass) {
325d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                newgroup = 0;
326d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                break;
327d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
328d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            prevzptr = zptr;
329d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            zptr = zptr->z_next;
330d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
331d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (!newgroup) {
332d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            for (tmprrecp = zptr->z_rr;
333d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 tmprrecp->r_grpnext;
334d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 tmprrecp = tmprrecp->r_grpnext)
335d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    ;
336d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            tmprrecp->r_grpnext = rrecp;
337d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            rrecp->r_grpnext = NULL;
338d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            done = 1;
339d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += dlen;
340d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            break;
341d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else {
342d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if ((n = dn_expand(answer, eom, cp, primary,
343d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           sizeof primary)) < 0)
344d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (n);
345d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += n;
346d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /*
347d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * We don't have to bounds check here because the
348d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             * next use of 'cp' is in dn_expand().
349d7ce700605e1af0e455e31ec11f19ff21d26b525darylm             */
350d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp1 = (char *)soardata;
351d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            strcpy(cp1, primary);
352d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp1 += strlen(cp1) + 1;
353d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if ((n = dn_expand(answer, eom, cp, mailaddr,
354d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           sizeof mailaddr)) < 0)
355d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (n);
356d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += n;
357d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            strcpy(cp1, mailaddr);
358d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp1 += strlen(cp1) + 1;
359d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + 5*INT32SZ > eom)
360d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
361d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            memcpy(cp1, cp, 5*INT32SZ);
362d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += 5*INT32SZ;
363d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp1 += 5*INT32SZ;
364d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            rdatasize = (int)((u_char *)cp1 - soardata);
365d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            zptr = calloc(1, sizeof(struct zonegrp));
366d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (zptr == NULL)
367d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                        return (-1);
368d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (zgrp_start == NULL)
369d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                zgrp_start = zptr;
370d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            else
371d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                prevzptr->z_next = zptr;
372d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            zptr->z_rr = rrecp;
373d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            rrecp->r_grpnext = NULL;
374d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            strcpy(zptr->z_origin, zname);
375d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            zptr->z_class = class;
376d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            memcpy(zptr->z_soardata, soardata, rdatasize);
377d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* fallthrough to process NS and A records */
378d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
379d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        } else if (qtype == T_NS) {
380d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (rcode == NOERROR && ancount > 0) {
381d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            strcpy(zname, dname);
382d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
383d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (strcasecmp(zname, zptr->z_origin) == 0)
384d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                break;
385d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
386d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (zptr == NULL)
387d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                /* should not happen */
388d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
389d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (nscount > 0) {
390d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                /*
391d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 * answer and authority sections contain
392d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 * the same information, skip answer section
393d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                 */
394d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                for (j = 0; j < ancount; j++) {
395d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                n = dn_skipname(cp, eom);
396d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (n < 0)
397d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    return (-1);
398d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                n += 2*INT16SZ + INT32SZ;
399d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (cp + n + INT16SZ > eom)
400d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    return (-1);
401d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                cp += n;
402d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                GETSHORT(dlen, cp);
403d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                cp += dlen;
404d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                }
405d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else
406d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                nscount = ancount;
407d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* fallthrough to process NS and A records */
408d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else {
409d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "cannot determine nameservers for %s:\
410d7ce700605e1af0e455e31ec11f19ff21d26b525darylmans=%d, auth=%d, add=%d, rcode=%d\n",
411d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname, ancount, nscount, arcount, hp->rcode);
412d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
413d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
414d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        } else if (qtype == T_A) {
415d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (rcode == NOERROR && ancount > 0) {
416d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            arcount = ancount;
417d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            ancount = nscount = 0;
418d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            /* fallthrough to process A records */
419d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            } else {
420d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "cannot determine address for %s:\
421d7ce700605e1af0e455e31ec11f19ff21d26b525darylmans=%d, auth=%d, add=%d, rcode=%d\n",
422d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                dname, ancount, nscount, arcount, hp->rcode);
423d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
424d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
425d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
426d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        /* process NS records for the zone */
427d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        j = 0;
428d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        for (i = 0; i < nscount; i++) {
429d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if ((n = dn_expand(answer, eom, cp, name,
430d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    sizeof name)) < 0)
431d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (n);
432d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += n;
433d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + 3 * INT16SZ + INT32SZ > eom)
434d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
435d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(type, cp);
436d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(class, cp);
437d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETLONG(ttl, cp);
438d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(dlen, cp);
439d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + dlen > eom)
440d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
441d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (strcasecmp(name, zname) == 0 &&
442d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            type == T_NS && class == qclass) {
443d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if ((n = dn_expand(answer, eom, cp,
444d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           name, sizeof name)) < 0)
445d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    return (n);
446d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                target = zptr->z_ns[j++].nsname;
447d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                strcpy(target, name);
448d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
449d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += dlen;
450d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
451d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (zptr->z_nscount == 0)
452d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            zptr->z_nscount = j;
453d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        /* get addresses for the nameservers */
454d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        for (i = 0; i < arcount; i++) {
455d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if ((n = dn_expand(answer, eom, cp, name,
456d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    sizeof name)) < 0)
457d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (n);
458d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += n;
459d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + 3 * INT16SZ + INT32SZ > eom)
460d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
461d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(type, cp);
462d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(class, cp);
463d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETLONG(ttl, cp);
464d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            GETSHORT(dlen, cp);
465d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (cp + dlen > eom)
466d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                return (-1);
467d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (type == T_A && dlen == INT32SZ && class == qclass) {
468d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            for (j = 0; j < zptr->z_nscount; j++)
469d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (strcasecmp(name, zptr->z_ns[j].nsname) == 0) {
470d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                memcpy(&zptr->z_ns[j].nsaddr1.s_addr, cp,
471d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                       INT32SZ);
472d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                break;
473d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                }
474d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
475d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            cp += dlen;
476d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
477d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (zptr->z_nscount == 0) {
478d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            dname = zname;
479d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            qtype = T_NS;
480d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            continue;
481d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
482d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        done = 1;
483d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        for (k = 0; k < zptr->z_nscount; k++)
484d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (zptr->z_ns[k].nsaddr1.s_addr == 0) {
485d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            done = 0;
486d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            dname = zptr->z_ns[k].nsname;
487d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            qtype = T_A;
488d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
489d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        } /* while */
490d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    }
491beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin    --ttl;  // Suppress the "Set but not used" warning/error for ttl.
492d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
493d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    _res.options |= RES_DEBUG;
494d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
495d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
496d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        /* append zone section */
497d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
498d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                     zptr->z_class, ns_t_soa, 0);
499d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (rrecp == NULL) {
500d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "saverrec error\n");
501d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fflush(stderr);
502d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
503d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
504d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        rrecp->r_grpnext = zptr->z_rr;
505d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        zptr->z_rr = rrecp;
506d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
507d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        n = res_mkupdate(zptr->z_rr, packet, sizeof packet);
508d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (n < 0) {
509d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "res_mkupdate error\n");
510d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fflush(stderr);
511d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            return (-1);
512d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        } else
513d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stdout, "res_mkupdate: packet size = %d\n", n);
514d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
515beaaa3b715381d05c454619a66dd6d27c0b420e5Olivier Martin        /* Override the list of NS records from res_init() with
516d7ce700605e1af0e455e31ec11f19ff21d26b525darylm         * the authoritative nameservers for the zone being updated.
517d7ce700605e1af0e455e31ec11f19ff21d26b525darylm         * Sort primary to be the first in the list of nameservers.
518d7ce700605e1af0e455e31ec11f19ff21d26b525darylm         */
519d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        for (i = 0; i < zptr->z_nscount; i++) {
520d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            if (strcasecmp(zptr->z_ns[i].nsname,
521d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                       zptr->z_soardata) == 0) {
522d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                struct in_addr tmpaddr;
523d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
524d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                if (i != 0) {
525d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    strcpy(zptr->z_ns[i].nsname,
526d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           zptr->z_ns[0].nsname);
527d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    strcpy(zptr->z_ns[0].nsname,
528d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                           zptr->z_soardata);
529d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    tmpaddr = zptr->z_ns[i].nsaddr1;
530d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    zptr->z_ns[i].nsaddr1 =
531d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                        zptr->z_ns[0].nsaddr1;
532d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    zptr->z_ns[0].nsaddr1 = tmpaddr;
533d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                }
534d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                break;
535d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            }
536d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
537d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        for (i = 0; i < MAXNS; i++) {
538d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            _res.nsaddr_list[i].sin_addr = zptr->z_ns[i].nsaddr1;
539d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            _res.nsaddr_list[i].sin_family = AF_INET;
540d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            _res.nsaddr_list[i].sin_port = htons(NAMESERVER_PORT);
541d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        }
542d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        _res.nscount = (zptr->z_nscount < MAXNS) ?
543d7ce700605e1af0e455e31ec11f19ff21d26b525darylm                    zptr->z_nscount : MAXNS;
544d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        n = res_send(packet, n, answer, sizeof(answer));
545d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        if (n < 0) {
546d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            fprintf(stderr, "res_send: send error, n=%d\n", n);
547d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            break;
548d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        } else
549d7ce700605e1af0e455e31ec11f19ff21d26b525darylm            numzones++;
550d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    }
551d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
552d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    /* free malloc'ed memory */
553d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    while(zgrp_start) {
554d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        zptr = zgrp_start;
555d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        zgrp_start = zgrp_start->z_next;
556d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        res_freeupdrec(zptr->z_rr);  /* Zone section we allocated. */
557d7ce700605e1af0e455e31ec11f19ff21d26b525darylm        free((char *)zptr);
558d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    }
559d7ce700605e1af0e455e31ec11f19ff21d26b525darylm
560d7ce700605e1af0e455e31ec11f19ff21d26b525darylm    return (numzones);
561d7ce700605e1af0e455e31ec11f19ff21d26b525darylm}
562