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