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