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