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