2 * SPDX-License-Identifier: ISC
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996-1999 by Internet Software Consortium.
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 * Based on the Dynamic DNS reference implementation by Viraj Bais
23 * <viraj_bais@ccm.fm.intel.com>
26 #include "port_before.h"
28 #include <sys/param.h>
30 #include <netinet/in.h>
31 #include <arpa/nameser.h>
32 #include <arpa/inet.h>
38 #include <res_update.h>
49 #include "port_after.h"
51 /* Options. Leave them on. */
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 *);
62 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
69 int res_protocolnumber(const char *);
73 int res_servicenumber(const char *);
76 * Form update packets.
77 * Returns the size of the resulting packet if no error
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
90 res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
91 ns_updrec *rrecp_start = rrecp_in;
93 u_char *cp, *sp2, *startp, *endp;
94 int n, i, soanum, multiline;
99 u_char buf3[MAXDNAME];
100 int section, numrrs = 0, counts[ns_s_max];
101 u_int16_t rtype, rclass;
103 u_char *dnptrs[20], **dpp, **lastdnptr;
110 * Initialize header fields.
112 if ((buf == NULL) || (buflen < HFIXEDSZ))
114 memset(buf, 0, HFIXEDSZ);
116 statp->id = res_nrandomid(statp);
117 hp->id = htons(statp->id);
118 hp->opcode = ns_o_update;
125 lastdnptr = dnptrs + nitems(dnptrs);
127 if (rrecp_start == NULL)
129 else if (rrecp_start->r_section != S_ZONE)
132 memset(counts, 0, sizeof counts);
133 for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
135 section = rrecp->r_section;
136 if (section < 0 || section >= ns_s_max)
139 for (i = section + 1; i < ns_s_max; i++)
142 rtype = rrecp->r_type;
143 rclass = rrecp->r_class;
145 /* overload class and type */
146 if (section == S_PREREQ) {
148 switch (rrecp->r_opcode) {
164 if (rrecp->r_size == 0)
169 "res_mkupdate: incorrect opcode: %d\n",
174 } else if (section == S_UPDATE) {
175 switch (rrecp->r_opcode) {
177 rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
183 "res_mkupdate: incorrect opcode: %d\n",
191 * XXX appending default domain to owner name is omitted,
192 * fqdn must be provided
194 if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
198 ShrinkBuffer(n + 2*INT16SZ);
200 PUTSHORT(rclass, cp);
201 if (section == S_ZONE) {
202 if (numrrs != 1 || rrecp->r_type != T_SOA)
206 ShrinkBuffer(INT32SZ + INT16SZ);
208 sp2 = cp; /*%< save pointer to length byte */
210 if (rrecp->r_size == 0) {
211 if (section == S_UPDATE && rclass != C_ANY)
218 startp = rrecp->r_data;
219 endp = startp + rrecp->r_size - 1;
220 /* XXX this should be done centrally. */
221 switch (rrecp->r_type) {
223 if (!getword_str(buf2, sizeof buf2, &startp, endp))
225 if (!inet_aton(buf2, &ina))
227 n1 = ntohl(ina.s_addr);
228 ShrinkBuffer(INT32SZ);
238 if (!getword_str(buf2, sizeof buf2, &startp, endp))
240 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
249 for (i = 0; i < 2; i++) {
250 if (!getword_str(buf2, sizeof buf2, &startp,
253 n = dn_comp(buf2, cp, buflen,
260 if (rrecp->r_type == T_SOA) {
261 ShrinkBuffer(5 * INT32SZ);
262 while (isspace(*startp) || !*startp)
264 if (*startp == '(') {
269 /* serial, refresh, retry, expire, minimum */
270 for (i = 0; i < 5; i++) {
271 soanum = getnum_str(&startp, endp);
277 while (isspace(*startp) || !*startp)
287 n = getnum_str(&startp, endp);
290 ShrinkBuffer(INT16SZ);
292 if (!getword_str(buf2, sizeof buf2, &startp, endp))
294 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
301 n = getnum_str(&startp, endp);
304 ShrinkBuffer(INT16SZ);
307 n = getnum_str(&startp, endp);
310 ShrinkBuffer(INT16SZ);
313 n = getnum_str(&startp, endp);
316 ShrinkBuffer(INT16SZ);
319 if (!getword_str(buf2, sizeof buf2, &startp, endp))
321 n = dn_comp(buf2, cp, buflen, NULL, NULL);
328 n = getnum_str(&startp, endp);
332 ShrinkBuffer(INT16SZ);
333 for (i = 0; i < 2; i++) {
334 if (!getword_str(buf2, sizeof buf2, &startp,
337 n = dn_comp(buf2, cp, buflen, dnptrs,
347 unsigned int maxbm = 0;
349 if (!getword_str(buf2, sizeof buf2, &startp, endp))
351 if (!inet_aton(buf2, &ina))
353 n1 = ntohl(ina.s_addr);
354 ShrinkBuffer(INT32SZ);
357 if (!getword_str(buf2, sizeof buf2, &startp, endp))
359 if ((i = res_protocolnumber(buf2)) < 0)
364 for (i = 0; i < MAXPORT/8 ; i++)
367 while (getword_str(buf2, sizeof buf2, &startp, endp)) {
368 if ((n = res_servicenumber(buf2)) <= 0)
372 bm[n/8] |= (0x80>>(n%8));
373 if ((unsigned)n > maxbm)
380 memcpy(cp, bm, maxbm);
385 for (i = 0; i < 2; i++) {
386 if ((n = getstr_str(buf2, sizeof buf2,
399 if ((n = getstr_str(buf2, sizeof buf2,
400 &startp, endp)) < 0) {
401 if (cp != (sp2 + INT16SZ))
415 if ((n = getstr_str(buf2, sizeof buf2, &startp,
427 if ((n = getstr_str(buf2, sizeof buf2, &startp,
430 if ((n > 255) || (n == 0))
436 if ((n = getstr_str(buf2, sizeof buf2, &startp,
447 if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
456 if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
468 int sig_type, success, dateerror;
469 u_int32_t exptime, timesigned;
472 if ((n = getword_str(buf2, sizeof buf2,
475 sig_type = sym_ston(__p_type_syms, buf2, &success);
476 if (!success || sig_type == ns_t_any)
478 ShrinkBuffer(INT16SZ);
479 PUTSHORT(sig_type, cp);
481 n = getnum_str(&startp, endp);
487 n = getnum_str(&startp, endp);
488 if (n <= 0 || n > 255)
493 if (!getword_str(buf2, sizeof buf2, &startp, endp))
495 exptime = ns_datetosecs(buf2, &dateerror);
497 ShrinkBuffer(INT32SZ);
505 ottl = strtoul(buf2, &ulendp, 10);
507 (ulendp != NULL && *ulendp != '\0'))
509 ShrinkBuffer(INT32SZ);
511 if (!getword_str(buf2, sizeof buf2, &startp,
514 exptime = ns_datetosecs(buf2, &dateerror);
519 ShrinkBuffer(INT32SZ);
520 PUTLONG(exptime, cp);
522 if (!getword_str(buf2, sizeof buf2, &startp, endp))
524 timesigned = ns_datetosecs(buf2, &dateerror);
526 ShrinkBuffer(INT32SZ);
527 PUTLONG(timesigned, cp);
532 n = getnum_str(&startp, endp);
535 ShrinkBuffer(INT16SZ);
538 if (!getword_str(buf2, sizeof buf2, &startp, endp))
540 n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
546 if ((n = getword_str(buf2, sizeof buf2,
549 siglen = b64_pton(buf2, buf3, sizeof(buf3));
552 ShrinkBuffer(siglen);
553 memcpy(cp, buf3, siglen);
560 n = gethexnum_str(&startp, endp);
563 ShrinkBuffer(INT16SZ);
566 n = getnum_str(&startp, endp);
572 n = getnum_str(&startp, endp);
578 if ((n = getword_str(buf2, sizeof buf2,
581 keylen = b64_pton(buf2, buf3, sizeof(buf3));
584 ShrinkBuffer(keylen);
585 memcpy(cp, buf3, keylen);
590 int success, nxt_type;
595 if (!getword_str(buf2, sizeof buf2, &startp, endp))
597 n = dn_comp(buf2, cp, buflen, NULL, NULL);
603 memset(data, 0, sizeof data);
605 if (!getword_str(buf2, sizeof buf2, &startp,
608 nxt_type = sym_ston(__p_type_syms, buf2,
610 if (!success || !ns_t_rr_p(nxt_type))
612 NS_NXT_BIT_SET(nxt_type, data);
613 if (nxt_type > maxtype)
616 n = maxtype/NS_NXT_BITS+1;
624 n = getnum_str(&startp, endp);
627 ShrinkBuffer(INT16SZ);
630 n = getnum_str(&startp, endp);
633 ShrinkBuffer(INT16SZ);
636 n = getnum_str(&startp, endp);
642 if ((n = getword_str(buf2, sizeof buf2,
645 certlen = b64_pton(buf2, buf3, sizeof(buf3));
648 ShrinkBuffer(certlen);
649 memcpy(cp, buf3, certlen);
653 if (!getword_str(buf2, sizeof buf2, &startp, endp))
655 if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
657 ShrinkBuffer(NS_IN6ADDRSZ);
658 memcpy(cp, &in6a, NS_IN6ADDRSZ);
662 /* Order Preference Flags Service Replacement Regexp */
664 n = getnum_str(&startp, endp);
665 if (n < 0 || n > 65535)
667 ShrinkBuffer(INT16SZ);
670 n = getnum_str(&startp, endp);
671 if (n < 0 || n > 65535)
673 ShrinkBuffer(INT16SZ);
676 if ((n = getstr_str(buf2, sizeof buf2,
677 &startp, endp)) < 0) {
686 /* Service Classes */
687 if ((n = getstr_str(buf2, sizeof buf2,
688 &startp, endp)) < 0) {
698 if ((n = getstr_str(buf2, sizeof buf2,
699 &startp, endp)) < 0) {
709 if (!getword_str(buf2, sizeof buf2, &startp, endp))
711 n = dn_comp(buf2, cp, buflen, NULL, NULL);
720 n = (u_int16_t)((cp - sp2) - INT16SZ);
724 hp->qdcount = htons(counts[0]);
725 hp->ancount = htons(counts[1]);
726 hp->nscount = htons(counts[2]);
727 hp->arcount = htons(counts[3]);
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.
737 getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
741 for (cp = buf; *startpp <= endp; ) {
743 if (isspace(c) || c == '\0') {
744 if (cp != buf) /*%< trailing whitespace */
746 else { /*%< leading whitespace */
752 if (cp >= buf+size-1)
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
765 static char digits[] = "0123456789";
767 getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
775 for (cp = buf; *startpp <= endp; ) {
776 if ((c = **startpp) == '\0')
778 /* leading white space */
779 if ((cp == buf) && !seen_quote && isspace(c)) {
817 (strchr(digits, c) - digits);
827 } else if (!inquote && isspace(c))
829 if (cp >= buf+size-1)
837 return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
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.
845 gethexnum_str(u_char **startpp, u_char *endp) {
850 if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
851 return getnum_str(startpp, endp);
853 for (n = 0; *startpp <= endp; ) {
855 if (isspace(c) || c == '\0') {
856 if (seendigit) /*%< trailing whitespace */
858 else { /*%< leading whitespace */
864 while ((*startpp <= endp) &&
865 ((c = **startpp) != '\n'))
872 if (c == ')' && seendigit) {
880 n = n * 16 + (c - '0');
882 n = n * 16 + (tolower(c) - 'a' + 10);
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.
893 getnum_str(u_char **startpp, u_char *endp) {
898 for (n = 0; *startpp <= endp; ) {
900 if (isspace(c) || c == '\0') {
901 if (seendigit) /*%< trailing whitespace */
903 else { /*%< leading whitespace */
909 while ((*startpp <= endp) &&
910 ((c = **startpp) != '\n'))
917 if (c == ')' && seendigit) {
924 n = n * 10 + (c - '0');
931 * Allocate a resource record buffer & save rr info.
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));
938 if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
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;
948 rrecp->r_section = (ns_sect)section;
953 * Free a resource record buffer created by res_mkupdrec.
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);
964 struct valuelist * next;
965 struct valuelist * prev;
970 static struct valuelist *servicelist, *protolist;
973 res_buildservicelist(void) {
975 struct valuelist *slp;
982 while ((sp = getservent()) != NULL) {
983 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
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);
994 slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
995 slp->next = servicelist;
998 servicelist->prev = slp;
1006 res_destroyservicelist() {
1007 struct valuelist *slp, *slp_next;
1009 for (slp = servicelist; slp != NULL; slp = slp_next) {
1010 slp_next = slp->next;
1015 servicelist = (struct valuelist *)0;
1023 res_buildprotolist(void) {
1024 struct protoent *pp;
1025 struct valuelist *slp;
1032 while ((pp = getprotoent()) != NULL) {
1033 slp = (struct valuelist *)malloc(sizeof(struct valuelist));
1036 slp->name = strdup(pp->p_name);
1037 if (slp->name == NULL) {
1041 slp->port = pp->p_proto; /*%< host byte order */
1042 slp->next = protolist;
1045 protolist->prev = slp;
1053 res_destroyprotolist(void) {
1054 struct valuelist *plp, *plp_next;
1056 for (plp = protolist; plp != NULL; plp = plp_next) {
1057 plp_next = plp->next;
1061 protolist = (struct valuelist *)0;
1066 findservice(const char *s, struct valuelist **list) {
1067 struct valuelist *lp = *list;
1070 for (; lp != NULL; lp = lp->next)
1071 if (strcasecmp(lp->name, s) == 0) {
1073 lp->prev->next = lp->next;
1075 lp->next->prev = lp->prev;
1080 return (lp->port); /*%< host byte order */
1082 if (sscanf(s, "%d", &n) != 1 || n <= 0)
1088 * Convert service name or (ascii) number to int.
1094 res_servicenumber(const char *p) {
1095 if (servicelist == (struct valuelist *)0)
1096 res_buildservicelist();
1097 return (findservice(p, &servicelist));
1101 * Convert protocol name or (ascii) number to int.
1107 res_protocolnumber(const char *p) {
1108 if (protolist == (struct valuelist *)0)
1109 res_buildprotolist();
1110 return (findservice(p, &protolist));
1114 static struct servent *
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;
1121 for (; lp != NULL; lp = lp->next) {
1122 if (port != (u_int16_t)lp->port) /*%< Host byte order. */
1124 if (strcasecmp(lp->proto, proto) == 0) {
1126 lp->prev->next = lp->next;
1128 lp->next->prev = lp->prev;
1133 serv.s_name = lp->name;
1134 serv.s_port = htons((u_int16_t)lp->port);
1135 serv.s_proto = lp->proto;
1142 static struct protoent *
1143 cgetprotobynumber(int proto) { /*%< Host byte order. */
1144 struct valuelist **list = &protolist;
1145 struct valuelist *lp = *list;
1146 static struct protoent prot;
1148 for (; lp != NULL; lp = lp->next)
1149 if (lp->port == proto) { /*%< Host byte order. */
1151 lp->prev->next = lp->next;
1153 lp->next->prev = lp->prev;
1158 prot.p_name = lp->name;
1159 prot.p_proto = lp->port; /*%< Host byte order. */
1166 res_protocolname(int num) {
1167 static char number[8];
1168 struct protoent *pp;
1170 if (protolist == (struct valuelist *)0)
1171 res_buildprotolist();
1172 pp = cgetprotobynumber(num);
1174 (void) sprintf(number, "%d", num);
1177 return (pp->p_name);
1181 res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
1182 static char number[8];
1185 if (servicelist == (struct valuelist *)0)
1186 res_buildservicelist();
1187 ss = cgetservbyport(htons(port), proto);
1189 (void) sprintf(number, "%d", port);
1192 return (ss->s_name);