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