]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/res_update.c
IntelFsp2WrapperPkg: Update gFspWrapperTokenSpaceGuid to gIntelFsp2WrapperTokenSpaceGuid.
[mirror_edk2.git] / StdLib / BsdSocketLib / res_update.c
1 /** @file
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.
7
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.
10 **/
11 /*
12 * Copyright (c) 1996 by Internet Software Consortium.
13 *
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.
17 *
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
25 * SOFTWARE.
26 */
27
28 /*
29 * Portions copyright (c) 1999, 2000
30 * Intel Corporation.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 *
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 *
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.
43 *
44 * 3. All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 *
47 * This product includes software developed by Intel Corporation and
48 * its contributors.
49 *
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.
53 *
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.
65 *
66 */
67
68 /*
69 * Based on the Dynamic DNS reference implementation by Viraj Bais
70 * <viraj_bais@ccm.fm.intel.com>
71 */
72
73 #include <sys/param.h>
74 #include <sys/socket.h>
75 #include <sys/time.h>
76 #include <netinet/in.h>
77 #include <arpa/inet.h>
78 #include <arpa/nameser.h>
79 #include <errno.h>
80 #include <limits.h>
81 #include <netdb.h>
82 #include <resolv.h>
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86
87 /*
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.
94 *
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.
99 */
100
101 #define NSMAX 16
102
103 struct ns1 {
104 char nsname[MAXDNAME];
105 struct in_addr nsaddr1;
106 };
107
108 struct zonegrp {
109 char z_origin[MAXDNAME];
110 int16_t z_class;
111 char z_soardata[MAXDNAME + 5 * INT32SZ];
112 struct ns1 z_ns[NSMAX];
113 int z_nscount;
114 ns_updrec * z_rr;
115 struct zonegrp *z_next;
116 };
117
118
119 int
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],
124 mailaddr[MAXDNAME];
125 u_char soardata[2*MAXCDNAME+5*INT32SZ];
126 char *dname, *svdname, *cp1, *target;
127 u_char *cp, *eom;
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;
133 u_int32_t ttl;
134
135 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
136 h_errno = NETDB_INTERNAL;
137 return (-1);
138 }
139
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] == '.')
144 dname[n-1] = '\0';
145 qtype = T_SOA;
146 qclass = rrecp->r_class;
147 done = 0;
148 seen_before = 0;
149
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)
158 seen_before++;
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) {
164 seen_before++;
165 break;
166 }
167 if (seen_before) {
168 /*
169 * Append to the end of
170 * current group.
171 */
172 for (tmprrecp = tmpzptr->z_rr;
173 tmprrecp->r_grpnext;
174 tmprrecp = tmprrecp->r_grpnext)
175 (void)NULL;
176 tmprrecp->r_grpnext = rrecp;
177 rrecp->r_grpnext = NULL;
178 done = 1;
179 break;
180 }
181 }
182 } else if (qtype == T_A) {
183 for (tmpzptr = zgrp_start;
184 tmpzptr && !done;
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,
189 dname) == 0 &&
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;
193 done = 1;
194 break;
195 }
196 }
197 if (done)
198 break;
199 n = res_mkquery(QUERY, dname, qclass, qtype, NULL,
200 0, NULL, buf, sizeof buf);
201 if (n <= 0) {
202 fprintf(stderr, "res_update: mkquery failed\n");
203 return (n);
204 }
205 n = res_send(buf, n, answer, sizeof answer);
206 if (n < 0) {
207 fprintf(stderr, "res_update: send error for %s\n",
208 rrecp->r_dname);
209 return (n);
210 }
211 if (n < HFIXEDSZ)
212 return (-1);
213 ancount = ntohs(hp->ancount);
214 nscount = ntohs(hp->nscount);
215 arcount = ntohs(hp->arcount);
216 rcode = hp->rcode;
217 cp = answer + HFIXEDSZ;
218 eom = answer + n;
219 /* skip the question section */
220 n = dn_skipname(cp, eom);
221 if (n < 0 || cp + n + 2 * INT16SZ > eom)
222 return (-1);
223 cp += n + 2 * INT16SZ;
224
225 if (qtype == T_SOA) {
226 if (ancount == 0 && nscount == 0 && arcount == 0) {
227 /*
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
233 */
234 dname = strchr(dname, '.');
235 if (dname != NULL)
236 dname++;
237 continue;
238 } else if ((rcode == NOERROR || rcode == NXDOMAIN) &&
239 ancount == 0 &&
240 nscount == 1 && arcount == 0) {
241 /*
242 * name/data does not exist, soa record supplied in the
243 * authority section
244 */
245 /* authority section must contain the soa record */
246 if ((n = dn_expand(answer, eom, cp, zname,
247 sizeof zname)) < 0)
248 return (n);
249 cp += n;
250 if (cp + 2 * INT16SZ > eom)
251 return (-1);
252 GETSHORT(type, cp);
253 GETSHORT(class, cp);
254 if (type != T_SOA || class != qclass) {
255 fprintf(stderr, "unknown answer\n");
256 return (-1);
257 }
258 myzone = 0;
259 svdname = dname;
260 while (dname)
261 if (strcasecmp(dname, zname) == 0) {
262 myzone = 1;
263 break;
264 } else if ((dname = strchr(dname, '.')) != NULL)
265 dname++;
266 if (!myzone) {
267 dname = strchr(svdname, '.');
268 if (dname != NULL)
269 dname++;
270 continue;
271 }
272 nscount = 0;
273 /* fallthrough */
274 } else if (rcode == NOERROR && ancount == 1) {
275 /*
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
282 */
283 /* answer section must contain the soa record */
284 if ((n = dn_expand(answer, eom, cp, zname,
285 sizeof zname)) < 0)
286 return (n);
287 else
288 cp += n;
289 if (cp + 2 * INT16SZ > eom)
290 return (-1);
291 GETSHORT(type, cp);
292 GETSHORT(class, cp);
293 if (type == T_CNAME) {
294 dname = strchr(dname, '.');
295 if (dname != NULL)
296 dname++;
297 continue;
298 }
299 if (strcasecmp(dname, zname) != 0 ||
300 type != T_SOA ||
301 class != rrecp->r_class) {
302 fprintf(stderr, "unknown answer\n");
303 return (-1);
304 }
305 /* FALLTHROUGH */
306 } else {
307 fprintf(stderr,
308 "unknown response: ans=%d, auth=%d, add=%d, rcode=%d\n",
309 ancount, nscount, arcount, hp->rcode);
310 return (-1);
311 }
312 if (cp + INT32SZ + INT16SZ > eom)
313 return (-1);
314 /* continue processing the soa record */
315 GETLONG(ttl, cp);
316 GETSHORT(dlen, cp);
317 if (cp + dlen > eom)
318 return (-1);
319 newgroup = 1;
320 zptr = zgrp_start;
321 prevzptr = NULL;
322 while (zptr) {
323 if (strcasecmp(zname, zptr->z_origin) == 0 &&
324 type == T_SOA && class == qclass) {
325 newgroup = 0;
326 break;
327 }
328 prevzptr = zptr;
329 zptr = zptr->z_next;
330 }
331 if (!newgroup) {
332 for (tmprrecp = zptr->z_rr;
333 tmprrecp->r_grpnext;
334 tmprrecp = tmprrecp->r_grpnext)
335 ;
336 tmprrecp->r_grpnext = rrecp;
337 rrecp->r_grpnext = NULL;
338 done = 1;
339 cp += dlen;
340 break;
341 } else {
342 if ((n = dn_expand(answer, eom, cp, primary,
343 sizeof primary)) < 0)
344 return (n);
345 cp += n;
346 /*
347 * We don't have to bounds check here because the
348 * next use of 'cp' is in dn_expand().
349 */
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)
355 return (n);
356 cp += n;
357 strcpy(cp1, mailaddr);
358 cp1 += strlen(cp1) + 1;
359 if (cp + 5*INT32SZ > eom)
360 return (-1);
361 memcpy(cp1, cp, 5*INT32SZ);
362 cp += 5*INT32SZ;
363 cp1 += 5*INT32SZ;
364 rdatasize = (int)((u_char *)cp1 - soardata);
365 zptr = calloc(1, sizeof(struct zonegrp));
366 if (zptr == NULL)
367 return (-1);
368 if (zgrp_start == NULL)
369 zgrp_start = zptr;
370 else
371 prevzptr->z_next = zptr;
372 zptr->z_rr = rrecp;
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 */
378 }
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)
384 break;
385 }
386 if (zptr == NULL)
387 /* should not happen */
388 return (-1);
389 if (nscount > 0) {
390 /*
391 * answer and authority sections contain
392 * the same information, skip answer section
393 */
394 for (j = 0; j < ancount; j++) {
395 n = dn_skipname(cp, eom);
396 if (n < 0)
397 return (-1);
398 n += 2*INT16SZ + INT32SZ;
399 if (cp + n + INT16SZ > eom)
400 return (-1);
401 cp += n;
402 GETSHORT(dlen, cp);
403 cp += dlen;
404 }
405 } else
406 nscount = ancount;
407 /* fallthrough to process NS and A records */
408 } else {
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);
412 return (-1);
413 }
414 } else if (qtype == T_A) {
415 if (rcode == NOERROR && ancount > 0) {
416 arcount = ancount;
417 ancount = nscount = 0;
418 /* fallthrough to process A records */
419 } else {
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);
423 return (-1);
424 }
425 }
426 /* process NS records for the zone */
427 j = 0;
428 for (i = 0; i < nscount; i++) {
429 if ((n = dn_expand(answer, eom, cp, name,
430 sizeof name)) < 0)
431 return (n);
432 cp += n;
433 if (cp + 3 * INT16SZ + INT32SZ > eom)
434 return (-1);
435 GETSHORT(type, cp);
436 GETSHORT(class, cp);
437 GETLONG(ttl, cp);
438 GETSHORT(dlen, cp);
439 if (cp + dlen > eom)
440 return (-1);
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)
445 return (n);
446 target = zptr->z_ns[j++].nsname;
447 strcpy(target, name);
448 }
449 cp += dlen;
450 }
451 if (zptr->z_nscount == 0)
452 zptr->z_nscount = j;
453 /* get addresses for the nameservers */
454 for (i = 0; i < arcount; i++) {
455 if ((n = dn_expand(answer, eom, cp, name,
456 sizeof name)) < 0)
457 return (n);
458 cp += n;
459 if (cp + 3 * INT16SZ + INT32SZ > eom)
460 return (-1);
461 GETSHORT(type, cp);
462 GETSHORT(class, cp);
463 GETLONG(ttl, cp);
464 GETSHORT(dlen, cp);
465 if (cp + dlen > eom)
466 return (-1);
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,
471 INT32SZ);
472 break;
473 }
474 }
475 cp += dlen;
476 }
477 if (zptr->z_nscount == 0) {
478 dname = zname;
479 qtype = T_NS;
480 continue;
481 }
482 done = 1;
483 for (k = 0; k < zptr->z_nscount; k++)
484 if (zptr->z_ns[k].nsaddr1.s_addr == 0) {
485 done = 0;
486 dname = zptr->z_ns[k].nsname;
487 qtype = T_A;
488 }
489 } /* while */
490 }
491 --ttl; // Suppress the "Set but not used" warning/error for ttl.
492
493 _res.options |= RES_DEBUG;
494 for (zptr = zgrp_start; zptr; zptr = zptr->z_next) {
495
496 /* append zone section */
497 rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
498 zptr->z_class, ns_t_soa, 0);
499 if (rrecp == NULL) {
500 fprintf(stderr, "saverrec error\n");
501 fflush(stderr);
502 return (-1);
503 }
504 rrecp->r_grpnext = zptr->z_rr;
505 zptr->z_rr = rrecp;
506
507 n = res_mkupdate(zptr->z_rr, packet, sizeof packet);
508 if (n < 0) {
509 fprintf(stderr, "res_mkupdate error\n");
510 fflush(stderr);
511 return (-1);
512 } else
513 fprintf(stdout, "res_mkupdate: packet size = %d\n", n);
514
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.
518 */
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;
523
524 if (i != 0) {
525 strcpy(zptr->z_ns[i].nsname,
526 zptr->z_ns[0].nsname);
527 strcpy(zptr->z_ns[0].nsname,
528 zptr->z_soardata);
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;
533 }
534 break;
535 }
536 }
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);
541 }
542 _res.nscount = (zptr->z_nscount < MAXNS) ?
543 zptr->z_nscount : MAXNS;
544 n = res_send(packet, n, answer, sizeof(answer));
545 if (n < 0) {
546 fprintf(stderr, "res_send: send error, n=%d\n", n);
547 break;
548 } else
549 numzones++;
550 }
551
552 /* free malloc'ed memory */
553 while(zgrp_start) {
554 zptr = zgrp_start;
555 zgrp_start = zgrp_start->z_next;
556 res_freeupdrec(zptr->z_rr); /* Zone section we allocated. */
557 free((char *)zptr);
558 }
559
560 return (numzones);
561 }