res_mkupdate.c revision 158782
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/*
19 * Based on the Dynamic DNS reference implementation by Viraj Bais
20 * <viraj_bais@ccm.fm.intel.com>
21 */
22
23#if !defined(lint) && !defined(SABER)
24static const char rcsid[] = "$Id: res_mkupdate.c,v 1.1.2.1.4.5 2005/10/14 05:43:47 marka Exp $";
25#endif /* not lint */
26
27#include "port_before.h"
28
29#include <sys/types.h>
30#include <sys/param.h>
31
32#include <netinet/in.h>
33#include <arpa/nameser.h>
34#include <arpa/inet.h>
35
36#include <errno.h>
37#include <limits.h>
38#include <netdb.h>
39#include <resolv.h>
40#include <res_update.h>
41#include <stdio.h>
42#include <stdlib.h>
43#include <string.h>
44#include <unistd.h>
45#include <ctype.h>
46
47#include "port_after.h"
48
49/* Options.  Leave them on. */
50#define DEBUG
51#define MAXPORT 1024
52
53static int getnum_str(u_char **, u_char *);
54static int gethexnum_str(u_char **, u_char *);
55static int getword_str(char *, int, u_char **, u_char *);
56static int getstr_str(char *, int, u_char **, u_char *);
57
58#define ShrinkBuffer(x)  if ((buflen -= x) < 0) return (-2);
59
60/* Forward. */
61
62int res_protocolnumber(const char *);
63int res_servicenumber(const char *);
64
65/*
66 * Form update packets.
67 * Returns the size of the resulting packet if no error
68 * On error,
69 *	returns -1 if error in reading a word/number in rdata
70 *		   portion for update packets
71 *		-2 if length of buffer passed is insufficient
72 *		-3 if zone section is not the first section in
73 *		   the linked list, or section order has a problem
74 *		-4 on a number overflow
75 *		-5 unknown operation or no records
76 */
77int
78res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
79	ns_updrec *rrecp_start = rrecp_in;
80	HEADER *hp;
81	u_char *cp, *sp2, *startp, *endp;
82	int n, i, soanum, multiline;
83	ns_updrec *rrecp;
84	struct in_addr ina;
85	struct in6_addr in6a;
86        char buf2[MAXDNAME];
87	u_char buf3[MAXDNAME];
88	int section, numrrs = 0, counts[ns_s_max];
89	u_int16_t rtype, rclass;
90	u_int32_t n1, rttl;
91	u_char *dnptrs[20], **dpp, **lastdnptr;
92	int siglen, keylen, certlen;
93
94	/*
95	 * Initialize header fields.
96	 */
97	if ((buf == NULL) || (buflen < HFIXEDSZ))
98		return (-1);
99	memset(buf, 0, HFIXEDSZ);
100	hp = (HEADER *) buf;
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			/* RFC 1183 */
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			/* RFC 1183 */
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 */
716static int
717getword_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 */
745static char digits[] = "0123456789";
746static int
747getstr_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 * Get a whitespace delimited base 16 number from a string (not file) into buf
821 * update the start pointer to point after the number in the string.
822 */
823static int
824gethexnum_str(u_char **startpp, u_char *endp) {
825        int c, n;
826        int seendigit = 0;
827        int m = 0;
828
829	if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
830		return getnum_str(startpp, endp);
831	(*startpp)+=2;
832        for (n = 0; *startpp <= endp; ) {
833                c = **startpp;
834                if (isspace(c) || c == '\0') {
835                        if (seendigit) /* trailing whitespace */
836                                break;
837                        else { /* leading whitespace */
838                                (*startpp)++;
839                                continue;
840                        }
841                }
842                if (c == ';') {
843                        while ((*startpp <= endp) &&
844			       ((c = **startpp) != '\n'))
845					(*startpp)++;
846                        if (seendigit)
847                                break;
848                        continue;
849                }
850                if (!isxdigit(c)) {
851                        if (c == ')' && seendigit) {
852                                (*startpp)--;
853                                break;
854                        }
855			return (-1);
856                }
857                (*startpp)++;
858		if (isdigit(c))
859	                n = n * 16 + (c - '0');
860		else
861			n = n * 16 + (tolower(c) - 'a' + 10);
862                seendigit = 1;
863        }
864        return (n + m);
865}
866
867/*
868 * Get a whitespace delimited base 10 number from a string (not file) into buf
869 * update the start pointer to point after the number in the string.
870 */
871static int
872getnum_str(u_char **startpp, u_char *endp) {
873        int c, n;
874        int seendigit = 0;
875        int m = 0;
876
877        for (n = 0; *startpp <= endp; ) {
878                c = **startpp;
879                if (isspace(c) || c == '\0') {
880                        if (seendigit) /* trailing whitespace */
881                                break;
882                        else { /* leading whitespace */
883                                (*startpp)++;
884                                continue;
885                        }
886                }
887                if (c == ';') {
888                        while ((*startpp <= endp) &&
889			       ((c = **startpp) != '\n'))
890					(*startpp)++;
891                        if (seendigit)
892                                break;
893                        continue;
894                }
895                if (!isdigit(c)) {
896                        if (c == ')' && seendigit) {
897                                (*startpp)--;
898                                break;
899                        }
900			return (-1);
901                }
902                (*startpp)++;
903                n = n * 10 + (c - '0');
904                seendigit = 1;
905        }
906        return (n + m);
907}
908
909/*
910 * Allocate a resource record buffer & save rr info.
911 */
912ns_updrec *
913res_mkupdrec(int section, const char *dname,
914	     u_int class, u_int type, u_long ttl) {
915	ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
916
917	if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
918		if (rrecp)
919			free((char *)rrecp);
920		return (NULL);
921	}
922	INIT_LINK(rrecp, r_link);
923	INIT_LINK(rrecp, r_glink);
924 	rrecp->r_class = (ns_class)class;
925	rrecp->r_type = (ns_type)type;
926	rrecp->r_ttl = ttl;
927	rrecp->r_section = (ns_sect)section;
928	return (rrecp);
929}
930
931/*
932 * Free a resource record buffer created by res_mkupdrec.
933 */
934void
935res_freeupdrec(ns_updrec *rrecp) {
936	/* Note: freeing r_dp is the caller's responsibility. */
937	if (rrecp->r_dname != NULL)
938		free(rrecp->r_dname);
939	free(rrecp);
940}
941
942struct valuelist {
943	struct valuelist *	next;
944	struct valuelist *	prev;
945	char *			name;
946	char *			proto;
947	int			port;
948};
949static struct valuelist *servicelist, *protolist;
950
951static void
952res_buildservicelist() {
953	struct servent *sp;
954	struct valuelist *slp;
955
956#ifdef MAYBE_HESIOD
957	setservent(0);
958#else
959	setservent(1);
960#endif
961	while ((sp = getservent()) != NULL) {
962		slp = (struct valuelist *)malloc(sizeof(struct valuelist));
963		if (!slp)
964			break;
965		slp->name = strdup(sp->s_name);
966		slp->proto = strdup(sp->s_proto);
967		if ((slp->name == NULL) || (slp->proto == NULL)) {
968			if (slp->name) free(slp->name);
969			if (slp->proto) free(slp->proto);
970			free(slp);
971			break;
972		}
973		slp->port = ntohs((u_int16_t)sp->s_port);  /* host byt order */
974		slp->next = servicelist;
975		slp->prev = NULL;
976		if (servicelist)
977			servicelist->prev = slp;
978		servicelist = slp;
979	}
980	endservent();
981}
982
983void
984res_destroyservicelist() {
985	struct valuelist *slp, *slp_next;
986
987	for (slp = servicelist; slp != NULL; slp = slp_next) {
988		slp_next = slp->next;
989		free(slp->name);
990		free(slp->proto);
991		free(slp);
992	}
993	servicelist = (struct valuelist *)0;
994}
995
996void
997res_buildprotolist(void) {
998	struct protoent *pp;
999	struct valuelist *slp;
1000
1001#ifdef MAYBE_HESIOD
1002	setprotoent(0);
1003#else
1004	setprotoent(1);
1005#endif
1006	while ((pp = getprotoent()) != NULL) {
1007		slp = (struct valuelist *)malloc(sizeof(struct valuelist));
1008		if (!slp)
1009			break;
1010		slp->name = strdup(pp->p_name);
1011		if (slp->name == NULL) {
1012			free(slp);
1013			break;
1014		}
1015		slp->port = pp->p_proto;	/* host byte order */
1016		slp->next = protolist;
1017		slp->prev = NULL;
1018		if (protolist)
1019			protolist->prev = slp;
1020		protolist = slp;
1021	}
1022	endprotoent();
1023}
1024
1025void
1026res_destroyprotolist(void) {
1027	struct valuelist *plp, *plp_next;
1028
1029	for (plp = protolist; plp != NULL; plp = plp_next) {
1030		plp_next = plp->next;
1031		free(plp->name);
1032		free(plp);
1033	}
1034	protolist = (struct valuelist *)0;
1035}
1036
1037static int
1038findservice(const char *s, struct valuelist **list) {
1039	struct valuelist *lp = *list;
1040	int n;
1041
1042	for (; lp != NULL; lp = lp->next)
1043		if (strcasecmp(lp->name, s) == 0) {
1044			if (lp != *list) {
1045				lp->prev->next = lp->next;
1046				if (lp->next)
1047					lp->next->prev = lp->prev;
1048				(*list)->prev = lp;
1049				lp->next = *list;
1050				*list = lp;
1051			}
1052			return (lp->port);	/* host byte order */
1053		}
1054	if (sscanf(s, "%d", &n) != 1 || n <= 0)
1055		n = -1;
1056	return (n);
1057}
1058
1059/*
1060 * Convert service name or (ascii) number to int.
1061 */
1062int
1063res_servicenumber(const char *p) {
1064	if (servicelist == (struct valuelist *)0)
1065		res_buildservicelist();
1066	return (findservice(p, &servicelist));
1067}
1068
1069/*
1070 * Convert protocol name or (ascii) number to int.
1071 */
1072int
1073res_protocolnumber(const char *p) {
1074	if (protolist == (struct valuelist *)0)
1075		res_buildprotolist();
1076	return (findservice(p, &protolist));
1077}
1078
1079static struct servent *
1080cgetservbyport(u_int16_t port, const char *proto) {	/* Host byte order. */
1081	struct valuelist **list = &servicelist;
1082	struct valuelist *lp = *list;
1083	static struct servent serv;
1084
1085	port = ntohs(port);
1086	for (; lp != NULL; lp = lp->next) {
1087		if (port != (u_int16_t)lp->port)	/* Host byte order. */
1088			continue;
1089		if (strcasecmp(lp->proto, proto) == 0) {
1090			if (lp != *list) {
1091				lp->prev->next = lp->next;
1092				if (lp->next)
1093					lp->next->prev = lp->prev;
1094				(*list)->prev = lp;
1095				lp->next = *list;
1096				*list = lp;
1097			}
1098			serv.s_name = lp->name;
1099			serv.s_port = htons((u_int16_t)lp->port);
1100			serv.s_proto = lp->proto;
1101			return (&serv);
1102		}
1103	}
1104	return (0);
1105}
1106
1107static struct protoent *
1108cgetprotobynumber(int proto) {				/* Host byte order. */
1109	struct valuelist **list = &protolist;
1110	struct valuelist *lp = *list;
1111	static struct protoent prot;
1112
1113	for (; lp != NULL; lp = lp->next)
1114		if (lp->port == proto) {		/* Host byte order. */
1115			if (lp != *list) {
1116				lp->prev->next = lp->next;
1117				if (lp->next)
1118					lp->next->prev = lp->prev;
1119				(*list)->prev = lp;
1120				lp->next = *list;
1121				*list = lp;
1122			}
1123			prot.p_name = lp->name;
1124			prot.p_proto = lp->port;	/* Host byte order. */
1125			return (&prot);
1126		}
1127	return (0);
1128}
1129
1130const char *
1131res_protocolname(int num) {
1132	static char number[8];
1133	struct protoent *pp;
1134
1135	if (protolist == (struct valuelist *)0)
1136		res_buildprotolist();
1137	pp = cgetprotobynumber(num);
1138	if (pp == 0)  {
1139		(void) sprintf(number, "%d", num);
1140		return (number);
1141	}
1142	return (pp->p_name);
1143}
1144
1145const char *
1146res_servicename(u_int16_t port, const char *proto) {	/* Host byte order. */
1147	static char number[8];
1148	struct servent *ss;
1149
1150	if (servicelist == (struct valuelist *)0)
1151		res_buildservicelist();
1152	ss = cgetservbyport(htons(port), proto);
1153	if (ss == 0)  {
1154		(void) sprintf(number, "%d", port);
1155		return (number);
1156	}
1157	return (ss->s_name);
1158}
1159