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