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