2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996-1999 by Internet Software Consortium.
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 * Based on the Dynamic DNS reference implementation by Viraj Bais
21 * <viraj_bais@ccm.fm.intel.com>
24 static const char rcsid
[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
26 #include "port_before.h"
28 #include <sys/types.h>
29 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <arpa/nameser.h>
33 #include <arpa/inet.h>
39 #include <res_update.h>
46 #include "port_after.h"
48 /* Options. Leave them on. */
52 static int getnum_str(u_char
**, u_char
*);
53 static int gethexnum_str(u_char
**, u_char
*);
54 static int getword_str(char *, int, u_char
**, u_char
*);
55 static int getstr_str(char *, int, u_char
**, u_char
*);
57 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
61 int res_protocolnumber(const char *);
62 int res_servicenumber(const char *);
65 * Form update packets.
66 * Returns the size of the resulting packet if no error
70 *\li -1 if error in reading a word/number in rdata
71 * portion for update packets
72 *\li -2 if length of buffer passed is insufficient
73 *\li -3 if zone section is not the first section in
74 * the linked list, or section order has a problem
75 *\li -4 on a number overflow
76 *\li -5 unknown operation or no records
79 res_nmkupdate(res_state statp
, ns_updrec
*rrecp_in
, u_char
*buf
, int buflen
) {
80 ns_updrec
*rrecp_start
= rrecp_in
;
82 u_char
*cp
, *sp2
, *startp
, *endp
;
83 int n
, i
, soanum
, multiline
;
88 u_char buf3
[MAXDNAME
];
89 int section
, numrrs
= 0, counts
[ns_s_max
];
90 u_int16_t rtype
, rclass
;
92 u_char
*dnptrs
[20], **dpp
, **lastdnptr
;
93 int siglen
, keylen
, certlen
;
96 * Initialize header fields.
98 if ((buf
== NULL
) || (buflen
< HFIXEDSZ
))
100 memset(buf
, 0, HFIXEDSZ
);
102 statp
->id
= res_nrandomid(statp
);
103 hp
->id
= htons(statp
->id
);
104 hp
->opcode
= ns_o_update
;
111 lastdnptr
= dnptrs
+ sizeof dnptrs
/ sizeof dnptrs
[0];
113 if (rrecp_start
== NULL
)
115 else if (rrecp_start
->r_section
!= S_ZONE
)
118 memset(counts
, 0, sizeof counts
);
119 for (rrecp
= rrecp_start
; rrecp
; rrecp
= NEXT(rrecp
, r_glink
)) {
121 section
= rrecp
->r_section
;
122 if (section
< 0 || section
>= ns_s_max
)
125 for (i
= section
+ 1; i
< ns_s_max
; i
++)
128 rtype
= rrecp
->r_type
;
129 rclass
= rrecp
->r_class
;
131 /* overload class and type */
132 if (section
== S_PREREQ
) {
134 switch (rrecp
->r_opcode
) {
150 if (rrecp
->r_size
== 0)
155 "res_mkupdate: incorrect opcode: %d\n",
160 } else if (section
== S_UPDATE
) {
161 switch (rrecp
->r_opcode
) {
163 rclass
= rrecp
->r_size
== 0 ? C_ANY
: C_NONE
;
169 "res_mkupdate: incorrect opcode: %d\n",
177 * XXX appending default domain to owner name is omitted,
178 * fqdn must be provided
180 if ((n
= dn_comp(rrecp
->r_dname
, cp
, buflen
, dnptrs
,
184 ShrinkBuffer(n
+ 2*INT16SZ
);
186 PUTSHORT(rclass
, cp
);
187 if (section
== S_ZONE
) {
188 if (numrrs
!= 1 || rrecp
->r_type
!= T_SOA
)
192 ShrinkBuffer(INT32SZ
+ INT16SZ
);
194 sp2
= cp
; /*%< save pointer to length byte */
196 if (rrecp
->r_size
== 0) {
197 if (section
== S_UPDATE
&& rclass
!= C_ANY
)
204 startp
= rrecp
->r_data
;
205 endp
= startp
+ rrecp
->r_size
- 1;
206 /* XXX this should be done centrally. */
207 switch (rrecp
->r_type
) {
209 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
211 if (!inet_aton(buf2
, &ina
))
213 n1
= ntohl(ina
.s_addr
);
214 ShrinkBuffer(INT32SZ
);
224 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
226 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
235 for (i
= 0; i
< 2; i
++) {
236 if (!getword_str(buf2
, sizeof buf2
, &startp
,
239 n
= dn_comp(buf2
, cp
, buflen
,
246 if (rrecp
->r_type
== T_SOA
) {
247 ShrinkBuffer(5 * INT32SZ
);
248 while (isspace(*startp
) || !*startp
)
250 if (*startp
== '(') {
255 /* serial, refresh, retry, expire, minimum */
256 for (i
= 0; i
< 5; i
++) {
257 soanum
= getnum_str(&startp
, endp
);
263 while (isspace(*startp
) || !*startp
)
273 n
= getnum_str(&startp
, endp
);
276 ShrinkBuffer(INT16SZ
);
278 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
280 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
287 n
= getnum_str(&startp
, endp
);
290 ShrinkBuffer(INT16SZ
);
293 n
= getnum_str(&startp
, endp
);
296 ShrinkBuffer(INT16SZ
);
299 n
= getnum_str(&startp
, endp
);
302 ShrinkBuffer(INT16SZ
);
305 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
307 n
= dn_comp(buf2
, cp
, buflen
, NULL
, NULL
);
314 n
= getnum_str(&startp
, endp
);
318 ShrinkBuffer(INT16SZ
);
319 for (i
= 0; i
< 2; i
++) {
320 if (!getword_str(buf2
, sizeof buf2
, &startp
,
323 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
,
333 unsigned int maxbm
= 0;
335 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
337 if (!inet_aton(buf2
, &ina
))
339 n1
= ntohl(ina
.s_addr
);
340 ShrinkBuffer(INT32SZ
);
343 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
345 if ((i
= res_protocolnumber(buf2
)) < 0)
350 for (i
= 0; i
< MAXPORT
/8 ; i
++)
353 while (getword_str(buf2
, sizeof buf2
, &startp
, endp
)) {
354 if ((n
= res_servicenumber(buf2
)) <= 0)
358 bm
[n
/8] |= (0x80>>(n
%8));
359 if ((unsigned)n
> maxbm
)
366 memcpy(cp
, bm
, maxbm
);
371 for (i
= 0; i
< 2; i
++) {
372 if ((n
= getstr_str(buf2
, sizeof buf2
,
385 if ((n
= getstr_str(buf2
, sizeof buf2
,
386 &startp
, endp
)) < 0) {
387 if (cp
!= (sp2
+ INT16SZ
))
401 if ((n
= getstr_str(buf2
, sizeof buf2
, &startp
,
413 if ((n
= getstr_str(buf2
, sizeof buf2
, &startp
,
416 if ((n
> 255) || (n
== 0))
422 if ((n
= getstr_str(buf2
, sizeof buf2
, &startp
,
433 if ((n
= inet_nsap_addr((char *)startp
, (u_char
*)buf2
, sizeof(buf2
))) != 0) {
442 if ((n
= loc_aton((char *)startp
, (u_char
*)buf2
)) != 0) {
451 int sig_type
, success
, dateerror
;
452 u_int32_t exptime
, timesigned
;
455 if ((n
= getword_str(buf2
, sizeof buf2
,
458 sig_type
= sym_ston(__p_type_syms
, buf2
, &success
);
459 if (!success
|| sig_type
== ns_t_any
)
461 ShrinkBuffer(INT16SZ
);
462 PUTSHORT(sig_type
, cp
);
464 n
= getnum_str(&startp
, endp
);
470 n
= getnum_str(&startp
, endp
);
471 if (n
<= 0 || n
> 255)
476 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
478 exptime
= ns_datetosecs(buf2
, &dateerror
);
480 ShrinkBuffer(INT32SZ
);
488 ottl
= strtoul(buf2
, &ulendp
, 10);
490 (ulendp
!= NULL
&& *ulendp
!= '\0'))
492 ShrinkBuffer(INT32SZ
);
494 if (!getword_str(buf2
, sizeof buf2
, &startp
,
497 exptime
= ns_datetosecs(buf2
, &dateerror
);
502 ShrinkBuffer(INT32SZ
);
503 PUTLONG(exptime
, cp
);
505 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
507 timesigned
= ns_datetosecs(buf2
, &dateerror
);
509 ShrinkBuffer(INT32SZ
);
510 PUTLONG(timesigned
, cp
);
515 n
= getnum_str(&startp
, endp
);
518 ShrinkBuffer(INT16SZ
);
521 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
523 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
529 if ((n
= getword_str(buf2
, sizeof buf2
,
532 siglen
= b64_pton(buf2
, buf3
, sizeof(buf3
));
535 ShrinkBuffer(siglen
);
536 memcpy(cp
, buf3
, siglen
);
542 n
= gethexnum_str(&startp
, endp
);
545 ShrinkBuffer(INT16SZ
);
548 n
= getnum_str(&startp
, endp
);
554 n
= getnum_str(&startp
, endp
);
560 if ((n
= getword_str(buf2
, sizeof buf2
,
563 keylen
= b64_pton(buf2
, buf3
, sizeof(buf3
));
566 ShrinkBuffer(keylen
);
567 memcpy(cp
, buf3
, keylen
);
572 int success
, nxt_type
;
577 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
579 n
= dn_comp(buf2
, cp
, buflen
, NULL
, NULL
);
585 memset(data
, 0, sizeof data
);
587 if (!getword_str(buf2
, sizeof buf2
, &startp
,
590 nxt_type
= sym_ston(__p_type_syms
, buf2
,
592 if (!success
|| !ns_t_rr_p(nxt_type
))
594 NS_NXT_BIT_SET(nxt_type
, data
);
595 if (nxt_type
> maxtype
)
598 n
= maxtype
/NS_NXT_BITS
+1;
606 n
= getnum_str(&startp
, endp
);
609 ShrinkBuffer(INT16SZ
);
612 n
= getnum_str(&startp
, endp
);
615 ShrinkBuffer(INT16SZ
);
618 n
= getnum_str(&startp
, endp
);
624 if ((n
= getword_str(buf2
, sizeof buf2
,
627 certlen
= b64_pton(buf2
, buf3
, sizeof(buf3
));
630 ShrinkBuffer(certlen
);
631 memcpy(cp
, buf3
, certlen
);
635 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
637 if (inet_pton(AF_INET6
, buf2
, &in6a
) <= 0)
639 ShrinkBuffer(NS_IN6ADDRSZ
);
640 memcpy(cp
, &in6a
, NS_IN6ADDRSZ
);
644 /* Order Preference Flags Service Replacement Regexp */
646 n
= getnum_str(&startp
, endp
);
647 if (n
< 0 || n
> 65535)
649 ShrinkBuffer(INT16SZ
);
652 n
= getnum_str(&startp
, endp
);
653 if (n
< 0 || n
> 65535)
655 ShrinkBuffer(INT16SZ
);
658 if ((n
= getstr_str(buf2
, sizeof buf2
,
659 &startp
, endp
)) < 0) {
668 /* Service Classes */
669 if ((n
= getstr_str(buf2
, sizeof buf2
,
670 &startp
, endp
)) < 0) {
680 if ((n
= getstr_str(buf2
, sizeof buf2
,
681 &startp
, endp
)) < 0) {
691 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
693 n
= dn_comp(buf2
, cp
, buflen
, NULL
, NULL
);
702 n
= (u_int16_t
)((cp
- sp2
) - INT16SZ
);
706 hp
->qdcount
= htons(counts
[0]);
707 hp
->ancount
= htons(counts
[1]);
708 hp
->nscount
= htons(counts
[2]);
709 hp
->arcount
= htons(counts
[3]);
714 * Get a whitespace delimited word from a string (not file)
715 * into buf. modify the start pointer to point after the
716 * word in the string.
719 getword_str(char *buf
, int size
, u_char
**startpp
, u_char
*endp
) {
723 for (cp
= buf
; *startpp
<= endp
; ) {
725 if (isspace(c
) || c
== '\0') {
726 if (cp
!= buf
) /*%< trailing whitespace */
728 else { /*%< leading whitespace */
734 if (cp
>= buf
+size
-1)
743 * get a white spae delimited string from memory. Process quoted strings
744 * and \\DDD escapes. Return length or -1 on error. Returned string may
747 static char digits
[] = "0123456789";
749 getstr_str(char *buf
, int size
, u_char
**startpp
, u_char
*endp
) {
757 for (cp
= buf
; *startpp
<= endp
; ) {
758 if ((c
= **startpp
) == '\0')
760 /* leading white space */
761 if ((cp
== buf
) && !seen_quote
&& isspace(c
)) {
799 (strchr(digits
, c
) - digits
);
809 } else if (!inquote
&& isspace(c
))
811 if (cp
>= buf
+size
-1)
819 return ((cp
== buf
)? (seen_quote
? 0: -1): (cp
- buf
));
823 * Get a whitespace delimited base 16 number from a string (not file) into buf
824 * update the start pointer to point after the number in the string.
827 gethexnum_str(u_char
**startpp
, u_char
*endp
) {
832 if (*startpp
+ 2 >= endp
|| strncasecmp((char *)*startpp
, "0x", 2) != 0)
833 return getnum_str(startpp
, endp
);
835 for (n
= 0; *startpp
<= endp
; ) {
837 if (isspace(c
) || c
== '\0') {
838 if (seendigit
) /*%< trailing whitespace */
840 else { /*%< leading whitespace */
846 while ((*startpp
<= endp
) &&
847 ((c
= **startpp
) != '\n'))
854 if (c
== ')' && seendigit
) {
862 n
= n
* 16 + (c
- '0');
864 n
= n
* 16 + (tolower(c
) - 'a' + 10);
871 * Get a whitespace delimited base 10 number from a string (not file) into buf
872 * update the start pointer to point after the number in the string.
875 getnum_str(u_char
**startpp
, u_char
*endp
) {
880 for (n
= 0; *startpp
<= endp
; ) {
882 if (isspace(c
) || c
== '\0') {
883 if (seendigit
) /*%< trailing whitespace */
885 else { /*%< leading whitespace */
891 while ((*startpp
<= endp
) &&
892 ((c
= **startpp
) != '\n'))
899 if (c
== ')' && seendigit
) {
906 n
= n
* 10 + (c
- '0');
913 * Allocate a resource record buffer & save rr info.
916 res_mkupdrec(int section
, const char *dname
,
917 u_int
class, u_int type
, u_long ttl
) {
918 ns_updrec
*rrecp
= (ns_updrec
*)calloc(1, sizeof(ns_updrec
));
920 if (!rrecp
|| !(rrecp
->r_dname
= strdup(dname
))) {
925 INIT_LINK(rrecp
, r_link
);
926 INIT_LINK(rrecp
, r_glink
);
927 rrecp
->r_class
= (ns_class
)class;
928 rrecp
->r_type
= (ns_type
)type
;
930 rrecp
->r_section
= (ns_sect
)section
;
935 * Free a resource record buffer created by res_mkupdrec.
938 res_freeupdrec(ns_updrec
*rrecp
) {
939 /* Note: freeing r_dp is the caller's responsibility. */
940 free(rrecp
->r_dname
);
945 struct valuelist
* next
;
946 struct valuelist
* prev
;
951 static struct valuelist
*servicelist
, *protolist
;
954 res_buildservicelist() {
956 struct valuelist
*slp
;
963 while ((sp
= getservent()) != NULL
) {
964 slp
= (struct valuelist
*)malloc(sizeof(struct valuelist
));
967 slp
->name
= strdup(sp
->s_name
);
968 slp
->proto
= strdup(sp
->s_proto
);
969 if ((slp
->name
== NULL
) || (slp
->proto
== NULL
)) {
975 slp
->port
= ntohs((u_int16_t
)sp
->s_port
); /*%< host byt order */
976 slp
->next
= servicelist
;
979 servicelist
->prev
= slp
;
986 res_destroyservicelist() {
987 struct valuelist
*slp
, *slp_next
;
989 for (slp
= servicelist
; slp
!= NULL
; slp
= slp_next
) {
990 slp_next
= slp
->next
;
999 res_buildprotolist(void) {
1000 struct protoent
*pp
;
1001 struct valuelist
*slp
;
1008 while ((pp
= getprotoent()) != NULL
) {
1009 slp
= (struct valuelist
*)malloc(sizeof(struct valuelist
));
1012 slp
->name
= strdup(pp
->p_name
);
1013 if (slp
->name
== NULL
) {
1017 slp
->port
= pp
->p_proto
; /*%< host byte order */
1018 slp
->next
= protolist
;
1021 protolist
->prev
= slp
;
1028 res_destroyprotolist(void) {
1029 struct valuelist
*plp
, *plp_next
;
1031 for (plp
= protolist
; plp
!= NULL
; plp
= plp_next
) {
1032 plp_next
= plp
->next
;
1040 findservice(const char *s
, struct valuelist
**list
) {
1041 struct valuelist
*lp
= *list
;
1044 for (; lp
!= NULL
; lp
= lp
->next
)
1045 if (strcasecmp(lp
->name
, s
) == 0) {
1047 lp
->prev
->next
= lp
->next
;
1049 lp
->next
->prev
= lp
->prev
;
1054 return (lp
->port
); /*%< host byte order */
1056 if (sscanf(s
, "%d", &n
) != 1 || n
<= 0)
1062 * Convert service name or (ascii) number to int.
1065 res_servicenumber(const char *p
) {
1066 if (servicelist
== NULL
)
1067 res_buildservicelist();
1068 return (findservice(p
, &servicelist
));
1072 * Convert protocol name or (ascii) number to int.
1075 res_protocolnumber(const char *p
) {
1076 if (protolist
== NULL
)
1077 res_buildprotolist();
1078 return (findservice(p
, &protolist
));
1081 static struct servent
*
1082 cgetservbyport(u_int16_t port
, const char *proto
) { /*%< Host byte order. */
1083 struct valuelist
**list
= &servicelist
;
1084 struct valuelist
*lp
= *list
;
1085 static struct servent serv
;
1088 for (; lp
!= NULL
; lp
= lp
->next
) {
1089 if (port
!= (u_int16_t
)lp
->port
) /*%< Host byte order. */
1091 if (strcasecmp(lp
->proto
, proto
) == 0) {
1093 lp
->prev
->next
= lp
->next
;
1095 lp
->next
->prev
= lp
->prev
;
1100 serv
.s_name
= lp
->name
;
1101 serv
.s_port
= htons((u_int16_t
)lp
->port
);
1102 serv
.s_proto
= lp
->proto
;
1109 static struct protoent
*
1110 cgetprotobynumber(int proto
) { /*%< Host byte order. */
1111 struct valuelist
**list
= &protolist
;
1112 struct valuelist
*lp
= *list
;
1113 static struct protoent prot
;
1115 for (; lp
!= NULL
; lp
= lp
->next
)
1116 if (lp
->port
== proto
) { /*%< Host byte order. */
1118 lp
->prev
->next
= lp
->next
;
1120 lp
->next
->prev
= lp
->prev
;
1125 prot
.p_name
= lp
->name
;
1126 prot
.p_proto
= lp
->port
; /*%< Host byte order. */
1133 res_protocolname(int num
) {
1134 static char number
[8];
1135 struct protoent
*pp
;
1137 if (protolist
== NULL
)
1138 res_buildprotolist();
1139 pp
= cgetprotobynumber(num
);
1141 (void) sprintf(number
, "%d", num
);
1144 return (pp
->p_name
);
1148 res_servicename(u_int16_t port
, const char *proto
) { /*%< Host byte order. */
1149 static char number
[8];
1152 if (servicelist
== NULL
)
1153 res_buildservicelist();
1154 ss
= cgetservbyport(htons(port
), proto
);
1156 (void) sprintf(number
, "%d", port
);
1159 return (ss
->s_name
);