1 /*
2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996-1999 by Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 *
17 * $Id: res_mkupdate.c,v 1.8 2005/10/14 05:44:26 marka Exp $
18 */
19
20 /*! \file
21 * \brief
22 * Based on the Dynamic DNS reference implementation by Viraj Bais
23 * <viraj_bais@ccm.fm.intel.com>
24 */
25
26 #include "port_before.h"
27
28 #include <sys/types.h>
29 #include <sys/param.h>
30
31 #include <netinet/in.h>
32 #include <arpa/nameser.h>
33 #include <arpa/inet.h>
34
35 #include <errno.h>
36 #include <limits.h>
37 #include <netdb.h>
38 #include <resolv.h>
39 #include <res_update.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <ctype.h>
45
46 #ifdef _LIBC
47 #include "isc/list.h"
48 #endif
49 #include "port_after.h"
50
51 /* Options. Leave them on. */
52 #define DEBUG
53 #define MAXPORT 1024
54
55 static int getnum_str(u_char **, u_char *);
56 static int gethexnum_str(u_char **, u_char *);
57 static int getword_str(char *, int, u_char **, u_char *);
58 static int getstr_str(char *, int, u_char **, u_char *);
59
60 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
61
62 /* Forward. */
63 #ifdef _LIBC
64 static
65 #endif
66 int res_protocolnumber(const char *);
67 #ifdef _LIBC
68 static
69 #endif
70 int res_servicenumber(const char *);
71
72 /*%
73 * Form update packets.
74 * Returns the size of the resulting packet if no error
75 *
76 * On error,
77 * returns
78 *\li -1 if error in reading a word/number in rdata
79 * portion for update packets
80 *\li -2 if length of buffer passed is insufficient
81 *\li -3 if zone section is not the first section in
82 * the linked list, or section order has a problem
83 *\li -4 on a number overflow
84 *\li -5 unknown operation or no records
85 */
86 int
res_nmkupdate(res_state statp,ns_updrec * rrecp_in,u_char * buf,int buflen)87 res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
88 ns_updrec *rrecp_start = rrecp_in;
89 HEADER *hp;
90 u_char *cp, *sp2, *startp, *endp;
91 int n, i, soanum, multiline;
92 ns_updrec *rrecp;
93 struct in_addr ina;
94 struct in6_addr in6a;
95 char buf2[MAXDNAME];
96 u_char buf3[MAXDNAME];
97 int section, numrrs = 0, counts[ns_s_max];
98 u_int16_t rtype, rclass;
99 u_int32_t n1, rttl;
100 u_char *dnptrs[20], **dpp, **lastdnptr;
101 #ifndef _LIBC
102 int siglen;
103 #endif
104 int keylen, certlen;
105
106 /*
107 * Initialize header fields.
108 */
109 if ((buf == NULL) || (buflen < HFIXEDSZ))
110 return (-1);
111 memset(buf, 0, HFIXEDSZ);
112 hp = (HEADER *) buf;
113 hp->id = htons(++statp->id);
114 hp->opcode = ns_o_update;
115 hp->rcode = NOERROR;
116 cp = buf + HFIXEDSZ;
117 buflen -= HFIXEDSZ;
118 dpp = dnptrs;
119 *dpp++ = buf;
120 *dpp++ = NULL;
121 lastdnptr = dnptrs + NELEM(dnptrs);
122
123 if (rrecp_start == NULL)
124 return (-5);
125 else if (rrecp_start->r_section != S_ZONE)
126 return (-3);
127
128 memset(counts, 0, sizeof counts);
129 for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
130 numrrs++;
131 section = rrecp->r_section;
132 if (section < 0 || section >= ns_s_max)
133 return (-1);
134 counts[section]++;
135 for (i = section + 1; i < ns_s_max; i++)
136 if (counts[i])
137 return (-3);
138 rtype = rrecp->r_type;
139 rclass = rrecp->r_class;
140 rttl = rrecp->r_ttl;
141 /* overload class and type */
142 if (section == S_PREREQ) {
143 rttl = 0;
144 switch (rrecp->r_opcode) {
145 case YXDOMAIN:
146 rclass = C_ANY;
147 rtype = T_ANY;
148 rrecp->r_size = 0;
149 break;
150 case NXDOMAIN:
151 rclass = C_NONE;
152 rtype = T_ANY;
153 rrecp->r_size = 0;
154 break;
155 case NXRRSET:
156 rclass = C_NONE;
157 rrecp->r_size = 0;
158 break;
159 case YXRRSET:
160 if (rrecp->r_size == 0)
161 rclass = C_ANY;
162 break;
163 default:
164 fprintf(stderr,
165 "res_mkupdate: incorrect opcode: %d\n",
166 rrecp->r_opcode);
167 fflush(stderr);
168 return (-1);
169 }
170 } else if (section == S_UPDATE) {
171 switch (rrecp->r_opcode) {
172 case DELETE:
173 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
174 break;
175 case ADD:
176 break;
177 default:
178 fprintf(stderr,
179 "res_mkupdate: incorrect opcode: %d\n",
180 rrecp->r_opcode);
181 fflush(stderr);
182 return (-1);
183 }
184 }
185
186 /*
187 * XXX appending default domain to owner name is omitted,
188 * fqdn must be provided
189 */
190 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
191 lastdnptr)) < 0)
192 return (-1);
193 cp += n;
194 ShrinkBuffer(n + 2*INT16SZ);
195 PUTSHORT(rtype, cp);
196 PUTSHORT(rclass, cp);
197 if (section == S_ZONE) {
198 if (numrrs != 1 || rrecp->r_type != T_SOA)
199 return (-3);
200 continue;
201 }
202 ShrinkBuffer(INT32SZ + INT16SZ);
203 PUTLONG(rttl, cp);
204 sp2 = cp; /*%< save pointer to length byte */
205 cp += INT16SZ;
206 if (rrecp->r_size == 0) {
207 if (section == S_UPDATE && rclass != C_ANY)
208 return (-1);
209 else {
210 PUTSHORT(0, sp2);
211 continue;
212 }
213 }
214 startp = rrecp->r_data;
215 endp = startp + rrecp->r_size - 1;
216 /* XXX this should be done centrally. */
217 switch (rrecp->r_type) {
218 case T_A:
219 if (!getword_str(buf2, sizeof buf2, &startp, endp))
220 return (-1);
221 if (!inet_aton(buf2, &ina))
222 return (-1);
223 n1 = ntohl(ina.s_addr);
224 ShrinkBuffer(INT32SZ);
225 PUTLONG(n1, cp);
226 break;
227 case T_CNAME:
228 case T_MB:
229 case T_MG:
230 case T_MR:
231 case T_NS:
232 case T_PTR:
233 case ns_t_dname:
234 if (!getword_str(buf2, sizeof buf2, &startp, endp))
235 return (-1);
236 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
237 if (n < 0)
238 return (-1);
239 cp += n;
240 ShrinkBuffer(n);
241 break;
242 case T_MINFO:
243 case T_SOA:
244 case T_RP:
245 for (i = 0; i < 2; i++) {
246 if (!getword_str(buf2, sizeof buf2, &startp,
247 endp))
248 return (-1);
249 n = dn_comp(buf2, cp, buflen,
250 dnptrs, lastdnptr);
251 if (n < 0)
252 return (-1);
253 cp += n;
254 ShrinkBuffer(n);
255 }
256 if (rrecp->r_type == T_SOA) {
257 ShrinkBuffer(5 * INT32SZ);
258 while (isspace(*startp) || !*startp)
259 startp++;
260 if (*startp == '(') {
261 multiline = 1;
262 startp++;
263 } else
264 multiline = 0;
265 /* serial, refresh, retry, expire, minimum */
266 for (i = 0; i < 5; i++) {
267 soanum = getnum_str(&startp, endp);
268 if (soanum < 0)
269 return (-1);
270 PUTLONG(soanum, cp);
271 }
272 if (multiline) {
273 while (isspace(*startp) || !*startp)
274 startp++;
275 if (*startp != ')')
276 return (-1);
277 }
278 }
279 break;
280 case T_MX:
281 case T_AFSDB:
282 case T_RT:
283 n = getnum_str(&startp, endp);
284 if (n < 0)
285 return (-1);
286 ShrinkBuffer(INT16SZ);
287 PUTSHORT(n, cp);
288 if (!getword_str(buf2, sizeof buf2, &startp, endp))
289 return (-1);
290 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
291 if (n < 0)
292 return (-1);
293 cp += n;
294 ShrinkBuffer(n);
295 break;
296 case T_SRV:
297 n = getnum_str(&startp, endp);
298 if (n < 0)
299 return (-1);
300 ShrinkBuffer(INT16SZ);
301 PUTSHORT(n, cp);
302
303 n = getnum_str(&startp, endp);
304 if (n < 0)
305 return (-1);
306 ShrinkBuffer(INT16SZ);
307 PUTSHORT(n, cp);
308
309 n = getnum_str(&startp, endp);
310 if (n < 0)
311 return (-1);
312 ShrinkBuffer(INT16SZ);
313 PUTSHORT(n, cp);
314
315 if (!getword_str(buf2, sizeof buf2, &startp, endp))
316 return (-1);
317 n = dn_comp(buf2, cp, buflen, NULL, NULL);
318 if (n < 0)
319 return (-1);
320 cp += n;
321 ShrinkBuffer(n);
322 break;
323 case T_PX:
324 n = getnum_str(&startp, endp);
325 if (n < 0)
326 return (-1);
327 PUTSHORT(n, cp);
328 ShrinkBuffer(INT16SZ);
329 for (i = 0; i < 2; i++) {
330 if (!getword_str(buf2, sizeof buf2, &startp,
331 endp))
332 return (-1);
333 n = dn_comp(buf2, cp, buflen, dnptrs,
334 lastdnptr);
335 if (n < 0)
336 return (-1);
337 cp += n;
338 ShrinkBuffer(n);
339 }
340 break;
341 case T_WKS: {
342 char bm[MAXPORT/8];
343 unsigned int maxbm = 0;
344
345 if (!getword_str(buf2, sizeof buf2, &startp, endp))
346 return (-1);
347 if (!inet_aton(buf2, &ina))
348 return (-1);
349 n1 = ntohl(ina.s_addr);
350 ShrinkBuffer(INT32SZ);
351 PUTLONG(n1, cp);
352
353 if (!getword_str(buf2, sizeof buf2, &startp, endp))
354 return (-1);
355 if ((i = res_protocolnumber(buf2)) < 0)
356 return (-1);
357 ShrinkBuffer(1);
358 *cp++ = i & 0xff;
359
360 for (i = 0; i < MAXPORT/8 ; i++)
361 bm[i] = 0;
362
363 while (getword_str(buf2, sizeof buf2, &startp, endp)) {
364 if ((n = res_servicenumber(buf2)) <= 0)
365 return (-1);
366
367 if (n < MAXPORT) {
368 bm[n/8] |= (0x80>>(n%8));
369 if ((unsigned)n > maxbm)
370 maxbm = n;
371 } else
372 return (-1);
373 }
374 maxbm = maxbm/8 + 1;
375 ShrinkBuffer(maxbm);
376 memcpy(cp, bm, maxbm);
377 cp += maxbm;
378 break;
379 }
380 case T_HINFO:
381 for (i = 0; i < 2; i++) {
382 if ((n = getstr_str(buf2, sizeof buf2,
383 &startp, endp)) < 0)
384 return (-1);
385 if (n > 255)
386 return (-1);
387 ShrinkBuffer(n+1);
388 *cp++ = n;
389 memcpy(cp, buf2, n);
390 cp += n;
391 }
392 break;
393 case T_TXT:
394 for (;;) {
395 if ((n = getstr_str(buf2, sizeof buf2,
396 &startp, endp)) < 0) {
397 if (cp != (sp2 + INT16SZ))
398 break;
399 return (-1);
400 }
401 if (n > 255)
402 return (-1);
403 ShrinkBuffer(n+1);
404 *cp++ = n;
405 memcpy(cp, buf2, n);
406 cp += n;
407 }
408 break;
409 case T_X25:
410 /* RFC1183 */
411 if ((n = getstr_str(buf2, sizeof buf2, &startp,
412 endp)) < 0)
413 return (-1);
414 if (n > 255)
415 return (-1);
416 ShrinkBuffer(n+1);
417 *cp++ = n;
418 memcpy(cp, buf2, n);
419 cp += n;
420 break;
421 case T_ISDN:
422 /* RFC1183 */
423 if ((n = getstr_str(buf2, sizeof buf2, &startp,
424 endp)) < 0)
425 return (-1);
426 if ((n > 255) || (n == 0))
427 return (-1);
428 ShrinkBuffer(n+1);
429 *cp++ = n;
430 memcpy(cp, buf2, n);
431 cp += n;
432 if ((n = getstr_str(buf2, sizeof buf2, &startp,
433 endp)) < 0)
434 n = 0;
435 if (n > 255)
436 return (-1);
437 ShrinkBuffer(n+1);
438 *cp++ = n;
439 memcpy(cp, buf2, n);
440 cp += n;
441 break;
442 case T_NSAP:
443 if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
444 ShrinkBuffer(n);
445 memcpy(cp, buf2, n);
446 cp += n;
447 } else {
448 return (-1);
449 }
450 break;
451 case T_LOC:
452 if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
453 ShrinkBuffer(n);
454 memcpy(cp, buf2, n);
455 cp += n;
456 } else
457 return (-1);
458 break;
459 case ns_t_sig:
460 #ifdef _LIBC
461 return (-1);
462 #else
463 {
464 int sig_type, success, dateerror;
465 u_int32_t exptime, timesigned;
466
467 /* type */
468 if ((n = getword_str(buf2, sizeof buf2,
469 &startp, endp)) < 0)
470 return (-1);
471 sig_type = sym_ston(__p_type_syms, buf2, &success);
472 if (!success || sig_type == ns_t_any)
473 return (-1);
474 ShrinkBuffer(INT16SZ);
475 PUTSHORT(sig_type, cp);
476 /* alg */
477 n = getnum_str(&startp, endp);
478 if (n < 0)
479 return (-1);
480 ShrinkBuffer(1);
481 *cp++ = n;
482 /* labels */
483 n = getnum_str(&startp, endp);
484 if (n <= 0 || n > 255)
485 return (-1);
486 ShrinkBuffer(1);
487 *cp++ = n;
488 /* ottl & expire */
489 if (!getword_str(buf2, sizeof buf2, &startp, endp))
490 return (-1);
491 exptime = ns_datetosecs(buf2, &dateerror);
492 if (!dateerror) {
493 ShrinkBuffer(INT32SZ);
494 PUTLONG(rttl, cp);
495 }
496 else {
497 char *ulendp;
498 u_int32_t ottl;
499
500 errno = 0;
501 ottl = strtoul(buf2, &ulendp, 10);
502 if (errno != 0 ||
503 (ulendp != NULL && *ulendp != '\0'))
504 return (-1);
505 ShrinkBuffer(INT32SZ);
506 PUTLONG(ottl, cp);
507 if (!getword_str(buf2, sizeof buf2, &startp,
508 endp))
509 return (-1);
510 exptime = ns_datetosecs(buf2, &dateerror);
511 if (dateerror)
512 return (-1);
513 }
514 /* expire */
515 ShrinkBuffer(INT32SZ);
516 PUTLONG(exptime, cp);
517 /* timesigned */
518 if (!getword_str(buf2, sizeof buf2, &startp, endp))
519 return (-1);
520 timesigned = ns_datetosecs(buf2, &dateerror);
521 if (!dateerror) {
522 ShrinkBuffer(INT32SZ);
523 PUTLONG(timesigned, cp);
524 }
525 else
526 return (-1);
527 /* footprint */
528 n = getnum_str(&startp, endp);
529 if (n < 0)
530 return (-1);
531 ShrinkBuffer(INT16SZ);
532 PUTSHORT(n, cp);
533 /* signer name */
534 if (!getword_str(buf2, sizeof buf2, &startp, endp))
535 return (-1);
536 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
537 if (n < 0)
538 return (-1);
539 cp += n;
540 ShrinkBuffer(n);
541 /* sig */
542 if ((n = getword_str(buf2, sizeof buf2,
543 &startp, endp)) < 0)
544 return (-1);
545 siglen = b64_pton(buf2, buf3, sizeof(buf3));
546 if (siglen < 0)
547 return (-1);
548 ShrinkBuffer(siglen);
549 memcpy(cp, buf3, siglen);
550 cp += siglen;
551 break;
552 }
553 #endif
554 case ns_t_key:
555 /* flags */
556 n = gethexnum_str(&startp, endp);
557 if (n < 0)
558 return (-1);
559 ShrinkBuffer(INT16SZ);
560 PUTSHORT(n, cp);
561 /* proto */
562 n = getnum_str(&startp, endp);
563 if (n < 0)
564 return (-1);
565 ShrinkBuffer(1);
566 *cp++ = n;
567 /* alg */
568 n = getnum_str(&startp, endp);
569 if (n < 0)
570 return (-1);
571 ShrinkBuffer(1);
572 *cp++ = n;
573 /* key */
574 if ((n = getword_str(buf2, sizeof buf2,
575 &startp, endp)) < 0)
576 return (-1);
577 keylen = b64_pton(buf2, buf3, sizeof(buf3));
578 if (keylen < 0)
579 return (-1);
580 ShrinkBuffer(keylen);
581 memcpy(cp, buf3, keylen);
582 cp += keylen;
583 break;
584 case ns_t_nxt:
585 {
586 int success, nxt_type;
587 u_char data[32];
588 int maxtype;
589
590 /* next name */
591 if (!getword_str(buf2, sizeof buf2, &startp, endp))
592 return (-1);
593 n = dn_comp(buf2, cp, buflen, NULL, NULL);
594 if (n < 0)
595 return (-1);
596 cp += n;
597 ShrinkBuffer(n);
598 maxtype = 0;
599 memset(data, 0, sizeof data);
600 for (;;) {
601 if (!getword_str(buf2, sizeof buf2, &startp,
602 endp))
603 break;
604 nxt_type = sym_ston(__p_type_syms, buf2,
605 &success);
606 if (!success || !ns_t_rr_p(nxt_type))
607 return (-1);
608 NS_NXT_BIT_SET(nxt_type, data);
609 if (nxt_type > maxtype)
610 maxtype = nxt_type;
611 }
612 n = maxtype/NS_NXT_BITS+1;
613 ShrinkBuffer(n);
614 memcpy(cp, data, n);
615 cp += n;
616 break;
617 }
618 case ns_t_cert:
619 /* type */
620 n = getnum_str(&startp, endp);
621 if (n < 0)
622 return (-1);
623 ShrinkBuffer(INT16SZ);
624 PUTSHORT(n, cp);
625 /* key tag */
626 n = getnum_str(&startp, endp);
627 if (n < 0)
628 return (-1);
629 ShrinkBuffer(INT16SZ);
630 PUTSHORT(n, cp);
631 /* alg */
632 n = getnum_str(&startp, endp);
633 if (n < 0)
634 return (-1);
635 ShrinkBuffer(1);
636 *cp++ = n;
637 /* cert */
638 if ((n = getword_str(buf2, sizeof buf2,
639 &startp, endp)) < 0)
640 return (-1);
641 certlen = b64_pton(buf2, buf3, sizeof(buf3));
642 if (certlen < 0)
643 return (-1);
644 ShrinkBuffer(certlen);
645 memcpy(cp, buf3, certlen);
646 cp += certlen;
647 break;
648 case ns_t_aaaa:
649 if (!getword_str(buf2, sizeof buf2, &startp, endp))
650 return (-1);
651 if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
652 return (-1);
653 ShrinkBuffer(NS_IN6ADDRSZ);
654 memcpy(cp, &in6a, NS_IN6ADDRSZ);
655 cp += NS_IN6ADDRSZ;
656 break;
657 case ns_t_naptr:
658 /* Order Preference Flags Service Replacement Regexp */
659 /* Order */
660 n = getnum_str(&startp, endp);
661 if (n < 0 || n > 65535)
662 return (-1);
663 ShrinkBuffer(INT16SZ);
664 PUTSHORT(n, cp);
665 /* Preference */
666 n = getnum_str(&startp, endp);
667 if (n < 0 || n > 65535)
668 return (-1);
669 ShrinkBuffer(INT16SZ);
670 PUTSHORT(n, cp);
671 /* Flags */
672 if ((n = getstr_str(buf2, sizeof buf2,
673 &startp, endp)) < 0) {
674 return (-1);
675 }
676 if (n > 255)
677 return (-1);
678 ShrinkBuffer(n+1);
679 *cp++ = n;
680 memcpy(cp, buf2, n);
681 cp += n;
682 /* Service Classes */
683 if ((n = getstr_str(buf2, sizeof buf2,
684 &startp, endp)) < 0) {
685 return (-1);
686 }
687 if (n > 255)
688 return (-1);
689 ShrinkBuffer(n+1);
690 *cp++ = n;
691 memcpy(cp, buf2, n);
692 cp += n;
693 /* Pattern */
694 if ((n = getstr_str(buf2, sizeof buf2,
695 &startp, endp)) < 0) {
696 return (-1);
697 }
698 if (n > 255)
699 return (-1);
700 ShrinkBuffer(n+1);
701 *cp++ = n;
702 memcpy(cp, buf2, n);
703 cp += n;
704 /* Replacement */
705 if (!getword_str(buf2, sizeof buf2, &startp, endp))
706 return (-1);
707 n = dn_comp(buf2, cp, buflen, NULL, NULL);
708 if (n < 0)
709 return (-1);
710 cp += n;
711 ShrinkBuffer(n);
712 break;
713 default:
714 return (-1);
715 } /*switch*/
716 n = (u_int16_t)((cp - sp2) - INT16SZ);
717 PUTSHORT(n, sp2);
718 } /*for*/
719
720 hp->qdcount = htons(counts[0]);
721 hp->ancount = htons(counts[1]);
722 hp->nscount = htons(counts[2]);
723 hp->arcount = htons(counts[3]);
724 return (cp - buf);
725 }
726
727 /*%
728 * Get a whitespace delimited word from a string (not file)
729 * into buf. modify the start pointer to point after the
730 * word in the string.
731 */
732 static int
getword_str(char * buf,int size,u_char ** startpp,u_char * endp)733 getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
734 char *cp;
735 int c;
736
737 for (cp = buf; *startpp <= endp; ) {
738 c = **startpp;
739 if (isspace(c) || c == '\0') {
740 if (cp != buf) /*%< trailing whitespace */
741 break;
742 else { /*%< leading whitespace */
743 (*startpp)++;
744 continue;
745 }
746 }
747 (*startpp)++;
748 if (cp >= buf+size-1)
749 break;
750 *cp++ = (u_char)c;
751 }
752 *cp = '\0';
753 return (cp != buf);
754 }
755
756 /*%
757 * get a white spae delimited string from memory. Process quoted strings
758 * and \\DDD escapes. Return length or -1 on error. Returned string may
759 * contain nulls.
760 */
761 static char digits[] = "0123456789";
762 static int
getstr_str(char * buf,int size,u_char ** startpp,u_char * endp)763 getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
764 char *cp;
765 int c, c1 = 0;
766 int inquote = 0;
767 int seen_quote = 0;
768 int escape = 0;
769 int dig = 0;
770
771 for (cp = buf; *startpp <= endp; ) {
772 if ((c = **startpp) == '\0')
773 break;
774 /* leading white space */
775 if ((cp == buf) && !seen_quote && isspace(c)) {
776 (*startpp)++;
777 continue;
778 }
779
780 switch (c) {
781 case '\\':
782 if (!escape) {
783 escape = 1;
784 dig = 0;
785 c1 = 0;
786 (*startpp)++;
787 continue;
788 }
789 goto do_escape;
790 case '"':
791 if (!escape) {
792 inquote = !inquote;
793 seen_quote = 1;
794 (*startpp)++;
795 continue;
796 }
797 /* fall through */
798 default:
799 do_escape:
800 if (escape) {
801 switch (c) {
802 case '0':
803 case '1':
804 case '2':
805 case '3':
806 case '4':
807 case '5':
808 case '6':
809 case '7':
810 case '8':
811 case '9':
812 c1 = c1 * 10 +
813 (strchr(digits, c) - digits);
814
815 if (++dig == 3) {
816 c = c1 &0xff;
817 break;
818 }
819 (*startpp)++;
820 continue;
821 }
822 escape = 0;
823 } else if (!inquote && isspace(c))
824 goto done;
825 if (cp >= buf+size-1)
826 goto done;
827 *cp++ = (u_char)c;
828 (*startpp)++;
829 }
830 }
831 done:
832 *cp = '\0';
833 return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
834 }
835
836 /*%
837 * Get a whitespace delimited base 16 number from a string (not file) into buf
838 * update the start pointer to point after the number in the string.
839 */
840 static int
gethexnum_str(u_char ** startpp,u_char * endp)841 gethexnum_str(u_char **startpp, u_char *endp) {
842 int c, n;
843 int seendigit = 0;
844 int m = 0;
845
846 if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
847 return getnum_str(startpp, endp);
848 (*startpp)+=2;
849 for (n = 0; *startpp <= endp; ) {
850 c = **startpp;
851 if (isspace(c) || c == '\0') {
852 if (seendigit) /*%< trailing whitespace */
853 break;
854 else { /*%< leading whitespace */
855 (*startpp)++;
856 continue;
857 }
858 }
859 if (c == ';') {
860 while ((*startpp <= endp) &&
861 ((c = **startpp) != '\n'))
862 (*startpp)++;
863 if (seendigit)
864 break;
865 continue;
866 }
867 if (!isxdigit(c)) {
868 if (c == ')' && seendigit) {
869 (*startpp)--;
870 break;
871 }
872 return (-1);
873 }
874 (*startpp)++;
875 if (isdigit(c))
876 n = n * 16 + (c - '0');
877 else
878 n = n * 16 + (tolower(c) - 'a' + 10);
879 seendigit = 1;
880 }
881 return (n + m);
882 }
883
884 /*%
885 * Get a whitespace delimited base 10 number from a string (not file) into buf
886 * update the start pointer to point after the number in the string.
887 */
888 static int
getnum_str(u_char ** startpp,u_char * endp)889 getnum_str(u_char **startpp, u_char *endp) {
890 int c, n;
891 int seendigit = 0;
892 int m = 0;
893
894 for (n = 0; *startpp <= endp; ) {
895 c = **startpp;
896 if (isspace(c) || c == '\0') {
897 if (seendigit) /*%< trailing whitespace */
898 break;
899 else { /*%< leading whitespace */
900 (*startpp)++;
901 continue;
902 }
903 }
904 if (c == ';') {
905 while ((*startpp <= endp) &&
906 ((c = **startpp) != '\n'))
907 (*startpp)++;
908 if (seendigit)
909 break;
910 continue;
911 }
912 if (!isdigit(c)) {
913 if (c == ')' && seendigit) {
914 (*startpp)--;
915 break;
916 }
917 return (-1);
918 }
919 (*startpp)++;
920 n = n * 10 + (c - '0');
921 seendigit = 1;
922 }
923 return (n + m);
924 }
925
926 /*%
927 * Allocate a resource record buffer & save rr info.
928 */
929 ns_updrec *
res_mkupdrec(int section,const char * dname,u_int class,u_int type,u_long ttl)930 res_mkupdrec(int section, const char *dname,
931 u_int class, u_int type, u_long ttl) {
932 ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
933
934 if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
935 if (rrecp)
936 free((char *)rrecp);
937 return (NULL);
938 }
939 INIT_LINK(rrecp, r_link);
940 INIT_LINK(rrecp, r_glink);
941 rrecp->r_class = (ns_class)class;
942 rrecp->r_type = (ns_type)type;
943 rrecp->r_ttl = ttl;
944 rrecp->r_section = (ns_sect)section;
945 return (rrecp);
946 }
947
948 /*%
949 * Free a resource record buffer created by res_mkupdrec.
950 */
951 void
res_freeupdrec(ns_updrec * rrecp)952 res_freeupdrec(ns_updrec *rrecp) {
953 /* Note: freeing r_dp is the caller's responsibility. */
954 if (rrecp->r_dname != NULL)
955 free(rrecp->r_dname);
956 free(rrecp);
957 }
958
959 struct valuelist {
960 struct valuelist * next;
961 struct valuelist * prev;
962 char * name;
963 char * proto;
964 int port;
965 };
966 static struct valuelist *servicelist, *protolist;
967
968 static void
res_buildservicelist(void)969 res_buildservicelist(void) {
970 struct servent *sp;
971 struct valuelist *slp;
972
973 #ifdef MAYBE_HESIOD
974 setservent(0);
975 #else
976 setservent(1);
977 #endif
978 while ((sp = getservent()) != NULL) {
979 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
980 if (!slp)
981 break;
982 slp->name = strdup(sp->s_name);
983 slp->proto = strdup(sp->s_proto);
984 if ((slp->name == NULL) || (slp->proto == NULL)) {
985 if (slp->name) free(slp->name);
986 if (slp->proto) free(slp->proto);
987 free(slp);
988 break;
989 }
990 slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
991 slp->next = servicelist;
992 slp->prev = NULL;
993 if (servicelist)
994 servicelist->prev = slp;
995 servicelist = slp;
996 }
997 endservent();
998 }
999
1000 #ifndef _LIBC
1001 void
res_destroyservicelist()1002 res_destroyservicelist() {
1003 struct valuelist *slp, *slp_next;
1004
1005 for (slp = servicelist; slp != NULL; slp = slp_next) {
1006 slp_next = slp->next;
1007 free(slp->name);
1008 free(slp->proto);
1009 free(slp);
1010 }
1011 servicelist = (struct valuelist *)0;
1012 }
1013 #endif
1014
1015 void
res_buildprotolist(void)1016 res_buildprotolist(void) {
1017 struct protoent *pp;
1018 struct valuelist *slp;
1019
1020 #ifdef MAYBE_HESIOD
1021 setprotoent(0);
1022 #else
1023 setprotoent(1);
1024 #endif
1025 while ((pp = getprotoent()) != NULL) {
1026 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
1027 if (!slp)
1028 break;
1029 slp->name = strdup(pp->p_name);
1030 if (slp->name == NULL) {
1031 free(slp);
1032 break;
1033 }
1034 slp->port = pp->p_proto; /*%< host byte order */
1035 slp->next = protolist;
1036 slp->prev = NULL;
1037 if (protolist)
1038 protolist->prev = slp;
1039 protolist = slp;
1040 }
1041 endprotoent();
1042 }
1043
1044 #ifndef _LIBC
1045 void
res_destroyprotolist(void)1046 res_destroyprotolist(void) {
1047 struct valuelist *plp, *plp_next;
1048
1049 for (plp = protolist; plp != NULL; plp = plp_next) {
1050 plp_next = plp->next;
1051 free(plp->name);
1052 free(plp);
1053 }
1054 protolist = (struct valuelist *)0;
1055 }
1056 #endif
1057
1058 static int
findservice(const char * s,struct valuelist ** list)1059 findservice(const char *s, struct valuelist **list) {
1060 struct valuelist *lp = *list;
1061 int n;
1062
1063 for (; lp != NULL; lp = lp->next)
1064 if (strcasecmp(lp->name, s) == 0) {
1065 if (lp != *list) {
1066 lp->prev->next = lp->next;
1067 if (lp->next)
1068 lp->next->prev = lp->prev;
1069 (*list)->prev = lp;
1070 lp->next = *list;
1071 *list = lp;
1072 }
1073 return (lp->port); /*%< host byte order */
1074 }
1075 if (sscanf(s, "%d", &n) != 1 || n <= 0)
1076 n = -1;
1077 return (n);
1078 }
1079
1080 /*%
1081 * Convert service name or (ascii) number to int.
1082 */
1083 #ifdef _LIBC
1084 static
1085 #endif
1086 int
res_servicenumber(const char * p)1087 res_servicenumber(const char *p) {
1088 if (servicelist == (struct valuelist *)0)
1089 res_buildservicelist();
1090 return (findservice(p, &servicelist));
1091 }
1092
1093 /*%
1094 * Convert protocol name or (ascii) number to int.
1095 */
1096 #ifdef _LIBC
1097 static
1098 #endif
1099 int
res_protocolnumber(const char * p)1100 res_protocolnumber(const char *p) {
1101 if (protolist == (struct valuelist *)0)
1102 res_buildprotolist();
1103 return (findservice(p, &protolist));
1104 }
1105
1106 #ifndef _LIBC
1107 static struct servent *
cgetservbyport(u_int16_t port,const char * proto)1108 cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */
1109 struct valuelist **list = &servicelist;
1110 struct valuelist *lp = *list;
1111 static struct servent serv;
1112
1113 port = ntohs(port);
1114 for (; lp != NULL; lp = lp->next) {
1115 if (port != (u_int16_t)lp->port) /*%< Host byte order. */
1116 continue;
1117 if (strcasecmp(lp->proto, proto) == 0) {
1118 if (lp != *list) {
1119 lp->prev->next = lp->next;
1120 if (lp->next)
1121 lp->next->prev = lp->prev;
1122 (*list)->prev = lp;
1123 lp->next = *list;
1124 *list = lp;
1125 }
1126 serv.s_name = lp->name;
1127 serv.s_port = htons((u_int16_t)lp->port);
1128 serv.s_proto = lp->proto;
1129 return (&serv);
1130 }
1131 }
1132 return (0);
1133 }
1134
1135 static struct protoent *
cgetprotobynumber(int proto)1136 cgetprotobynumber(int proto) { /*%< Host byte order. */
1137 struct valuelist **list = &protolist;
1138 struct valuelist *lp = *list;
1139 static struct protoent prot;
1140
1141 for (; lp != NULL; lp = lp->next)
1142 if (lp->port == proto) { /*%< Host byte order. */
1143 if (lp != *list) {
1144 lp->prev->next = lp->next;
1145 if (lp->next)
1146 lp->next->prev = lp->prev;
1147 (*list)->prev = lp;
1148 lp->next = *list;
1149 *list = lp;
1150 }
1151 prot.p_name = lp->name;
1152 prot.p_proto = lp->port; /*%< Host byte order. */
1153 return (&prot);
1154 }
1155 return (0);
1156 }
1157
1158 const char *
res_protocolname(int num)1159 res_protocolname(int num) {
1160 static char number[8];
1161 struct protoent *pp;
1162
1163 if (protolist == (struct valuelist *)0)
1164 res_buildprotolist();
1165 pp = cgetprotobynumber(num);
1166 if (pp == NULL) {
1167 (void) sprintf(number, "%d", num);
1168 return (number);
1169 }
1170 return (pp->p_name);
1171 }
1172
1173 const char *
res_servicename(u_int16_t port,const char * proto)1174 res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
1175 static char number[8];
1176 struct servent *ss;
1177
1178 if (servicelist == (struct valuelist *)0)
1179 res_buildservicelist();
1180 ss = cgetservbyport(htons(port), proto);
1181 if (ss == NULL) {
1182 (void) sprintf(number, "%d", port);
1183 return (number);
1184 }
1185 return (ss->s_name);
1186 }
1187 #endif /* !_LIBC */
1188