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