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