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