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