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