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