]>
git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/res_update.c
2 Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
3 This program and the accompanying materials are licensed and made available
4 under the terms and conditions of the BSD License which accompanies this
5 distribution. The full text of the license may be found at
6 http://opensource.org/licenses/bsd-license.php.
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 * Copyright (c) 1996 by Internet Software Consortium.
14 * Permission to use, copy, modify, and distribute this software for any
15 * purpose with or without fee is hereby granted, provided that the above
16 * copyright notice and this permission notice appear in all copies.
18 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
19 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
21 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
22 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
23 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
24 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29 * Portions copyright (c) 1999, 2000
31 * All rights reserved.
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
47 * This product includes software developed by Intel Corporation and
50 * 4. Neither the name of Intel Corporation or its contributors may be
51 * used to endorse or promote products derived from this software
52 * without specific prior written permission.
54 * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
55 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
57 * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
58 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
59 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
60 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
61 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
62 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
63 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
64 * THE POSSIBILITY OF SUCH DAMAGE.
69 * Based on the Dynamic DNS reference implementation by Viraj Bais
70 * <viraj_bais@ccm.fm.intel.com>
73 #include <sys/param.h>
74 #include <sys/socket.h>
76 #include <netinet/in.h>
77 #include <arpa/inet.h>
78 #include <arpa/nameser.h>
88 * Separate a linked list of records into groups so that all records
89 * in a group will belong to a single zone on the nameserver.
90 * Create a dynamic update packet for each zone and send it to the
91 * nameservers for that zone, and await answer.
92 * Abort if error occurs in updating any zone.
93 * Return the number of zones updated on success, < 0 on error.
95 * On error, caller must deal with the unsynchronized zones
96 * eg. an A record might have been successfully added to the forward
97 * zone but the corresponding PTR record would be missing if error
98 * was encountered while updating the reverse zone.
104 char nsname
[MAXDNAME
];
105 struct in_addr nsaddr1
;
109 char z_origin
[MAXDNAME
];
111 char z_soardata
[MAXDNAME
+ 5 * INT32SZ
];
112 struct ns1 z_ns
[NSMAX
];
115 struct zonegrp
*z_next
;
120 res_update(ns_updrec
*rrecp_in
) {
121 ns_updrec
*rrecp
, *tmprrecp
;
122 u_char buf
[PACKETSZ
], answer
[PACKETSZ
], packet
[2*PACKETSZ
];
123 char name
[MAXDNAME
], zname
[MAXDNAME
], primary
[MAXDNAME
],
125 u_char soardata
[2*MAXCDNAME
+5*INT32SZ
];
126 char *dname
, *svdname
, *cp1
, *target
;
128 HEADER
*hp
= (HEADER
*) answer
;
129 struct zonegrp
*zptr
= NULL
, *tmpzptr
, *prevzptr
, *zgrp_start
= NULL
;
130 int i
, j
, k
= 0, n
, ancount
, nscount
, arcount
, rcode
, rdatasize
,
131 newgroup
, done
, myzone
, seen_before
, numzones
= 0;
132 u_int16_t dlen
, class, qclass
, type
, qtype
;
135 if ((_res
.options
& RES_INIT
) == 0 && res_init() == -1) {
136 h_errno
= NETDB_INTERNAL
;
140 for (rrecp
= rrecp_in
; rrecp
; rrecp
= rrecp
->r_next
) {
141 dname
= rrecp
->r_dname
;
142 n
= (int)strlen(dname
);
143 if (dname
[n
-1] == '.')
146 qclass
= rrecp
->r_class
;
150 while (!done
&& dname
) {
151 if (qtype
== T_SOA
) {
152 for (tmpzptr
= zgrp_start
;
153 tmpzptr
&& !seen_before
;
154 tmpzptr
= tmpzptr
->z_next
) {
155 if (strcasecmp(dname
,
156 tmpzptr
->z_origin
) == 0 &&
157 tmpzptr
->z_class
== qclass
)
159 for (tmprrecp
= tmpzptr
->z_rr
;
160 tmprrecp
&& !seen_before
;
161 tmprrecp
= tmprrecp
->r_grpnext
)
162 if (strcasecmp(dname
, tmprrecp
->r_dname
) == 0
163 && tmprrecp
->r_class
== qclass
) {
169 * Append to the end of
172 for (tmprrecp
= tmpzptr
->z_rr
;
174 tmprrecp
= tmprrecp
->r_grpnext
)
176 tmprrecp
->r_grpnext
= rrecp
;
177 rrecp
->r_grpnext
= NULL
;
182 } else if (qtype
== T_A
) {
183 for (tmpzptr
= zgrp_start
;
185 tmpzptr
= tmpzptr
->z_next
)
186 for (i
= 0; i
< tmpzptr
->z_nscount
; i
++)
187 if (tmpzptr
->z_class
== qclass
&&
188 strcasecmp(tmpzptr
->z_ns
[i
].nsname
,
190 tmpzptr
->z_ns
[i
].nsaddr1
.s_addr
!= 0) {
191 zptr
->z_ns
[k
].nsaddr1
.s_addr
=
192 tmpzptr
->z_ns
[i
].nsaddr1
.s_addr
;
199 n
= res_mkquery(QUERY
, dname
, qclass
, qtype
, NULL
,
200 0, NULL
, buf
, sizeof buf
);
202 fprintf(stderr
, "res_update: mkquery failed\n");
205 n
= res_send(buf
, n
, answer
, sizeof answer
);
207 fprintf(stderr
, "res_update: send error for %s\n",
213 ancount
= ntohs(hp
->ancount
);
214 nscount
= ntohs(hp
->nscount
);
215 arcount
= ntohs(hp
->arcount
);
217 cp
= answer
+ HFIXEDSZ
;
219 /* skip the question section */
220 n
= dn_skipname(cp
, eom
);
221 if (n
< 0 || cp
+ n
+ 2 * INT16SZ
> eom
)
223 cp
+= n
+ 2 * INT16SZ
;
225 if (qtype
== T_SOA
) {
226 if (ancount
== 0 && nscount
== 0 && arcount
== 0) {
228 * if (rcode == NOERROR) then the dname exists but
229 * has no soa record associated with it.
230 * if (rcode == NXDOMAIN) then the dname does not
231 * exist and the server is replying out of NCACHE.
232 * in either case, proceed with the next try
234 dname
= strchr(dname
, '.');
238 } else if ((rcode
== NOERROR
|| rcode
== NXDOMAIN
) &&
240 nscount
== 1 && arcount
== 0) {
242 * name/data does not exist, soa record supplied in the
245 /* authority section must contain the soa record */
246 if ((n
= dn_expand(answer
, eom
, cp
, zname
,
250 if (cp
+ 2 * INT16SZ
> eom
)
254 if (type
!= T_SOA
|| class != qclass
) {
255 fprintf(stderr
, "unknown answer\n");
261 if (strcasecmp(dname
, zname
) == 0) {
264 } else if ((dname
= strchr(dname
, '.')) != NULL
)
267 dname
= strchr(svdname
, '.');
274 } else if (rcode
== NOERROR
&& ancount
== 1) {
276 * found the zone name
277 * new servers will supply NS records for the zone
278 * in authority section and A records for those
279 * nameservers in the additional section
280 * older servers have to be explicitly queried for
281 * NS records for the zone
283 /* answer section must contain the soa record */
284 if ((n
= dn_expand(answer
, eom
, cp
, zname
,
289 if (cp
+ 2 * INT16SZ
> eom
)
293 if (type
== T_CNAME
) {
294 dname
= strchr(dname
, '.');
299 if (strcasecmp(dname
, zname
) != 0 ||
301 class != rrecp
->r_class
) {
302 fprintf(stderr
, "unknown answer\n");
308 "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
309 ancount
, nscount
, arcount
, hp
->rcode
);
312 if (cp
+ INT32SZ
+ INT16SZ
> eom
)
314 /* continue processing the soa record */
323 if (strcasecmp(zname
, zptr
->z_origin
) == 0 &&
324 type
== T_SOA
&& class == qclass
) {
332 for (tmprrecp
= zptr
->z_rr
;
334 tmprrecp
= tmprrecp
->r_grpnext
)
336 tmprrecp
->r_grpnext
= rrecp
;
337 rrecp
->r_grpnext
= NULL
;
342 if ((n
= dn_expand(answer
, eom
, cp
, primary
,
343 sizeof primary
)) < 0)
347 * We don't have to bounds check here because the
348 * next use of 'cp' is in dn_expand().
350 cp1
= (char *)soardata
;
351 strcpy(cp1
, primary
);
352 cp1
+= strlen(cp1
) + 1;
353 if ((n
= dn_expand(answer
, eom
, cp
, mailaddr
,
354 sizeof mailaddr
)) < 0)
357 strcpy(cp1
, mailaddr
);
358 cp1
+= strlen(cp1
) + 1;
359 if (cp
+ 5*INT32SZ
> eom
)
361 memcpy(cp1
, cp
, 5*INT32SZ
);
364 rdatasize
= (int)((u_char
*)cp1
- soardata
);
365 zptr
= calloc(1, sizeof(struct zonegrp
));
368 if (zgrp_start
== NULL
)
371 prevzptr
->z_next
= zptr
;
373 rrecp
->r_grpnext
= NULL
;
374 strcpy(zptr
->z_origin
, zname
);
375 zptr
->z_class
= class;
376 memcpy(zptr
->z_soardata
, soardata
, rdatasize
);
377 /* fallthrough to process NS and A records */
379 } else if (qtype
== T_NS
) {
380 if (rcode
== NOERROR
&& ancount
> 0) {
381 strcpy(zname
, dname
);
382 for (zptr
= zgrp_start
; zptr
; zptr
= zptr
->z_next
) {
383 if (strcasecmp(zname
, zptr
->z_origin
) == 0)
387 /* should not happen */
391 * answer and authority sections contain
392 * the same information, skip answer section
394 for (j
= 0; j
< ancount
; j
++) {
395 n
= dn_skipname(cp
, eom
);
398 n
+= 2*INT16SZ
+ INT32SZ
;
399 if (cp
+ n
+ INT16SZ
> eom
)
407 /* fallthrough to process NS and A records */
409 fprintf(stderr
, "cannot determine nameservers for %s:\
410 ans=%d, auth=%d, add=%d, rcode=%d\n",
411 dname
, ancount
, nscount
, arcount
, hp
->rcode
);
414 } else if (qtype
== T_A
) {
415 if (rcode
== NOERROR
&& ancount
> 0) {
417 ancount
= nscount
= 0;
418 /* fallthrough to process A records */
420 fprintf(stderr
, "cannot determine address for %s:\
421 ans=%d, auth=%d, add=%d, rcode=%d\n",
422 dname
, ancount
, nscount
, arcount
, hp
->rcode
);
426 /* process NS records for the zone */
428 for (i
= 0; i
< nscount
; i
++) {
429 if ((n
= dn_expand(answer
, eom
, cp
, name
,
433 if (cp
+ 3 * INT16SZ
+ INT32SZ
> eom
)
441 if (strcasecmp(name
, zname
) == 0 &&
442 type
== T_NS
&& class == qclass
) {
443 if ((n
= dn_expand(answer
, eom
, cp
,
444 name
, sizeof name
)) < 0)
446 target
= zptr
->z_ns
[j
++].nsname
;
447 strcpy(target
, name
);
451 if (zptr
->z_nscount
== 0)
453 /* get addresses for the nameservers */
454 for (i
= 0; i
< arcount
; i
++) {
455 if ((n
= dn_expand(answer
, eom
, cp
, name
,
459 if (cp
+ 3 * INT16SZ
+ INT32SZ
> eom
)
467 if (type
== T_A
&& dlen
== INT32SZ
&& class == qclass
) {
468 for (j
= 0; j
< zptr
->z_nscount
; j
++)
469 if (strcasecmp(name
, zptr
->z_ns
[j
].nsname
) == 0) {
470 memcpy(&zptr
->z_ns
[j
].nsaddr1
.s_addr
, cp
,
477 if (zptr
->z_nscount
== 0) {
483 for (k
= 0; k
< zptr
->z_nscount
; k
++)
484 if (zptr
->z_ns
[k
].nsaddr1
.s_addr
== 0) {
486 dname
= zptr
->z_ns
[k
].nsname
;
491 --ttl
; // Suppress the "Set but not used" warning/error for ttl.
493 _res
.options
|= RES_DEBUG
;
494 for (zptr
= zgrp_start
; zptr
; zptr
= zptr
->z_next
) {
496 /* append zone section */
497 rrecp
= res_mkupdrec(ns_s_zn
, zptr
->z_origin
,
498 zptr
->z_class
, ns_t_soa
, 0);
500 fprintf(stderr
, "saverrec error\n");
504 rrecp
->r_grpnext
= zptr
->z_rr
;
507 n
= res_mkupdate(zptr
->z_rr
, packet
, sizeof packet
);
509 fprintf(stderr
, "res_mkupdate error\n");
513 fprintf(stdout
, "res_mkupdate: packet size = %d\n", n
);
515 /* Override the list of NS records from res_init() with
516 * the authoritative nameservers for the zone being updated.
517 * Sort primary to be the first in the list of nameservers.
519 for (i
= 0; i
< zptr
->z_nscount
; i
++) {
520 if (strcasecmp(zptr
->z_ns
[i
].nsname
,
521 zptr
->z_soardata
) == 0) {
522 struct in_addr tmpaddr
;
525 strcpy(zptr
->z_ns
[i
].nsname
,
526 zptr
->z_ns
[0].nsname
);
527 strcpy(zptr
->z_ns
[0].nsname
,
529 tmpaddr
= zptr
->z_ns
[i
].nsaddr1
;
530 zptr
->z_ns
[i
].nsaddr1
=
531 zptr
->z_ns
[0].nsaddr1
;
532 zptr
->z_ns
[0].nsaddr1
= tmpaddr
;
537 for (i
= 0; i
< MAXNS
; i
++) {
538 _res
.nsaddr_list
[i
].sin_addr
= zptr
->z_ns
[i
].nsaddr1
;
539 _res
.nsaddr_list
[i
].sin_family
= AF_INET
;
540 _res
.nsaddr_list
[i
].sin_port
= htons(NAMESERVER_PORT
);
542 _res
.nscount
= (zptr
->z_nscount
< MAXNS
) ?
543 zptr
->z_nscount
: MAXNS
;
544 n
= res_send(packet
, n
, answer
, sizeof(answer
));
546 fprintf(stderr
, "res_send: send error, n=%d\n", n
);
552 /* free malloc'ed memory */
555 zgrp_start
= zgrp_start
->z_next
;
556 res_freeupdrec(zptr
->z_rr
); /* Zone section we allocated. */