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