res_mkupdate.c revision 158782
1158782Sume/*
2158782Sume * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3158782Sume * Copyright (c) 1996-1999 by Internet Software Consortium.
4158782Sume *
5158782Sume * Permission to use, copy, modify, and distribute this software for any
6158782Sume * purpose with or without fee is hereby granted, provided that the above
7158782Sume * copyright notice and this permission notice appear in all copies.
8158782Sume *
9158782Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10158782Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11158782Sume * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12158782Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13158782Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14158782Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15158782Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16158782Sume */
17158782Sume
18158782Sume/*
19158782Sume * Based on the Dynamic DNS reference implementation by Viraj Bais
20158782Sume * <viraj_bais@ccm.fm.intel.com>
21158782Sume */
22158782Sume
23158782Sume#if !defined(lint) && !defined(SABER)
24158782Sumestatic const char rcsid[] = "$Id: res_mkupdate.c,v 1.1.2.1.4.5 2005/10/14 05:43:47 marka Exp $";
25158782Sume#endif /* not lint */
26158782Sume
27158782Sume#include "port_before.h"
28158782Sume
29158782Sume#include <sys/types.h>
30158782Sume#include <sys/param.h>
31158782Sume
32158782Sume#include <netinet/in.h>
33158782Sume#include <arpa/nameser.h>
34158782Sume#include <arpa/inet.h>
35158782Sume
36158782Sume#include <errno.h>
37158782Sume#include <limits.h>
38158782Sume#include <netdb.h>
39158782Sume#include <resolv.h>
40158782Sume#include <res_update.h>
41158782Sume#include <stdio.h>
42158782Sume#include <stdlib.h>
43158782Sume#include <string.h>
44158782Sume#include <unistd.h>
45158782Sume#include <ctype.h>
46158782Sume
47158782Sume#include "port_after.h"
48158782Sume
49158782Sume/* Options.  Leave them on. */
50158782Sume#define DEBUG
51158782Sume#define MAXPORT 1024
52158782Sume
53158782Sumestatic int getnum_str(u_char **, u_char *);
54158782Sumestatic int gethexnum_str(u_char **, u_char *);
55158782Sumestatic int getword_str(char *, int, u_char **, u_char *);
56158782Sumestatic int getstr_str(char *, int, u_char **, u_char *);
57158782Sume
58158782Sume#define ShrinkBuffer(x)  if ((buflen -= x) < 0) return (-2);
59158782Sume
60158782Sume/* Forward. */
61158782Sume
62158782Sumeint res_protocolnumber(const char *);
63158782Sumeint res_servicenumber(const char *);
64158782Sume
65158782Sume/*
66158782Sume * Form update packets.
67158782Sume * Returns the size of the resulting packet if no error
68158782Sume * On error,
69158782Sume *	returns -1 if error in reading a word/number in rdata
70158782Sume *		   portion for update packets
71158782Sume *		-2 if length of buffer passed is insufficient
72158782Sume *		-3 if zone section is not the first section in
73158782Sume *		   the linked list, or section order has a problem
74158782Sume *		-4 on a number overflow
75158782Sume *		-5 unknown operation or no records
76158782Sume */
77158782Sumeint
78158782Sumeres_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
79158782Sume	ns_updrec *rrecp_start = rrecp_in;
80158782Sume	HEADER *hp;
81158782Sume	u_char *cp, *sp2, *startp, *endp;
82158782Sume	int n, i, soanum, multiline;
83158782Sume	ns_updrec *rrecp;
84158782Sume	struct in_addr ina;
85158782Sume	struct in6_addr in6a;
86158782Sume        char buf2[MAXDNAME];
87158782Sume	u_char buf3[MAXDNAME];
88158782Sume	int section, numrrs = 0, counts[ns_s_max];
89158782Sume	u_int16_t rtype, rclass;
90158782Sume	u_int32_t n1, rttl;
91158782Sume	u_char *dnptrs[20], **dpp, **lastdnptr;
92158782Sume	int siglen, keylen, certlen;
93158782Sume
94158782Sume	/*
95158782Sume	 * Initialize header fields.
96158782Sume	 */
97158782Sume	if ((buf == NULL) || (buflen < HFIXEDSZ))
98158782Sume		return (-1);
99158782Sume	memset(buf, 0, HFIXEDSZ);
100158782Sume	hp = (HEADER *) buf;
101158782Sume	hp->id = htons(++statp->id);
102158782Sume	hp->opcode = ns_o_update;
103158782Sume	hp->rcode = NOERROR;
104158782Sume	cp = buf + HFIXEDSZ;
105158782Sume	buflen -= HFIXEDSZ;
106158782Sume	dpp = dnptrs;
107158782Sume	*dpp++ = buf;
108158782Sume	*dpp++ = NULL;
109158782Sume	lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
110158782Sume
111158782Sume	if (rrecp_start == NULL)
112158782Sume		return (-5);
113158782Sume	else if (rrecp_start->r_section != S_ZONE)
114158782Sume		return (-3);
115158782Sume
116158782Sume	memset(counts, 0, sizeof counts);
117158782Sume	for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
118158782Sume		numrrs++;
119158782Sume                section = rrecp->r_section;
120158782Sume		if (section < 0 || section >= ns_s_max)
121158782Sume			return (-1);
122158782Sume		counts[section]++;
123158782Sume		for (i = section + 1; i < ns_s_max; i++)
124158782Sume			if (counts[i])
125158782Sume				return (-3);
126158782Sume		rtype = rrecp->r_type;
127158782Sume		rclass = rrecp->r_class;
128158782Sume		rttl = rrecp->r_ttl;
129158782Sume		/* overload class and type */
130158782Sume		if (section == S_PREREQ) {
131158782Sume			rttl = 0;
132158782Sume			switch (rrecp->r_opcode) {
133158782Sume			case YXDOMAIN:
134158782Sume				rclass = C_ANY;
135158782Sume				rtype = T_ANY;
136158782Sume				rrecp->r_size = 0;
137158782Sume				break;
138158782Sume			case NXDOMAIN:
139158782Sume				rclass = C_NONE;
140158782Sume				rtype = T_ANY;
141158782Sume				rrecp->r_size = 0;
142158782Sume				break;
143158782Sume			case NXRRSET:
144158782Sume				rclass = C_NONE;
145158782Sume				rrecp->r_size = 0;
146158782Sume				break;
147158782Sume			case YXRRSET:
148158782Sume				if (rrecp->r_size == 0)
149158782Sume					rclass = C_ANY;
150158782Sume				break;
151158782Sume			default:
152158782Sume				fprintf(stderr,
153158782Sume					"res_mkupdate: incorrect opcode: %d\n",
154158782Sume					rrecp->r_opcode);
155158782Sume				fflush(stderr);
156158782Sume				return (-1);
157158782Sume			}
158158782Sume		} else if (section == S_UPDATE) {
159158782Sume			switch (rrecp->r_opcode) {
160158782Sume			case DELETE:
161158782Sume				rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
162158782Sume				break;
163158782Sume			case ADD:
164158782Sume				break;
165158782Sume			default:
166158782Sume				fprintf(stderr,
167158782Sume					"res_mkupdate: incorrect opcode: %d\n",
168158782Sume					rrecp->r_opcode);
169158782Sume				fflush(stderr);
170158782Sume				return (-1);
171158782Sume			}
172158782Sume		}
173158782Sume
174158782Sume		/*
175158782Sume		 * XXX	appending default domain to owner name is omitted,
176158782Sume		 *	fqdn must be provided
177158782Sume		 */
178158782Sume		if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
179158782Sume				 lastdnptr)) < 0)
180158782Sume			return (-1);
181158782Sume		cp += n;
182158782Sume		ShrinkBuffer(n + 2*INT16SZ);
183158782Sume		PUTSHORT(rtype, cp);
184158782Sume		PUTSHORT(rclass, cp);
185158782Sume		if (section == S_ZONE) {
186158782Sume			if (numrrs != 1 || rrecp->r_type != T_SOA)
187158782Sume				return (-3);
188158782Sume			continue;
189158782Sume		}
190158782Sume		ShrinkBuffer(INT32SZ + INT16SZ);
191158782Sume		PUTLONG(rttl, cp);
192158782Sume		sp2 = cp;  /* save pointer to length byte */
193158782Sume		cp += INT16SZ;
194158782Sume		if (rrecp->r_size == 0) {
195158782Sume			if (section == S_UPDATE && rclass != C_ANY)
196158782Sume				return (-1);
197158782Sume			else {
198158782Sume				PUTSHORT(0, sp2);
199158782Sume				continue;
200158782Sume			}
201158782Sume		}
202158782Sume		startp = rrecp->r_data;
203158782Sume		endp = startp + rrecp->r_size - 1;
204158782Sume		/* XXX this should be done centrally. */
205158782Sume		switch (rrecp->r_type) {
206158782Sume		case T_A:
207158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
208158782Sume				return (-1);
209158782Sume			if (!inet_aton(buf2, &ina))
210158782Sume				return (-1);
211158782Sume			n1 = ntohl(ina.s_addr);
212158782Sume			ShrinkBuffer(INT32SZ);
213158782Sume			PUTLONG(n1, cp);
214158782Sume			break;
215158782Sume		case T_CNAME:
216158782Sume		case T_MB:
217158782Sume		case T_MG:
218158782Sume		case T_MR:
219158782Sume		case T_NS:
220158782Sume		case T_PTR:
221158782Sume		case ns_t_dname:
222158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
223158782Sume				return (-1);
224158782Sume			n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
225158782Sume			if (n < 0)
226158782Sume				return (-1);
227158782Sume			cp += n;
228158782Sume			ShrinkBuffer(n);
229158782Sume			break;
230158782Sume		case T_MINFO:
231158782Sume		case T_SOA:
232158782Sume		case T_RP:
233158782Sume			for (i = 0; i < 2; i++) {
234158782Sume				if (!getword_str(buf2, sizeof buf2, &startp,
235158782Sume						 endp))
236158782Sume				return (-1);
237158782Sume				n = dn_comp(buf2, cp, buflen,
238158782Sume					    dnptrs, lastdnptr);
239158782Sume				if (n < 0)
240158782Sume					return (-1);
241158782Sume				cp += n;
242158782Sume				ShrinkBuffer(n);
243158782Sume			}
244158782Sume			if (rrecp->r_type == T_SOA) {
245158782Sume				ShrinkBuffer(5 * INT32SZ);
246158782Sume				while (isspace(*startp) || !*startp)
247158782Sume					startp++;
248158782Sume				if (*startp == '(') {
249158782Sume					multiline = 1;
250158782Sume					startp++;
251158782Sume				} else
252158782Sume					multiline = 0;
253158782Sume				/* serial, refresh, retry, expire, minimum */
254158782Sume				for (i = 0; i < 5; i++) {
255158782Sume					soanum = getnum_str(&startp, endp);
256158782Sume					if (soanum < 0)
257158782Sume						return (-1);
258158782Sume					PUTLONG(soanum, cp);
259158782Sume				}
260158782Sume				if (multiline) {
261158782Sume					while (isspace(*startp) || !*startp)
262158782Sume						startp++;
263158782Sume					if (*startp != ')')
264158782Sume						return (-1);
265158782Sume				}
266158782Sume			}
267158782Sume			break;
268158782Sume		case T_MX:
269158782Sume		case T_AFSDB:
270158782Sume		case T_RT:
271158782Sume			n = getnum_str(&startp, endp);
272158782Sume			if (n < 0)
273158782Sume				return (-1);
274158782Sume			ShrinkBuffer(INT16SZ);
275158782Sume			PUTSHORT(n, cp);
276158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
277158782Sume				return (-1);
278158782Sume			n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
279158782Sume			if (n < 0)
280158782Sume				return (-1);
281158782Sume			cp += n;
282158782Sume			ShrinkBuffer(n);
283158782Sume			break;
284158782Sume		case T_SRV:
285158782Sume			n = getnum_str(&startp, endp);
286158782Sume			if (n < 0)
287158782Sume				return (-1);
288158782Sume			ShrinkBuffer(INT16SZ);
289158782Sume			PUTSHORT(n, cp);
290158782Sume
291158782Sume			n = getnum_str(&startp, endp);
292158782Sume			if (n < 0)
293158782Sume				return (-1);
294158782Sume			ShrinkBuffer(INT16SZ);
295158782Sume			PUTSHORT(n, cp);
296158782Sume
297158782Sume			n = getnum_str(&startp, endp);
298158782Sume			if (n < 0)
299158782Sume				return (-1);
300158782Sume			ShrinkBuffer(INT16SZ);
301158782Sume			PUTSHORT(n, cp);
302158782Sume
303158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
304158782Sume				return (-1);
305158782Sume			n = dn_comp(buf2, cp, buflen, NULL, NULL);
306158782Sume			if (n < 0)
307158782Sume				return (-1);
308158782Sume			cp += n;
309158782Sume			ShrinkBuffer(n);
310158782Sume			break;
311158782Sume		case T_PX:
312158782Sume			n = getnum_str(&startp, endp);
313158782Sume			if (n < 0)
314158782Sume				return (-1);
315158782Sume			PUTSHORT(n, cp);
316158782Sume			ShrinkBuffer(INT16SZ);
317158782Sume			for (i = 0; i < 2; i++) {
318158782Sume				if (!getword_str(buf2, sizeof buf2, &startp,
319158782Sume						 endp))
320158782Sume					return (-1);
321158782Sume				n = dn_comp(buf2, cp, buflen, dnptrs,
322158782Sume					    lastdnptr);
323158782Sume				if (n < 0)
324158782Sume					return (-1);
325158782Sume				cp += n;
326158782Sume				ShrinkBuffer(n);
327158782Sume			}
328158782Sume			break;
329158782Sume		case T_WKS: {
330158782Sume			char bm[MAXPORT/8];
331158782Sume			unsigned int maxbm = 0;
332158782Sume
333158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
334158782Sume				return (-1);
335158782Sume			if (!inet_aton(buf2, &ina))
336158782Sume				return (-1);
337158782Sume			n1 = ntohl(ina.s_addr);
338158782Sume			ShrinkBuffer(INT32SZ);
339158782Sume			PUTLONG(n1, cp);
340158782Sume
341158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
342158782Sume				return (-1);
343158782Sume			if ((i = res_protocolnumber(buf2)) < 0)
344158782Sume				return (-1);
345158782Sume			ShrinkBuffer(1);
346158782Sume			*cp++ = i & 0xff;
347158782Sume
348158782Sume			for (i = 0; i < MAXPORT/8 ; i++)
349158782Sume				bm[i] = 0;
350158782Sume
351158782Sume			while (getword_str(buf2, sizeof buf2, &startp, endp)) {
352158782Sume				if ((n = res_servicenumber(buf2)) <= 0)
353158782Sume					return (-1);
354158782Sume
355158782Sume				if (n < MAXPORT) {
356158782Sume					bm[n/8] |= (0x80>>(n%8));
357158782Sume					if ((unsigned)n > maxbm)
358158782Sume						maxbm = n;
359158782Sume				} else
360158782Sume					return (-1);
361158782Sume			}
362158782Sume			maxbm = maxbm/8 + 1;
363158782Sume			ShrinkBuffer(maxbm);
364158782Sume			memcpy(cp, bm, maxbm);
365158782Sume			cp += maxbm;
366158782Sume			break;
367158782Sume		}
368158782Sume		case T_HINFO:
369158782Sume			for (i = 0; i < 2; i++) {
370158782Sume				if ((n = getstr_str(buf2, sizeof buf2,
371158782Sume						&startp, endp)) < 0)
372158782Sume					return (-1);
373158782Sume				if (n > 255)
374158782Sume					return (-1);
375158782Sume				ShrinkBuffer(n+1);
376158782Sume				*cp++ = n;
377158782Sume				memcpy(cp, buf2, n);
378158782Sume				cp += n;
379158782Sume			}
380158782Sume			break;
381158782Sume		case T_TXT:
382158782Sume			for (;;) {
383158782Sume				if ((n = getstr_str(buf2, sizeof buf2,
384158782Sume						&startp, endp)) < 0) {
385158782Sume					if (cp != (sp2 + INT16SZ))
386158782Sume						break;
387158782Sume					return (-1);
388158782Sume				}
389158782Sume				if (n > 255)
390158782Sume					return (-1);
391158782Sume				ShrinkBuffer(n+1);
392158782Sume				*cp++ = n;
393158782Sume				memcpy(cp, buf2, n);
394158782Sume				cp += n;
395158782Sume			}
396158782Sume			break;
397158782Sume		case T_X25:
398158782Sume			/* RFC 1183 */
399158782Sume			if ((n = getstr_str(buf2, sizeof buf2, &startp,
400158782Sume					 endp)) < 0)
401158782Sume				return (-1);
402158782Sume			if (n > 255)
403158782Sume				return (-1);
404158782Sume			ShrinkBuffer(n+1);
405158782Sume			*cp++ = n;
406158782Sume			memcpy(cp, buf2, n);
407158782Sume			cp += n;
408158782Sume			break;
409158782Sume		case T_ISDN:
410158782Sume			/* RFC 1183 */
411158782Sume			if ((n = getstr_str(buf2, sizeof buf2, &startp,
412158782Sume					 endp)) < 0)
413158782Sume				return (-1);
414158782Sume			if ((n > 255) || (n == 0))
415158782Sume				return (-1);
416158782Sume			ShrinkBuffer(n+1);
417158782Sume			*cp++ = n;
418158782Sume			memcpy(cp, buf2, n);
419158782Sume			cp += n;
420158782Sume			if ((n = getstr_str(buf2, sizeof buf2, &startp,
421158782Sume					 endp)) < 0)
422158782Sume				n = 0;
423158782Sume			if (n > 255)
424158782Sume				return (-1);
425158782Sume			ShrinkBuffer(n+1);
426158782Sume			*cp++ = n;
427158782Sume			memcpy(cp, buf2, n);
428158782Sume			cp += n;
429158782Sume			break;
430158782Sume		case T_NSAP:
431158782Sume			if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
432158782Sume				ShrinkBuffer(n);
433158782Sume				memcpy(cp, buf2, n);
434158782Sume				cp += n;
435158782Sume			} else {
436158782Sume				return (-1);
437158782Sume			}
438158782Sume			break;
439158782Sume		case T_LOC:
440158782Sume			if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
441158782Sume				ShrinkBuffer(n);
442158782Sume				memcpy(cp, buf2, n);
443158782Sume				cp += n;
444158782Sume			} else
445158782Sume				return (-1);
446158782Sume			break;
447158782Sume		case ns_t_sig:
448158782Sume		    {
449158782Sume			int sig_type, success, dateerror;
450158782Sume			u_int32_t exptime, timesigned;
451158782Sume
452158782Sume			/* type */
453158782Sume			if ((n = getword_str(buf2, sizeof buf2,
454158782Sume					     &startp, endp)) < 0)
455158782Sume				return (-1);
456158782Sume			sig_type = sym_ston(__p_type_syms, buf2, &success);
457158782Sume			if (!success || sig_type == ns_t_any)
458158782Sume				return (-1);
459158782Sume			ShrinkBuffer(INT16SZ);
460158782Sume			PUTSHORT(sig_type, cp);
461158782Sume			/* alg */
462158782Sume			n = getnum_str(&startp, endp);
463158782Sume			if (n < 0)
464158782Sume				return (-1);
465158782Sume			ShrinkBuffer(1);
466158782Sume			*cp++ = n;
467158782Sume			/* labels */
468158782Sume			n = getnum_str(&startp, endp);
469158782Sume			if (n <= 0 || n > 255)
470158782Sume				return (-1);
471158782Sume			ShrinkBuffer(1);
472158782Sume			*cp++ = n;
473158782Sume			/* ottl  & expire */
474158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
475158782Sume				return (-1);
476158782Sume			exptime = ns_datetosecs(buf2, &dateerror);
477158782Sume			if (!dateerror) {
478158782Sume				ShrinkBuffer(INT32SZ);
479158782Sume				PUTLONG(rttl, cp);
480158782Sume			}
481158782Sume			else {
482158782Sume				char *ulendp;
483158782Sume				u_int32_t ottl;
484158782Sume
485158782Sume				errno = 0;
486158782Sume				ottl = strtoul(buf2, &ulendp, 10);
487158782Sume				if (errno != 0 ||
488158782Sume				    (ulendp != NULL && *ulendp != '\0'))
489158782Sume					return (-1);
490158782Sume				ShrinkBuffer(INT32SZ);
491158782Sume				PUTLONG(ottl, cp);
492158782Sume				if (!getword_str(buf2, sizeof buf2, &startp,
493158782Sume						 endp))
494158782Sume					return (-1);
495158782Sume				exptime = ns_datetosecs(buf2, &dateerror);
496158782Sume				if (dateerror)
497158782Sume					return (-1);
498158782Sume			}
499158782Sume			/* expire */
500158782Sume			ShrinkBuffer(INT32SZ);
501158782Sume			PUTLONG(exptime, cp);
502158782Sume			/* timesigned */
503158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
504158782Sume				return (-1);
505158782Sume			timesigned = ns_datetosecs(buf2, &dateerror);
506158782Sume			if (!dateerror) {
507158782Sume				ShrinkBuffer(INT32SZ);
508158782Sume				PUTLONG(timesigned, cp);
509158782Sume			}
510158782Sume			else
511158782Sume				return (-1);
512158782Sume			/* footprint */
513158782Sume			n = getnum_str(&startp, endp);
514158782Sume			if (n < 0)
515158782Sume				return (-1);
516158782Sume			ShrinkBuffer(INT16SZ);
517158782Sume			PUTSHORT(n, cp);
518158782Sume			/* signer name */
519158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
520158782Sume				return (-1);
521158782Sume			n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
522158782Sume			if (n < 0)
523158782Sume				return (-1);
524158782Sume			cp += n;
525158782Sume			ShrinkBuffer(n);
526158782Sume			/* sig */
527158782Sume			if ((n = getword_str(buf2, sizeof buf2,
528158782Sume					     &startp, endp)) < 0)
529158782Sume				return (-1);
530158782Sume			siglen = b64_pton(buf2, buf3, sizeof(buf3));
531158782Sume			if (siglen < 0)
532158782Sume				return (-1);
533158782Sume			ShrinkBuffer(siglen);
534158782Sume			memcpy(cp, buf3, siglen);
535158782Sume			cp += siglen;
536158782Sume			break;
537158782Sume		    }
538158782Sume		case ns_t_key:
539158782Sume			/* flags */
540158782Sume			n = gethexnum_str(&startp, endp);
541158782Sume			if (n < 0)
542158782Sume				return (-1);
543158782Sume			ShrinkBuffer(INT16SZ);
544158782Sume			PUTSHORT(n, cp);
545158782Sume			/* proto */
546158782Sume			n = getnum_str(&startp, endp);
547158782Sume			if (n < 0)
548158782Sume				return (-1);
549158782Sume			ShrinkBuffer(1);
550158782Sume			*cp++ = n;
551158782Sume			/* alg */
552158782Sume			n = getnum_str(&startp, endp);
553158782Sume			if (n < 0)
554158782Sume				return (-1);
555158782Sume			ShrinkBuffer(1);
556158782Sume			*cp++ = n;
557158782Sume			/* key */
558158782Sume			if ((n = getword_str(buf2, sizeof buf2,
559158782Sume					     &startp, endp)) < 0)
560158782Sume				return (-1);
561158782Sume			keylen = b64_pton(buf2, buf3, sizeof(buf3));
562158782Sume			if (keylen < 0)
563158782Sume				return (-1);
564158782Sume			ShrinkBuffer(keylen);
565158782Sume			memcpy(cp, buf3, keylen);
566158782Sume			cp += keylen;
567158782Sume			break;
568158782Sume		case ns_t_nxt:
569158782Sume		    {
570158782Sume			int success, nxt_type;
571158782Sume			u_char data[32];
572158782Sume			int maxtype;
573158782Sume
574158782Sume			/* next name */
575158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
576158782Sume				return (-1);
577158782Sume			n = dn_comp(buf2, cp, buflen, NULL, NULL);
578158782Sume			if (n < 0)
579158782Sume				return (-1);
580158782Sume			cp += n;
581158782Sume			ShrinkBuffer(n);
582158782Sume			maxtype = 0;
583158782Sume			memset(data, 0, sizeof data);
584158782Sume			for (;;) {
585158782Sume				if (!getword_str(buf2, sizeof buf2, &startp,
586158782Sume						 endp))
587158782Sume					break;
588158782Sume				nxt_type = sym_ston(__p_type_syms, buf2,
589158782Sume						    &success);
590158782Sume				if (!success || !ns_t_rr_p(nxt_type))
591158782Sume					return (-1);
592158782Sume				NS_NXT_BIT_SET(nxt_type, data);
593158782Sume				if (nxt_type > maxtype)
594158782Sume					maxtype = nxt_type;
595158782Sume			}
596158782Sume			n = maxtype/NS_NXT_BITS+1;
597158782Sume			ShrinkBuffer(n);
598158782Sume			memcpy(cp, data, n);
599158782Sume			cp += n;
600158782Sume			break;
601158782Sume		    }
602158782Sume		case ns_t_cert:
603158782Sume			/* type */
604158782Sume			n = getnum_str(&startp, endp);
605158782Sume			if (n < 0)
606158782Sume				return (-1);
607158782Sume			ShrinkBuffer(INT16SZ);
608158782Sume			PUTSHORT(n, cp);
609158782Sume			/* key tag */
610158782Sume			n = getnum_str(&startp, endp);
611158782Sume			if (n < 0)
612158782Sume				return (-1);
613158782Sume			ShrinkBuffer(INT16SZ);
614158782Sume			PUTSHORT(n, cp);
615158782Sume			/* alg */
616158782Sume			n = getnum_str(&startp, endp);
617158782Sume			if (n < 0)
618158782Sume				return (-1);
619158782Sume			ShrinkBuffer(1);
620158782Sume			*cp++ = n;
621158782Sume			/* cert */
622158782Sume			if ((n = getword_str(buf2, sizeof buf2,
623158782Sume					     &startp, endp)) < 0)
624158782Sume				return (-1);
625158782Sume			certlen = b64_pton(buf2, buf3, sizeof(buf3));
626158782Sume			if (certlen < 0)
627158782Sume				return (-1);
628158782Sume			ShrinkBuffer(certlen);
629158782Sume			memcpy(cp, buf3, certlen);
630158782Sume			cp += certlen;
631158782Sume			break;
632158782Sume		case ns_t_aaaa:
633158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
634158782Sume				return (-1);
635158782Sume			if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
636158782Sume				return (-1);
637158782Sume			ShrinkBuffer(NS_IN6ADDRSZ);
638158782Sume			memcpy(cp, &in6a, NS_IN6ADDRSZ);
639158782Sume			cp += NS_IN6ADDRSZ;
640158782Sume			break;
641158782Sume		case ns_t_naptr:
642158782Sume			/* Order Preference Flags Service Replacement Regexp */
643158782Sume			/* Order */
644158782Sume			n = getnum_str(&startp, endp);
645158782Sume			if (n < 0 || n > 65535)
646158782Sume				return (-1);
647158782Sume			ShrinkBuffer(INT16SZ);
648158782Sume			PUTSHORT(n, cp);
649158782Sume			/* Preference */
650158782Sume			n = getnum_str(&startp, endp);
651158782Sume			if (n < 0 || n > 65535)
652158782Sume				return (-1);
653158782Sume			ShrinkBuffer(INT16SZ);
654158782Sume			PUTSHORT(n, cp);
655158782Sume			/* Flags */
656158782Sume			if ((n = getstr_str(buf2, sizeof buf2,
657158782Sume					&startp, endp)) < 0) {
658158782Sume				return (-1);
659158782Sume			}
660158782Sume			if (n > 255)
661158782Sume				return (-1);
662158782Sume			ShrinkBuffer(n+1);
663158782Sume			*cp++ = n;
664158782Sume			memcpy(cp, buf2, n);
665158782Sume			cp += n;
666158782Sume			/* Service Classes */
667158782Sume			if ((n = getstr_str(buf2, sizeof buf2,
668158782Sume					&startp, endp)) < 0) {
669158782Sume				return (-1);
670158782Sume			}
671158782Sume			if (n > 255)
672158782Sume				return (-1);
673158782Sume			ShrinkBuffer(n+1);
674158782Sume			*cp++ = n;
675158782Sume			memcpy(cp, buf2, n);
676158782Sume			cp += n;
677158782Sume			/* Pattern */
678158782Sume			if ((n = getstr_str(buf2, sizeof buf2,
679158782Sume					&startp, endp)) < 0) {
680158782Sume				return (-1);
681158782Sume			}
682158782Sume			if (n > 255)
683158782Sume				return (-1);
684158782Sume			ShrinkBuffer(n+1);
685158782Sume			*cp++ = n;
686158782Sume			memcpy(cp, buf2, n);
687158782Sume			cp += n;
688158782Sume			/* Replacement */
689158782Sume			if (!getword_str(buf2, sizeof buf2, &startp, endp))
690158782Sume				return (-1);
691158782Sume			n = dn_comp(buf2, cp, buflen, NULL, NULL);
692158782Sume			if (n < 0)
693158782Sume				return (-1);
694158782Sume			cp += n;
695158782Sume			ShrinkBuffer(n);
696158782Sume			break;
697158782Sume		default:
698158782Sume			return (-1);
699158782Sume		} /*switch*/
700158782Sume		n = (u_int16_t)((cp - sp2) - INT16SZ);
701158782Sume		PUTSHORT(n, sp2);
702158782Sume	} /*for*/
703158782Sume
704158782Sume	hp->qdcount = htons(counts[0]);
705158782Sume	hp->ancount = htons(counts[1]);
706158782Sume	hp->nscount = htons(counts[2]);
707158782Sume	hp->arcount = htons(counts[3]);
708158782Sume	return (cp - buf);
709158782Sume}
710158782Sume
711158782Sume/*
712158782Sume * Get a whitespace delimited word from a string (not file)
713158782Sume * into buf. modify the start pointer to point after the
714158782Sume * word in the string.
715158782Sume */
716158782Sumestatic int
717158782Sumegetword_str(char *buf, int size, u_char **startpp, u_char *endp) {
718158782Sume        char *cp;
719158782Sume        int c;
720158782Sume
721158782Sume        for (cp = buf; *startpp <= endp; ) {
722158782Sume                c = **startpp;
723158782Sume                if (isspace(c) || c == '\0') {
724158782Sume                        if (cp != buf) /* trailing whitespace */
725158782Sume                                break;
726158782Sume                        else { /* leading whitespace */
727158782Sume                                (*startpp)++;
728158782Sume                                continue;
729158782Sume                        }
730158782Sume                }
731158782Sume                (*startpp)++;
732158782Sume                if (cp >= buf+size-1)
733158782Sume                        break;
734158782Sume                *cp++ = (u_char)c;
735158782Sume        }
736158782Sume        *cp = '\0';
737158782Sume        return (cp != buf);
738158782Sume}
739158782Sume
740158782Sume/*
741158782Sume * get a white spae delimited string from memory.  Process quoted strings
742158782Sume * and \DDD escapes.  Return length or -1 on error.  Returned string may
743158782Sume * contain nulls.
744158782Sume */
745158782Sumestatic char digits[] = "0123456789";
746158782Sumestatic int
747158782Sumegetstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
748158782Sume        char *cp;
749158782Sume        int c, c1 = 0;
750158782Sume	int inquote = 0;
751158782Sume	int seen_quote = 0;
752158782Sume	int escape = 0;
753158782Sume	int dig = 0;
754158782Sume
755158782Sume	for (cp = buf; *startpp <= endp; ) {
756158782Sume                if ((c = **startpp) == '\0')
757158782Sume			break;
758158782Sume		/* leading white space */
759158782Sume		if ((cp == buf) && !seen_quote && isspace(c)) {
760158782Sume			(*startpp)++;
761158782Sume			continue;
762158782Sume		}
763158782Sume
764158782Sume		switch (c) {
765158782Sume		case '\\':
766158782Sume			if (!escape)  {
767158782Sume				escape = 1;
768158782Sume				dig = 0;
769158782Sume				c1 = 0;
770158782Sume				(*startpp)++;
771158782Sume				continue;
772158782Sume			}
773158782Sume			goto do_escape;
774158782Sume		case '"':
775158782Sume			if (!escape) {
776158782Sume				inquote = !inquote;
777158782Sume				seen_quote = 1;
778158782Sume				(*startpp)++;
779158782Sume				continue;
780158782Sume			}
781158782Sume			/* fall through */
782158782Sume		default:
783158782Sume		do_escape:
784158782Sume			if (escape) {
785158782Sume				switch (c) {
786158782Sume				case '0':
787158782Sume				case '1':
788158782Sume				case '2':
789158782Sume				case '3':
790158782Sume				case '4':
791158782Sume				case '5':
792158782Sume				case '6':
793158782Sume				case '7':
794158782Sume				case '8':
795158782Sume				case '9':
796158782Sume					c1 = c1 * 10 +
797158782Sume						(strchr(digits, c) - digits);
798158782Sume
799158782Sume					if (++dig == 3) {
800158782Sume						c = c1 &0xff;
801158782Sume						break;
802158782Sume					}
803158782Sume					(*startpp)++;
804158782Sume					continue;
805158782Sume				}
806158782Sume				escape = 0;
807158782Sume			} else if (!inquote && isspace(c))
808158782Sume				goto done;
809158782Sume			if (cp >= buf+size-1)
810158782Sume				goto done;
811158782Sume			*cp++ = (u_char)c;
812158782Sume			(*startpp)++;
813158782Sume		}
814158782Sume	}
815158782Sume done:
816158782Sume	*cp = '\0';
817158782Sume	return ((cp == buf)?  (seen_quote? 0: -1): (cp - buf));
818158782Sume}
819158782Sume/*
820158782Sume * Get a whitespace delimited base 16 number from a string (not file) into buf
821158782Sume * update the start pointer to point after the number in the string.
822158782Sume */
823158782Sumestatic int
824158782Sumegethexnum_str(u_char **startpp, u_char *endp) {
825158782Sume        int c, n;
826158782Sume        int seendigit = 0;
827158782Sume        int m = 0;
828158782Sume
829158782Sume	if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
830158782Sume		return getnum_str(startpp, endp);
831158782Sume	(*startpp)+=2;
832158782Sume        for (n = 0; *startpp <= endp; ) {
833158782Sume                c = **startpp;
834158782Sume                if (isspace(c) || c == '\0') {
835158782Sume                        if (seendigit) /* trailing whitespace */
836158782Sume                                break;
837158782Sume                        else { /* leading whitespace */
838158782Sume                                (*startpp)++;
839158782Sume                                continue;
840158782Sume                        }
841158782Sume                }
842158782Sume                if (c == ';') {
843158782Sume                        while ((*startpp <= endp) &&
844158782Sume			       ((c = **startpp) != '\n'))
845158782Sume					(*startpp)++;
846158782Sume                        if (seendigit)
847158782Sume                                break;
848158782Sume                        continue;
849158782Sume                }
850158782Sume                if (!isxdigit(c)) {
851158782Sume                        if (c == ')' && seendigit) {
852158782Sume                                (*startpp)--;
853158782Sume                                break;
854158782Sume                        }
855158782Sume			return (-1);
856158782Sume                }
857158782Sume                (*startpp)++;
858158782Sume		if (isdigit(c))
859158782Sume	                n = n * 16 + (c - '0');
860158782Sume		else
861158782Sume			n = n * 16 + (tolower(c) - 'a' + 10);
862158782Sume                seendigit = 1;
863158782Sume        }
864158782Sume        return (n + m);
865158782Sume}
866158782Sume
867158782Sume/*
868158782Sume * Get a whitespace delimited base 10 number from a string (not file) into buf
869158782Sume * update the start pointer to point after the number in the string.
870158782Sume */
871158782Sumestatic int
872158782Sumegetnum_str(u_char **startpp, u_char *endp) {
873158782Sume        int c, n;
874158782Sume        int seendigit = 0;
875158782Sume        int m = 0;
876158782Sume
877158782Sume        for (n = 0; *startpp <= endp; ) {
878158782Sume                c = **startpp;
879158782Sume                if (isspace(c) || c == '\0') {
880158782Sume                        if (seendigit) /* trailing whitespace */
881158782Sume                                break;
882158782Sume                        else { /* leading whitespace */
883158782Sume                                (*startpp)++;
884158782Sume                                continue;
885158782Sume                        }
886158782Sume                }
887158782Sume                if (c == ';') {
888158782Sume                        while ((*startpp <= endp) &&
889158782Sume			       ((c = **startpp) != '\n'))
890158782Sume					(*startpp)++;
891158782Sume                        if (seendigit)
892158782Sume                                break;
893158782Sume                        continue;
894158782Sume                }
895158782Sume                if (!isdigit(c)) {
896158782Sume                        if (c == ')' && seendigit) {
897158782Sume                                (*startpp)--;
898158782Sume                                break;
899158782Sume                        }
900158782Sume			return (-1);
901158782Sume                }
902158782Sume                (*startpp)++;
903158782Sume                n = n * 10 + (c - '0');
904158782Sume                seendigit = 1;
905158782Sume        }
906158782Sume        return (n + m);
907158782Sume}
908158782Sume
909158782Sume/*
910158782Sume * Allocate a resource record buffer & save rr info.
911158782Sume */
912158782Sumens_updrec *
913158782Sumeres_mkupdrec(int section, const char *dname,
914158782Sume	     u_int class, u_int type, u_long ttl) {
915158782Sume	ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
916158782Sume
917158782Sume	if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
918158782Sume		if (rrecp)
919158782Sume			free((char *)rrecp);
920158782Sume		return (NULL);
921158782Sume	}
922158782Sume	INIT_LINK(rrecp, r_link);
923158782Sume	INIT_LINK(rrecp, r_glink);
924158782Sume 	rrecp->r_class = (ns_class)class;
925158782Sume	rrecp->r_type = (ns_type)type;
926158782Sume	rrecp->r_ttl = ttl;
927158782Sume	rrecp->r_section = (ns_sect)section;
928158782Sume	return (rrecp);
929158782Sume}
930158782Sume
931158782Sume/*
932158782Sume * Free a resource record buffer created by res_mkupdrec.
933158782Sume */
934158782Sumevoid
935158782Sumeres_freeupdrec(ns_updrec *rrecp) {
936158782Sume	/* Note: freeing r_dp is the caller's responsibility. */
937158782Sume	if (rrecp->r_dname != NULL)
938158782Sume		free(rrecp->r_dname);
939158782Sume	free(rrecp);
940158782Sume}
941158782Sume
942158782Sumestruct valuelist {
943158782Sume	struct valuelist *	next;
944158782Sume	struct valuelist *	prev;
945158782Sume	char *			name;
946158782Sume	char *			proto;
947158782Sume	int			port;
948158782Sume};
949158782Sumestatic struct valuelist *servicelist, *protolist;
950158782Sume
951158782Sumestatic void
952158782Sumeres_buildservicelist() {
953158782Sume	struct servent *sp;
954158782Sume	struct valuelist *slp;
955158782Sume
956158782Sume#ifdef MAYBE_HESIOD
957158782Sume	setservent(0);
958158782Sume#else
959158782Sume	setservent(1);
960158782Sume#endif
961158782Sume	while ((sp = getservent()) != NULL) {
962158782Sume		slp = (struct valuelist *)malloc(sizeof(struct valuelist));
963158782Sume		if (!slp)
964158782Sume			break;
965158782Sume		slp->name = strdup(sp->s_name);
966158782Sume		slp->proto = strdup(sp->s_proto);
967158782Sume		if ((slp->name == NULL) || (slp->proto == NULL)) {
968158782Sume			if (slp->name) free(slp->name);
969158782Sume			if (slp->proto) free(slp->proto);
970158782Sume			free(slp);
971158782Sume			break;
972158782Sume		}
973158782Sume		slp->port = ntohs((u_int16_t)sp->s_port);  /* host byt order */
974158782Sume		slp->next = servicelist;
975158782Sume		slp->prev = NULL;
976158782Sume		if (servicelist)
977158782Sume			servicelist->prev = slp;
978158782Sume		servicelist = slp;
979158782Sume	}
980158782Sume	endservent();
981158782Sume}
982158782Sume
983158782Sumevoid
984158782Sumeres_destroyservicelist() {
985158782Sume	struct valuelist *slp, *slp_next;
986158782Sume
987158782Sume	for (slp = servicelist; slp != NULL; slp = slp_next) {
988158782Sume		slp_next = slp->next;
989158782Sume		free(slp->name);
990158782Sume		free(slp->proto);
991158782Sume		free(slp);
992158782Sume	}
993158782Sume	servicelist = (struct valuelist *)0;
994158782Sume}
995158782Sume
996158782Sumevoid
997158782Sumeres_buildprotolist(void) {
998158782Sume	struct protoent *pp;
999158782Sume	struct valuelist *slp;
1000158782Sume
1001158782Sume#ifdef MAYBE_HESIOD
1002158782Sume	setprotoent(0);
1003158782Sume#else
1004158782Sume	setprotoent(1);
1005158782Sume#endif
1006158782Sume	while ((pp = getprotoent()) != NULL) {
1007158782Sume		slp = (struct valuelist *)malloc(sizeof(struct valuelist));
1008158782Sume		if (!slp)
1009158782Sume			break;
1010158782Sume		slp->name = strdup(pp->p_name);
1011158782Sume		if (slp->name == NULL) {
1012158782Sume			free(slp);
1013158782Sume			break;
1014158782Sume		}
1015158782Sume		slp->port = pp->p_proto;	/* host byte order */
1016158782Sume		slp->next = protolist;
1017158782Sume		slp->prev = NULL;
1018158782Sume		if (protolist)
1019158782Sume			protolist->prev = slp;
1020158782Sume		protolist = slp;
1021158782Sume	}
1022158782Sume	endprotoent();
1023158782Sume}
1024158782Sume
1025158782Sumevoid
1026158782Sumeres_destroyprotolist(void) {
1027158782Sume	struct valuelist *plp, *plp_next;
1028158782Sume
1029158782Sume	for (plp = protolist; plp != NULL; plp = plp_next) {
1030158782Sume		plp_next = plp->next;
1031158782Sume		free(plp->name);
1032158782Sume		free(plp);
1033158782Sume	}
1034158782Sume	protolist = (struct valuelist *)0;
1035158782Sume}
1036158782Sume
1037158782Sumestatic int
1038158782Sumefindservice(const char *s, struct valuelist **list) {
1039158782Sume	struct valuelist *lp = *list;
1040158782Sume	int n;
1041158782Sume
1042158782Sume	for (; lp != NULL; lp = lp->next)
1043158782Sume		if (strcasecmp(lp->name, s) == 0) {
1044158782Sume			if (lp != *list) {
1045158782Sume				lp->prev->next = lp->next;
1046158782Sume				if (lp->next)
1047158782Sume					lp->next->prev = lp->prev;
1048158782Sume				(*list)->prev = lp;
1049158782Sume				lp->next = *list;
1050158782Sume				*list = lp;
1051158782Sume			}
1052158782Sume			return (lp->port);	/* host byte order */
1053158782Sume		}
1054158782Sume	if (sscanf(s, "%d", &n) != 1 || n <= 0)
1055158782Sume		n = -1;
1056158782Sume	return (n);
1057158782Sume}
1058158782Sume
1059158782Sume/*
1060158782Sume * Convert service name or (ascii) number to int.
1061158782Sume */
1062158782Sumeint
1063158782Sumeres_servicenumber(const char *p) {
1064158782Sume	if (servicelist == (struct valuelist *)0)
1065158782Sume		res_buildservicelist();
1066158782Sume	return (findservice(p, &servicelist));
1067158782Sume}
1068158782Sume
1069158782Sume/*
1070158782Sume * Convert protocol name or (ascii) number to int.
1071158782Sume */
1072158782Sumeint
1073158782Sumeres_protocolnumber(const char *p) {
1074158782Sume	if (protolist == (struct valuelist *)0)
1075158782Sume		res_buildprotolist();
1076158782Sume	return (findservice(p, &protolist));
1077158782Sume}
1078158782Sume
1079158782Sumestatic struct servent *
1080158782Sumecgetservbyport(u_int16_t port, const char *proto) {	/* Host byte order. */
1081158782Sume	struct valuelist **list = &servicelist;
1082158782Sume	struct valuelist *lp = *list;
1083158782Sume	static struct servent serv;
1084158782Sume
1085158782Sume	port = ntohs(port);
1086158782Sume	for (; lp != NULL; lp = lp->next) {
1087158782Sume		if (port != (u_int16_t)lp->port)	/* Host byte order. */
1088158782Sume			continue;
1089158782Sume		if (strcasecmp(lp->proto, proto) == 0) {
1090158782Sume			if (lp != *list) {
1091158782Sume				lp->prev->next = lp->next;
1092158782Sume				if (lp->next)
1093158782Sume					lp->next->prev = lp->prev;
1094158782Sume				(*list)->prev = lp;
1095158782Sume				lp->next = *list;
1096158782Sume				*list = lp;
1097158782Sume			}
1098158782Sume			serv.s_name = lp->name;
1099158782Sume			serv.s_port = htons((u_int16_t)lp->port);
1100158782Sume			serv.s_proto = lp->proto;
1101158782Sume			return (&serv);
1102158782Sume		}
1103158782Sume	}
1104158782Sume	return (0);
1105158782Sume}
1106158782Sume
1107158782Sumestatic struct protoent *
1108158782Sumecgetprotobynumber(int proto) {				/* Host byte order. */
1109158782Sume	struct valuelist **list = &protolist;
1110158782Sume	struct valuelist *lp = *list;
1111158782Sume	static struct protoent prot;
1112158782Sume
1113158782Sume	for (; lp != NULL; lp = lp->next)
1114158782Sume		if (lp->port == proto) {		/* Host byte order. */
1115158782Sume			if (lp != *list) {
1116158782Sume				lp->prev->next = lp->next;
1117158782Sume				if (lp->next)
1118158782Sume					lp->next->prev = lp->prev;
1119158782Sume				(*list)->prev = lp;
1120158782Sume				lp->next = *list;
1121158782Sume				*list = lp;
1122158782Sume			}
1123158782Sume			prot.p_name = lp->name;
1124158782Sume			prot.p_proto = lp->port;	/* Host byte order. */
1125158782Sume			return (&prot);
1126158782Sume		}
1127158782Sume	return (0);
1128158782Sume}
1129158782Sume
1130158782Sumeconst char *
1131158782Sumeres_protocolname(int num) {
1132158782Sume	static char number[8];
1133158782Sume	struct protoent *pp;
1134158782Sume
1135158782Sume	if (protolist == (struct valuelist *)0)
1136158782Sume		res_buildprotolist();
1137158782Sume	pp = cgetprotobynumber(num);
1138158782Sume	if (pp == 0)  {
1139158782Sume		(void) sprintf(number, "%d", num);
1140158782Sume		return (number);
1141158782Sume	}
1142158782Sume	return (pp->p_name);
1143158782Sume}
1144158782Sume
1145158782Sumeconst char *
1146158782Sumeres_servicename(u_int16_t port, const char *proto) {	/* Host byte order. */
1147158782Sume	static char number[8];
1148158782Sume	struct servent *ss;
1149158782Sume
1150158782Sume	if (servicelist == (struct valuelist *)0)
1151158782Sume		res_buildservicelist();
1152158782Sume	ss = cgetservbyport(htons(port), proto);
1153158782Sume	if (ss == 0)  {
1154158782Sume		(void) sprintf(number, "%d", port);
1155158782Sume		return (number);
1156158782Sume	}
1157158782Sume	return (ss->s_name);
1158158782Sume}
1159