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