1 | /** @file
|
---|
2 | Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
|
---|
3 | This program and the accompanying materials are licensed and made available
|
---|
4 | under the terms and conditions of the BSD License which accompanies this
|
---|
5 | distribution. The full text of the license may be found at
|
---|
6 | http://opensource.org/licenses/bsd-license.php.
|
---|
7 |
|
---|
8 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
---|
9 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
---|
10 | **/
|
---|
11 | /*
|
---|
12 | * Copyright (c) 1996 by Internet Software Consortium.
|
---|
13 | *
|
---|
14 | * Permission to use, copy, modify, and distribute this software for any
|
---|
15 | * purpose with or without fee is hereby granted, provided that the above
|
---|
16 | * copyright notice and this permission notice appear in all copies.
|
---|
17 | *
|
---|
18 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
---|
19 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
---|
20 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
---|
21 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
---|
22 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
---|
23 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
---|
24 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
---|
25 | * SOFTWARE.
|
---|
26 | */
|
---|
27 |
|
---|
28 | /*
|
---|
29 | * Portions copyright (c) 1999, 2000
|
---|
30 | * Intel Corporation.
|
---|
31 | * All rights reserved.
|
---|
32 | *
|
---|
33 | * Redistribution and use in source and binary forms, with or without
|
---|
34 | * modification, are permitted provided that the following conditions
|
---|
35 | * are met:
|
---|
36 | *
|
---|
37 | * 1. Redistributions of source code must retain the above copyright
|
---|
38 | * notice, this list of conditions and the following disclaimer.
|
---|
39 | *
|
---|
40 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
41 | * notice, this list of conditions and the following disclaimer in the
|
---|
42 | * documentation and/or other materials provided with the distribution.
|
---|
43 | *
|
---|
44 | * 3. All advertising materials mentioning features or use of this software
|
---|
45 | * must display the following acknowledgement:
|
---|
46 | *
|
---|
47 | * This product includes software developed by Intel Corporation and
|
---|
48 | * its contributors.
|
---|
49 | *
|
---|
50 | * 4. Neither the name of Intel Corporation or its contributors may be
|
---|
51 | * used to endorse or promote products derived from this software
|
---|
52 | * without specific prior written permission.
|
---|
53 | *
|
---|
54 | * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
|
---|
55 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
---|
56 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
---|
57 | * ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
|
---|
58 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
---|
59 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
---|
60 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
---|
61 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
---|
62 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
---|
63 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
---|
64 | * THE POSSIBILITY OF SUCH DAMAGE.
|
---|
65 | *
|
---|
66 | */
|
---|
67 |
|
---|
68 | /*
|
---|
69 | * Based on the Dynamic DNS reference implementation by Viraj Bais
|
---|
70 | * <[email protected]>
|
---|
71 | */
|
---|
72 |
|
---|
73 | #include <sys/types.h>
|
---|
74 | #include <sys/param.h>
|
---|
75 |
|
---|
76 | #include <netinet/in.h>
|
---|
77 | #include <arpa/nameser.h>
|
---|
78 | #include <arpa/inet.h>
|
---|
79 |
|
---|
80 | #include <errno.h>
|
---|
81 | #include <limits.h>
|
---|
82 | #include <netdb.h>
|
---|
83 | #include <resolv.h>
|
---|
84 | #include <stdio.h>
|
---|
85 | #include <stdlib.h>
|
---|
86 | #include <string.h>
|
---|
87 | #include <unistd.h>
|
---|
88 | #include <ctype.h>
|
---|
89 |
|
---|
90 | #include "res_config.h"
|
---|
91 |
|
---|
92 | static int getnum_str(u_char **, u_char *);
|
---|
93 | static int getword_str(char *, int, u_char **, u_char *);
|
---|
94 |
|
---|
95 | #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
|
---|
96 |
|
---|
97 | /*
|
---|
98 | * Form update packets.
|
---|
99 | * Returns the size of the resulting packet if no error
|
---|
100 | * On error,
|
---|
101 | * returns -1 if error in reading a word/number in rdata
|
---|
102 | * portion for update packets
|
---|
103 | * -2 if length of buffer passed is insufficient
|
---|
104 | * -3 if zone section is not the first section in
|
---|
105 | * the linked list, or section order has a problem
|
---|
106 | * -4 on a number overflow
|
---|
107 | * -5 unknown operation or no records
|
---|
108 | */
|
---|
109 | int
|
---|
110 | res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
|
---|
111 | ns_updrec *rrecp_start = rrecp_in;
|
---|
112 | HEADER *hp;
|
---|
113 | u_char *cp, *sp2, *startp, *endp;
|
---|
114 | int n, i, soanum, multiline;
|
---|
115 | ns_updrec *rrecp;
|
---|
116 | struct in_addr ina;
|
---|
117 | char buf2[MAXDNAME];
|
---|
118 | int section, numrrs = 0, counts[ns_s_max];
|
---|
119 | u_int16_t rtype, rclass;
|
---|
120 | u_int32_t n1, rttl;
|
---|
121 | u_char *dnptrs[20], **dpp, **lastdnptr;
|
---|
122 |
|
---|
123 | if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
|
---|
124 | h_errno = NETDB_INTERNAL;
|
---|
125 | return (-1);
|
---|
126 | }
|
---|
127 |
|
---|
128 | /*
|
---|
129 | * Initialize header fields.
|
---|
130 | */
|
---|
131 | if ((buf == NULL) || (buflen < HFIXEDSZ))
|
---|
132 | return (-1);
|
---|
133 | memset(buf, 0, HFIXEDSZ);
|
---|
134 | hp = (HEADER *) buf;
|
---|
135 | hp->id = htons(++_res.id);
|
---|
136 | hp->opcode = ns_o_update;
|
---|
137 | hp->rcode = NOERROR;
|
---|
138 | cp = buf + HFIXEDSZ;
|
---|
139 | buflen -= HFIXEDSZ;
|
---|
140 | dpp = dnptrs;
|
---|
141 | *dpp++ = buf;
|
---|
142 | *dpp++ = NULL;
|
---|
143 | lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
|
---|
144 |
|
---|
145 | if (rrecp_start == NULL)
|
---|
146 | return (-5);
|
---|
147 | else if (rrecp_start->r_section != S_ZONE)
|
---|
148 | return (-3);
|
---|
149 |
|
---|
150 | memset(counts, 0, sizeof counts);
|
---|
151 | for (rrecp = rrecp_start; rrecp; rrecp = rrecp->r_grpnext) {
|
---|
152 | numrrs++;
|
---|
153 | section = rrecp->r_section;
|
---|
154 | if (section < 0 || section >= ns_s_max)
|
---|
155 | return (-1);
|
---|
156 | counts[section]++;
|
---|
157 | for (i = section + 1; i < ns_s_max; i++)
|
---|
158 | if (counts[i])
|
---|
159 | return (-3);
|
---|
160 | rtype = rrecp->r_type;
|
---|
161 | rclass = rrecp->r_class;
|
---|
162 | rttl = rrecp->r_ttl;
|
---|
163 | /* overload class and type */
|
---|
164 | if (section == S_PREREQ) {
|
---|
165 | rttl = 0;
|
---|
166 | switch (rrecp->r_opcode) {
|
---|
167 | case YXDOMAIN:
|
---|
168 | rclass = C_ANY;
|
---|
169 | rtype = T_ANY;
|
---|
170 | rrecp->r_size = 0;
|
---|
171 | break;
|
---|
172 | case NXDOMAIN:
|
---|
173 | rclass = C_NONE;
|
---|
174 | rtype = T_ANY;
|
---|
175 | rrecp->r_size = 0;
|
---|
176 | break;
|
---|
177 | case NXRRSET:
|
---|
178 | rclass = C_NONE;
|
---|
179 | rrecp->r_size = 0;
|
---|
180 | break;
|
---|
181 | case YXRRSET:
|
---|
182 | if (rrecp->r_size == 0)
|
---|
183 | rclass = C_ANY;
|
---|
184 | break;
|
---|
185 | default:
|
---|
186 | fprintf(stderr,
|
---|
187 | "res_mkupdate: incorrect opcode: %d\n",
|
---|
188 | rrecp->r_opcode);
|
---|
189 | fflush(stderr);
|
---|
190 | return (-1);
|
---|
191 | }
|
---|
192 | } else if (section == S_UPDATE) {
|
---|
193 | switch (rrecp->r_opcode) {
|
---|
194 | case DELETE:
|
---|
195 | rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
|
---|
196 | break;
|
---|
197 | case ADD:
|
---|
198 | break;
|
---|
199 | default:
|
---|
200 | fprintf(stderr,
|
---|
201 | "res_mkupdate: incorrect opcode: %d\n",
|
---|
202 | rrecp->r_opcode);
|
---|
203 | fflush(stderr);
|
---|
204 | return (-1);
|
---|
205 | }
|
---|
206 | }
|
---|
207 |
|
---|
208 | /*
|
---|
209 | * XXX appending default domain to owner name is omitted,
|
---|
210 | * fqdn must be provided
|
---|
211 | */
|
---|
212 | if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
|
---|
213 | lastdnptr)) < 0)
|
---|
214 | return (-1);
|
---|
215 | cp += n;
|
---|
216 | ShrinkBuffer(n + 2*INT16SZ);
|
---|
217 | PUTSHORT(rtype, cp);
|
---|
218 | PUTSHORT(rclass, cp);
|
---|
219 | if (section == S_ZONE) {
|
---|
220 | if (numrrs != 1 || rrecp->r_type != T_SOA)
|
---|
221 | return (-3);
|
---|
222 | continue;
|
---|
223 | }
|
---|
224 | ShrinkBuffer(INT32SZ + INT16SZ);
|
---|
225 | PUTLONG(rttl, cp);
|
---|
226 | sp2 = cp; /* save pointer to length byte */
|
---|
227 | cp += INT16SZ;
|
---|
228 | if (rrecp->r_size == 0) {
|
---|
229 | if (section == S_UPDATE && rclass != C_ANY)
|
---|
230 | return (-1);
|
---|
231 | else {
|
---|
232 | PUTSHORT(0, sp2);
|
---|
233 | continue;
|
---|
234 | }
|
---|
235 | }
|
---|
236 | startp = rrecp->r_data;
|
---|
237 | endp = startp + rrecp->r_size - 1;
|
---|
238 | /* XXX this should be done centrally. */
|
---|
239 | switch (rrecp->r_type) {
|
---|
240 | case T_A:
|
---|
241 | if (!getword_str(buf2, sizeof buf2, &startp, endp))
|
---|
242 | return (-1);
|
---|
243 | if (!inet_aton(buf2, &ina))
|
---|
244 | return (-1);
|
---|
245 | n1 = ntohl(ina.s_addr);
|
---|
246 | ShrinkBuffer(INT32SZ);
|
---|
247 | PUTLONG(n1, cp);
|
---|
248 | break;
|
---|
249 | case T_CNAME:
|
---|
250 | case T_MB:
|
---|
251 | case T_MG:
|
---|
252 | case T_MR:
|
---|
253 | case T_NS:
|
---|
254 | case T_PTR:
|
---|
255 | if (!getword_str(buf2, sizeof buf2, &startp, endp))
|
---|
256 | return (-1);
|
---|
257 | n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
|
---|
258 | if (n < 0)
|
---|
259 | return (-1);
|
---|
260 | cp += n;
|
---|
261 | ShrinkBuffer(n);
|
---|
262 | break;
|
---|
263 | case T_MINFO:
|
---|
264 | case T_SOA:
|
---|
265 | case T_RP:
|
---|
266 | for (i = 0; i < 2; i++) {
|
---|
267 | if (!getword_str(buf2, sizeof buf2, &startp,
|
---|
268 | endp))
|
---|
269 | return (-1);
|
---|
270 | n = dn_comp(buf2, cp, buflen,
|
---|
271 | dnptrs, lastdnptr);
|
---|
272 | if (n < 0)
|
---|
273 | return (-1);
|
---|
274 | cp += n;
|
---|
275 | ShrinkBuffer(n);
|
---|
276 | }
|
---|
277 | if (rrecp->r_type == T_SOA) {
|
---|
278 | ShrinkBuffer(5 * INT32SZ);
|
---|
279 | while (isspace(*startp) || !*startp)
|
---|
280 | startp++;
|
---|
281 | if (*startp == '(') {
|
---|
282 | multiline = 1;
|
---|
283 | startp++;
|
---|
284 | } else
|
---|
285 | multiline = 0;
|
---|
286 | /* serial, refresh, retry, expire, minimum */
|
---|
287 | for (i = 0; i < 5; i++) {
|
---|
288 | soanum = getnum_str(&startp, endp);
|
---|
289 | if (soanum < 0)
|
---|
290 | return (-1);
|
---|
291 | PUTLONG(soanum, cp);
|
---|
292 | }
|
---|
293 | if (multiline) {
|
---|
294 | while (isspace(*startp) || !*startp)
|
---|
295 | startp++;
|
---|
296 | if (*startp != ')')
|
---|
297 | return (-1);
|
---|
298 | }
|
---|
299 | }
|
---|
300 | break;
|
---|
301 | case T_MX:
|
---|
302 | case T_AFSDB:
|
---|
303 | case T_RT:
|
---|
304 | n = getnum_str(&startp, endp);
|
---|
305 | if (n < 0)
|
---|
306 | return (-1);
|
---|
307 | PUTSHORT(n, cp);
|
---|
308 | ShrinkBuffer(INT16SZ);
|
---|
309 | if (!getword_str(buf2, sizeof buf2, &startp, endp))
|
---|
310 | return (-1);
|
---|
311 | n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
|
---|
312 | if (n < 0)
|
---|
313 | return (-1);
|
---|
314 | cp += n;
|
---|
315 | ShrinkBuffer(n);
|
---|
316 | break;
|
---|
317 | case T_PX:
|
---|
318 | n = getnum_str(&startp, endp);
|
---|
319 | if (n < 0)
|
---|
320 | return (-1);
|
---|
321 | PUTSHORT(n, cp);
|
---|
322 | ShrinkBuffer(INT16SZ);
|
---|
323 | for (i = 0; i < 2; i++) {
|
---|
324 | if (!getword_str(buf2, sizeof buf2, &startp,
|
---|
325 | endp))
|
---|
326 | return (-1);
|
---|
327 | n = dn_comp(buf2, cp, buflen, dnptrs,
|
---|
328 | lastdnptr);
|
---|
329 | if (n < 0)
|
---|
330 | return (-1);
|
---|
331 | cp += n;
|
---|
332 | ShrinkBuffer(n);
|
---|
333 | }
|
---|
334 | break;
|
---|
335 | case T_WKS:
|
---|
336 | case T_HINFO:
|
---|
337 | case T_TXT:
|
---|
338 | case T_X25:
|
---|
339 | case T_ISDN:
|
---|
340 | case T_NSAP:
|
---|
341 | case T_LOC:
|
---|
342 | /* XXX - more fine tuning needed here */
|
---|
343 | ShrinkBuffer(rrecp->r_size);
|
---|
344 | memcpy(cp, rrecp->r_data, rrecp->r_size);
|
---|
345 | cp += rrecp->r_size;
|
---|
346 | break;
|
---|
347 | default:
|
---|
348 | return (-1);
|
---|
349 | } /*switch*/
|
---|
350 | n = (u_int16_t)((cp - sp2) - INT16SZ);
|
---|
351 | PUTSHORT(n, sp2);
|
---|
352 | } /*for*/
|
---|
353 |
|
---|
354 | hp->qdcount = htons(counts[0]);
|
---|
355 | hp->ancount = htons(counts[1]);
|
---|
356 | hp->nscount = htons(counts[2]);
|
---|
357 | hp->arcount = htons(counts[3]);
|
---|
358 | return ((int)(cp - buf));
|
---|
359 | }
|
---|
360 |
|
---|
361 | /*
|
---|
362 | * Get a whitespace delimited word from a string (not file)
|
---|
363 | * into buf. modify the start pointer to point after the
|
---|
364 | * word in the string.
|
---|
365 | */
|
---|
366 | static int
|
---|
367 | getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
|
---|
368 | char *cp;
|
---|
369 | int c;
|
---|
370 |
|
---|
371 | for (cp = buf; *startpp <= endp; ) {
|
---|
372 | c = **startpp;
|
---|
373 | if (isspace(c) || c == '\0') {
|
---|
374 | if (cp != buf) /* trailing whitespace */
|
---|
375 | break;
|
---|
376 | else { /* leading whitespace */
|
---|
377 | (*startpp)++;
|
---|
378 | continue;
|
---|
379 | }
|
---|
380 | }
|
---|
381 | (*startpp)++;
|
---|
382 | if (cp >= buf+size-1)
|
---|
383 | break;
|
---|
384 | *cp++ = (u_char)c;
|
---|
385 | }
|
---|
386 | *cp = '\0';
|
---|
387 | return (cp != buf);
|
---|
388 | }
|
---|
389 |
|
---|
390 | /*
|
---|
391 | * Get a whitespace delimited number from a string (not file) into buf
|
---|
392 | * update the start pointer to point after the number in the string.
|
---|
393 | */
|
---|
394 | static int
|
---|
395 | getnum_str(u_char **startpp, u_char *endp) {
|
---|
396 | int c;
|
---|
397 | int n;
|
---|
398 | int seendigit = 0;
|
---|
399 | int m = 0;
|
---|
400 |
|
---|
401 | for (n = 0; *startpp <= endp; ) {
|
---|
402 | c = **startpp;
|
---|
403 | if (isspace(c) || c == '\0') {
|
---|
404 | if (seendigit) /* trailing whitespace */
|
---|
405 | break;
|
---|
406 | else { /* leading whitespace */
|
---|
407 | (*startpp)++;
|
---|
408 | continue;
|
---|
409 | }
|
---|
410 | }
|
---|
411 | if (c == ';') {
|
---|
412 | while ((*startpp <= endp) &&
|
---|
413 | ((c = **startpp) != '\n'))
|
---|
414 | (*startpp)++;
|
---|
415 | if (seendigit)
|
---|
416 | break;
|
---|
417 | continue;
|
---|
418 | }
|
---|
419 | if (!isdigit(c)) {
|
---|
420 | if (c == ')' && seendigit) {
|
---|
421 | (*startpp)--;
|
---|
422 | break;
|
---|
423 | }
|
---|
424 | return (-1);
|
---|
425 | }
|
---|
426 | (*startpp)++;
|
---|
427 | n = n * 10 + (c - '0');
|
---|
428 | seendigit = 1;
|
---|
429 | }
|
---|
430 | return (n + m);
|
---|
431 | }
|
---|
432 |
|
---|
433 | /*
|
---|
434 | * Allocate a resource record buffer & save rr info.
|
---|
435 | */
|
---|
436 | ns_updrec *
|
---|
437 | res_mkupdrec(int section, const char *dname,
|
---|
438 | u_int class, u_int type, u_long ttl) {
|
---|
439 | ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
|
---|
440 |
|
---|
441 | if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
|
---|
442 | free(rrecp);
|
---|
443 | return (NULL);
|
---|
444 | }
|
---|
445 | rrecp->r_class = (u_int16_t)class;
|
---|
446 | rrecp->r_type = (u_int16_t)type;
|
---|
447 | rrecp->r_ttl = (u_int32_t)ttl;
|
---|
448 | rrecp->r_section = (u_int8_t)section;
|
---|
449 | return (rrecp);
|
---|
450 | }
|
---|
451 |
|
---|
452 | /*
|
---|
453 | * Free a resource record buffer created by res_mkupdrec.
|
---|
454 | */
|
---|
455 | void
|
---|
456 | res_freeupdrec(ns_updrec *rrecp) {
|
---|
457 | /* Note: freeing r_dp is the caller's responsibility. */
|
---|
458 | if (rrecp->r_dname != NULL)
|
---|
459 | free(rrecp->r_dname);
|
---|
460 | free(rrecp);
|
---|
461 | }
|
---|