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