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