]> git.proxmox.com Git - mirror_edk2.git/blob - StdLib/BsdSocketLib/res_mkupdate.c
Fix a bug about the iSCSI DHCP dependency issue.
[mirror_edk2.git] / StdLib / BsdSocketLib / res_mkupdate.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/types.h>
64 #include <sys/param.h>
65
66 #include <netinet/in.h>
67 #include <arpa/nameser.h>
68 #include <arpa/inet.h>
69
70 #include <errno.h>
71 #include <limits.h>
72 #include <netdb.h>
73 #include <resolv.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 #include <unistd.h>
78 #include <ctype.h>
79
80 #include "res_config.h"
81
82 static int getnum_str(u_char **, u_char *);
83 static int getword_str(char *, int, u_char **, u_char *);
84
85 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
86
87 /*
88 * Form update packets.
89 * Returns the size of the resulting packet if no error
90 * On error,
91 * returns -1 if error in reading a word/number in rdata
92 * portion for update packets
93 * -2 if length of buffer passed is insufficient
94 * -3 if zone section is not the first section in
95 * the linked list, or section order has a problem
96 * -4 on a number overflow
97 * -5 unknown operation or no records
98 */
99 int
100 res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
101 ns_updrec *rrecp_start = rrecp_in;
102 HEADER *hp;
103 u_char *cp, *sp1, *sp2, *startp, *endp;
104 int n, i, soanum, multiline;
105 ns_updrec *rrecp;
106 struct in_addr ina;
107 char buf2[MAXDNAME];
108 int section, numrrs = 0, counts[ns_s_max];
109 u_int16_t rtype, rclass;
110 u_int32_t n1, rttl;
111 u_char *dnptrs[20], **dpp, **lastdnptr;
112
113 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
114 h_errno = NETDB_INTERNAL;
115 return (-1);
116 }
117
118 /*
119 * Initialize header fields.
120 */
121 if ((buf == NULL) || (buflen < HFIXEDSZ))
122 return (-1);
123 memset(buf, 0, HFIXEDSZ);
124 hp = (HEADER *) buf;
125 hp->id = htons(++_res.id);
126 hp->opcode = ns_o_update;
127 hp->rcode = NOERROR;
128 sp1 = buf + 2*INT16SZ; /* save pointer to zocount */
129 cp = buf + HFIXEDSZ;
130 buflen -= HFIXEDSZ;
131 dpp = dnptrs;
132 *dpp++ = buf;
133 *dpp++ = NULL;
134 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
135
136 if (rrecp_start == NULL)
137 return (-5);
138 else if (rrecp_start->r_section != S_ZONE)
139 return (-3);
140
141 memset(counts, 0, sizeof counts);
142 for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) {
143 numrrs++;
144 section = rrecp->r_section;
145 if (section < 0 || section >= ns_s_max)
146 return (-1);
147 counts[section]++;
148 for (i = section + 1; i < ns_s_max; i++)
149 if (counts[i])
150 return (-3);
151 rtype = rrecp->r_type;
152 rclass = rrecp->r_class;
153 rttl = rrecp->r_ttl;
154 /* overload class and type */
155 if (section == S_PREREQ) {
156 rttl = 0;
157 switch (rrecp->r_opcode) {
158 case YXDOMAIN:
159 rclass = C_ANY;
160 rtype = T_ANY;
161 rrecp->r_size = 0;
162 break;
163 case NXDOMAIN:
164 rclass = C_NONE;
165 rtype = T_ANY;
166 rrecp->r_size = 0;
167 break;
168 case NXRRSET:
169 rclass = C_NONE;
170 rrecp->r_size = 0;
171 break;
172 case YXRRSET:
173 if (rrecp->r_size == 0)
174 rclass = C_ANY;
175 break;
176 default:
177 fprintf(stderr,
178 "res_mkupdate: incorrect opcode: %d\n",
179 rrecp->r_opcode);
180 fflush(stderr);
181 return (-1);
182 }
183 } else if (section == S_UPDATE) {
184 switch (rrecp->r_opcode) {
185 case DELETE:
186 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
187 break;
188 case ADD:
189 break;
190 default:
191 fprintf(stderr,
192 "res_mkupdate: incorrect opcode: %d\n",
193 rrecp->r_opcode);
194 fflush(stderr);
195 return (-1);
196 }
197 }
198
199 /*
200 * XXX appending default domain to owner name is omitted,
201 * fqdn must be provided
202 */
203 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
204 lastdnptr)) < 0)
205 return (-1);
206 cp += n;
207 ShrinkBuffer(n + 2*INT16SZ);
208 PUTSHORT(rtype, cp);
209 PUTSHORT(rclass, cp);
210 if (section == S_ZONE) {
211 if (numrrs != 1 || rrecp->r_type != T_SOA)
212 return (-3);
213 continue;
214 }
215 ShrinkBuffer(INT32SZ + INT16SZ);
216 PUTLONG(rttl, cp);
217 sp2 = cp; /* save pointer to length byte */
218 cp += INT16SZ;
219 if (rrecp->r_size == 0) {
220 if (section == S_UPDATE && rclass != C_ANY)
221 return (-1);
222 else {
223 PUTSHORT(0, sp2);
224 continue;
225 }
226 }
227 startp = rrecp->r_data;
228 endp = startp + rrecp->r_size - 1;
229 /* XXX this should be done centrally. */
230 switch (rrecp->r_type) {
231 case T_A:
232 if (!getword_str(buf2, sizeof buf2, &startp, endp))
233 return (-1);
234 if (!inet_aton(buf2, &ina))
235 return (-1);
236 n1 = ntohl(ina.s_addr);
237 ShrinkBuffer(INT32SZ);
238 PUTLONG(n1, cp);
239 break;
240 case T_CNAME:
241 case T_MB:
242 case T_MG:
243 case T_MR:
244 case T_NS:
245 case T_PTR:
246 if (!getword_str(buf2, sizeof buf2, &startp, endp))
247 return (-1);
248 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
249 if (n < 0)
250 return (-1);
251 cp += n;
252 ShrinkBuffer(n);
253 break;
254 case T_MINFO:
255 case T_SOA:
256 case T_RP:
257 for (i = 0; i < 2; i++) {
258 if (!getword_str(buf2, sizeof buf2, &startp,
259 endp))
260 return (-1);
261 n = dn_comp(buf2, cp, buflen,
262 dnptrs, lastdnptr);
263 if (n < 0)
264 return (-1);
265 cp += n;
266 ShrinkBuffer(n);
267 }
268 if (rrecp->r_type == T_SOA) {
269 ShrinkBuffer(5 * INT32SZ);
270 while (isspace(*startp) || !*startp)
271 startp++;
272 if (*startp == '(') {
273 multiline = 1;
274 startp++;
275 } else
276 multiline = 0;
277 /* serial, refresh, retry, expire, minimum */
278 for (i = 0; i < 5; i++) {
279 soanum = getnum_str(&startp, endp);
280 if (soanum < 0)
281 return (-1);
282 PUTLONG(soanum, cp);
283 }
284 if (multiline) {
285 while (isspace(*startp) || !*startp)
286 startp++;
287 if (*startp != ')')
288 return (-1);
289 }
290 }
291 break;
292 case T_MX:
293 case T_AFSDB:
294 case T_RT:
295 n = getnum_str(&startp, endp);
296 if (n < 0)
297 return (-1);
298 PUTSHORT(n, cp);
299 ShrinkBuffer(INT16SZ);
300 if (!getword_str(buf2, sizeof buf2, &startp, endp))
301 return (-1);
302 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
303 if (n < 0)
304 return (-1);
305 cp += n;
306 ShrinkBuffer(n);
307 break;
308 case T_PX:
309 n = getnum_str(&startp, endp);
310 if (n < 0)
311 return (-1);
312 PUTSHORT(n, cp);
313 ShrinkBuffer(INT16SZ);
314 for (i = 0; i < 2; i++) {
315 if (!getword_str(buf2, sizeof buf2, &startp,
316 endp))
317 return (-1);
318 n = dn_comp(buf2, cp, buflen, dnptrs,
319 lastdnptr);
320 if (n < 0)
321 return (-1);
322 cp += n;
323 ShrinkBuffer(n);
324 }
325 break;
326 case T_WKS:
327 case T_HINFO:
328 case T_TXT:
329 case T_X25:
330 case T_ISDN:
331 case T_NSAP:
332 case T_LOC:
333 /* XXX - more fine tuning needed here */
334 ShrinkBuffer(rrecp->r_size);
335 memcpy(cp, rrecp->r_data, rrecp->r_size);
336 cp += rrecp->r_size;
337 break;
338 default:
339 return (-1);
340 } /*switch*/
341 n = (u_int16_t)((cp - sp2) - INT16SZ);
342 PUTSHORT(n, sp2);
343 } /*for*/
344
345 hp->qdcount = htons(counts[0]);
346 hp->ancount = htons(counts[1]);
347 hp->nscount = htons(counts[2]);
348 hp->arcount = htons(counts[3]);
349 return ((int)(cp - buf));
350 }
351
352 /*
353 * Get a whitespace delimited word from a string (not file)
354 * into buf. modify the start pointer to point after the
355 * word in the string.
356 */
357 static int
358 getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
359 char *cp;
360 int c;
361
362 for (cp = buf; *startpp <= endp; ) {
363 c = **startpp;
364 if (isspace(c) || c == '\0') {
365 if (cp != buf) /* trailing whitespace */
366 break;
367 else { /* leading whitespace */
368 (*startpp)++;
369 continue;
370 }
371 }
372 (*startpp)++;
373 if (cp >= buf+size-1)
374 break;
375 *cp++ = (u_char)c;
376 }
377 *cp = '\0';
378 return (cp != buf);
379 }
380
381 /*
382 * Get a whitespace delimited number from a string (not file) into buf
383 * update the start pointer to point after the number in the string.
384 */
385 static int
386 getnum_str(u_char **startpp, u_char *endp) {
387 int c;
388 int n;
389 int seendigit = 0;
390 int m = 0;
391
392 for (n = 0; *startpp <= endp; ) {
393 c = **startpp;
394 if (isspace(c) || c == '\0') {
395 if (seendigit) /* trailing whitespace */
396 break;
397 else { /* leading whitespace */
398 (*startpp)++;
399 continue;
400 }
401 }
402 if (c == ';') {
403 while ((*startpp <= endp) &&
404 ((c = **startpp) != '\n'))
405 (*startpp)++;
406 if (seendigit)
407 break;
408 continue;
409 }
410 if (!isdigit(c)) {
411 if (c == ')' && seendigit) {
412 (*startpp)--;
413 break;
414 }
415 return (-1);
416 }
417 (*startpp)++;
418 n = n * 10 + (c - '0');
419 seendigit = 1;
420 }
421 return (n + m);
422 }
423
424 /*
425 * Allocate a resource record buffer & save rr info.
426 */
427 ns_updrec *
428 res_mkupdrec(int section, const char *dname,
429 u_int class, u_int type, u_long ttl) {
430 ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
431
432 if (!rrecp || !(rrecp->r_dname = strdup(dname)))
433 return (NULL);
434 rrecp->r_class = (u_int16_t)class;
435 rrecp->r_type = (u_int16_t)type;
436 rrecp->r_ttl = (u_int32_t)ttl;
437 rrecp->r_section = (u_int8_t)section;
438 return (rrecp);
439 }
440
441 /*
442 * Free a resource record buffer created by res_mkupdrec.
443 */
444 void
445 res_freeupdrec(ns_updrec *rrecp) {
446 /* Note: freeing r_dp is the caller's responsibility. */
447 if (rrecp->r_dname != NULL)
448 free(rrecp->r_dname);
449 free(rrecp);
450 }