]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/res_update.c
Add missing IPv6 address definitions.
[mirror_edk2.git] / StdLib / BsdSocketLib / res_update.c
1 /*
2 * Copyright (c) 1996 by Internet Software Consortium.
3 *
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.
7 *
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
15 * SOFTWARE.
16 */
17
18 /*
19 * Portions copyright (c) 1999, 2000
20 * Intel Corporation.
21 * All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 *
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 *
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.
33 *
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 *
37 * This product includes software developed by Intel Corporation and
38 * its contributors.
39 *
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.
43 *
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.
55 *
56 */
57
58 /*
59 * Based on the Dynamic DNS reference implementation by Viraj Bais
60 * <viraj_bais@ccm.fm.intel.com>
61 */
62
63 #include <sys/param.h>
64 #include <sys/socket.h>
65 #include <sys/time.h>
66 #include <netinet/in.h>
67 #include <arpa/inet.h>
68 #include <arpa/nameser.h>
69 #include <errno.h>
70 #include <limits.h>
71 #include <netdb.h>
72 #include <resolv.h>
73 #include <stdio.h>
74 #include <stdlib.h>
75 #include <string.h>
76
77 /*
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.
84 *
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.
89 */
90
91 #define NSMAX 16
92
93 struct ns1 {
94 char nsname[MAXDNAME];
95 struct in_addr nsaddr1;
96 };
97
98 struct zonegrp {
99 char z_origin[MAXDNAME];
100 int16_t z_class;
101 char z_soardata[MAXDNAME + 5 * INT32SZ];
102 struct ns1 z_ns[NSMAX];
103 int z_nscount;
104 ns_updrec * z_rr;
105 struct zonegrp *z_next;
106 };
107
108
109 int
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],
114 mailaddr[MAXDNAME];
115 u_char soardata[2*MAXCDNAME+5*INT32SZ];
116 char *dname, *svdname, *cp1, *target;
117 u_char *cp, *eom;
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;
123 u_int32_t ttl;
124
125 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
126 h_errno = NETDB_INTERNAL;
127 return (-1);
128 }
129
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] == '.')
134 dname[n-1] = '\0';
135 qtype = T_SOA;
136 qclass = rrecp->r_class;
137 done = 0;
138 seen_before = 0;
139
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)
148 seen_before++;
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) {
154 seen_before++;
155 break;
156 }
157 if (seen_before) {
158 /*
159 * Append to the end of
160 * current group.
161 */
162 for (tmprrecp = tmpzptr->z_rr;
163 tmprrecp->r_grpnext;
164 tmprrecp = tmprrecp->r_grpnext)
165 (void)NULL;
166 tmprrecp->r_grpnext = rrecp;
167 rrecp->r_grpnext = NULL;
168 done = 1;
169 break;
170 }
171 }
172 } else if (qtype == T_A) {
173 for (tmpzptr = zgrp_start;
174 tmpzptr && !done;
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,
179 dname) == 0 &&
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;
183 done = 1;
184 break;
185 }
186 }
187 if (done)
188 break;
189 n = res_mkquery(QUERY, dname, qclass, qtype, NULL,
190 0, NULL, buf, sizeof buf);
191 if (n <= 0) {
192 fprintf(stderr, "res_update: mkquery failed\n");
193 return (n);
194 }
195 n = res_send(buf, n, answer, sizeof answer);
196 if (n < 0) {
197 fprintf(stderr, "res_update: send error for %s\n",
198 rrecp->r_dname);
199 return (n);
200 }
201 if (n < HFIXEDSZ)
202 return (-1);
203 ancount = ntohs(hp->ancount);
204 nscount = ntohs(hp->nscount);
205 arcount = ntohs(hp->arcount);
206 rcode = hp->rcode;
207 cp = answer + HFIXEDSZ;
208 eom = answer + n;
209 /* skip the question section */
210 n = dn_skipname(cp, eom);
211 if (n < 0 || cp + n + 2 * INT16SZ > eom)
212 return (-1);
213 cp += n + 2 * INT16SZ;
214
215 if (qtype == T_SOA) {
216 if (ancount == 0 && nscount == 0 && arcount == 0) {
217 /*
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
223 */
224 dname = strchr(dname, '.');
225 if (dname != NULL)
226 dname++;
227 continue;
228 } else if ((rcode == NOERROR || rcode == NXDOMAIN) &&
229 ancount == 0 &&
230 nscount == 1 && arcount == 0) {
231 /*
232 * name/data does not exist, soa record supplied in the
233 * authority section
234 */
235 /* authority section must contain the soa record */
236 if ((n = dn_expand(answer, eom, cp, zname,
237 sizeof zname)) < 0)
238 return (n);
239 cp += n;
240 if (cp + 2 * INT16SZ > eom)
241 return (-1);
242 GETSHORT(type, cp);
243 GETSHORT(class, cp);
244 if (type != T_SOA || class != qclass) {
245 fprintf(stderr, "unknown answer\n");
246 return (-1);
247 }
248 myzone = 0;
249 svdname = dname;
250 while (dname)
251 if (strcasecmp(dname, zname) == 0) {
252 myzone = 1;
253 break;
254 } else if ((dname = strchr(dname, '.')) != NULL)
255 dname++;
256 if (!myzone) {
257 dname = strchr(svdname, '.');
258 if (dname != NULL)
259 dname++;
260 continue;
261 }
262 nscount = 0;
263 /* fallthrough */
264 } else if (rcode == NOERROR && ancount == 1) {
265 /*
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
272 */
273 /* answer section must contain the soa record */
274 if ((n = dn_expand(answer, eom, cp, zname,
275 sizeof zname)) < 0)
276 return (n);
277 else
278 cp += n;
279 if (cp + 2 * INT16SZ > eom)
280 return (-1);
281 GETSHORT(type, cp);
282 GETSHORT(class, cp);
283 if (type == T_CNAME) {
284 dname = strchr(dname, '.');
285 if (dname != NULL)
286 dname++;
287 continue;
288 }
289 if (strcasecmp(dname, zname) != 0 ||
290 type != T_SOA ||
291 class != rrecp->r_class) {
292 fprintf(stderr, "unknown answer\n");
293 return (-1);
294 }
295 /* FALLTHROUGH */
296 } else {
297 fprintf(stderr,
298 "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
299 ancount, nscount, arcount, hp->rcode);
300 return (-1);
301 }
302 if (cp + INT32SZ + INT16SZ > eom)
303 return (-1);
304 /* continue processing the soa record */
305 GETLONG(ttl, cp);
306 GETSHORT(dlen, cp);
307 if (cp + dlen > eom)
308 return (-1);
309 newgroup = 1;
310 zptr = zgrp_start;
311 prevzptr = NULL;
312 while (zptr) {
313 if (strcasecmp(zname, zptr->z_origin) == 0 &&
314 type == T_SOA && class == qclass) {
315 newgroup = 0;
316 break;
317 }
318 prevzptr = zptr;
319 zptr = zptr->z_next;
320 }
321 if (!newgroup) {
322 for (tmprrecp = zptr->z_rr;
323 tmprrecp->r_grpnext;
324 tmprrecp = tmprrecp->r_grpnext)
325 ;
326 tmprrecp->r_grpnext = rrecp;
327 rrecp->r_grpnext = NULL;
328 done = 1;
329 cp += dlen;
330 break;
331 } else {
332 if ((n = dn_expand(answer, eom, cp, primary,
333 sizeof primary)) < 0)
334 return (n);
335 cp += n;
336 /*
337 * We don't have to bounds check here because the
338 * next use of 'cp' is in dn_expand().
339 */
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)
345 return (n);
346 cp += n;
347 strcpy(cp1, mailaddr);
348 cp1 += strlen(cp1) + 1;
349 if (cp + 5*INT32SZ > eom)
350 return (-1);
351 memcpy(cp1, cp, 5*INT32SZ);
352 cp += 5*INT32SZ;
353 cp1 += 5*INT32SZ;
354 rdatasize = (int)((u_char *)cp1 - soardata);
355 zptr = calloc(1, sizeof(struct zonegrp));
356 if (zptr == NULL)
357 return (-1);
358 if (zgrp_start == NULL)
359 zgrp_start = zptr;
360 else
361 prevzptr->z_next = zptr;
362 zptr->z_rr = rrecp;
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 */
368 }
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)
374 break;
375 }
376 if (zptr == NULL)
377 /* should not happen */
378 return (-1);
379 if (nscount > 0) {
380 /*
381 * answer and authority sections contain
382 * the same information, skip answer section
383 */
384 for (j = 0; j < ancount; j++) {
385 n = dn_skipname(cp, eom);
386 if (n < 0)
387 return (-1);
388 n += 2*INT16SZ + INT32SZ;
389 if (cp + n + INT16SZ > eom)
390 return (-1);
391 cp += n;
392 GETSHORT(dlen, cp);
393 cp += dlen;
394 }
395 } else
396 nscount = ancount;
397 /* fallthrough to process NS and A records */
398 } else {
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);
402 return (-1);
403 }
404 } else if (qtype == T_A) {
405 if (rcode == NOERROR && ancount > 0) {
406 arcount = ancount;
407 ancount = nscount = 0;
408 /* fallthrough to process A records */
409 } else {
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);
413 return (-1);
414 }
415 }
416 /* process NS records for the zone */
417 j = 0;
418 for (i = 0; i < nscount; i++) {
419 if ((n = dn_expand(answer, eom, cp, name,
420 sizeof name)) < 0)
421 return (n);
422 cp += n;
423 if (cp + 3 * INT16SZ + INT32SZ > eom)
424 return (-1);
425 GETSHORT(type, cp);
426 GETSHORT(class, cp);
427 GETLONG(ttl, cp);
428 GETSHORT(dlen, cp);
429 if (cp + dlen > eom)
430 return (-1);
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)
435 return (n);
436 target = zptr->z_ns[j++].nsname;
437 strcpy(target, name);
438 }
439 cp += dlen;
440 }
441 if (zptr->z_nscount == 0)
442 zptr->z_nscount = j;
443 /* get addresses for the nameservers */
444 for (i = 0; i < arcount; i++) {
445 if ((n = dn_expand(answer, eom, cp, name,
446 sizeof name)) < 0)
447 return (n);
448 cp += n;
449 if (cp + 3 * INT16SZ + INT32SZ > eom)
450 return (-1);
451 GETSHORT(type, cp);
452 GETSHORT(class, cp);
453 GETLONG(ttl, cp);
454 GETSHORT(dlen, cp);
455 if (cp + dlen > eom)
456 return (-1);
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,
461 INT32SZ);
462 break;
463 }
464 }
465 cp += dlen;
466 }
467 if (zptr->z_nscount == 0) {
468 dname = zname;
469 qtype = T_NS;
470 continue;
471 }
472 done = 1;
473 for (k = 0; k < zptr->z_nscount; k++)
474 if (zptr->z_ns[k].nsaddr1.s_addr == 0) {
475 done = 0;
476 dname = zptr->z_ns[k].nsname;
477 qtype = T_A;
478 }
479
480 } /* while */
481 }
482
483 _res.options |= RES_DEBUG;
484 for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
485
486 /* append zone section */
487 rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
488 zptr->z_class, ns_t_soa, 0);
489 if (rrecp == NULL) {
490 fprintf(stderr, "saverrec error\n");
491 fflush(stderr);
492 return (-1);
493 }
494 rrecp->r_grpnext = zptr->z_rr;
495 zptr->z_rr = rrecp;
496
497 n = res_mkupdate(zptr->z_rr, packet, sizeof packet);
498 if (n < 0) {
499 fprintf(stderr, "res_mkupdate error\n");
500 fflush(stderr);
501 return (-1);
502 } else
503 fprintf(stdout, "res_mkupdate: packet size = %d\n", n);
504
505 /*
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.
509 */
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;
514
515 if (i != 0) {
516 strcpy(zptr->z_ns[i].nsname,
517 zptr->z_ns[0].nsname);
518 strcpy(zptr->z_ns[0].nsname,
519 zptr->z_soardata);
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;
524 }
525 break;
526 }
527 }
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);
532 }
533 _res.nscount = (zptr->z_nscount < MAXNS) ?
534 zptr->z_nscount : MAXNS;
535 n = res_send(packet, n, answer, sizeof(answer));
536 if (n < 0) {
537 fprintf(stderr, "res_send: send error, n=%d\n", n);
538 break;
539 } else
540 numzones++;
541 }
542
543 /* free malloc'ed memory */
544 while(zgrp_start) {
545 zptr = zgrp_start;
546 zgrp_start = zgrp_start->z_next;
547 res_freeupdrec(zptr->z_rr); /* Zone section we allocated. */
548 free((char *)zptr);
549 }
550
551 return (numzones);
552 }