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