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