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