]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/res_update.c
a01d83203c2b77520bd2f78257497c9fe5731fb0
2 * Copyright (c) 1996 by Internet Software Consortium.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
19 * Portions copyright (c) 1999, 2000
21 * All rights reserved.
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
30 * 2. Redistributions in binary form must reproduce the above copyright
31 * notice, this list of conditions and the following disclaimer in the
32 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
37 * This product includes software developed by Intel Corporation and
40 * 4. Neither the name of Intel Corporation or its contributors may be
41 * used to endorse or promote products derived from this software
42 * without specific prior written permission.
44 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
45 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
48 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54 * THE POSSIBILITY OF SUCH DAMAGE.
59 * Based on the Dynamic DNS reference implementation by Viraj Bais
60 * <viraj_bais@ccm.fm.intel.com>
63 #include <sys/param.h>
64 #include <sys/socket.h>
66 #include <netinet/in.h>
67 #include <arpa/inet.h>
68 #include <arpa/nameser.h>
78 * Separate a linked list of records into groups so that all records
79 * in a group will belong to a single zone on the nameserver.
80 * Create a dynamic update packet for each zone and send it to the
81 * nameservers for that zone, and await answer.
82 * Abort if error occurs in updating any zone.
83 * Return the number of zones updated on success, < 0 on error.
85 * On error, caller must deal with the unsynchronized zones
86 * eg. an A record might have been successfully added to the forward
87 * zone but the corresponding PTR record would be missing if error
88 * was encountered while updating the reverse zone.
94 char nsname
[MAXDNAME
];
95 struct in_addr nsaddr1
;
99 char z_origin
[MAXDNAME
];
101 char z_soardata
[MAXDNAME
+ 5 * INT32SZ
];
102 struct ns1 z_ns
[NSMAX
];
105 struct zonegrp
*z_next
;
110 res_update(ns_updrec
*rrecp_in
) {
111 ns_updrec
*rrecp
, *tmprrecp
;
112 u_char buf
[PACKETSZ
], answer
[PACKETSZ
], packet
[2*PACKETSZ
];
113 char name
[MAXDNAME
], zname
[MAXDNAME
], primary
[MAXDNAME
],
115 u_char soardata
[2*MAXCDNAME
+5*INT32SZ
];
116 char *dname
, *svdname
, *cp1
, *target
;
118 HEADER
*hp
= (HEADER
*) answer
;
119 struct zonegrp
*zptr
= NULL
, *tmpzptr
, *prevzptr
, *zgrp_start
= NULL
;
120 int i
, j
, k
= 0, n
, ancount
, nscount
, arcount
, rcode
, rdatasize
,
121 newgroup
, done
, myzone
, seen_before
, numzones
= 0;
122 u_int16_t dlen
, class, qclass
, type
, qtype
;
125 if ((_res
.options
& RES_INIT
) == 0 && res_init() == -1) {
126 h_errno
= NETDB_INTERNAL
;
130 for (rrecp
= rrecp_in
; rrecp
; rrecp
= rrecp
->r_next
) {
131 dname
= rrecp
->r_dname
;
132 n
= (int)strlen(dname
);
133 if (dname
[n
-1] == '.')
136 qclass
= rrecp
->r_class
;
140 while (!done
&& dname
) {
141 if (qtype
== T_SOA
) {
142 for (tmpzptr
= zgrp_start
;
143 tmpzptr
&& !seen_before
;
144 tmpzptr
= tmpzptr
->z_next
) {
145 if (strcasecmp(dname
,
146 tmpzptr
->z_origin
) == 0 &&
147 tmpzptr
->z_class
== qclass
)
149 for (tmprrecp
= tmpzptr
->z_rr
;
150 tmprrecp
&& !seen_before
;
151 tmprrecp
= tmprrecp
->r_grpnext
)
152 if (strcasecmp(dname
, tmprrecp
->r_dname
) == 0
153 && tmprrecp
->r_class
== qclass
) {
159 * Append to the end of
162 for (tmprrecp
= tmpzptr
->z_rr
;
164 tmprrecp
= tmprrecp
->r_grpnext
)
166 tmprrecp
->r_grpnext
= rrecp
;
167 rrecp
->r_grpnext
= NULL
;
172 } else if (qtype
== T_A
) {
173 for (tmpzptr
= zgrp_start
;
175 tmpzptr
= tmpzptr
->z_next
)
176 for (i
= 0; i
< tmpzptr
->z_nscount
; i
++)
177 if (tmpzptr
->z_class
== qclass
&&
178 strcasecmp(tmpzptr
->z_ns
[i
].nsname
,
180 tmpzptr
->z_ns
[i
].nsaddr1
.s_addr
!= 0) {
181 zptr
->z_ns
[k
].nsaddr1
.s_addr
=
182 tmpzptr
->z_ns
[i
].nsaddr1
.s_addr
;
189 n
= res_mkquery(QUERY
, dname
, qclass
, qtype
, NULL
,
190 0, NULL
, buf
, sizeof buf
);
192 fprintf(stderr
, "res_update: mkquery failed\n");
195 n
= res_send(buf
, n
, answer
, sizeof answer
);
197 fprintf(stderr
, "res_update: send error for %s\n",
203 ancount
= ntohs(hp
->ancount
);
204 nscount
= ntohs(hp
->nscount
);
205 arcount
= ntohs(hp
->arcount
);
207 cp
= answer
+ HFIXEDSZ
;
209 /* skip the question section */
210 n
= dn_skipname(cp
, eom
);
211 if (n
< 0 || cp
+ n
+ 2 * INT16SZ
> eom
)
213 cp
+= n
+ 2 * INT16SZ
;
215 if (qtype
== T_SOA
) {
216 if (ancount
== 0 && nscount
== 0 && arcount
== 0) {
218 * if (rcode == NOERROR) then the dname exists but
219 * has no soa record associated with it.
220 * if (rcode == NXDOMAIN) then the dname does not
221 * exist and the server is replying out of NCACHE.
222 * in either case, proceed with the next try
224 dname
= strchr(dname
, '.');
228 } else if ((rcode
== NOERROR
|| rcode
== NXDOMAIN
) &&
230 nscount
== 1 && arcount
== 0) {
232 * name/data does not exist, soa record supplied in the
235 /* authority section must contain the soa record */
236 if ((n
= dn_expand(answer
, eom
, cp
, zname
,
240 if (cp
+ 2 * INT16SZ
> eom
)
244 if (type
!= T_SOA
|| class != qclass
) {
245 fprintf(stderr
, "unknown answer\n");
251 if (strcasecmp(dname
, zname
) == 0) {
254 } else if ((dname
= strchr(dname
, '.')) != NULL
)
257 dname
= strchr(svdname
, '.');
264 } else if (rcode
== NOERROR
&& ancount
== 1) {
266 * found the zone name
267 * new servers will supply NS records for the zone
268 * in authority section and A records for those
269 * nameservers in the additional section
270 * older servers have to be explicitly queried for
271 * NS records for the zone
273 /* answer section must contain the soa record */
274 if ((n
= dn_expand(answer
, eom
, cp
, zname
,
279 if (cp
+ 2 * INT16SZ
> eom
)
283 if (type
== T_CNAME
) {
284 dname
= strchr(dname
, '.');
289 if (strcasecmp(dname
, zname
) != 0 ||
291 class != rrecp
->r_class
) {
292 fprintf(stderr
, "unknown answer\n");
298 "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
299 ancount
, nscount
, arcount
, hp
->rcode
);
302 if (cp
+ INT32SZ
+ INT16SZ
> eom
)
304 /* continue processing the soa record */
313 if (strcasecmp(zname
, zptr
->z_origin
) == 0 &&
314 type
== T_SOA
&& class == qclass
) {
322 for (tmprrecp
= zptr
->z_rr
;
324 tmprrecp
= tmprrecp
->r_grpnext
)
326 tmprrecp
->r_grpnext
= rrecp
;
327 rrecp
->r_grpnext
= NULL
;
332 if ((n
= dn_expand(answer
, eom
, cp
, primary
,
333 sizeof primary
)) < 0)
337 * We don't have to bounds check here because the
338 * next use of 'cp' is in dn_expand().
340 cp1
= (char *)soardata
;
341 strcpy(cp1
, primary
);
342 cp1
+= strlen(cp1
) + 1;
343 if ((n
= dn_expand(answer
, eom
, cp
, mailaddr
,
344 sizeof mailaddr
)) < 0)
347 strcpy(cp1
, mailaddr
);
348 cp1
+= strlen(cp1
) + 1;
349 if (cp
+ 5*INT32SZ
> eom
)
351 memcpy(cp1
, cp
, 5*INT32SZ
);
354 rdatasize
= (int)((u_char
*)cp1
- soardata
);
355 zptr
= calloc(1, sizeof(struct zonegrp
));
358 if (zgrp_start
== NULL
)
361 prevzptr
->z_next
= zptr
;
363 rrecp
->r_grpnext
= NULL
;
364 strcpy(zptr
->z_origin
, zname
);
365 zptr
->z_class
= class;
366 memcpy(zptr
->z_soardata
, soardata
, rdatasize
);
367 /* fallthrough to process NS and A records */
369 } else if (qtype
== T_NS
) {
370 if (rcode
== NOERROR
&& ancount
> 0) {
371 strcpy(zname
, dname
);
372 for (zptr
= zgrp_start
; zptr
; zptr
= zptr
->z_next
) {
373 if (strcasecmp(zname
, zptr
->z_origin
) == 0)
377 /* should not happen */
381 * answer and authority sections contain
382 * the same information, skip answer section
384 for (j
= 0; j
< ancount
; j
++) {
385 n
= dn_skipname(cp
, eom
);
388 n
+= 2*INT16SZ
+ INT32SZ
;
389 if (cp
+ n
+ INT16SZ
> eom
)
397 /* fallthrough to process NS and A records */
399 fprintf(stderr
, "cannot determine nameservers for %s:\
400 ans=%d, auth=%d, add=%d, rcode=%d\n",
401 dname
, ancount
, nscount
, arcount
, hp
->rcode
);
404 } else if (qtype
== T_A
) {
405 if (rcode
== NOERROR
&& ancount
> 0) {
407 ancount
= nscount
= 0;
408 /* fallthrough to process A records */
410 fprintf(stderr
, "cannot determine address for %s:\
411 ans=%d, auth=%d, add=%d, rcode=%d\n",
412 dname
, ancount
, nscount
, arcount
, hp
->rcode
);
416 /* process NS records for the zone */
418 for (i
= 0; i
< nscount
; i
++) {
419 if ((n
= dn_expand(answer
, eom
, cp
, name
,
423 if (cp
+ 3 * INT16SZ
+ INT32SZ
> eom
)
431 if (strcasecmp(name
, zname
) == 0 &&
432 type
== T_NS
&& class == qclass
) {
433 if ((n
= dn_expand(answer
, eom
, cp
,
434 name
, sizeof name
)) < 0)
436 target
= zptr
->z_ns
[j
++].nsname
;
437 strcpy(target
, name
);
441 if (zptr
->z_nscount
== 0)
443 /* get addresses for the nameservers */
444 for (i
= 0; i
< arcount
; i
++) {
445 if ((n
= dn_expand(answer
, eom
, cp
, name
,
449 if (cp
+ 3 * INT16SZ
+ INT32SZ
> eom
)
457 if (type
== T_A
&& dlen
== INT32SZ
&& class == qclass
) {
458 for (j
= 0; j
< zptr
->z_nscount
; j
++)
459 if (strcasecmp(name
, zptr
->z_ns
[j
].nsname
) == 0) {
460 memcpy(&zptr
->z_ns
[j
].nsaddr1
.s_addr
, cp
,
467 if (zptr
->z_nscount
== 0) {
473 for (k
= 0; k
< zptr
->z_nscount
; k
++)
474 if (zptr
->z_ns
[k
].nsaddr1
.s_addr
== 0) {
476 dname
= zptr
->z_ns
[k
].nsname
;
483 _res
.options
|= RES_DEBUG
;
484 for (zptr
= zgrp_start
; zptr
; zptr
= zptr
->z_next
) {
486 /* append zone section */
487 rrecp
= res_mkupdrec(ns_s_zn
, zptr
->z_origin
,
488 zptr
->z_class
, ns_t_soa
, 0);
490 fprintf(stderr
, "saverrec error\n");
494 rrecp
->r_grpnext
= zptr
->z_rr
;
497 n
= res_mkupdate(zptr
->z_rr
, packet
, sizeof packet
);
499 fprintf(stderr
, "res_mkupdate error\n");
503 fprintf(stdout
, "res_mkupdate: packet size = %d\n", n
);
506 * Override the list of NS records from res_init() with
507 * the authoritative nameservers for the zone being updated.
508 * Sort primary to be the first in the list of nameservers.
510 for (i
= 0; i
< zptr
->z_nscount
; i
++) {
511 if (strcasecmp(zptr
->z_ns
[i
].nsname
,
512 zptr
->z_soardata
) == 0) {
513 struct in_addr tmpaddr
;
516 strcpy(zptr
->z_ns
[i
].nsname
,
517 zptr
->z_ns
[0].nsname
);
518 strcpy(zptr
->z_ns
[0].nsname
,
520 tmpaddr
= zptr
->z_ns
[i
].nsaddr1
;
521 zptr
->z_ns
[i
].nsaddr1
=
522 zptr
->z_ns
[0].nsaddr1
;
523 zptr
->z_ns
[0].nsaddr1
= tmpaddr
;
528 for (i
= 0; i
< MAXNS
; i
++) {
529 _res
.nsaddr_list
[i
].sin_addr
= zptr
->z_ns
[i
].nsaddr1
;
530 _res
.nsaddr_list
[i
].sin_family
= AF_INET
;
531 _res
.nsaddr_list
[i
].sin_port
= htons(NAMESERVER_PORT
);
533 _res
.nscount
= (zptr
->z_nscount
< MAXNS
) ?
534 zptr
->z_nscount
: MAXNS
;
535 n
= res_send(packet
, n
, answer
, sizeof(answer
));
537 fprintf(stderr
, "res_send: send error, n=%d\n", n
);
543 /* free malloc'ed memory */
546 zgrp_start
= zgrp_start
->z_next
;
547 res_freeupdrec(zptr
->z_rr
); /* Zone section we allocated. */