2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (c) 1996-2003 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.
17 * Internet Systems Consortium, Inc.
19 * Redwood City, CA 94063
25 * Based on the Dynamic DNS reference implementation by Viraj Bais
26 * <viraj_bais@ccm.fm.intel.com>
29 #if !defined(lint) && !defined(SABER) && !defined(__AROS__)
30 static const char rcsid
[] = "$Id$";
33 #include <sys/types.h>
34 #include <sys/param.h>
36 #include <netinet/in.h>
37 #include <arpa/inet.h>
38 #include <sys/socket.h>
49 #include "minires/minires.h"
50 #include "arpa/nameser.h"
52 /* Options. Leave them on. */
56 static int getnum_str(const u_char
**, const u_char
*);
57 static int gethexnum_str(const u_char
**, const u_char
*);
58 static int getword_str(char *, int,
59 const unsigned char **,
60 const unsigned char *);
61 static int getphrase_str(char *, int, const u_char
**, const u_char
*);
62 static int getstr_str(char *, int, const u_char
**, const u_char
*);
65 struct valuelist
* next
;
66 struct valuelist
* prev
;
72 static int findservice(const char *, struct valuelist
**);
73 static struct servent
*cgetservbyport(unsigned, const char *);
75 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
79 int res_protocolnumber(const char *);
80 int res_servicenumber(const char *);
81 static struct protoent
*cgetprotobynumber(int);
84 * Form update packets.
85 * Returns the size of the resulting packet if no error
87 * returns -1 if error in reading a word/number in rdata
88 * portion for update packets
89 * -2 if length of buffer passed is insufficient
90 * -3 if zone section is not the first section in
91 * the linked list, or section order has a problem
92 * -4 on a number overflow
93 * -5 unknown operation or no records
96 res_nmkupdate(res_state statp
,
97 ns_updrec
*rrecp_in
, double *bp
, unsigned *blp
) {
98 ns_updrec
*rrecp_start
= rrecp_in
;
101 const unsigned char *startp
, *endp
;
102 int n
, i
, soanum
, multiline
;
106 u_char buf3
[MAXDNAME
];
107 int section
, numrrs
= 0, counts
[ns_s_max
];
108 u_int16_t rtype
, rclass
;
110 u_char
*dnptrs
[20], **dpp
, **lastdnptr
;
112 __unused
unsigned siglen
;
114 unsigned buflen
= *blp
;
115 u_char
*buf
= (unsigned char *)bp
;
118 * Initialize header fields.
120 if ((buf
== NULL
) || (buflen
< HFIXEDSZ
))
122 memset(buf
, 0, HFIXEDSZ
);
124 hp
->id
= htons(++statp
->id
);
125 hp
->opcode
= ns_o_update
;
132 lastdnptr
= dnptrs
+ sizeof dnptrs
/ sizeof dnptrs
[0];
134 if (rrecp_start
== NULL
)
136 else if (rrecp_start
->r_section
!= S_ZONE
)
139 memset(counts
, 0, sizeof counts
);
140 for (rrecp
= rrecp_start
; rrecp
; rrecp
= ISC_LIST_NEXT(rrecp
,
143 section
= rrecp
->r_section
;
144 if (section
< 0 || section
>= ns_s_max
)
147 for (i
= section
+ 1; i
< ns_s_max
; i
++)
150 rtype
= rrecp
->r_type
;
151 rclass
= rrecp
->r_class
;
153 /* overload class and type */
154 if (section
== S_PREREQ
) {
156 switch (rrecp
->r_opcode
) {
172 if (rrecp
->r_size
== 0)
177 "res_mkupdate: incorrect opcode: %d\n",
182 } else if (section
== S_UPDATE
) {
183 switch (rrecp
->r_opcode
) {
185 rclass
= rrecp
->r_size
== 0 ? C_ANY
: C_NONE
;
191 "res_mkupdate: incorrect opcode: %d\n",
199 * XXX appending default domain to owner name is omitted,
200 * fqdn must be provided
202 if ((n
= dn_comp(rrecp
->r_dname
, cp
, buflen
, dnptrs
,
206 ShrinkBuffer(n
+ 2*INT16SZ
);
208 PUTSHORT(rclass
, cp
);
209 if (section
== S_ZONE
) {
210 if (numrrs
!= 1 || rrecp
->r_type
!= T_SOA
)
214 ShrinkBuffer(INT32SZ
+ INT16SZ
);
216 sp2
= cp
; /* save pointer to length byte */
218 if (rrecp
->r_size
== 0) {
219 if (section
== S_UPDATE
&& rclass
!= C_ANY
)
226 startp
= rrecp
->r_data
;
227 endp
= startp
+ rrecp
->r_size
- 1;
228 /* XXX this should be done centrally. */
229 switch (rrecp
->r_type
) {
231 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
233 if (!inet_aton(buf2
, &ina
))
235 n1
= ntohl(ina
.s_addr
);
236 ShrinkBuffer(INT32SZ
);
245 if (!getphrase_str(buf2
, sizeof buf2
, &startp
, endp
))
247 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
256 for (i
= 0; i
< 2; i
++) {
257 if (!getword_str(buf2
, sizeof buf2
, &startp
,
260 n
= dn_comp(buf2
, cp
, buflen
,
267 if (rrecp
->r_type
== T_SOA
) {
268 ShrinkBuffer(5 * INT32SZ
);
269 while (isspace(*startp
) || !*startp
)
271 if (*startp
== '(') {
276 /* serial, refresh, retry, expire, minimum */
277 for (i
= 0; i
< 5; i
++) {
278 soanum
= getnum_str(&startp
, endp
);
284 while (isspace(*startp
) || !*startp
)
294 n
= getnum_str(&startp
, endp
);
297 ShrinkBuffer(INT16SZ
);
299 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
301 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
308 n
= getnum_str(&startp
, endp
);
311 ShrinkBuffer(INT16SZ
);
314 n
= getnum_str(&startp
, endp
);
317 ShrinkBuffer(INT16SZ
);
320 n
= getnum_str(&startp
, endp
);
323 ShrinkBuffer(INT16SZ
);
326 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
328 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
335 n
= getnum_str(&startp
, endp
);
339 ShrinkBuffer(INT16SZ
);
340 for (i
= 0; i
< 2; i
++) {
341 if (!getword_str(buf2
, sizeof buf2
, &startp
,
344 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
,
356 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
358 if (!inet_aton(buf2
, &ina
))
360 n1
= ntohl(ina
.s_addr
);
361 ShrinkBuffer(INT32SZ
);
364 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
366 if ((i
= res_protocolnumber(buf2
)) < 0)
371 for (i
= 0; i
< MAXPORT
/8 ; i
++)
374 while (getword_str(buf2
, sizeof buf2
, &startp
, endp
)) {
375 if ((n1
= res_servicenumber(buf2
)) <= 0)
379 bm
[n1
/8] |= (0x80>>(n1
%8));
387 memcpy(cp
, bm
, maxbm
);
392 for (i
= 0; i
< 2; i
++) {
393 if ((n
= getstr_str(buf2
, sizeof buf2
,
400 memcpy(cp
, buf2
, (unsigned)n
);
406 if ((n
= getstr_str(buf2
, sizeof buf2
,
407 &startp
, endp
)) < 0) {
408 if (cp
!= (sp2
+ INT16SZ
))
416 memcpy(cp
, buf2
, (unsigned)n
);
422 if ((n
= getstr_str(buf2
, sizeof buf2
, &startp
,
429 memcpy(cp
, buf2
, (unsigned)n
);
434 if ((n
= getstr_str(buf2
, sizeof buf2
, &startp
,
437 if ((n
> 255) || (n
== 0))
441 memcpy(cp
, buf2
, (unsigned)n
);
443 if ((n
= getstr_str(buf2
, sizeof buf2
, &startp
,
450 memcpy(cp
, buf2
, (unsigned)n
);
455 if ((n
= inet_nsap_addr((char *)startp
, (u_char
*)buf2
, sizeof(buf2
))) != 0) {
464 if ((n
= loc_aton((char *)startp
, (u_char
*)buf2
)) != 0) {
473 int sig_type
, success
, dateerror
;
474 u_int32_t exptime
, timesigned
;
477 if ((n
= getword_str(buf2
, sizeof buf2
,
480 sig_type
= sym_ston(__p_type_syms
, buf2
, &success
);
481 if (!success
|| sig_type
== ns_t_any
)
483 ShrinkBuffer(INT16SZ
);
484 PUTSHORT(sig_type
, cp
);
486 n
= getnum_str(&startp
, endp
);
492 n
= getnum_str(&startp
, endp
);
493 if (n
<= 0 || n
> 255)
498 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
500 exptime
= ns_datetosecs(buf2
, &dateerror
);
502 ShrinkBuffer(INT32SZ
);
509 ottl
= strtoul(buf2
, &ulendp
, 10);
510 if (ulendp
!= NULL
&& *ulendp
!= '\0')
512 ShrinkBuffer(INT32SZ
);
514 if (!getword_str(buf2
, sizeof buf2
, &startp
,
517 exptime
= ns_datetosecs(buf2
, &dateerror
);
522 ShrinkBuffer(INT32SZ
);
523 PUTLONG(exptime
, cp
);
525 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
527 timesigned
= ns_datetosecs(buf2
, &dateerror
);
529 ShrinkBuffer(INT32SZ
);
530 PUTLONG(timesigned
, cp
);
535 n
= getnum_str(&startp
, endp
);
538 ShrinkBuffer(INT16SZ
);
541 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
543 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
549 if ((n
= getword_str(buf2
, sizeof buf2
,
552 siglen
= b64_pton(buf2
, buf3
, sizeof(buf3
));
555 ShrinkBuffer(siglen
);
556 memcpy(cp
, buf3
, siglen
);
562 int success
, nxt_type
;
567 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
569 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
575 memset(data
, 0, sizeof data
);
577 if (!getword_str(buf2
, sizeof buf2
, &startp
,
580 nxt_type
= sym_ston(__p_type_syms
, buf2
,
582 if (!success
|| !ns_t_rr_p(nxt_type
))
584 NS_NXT_BIT_SET(nxt_type
, data
);
585 if (nxt_type
> maxtype
)
588 n
= maxtype
/NS_NXT_BITS
+1;
598 n
= gethexnum_str(&startp
, endp
);
601 ShrinkBuffer(INT16SZ
);
604 n
= getnum_str(&startp
, endp
);
610 n
= getnum_str(&startp
, endp
);
616 if ((n
= getword_str(buf2
, sizeof buf2
,
619 keylen
= b64_pton(buf2
, buf3
, sizeof(buf3
));
622 ShrinkBuffer(keylen
);
623 memcpy(cp
, buf3
, keylen
);
628 n
= getnum_str(&startp
, endp
);
631 ShrinkBuffer(INT16SZ
);
634 n
= getnum_str(&startp
, endp
);
637 ShrinkBuffer(INT16SZ
);
640 n
= getnum_str(&startp
, endp
);
646 if ((n
= getword_str(buf2
, sizeof buf2
,
649 certlen
= b64_pton(buf2
, buf3
, sizeof(buf3
));
652 ShrinkBuffer(certlen
);
653 memcpy(cp
, buf3
, certlen
);
658 fprintf(stderr
, "NSupdate of RR type: %d not implemented\n",
662 n
= (u_int16_t
)((cp
- sp2
) - INT16SZ
);
666 hp
->qdcount
= htons(counts
[0]);
667 hp
->ancount
= htons(counts
[1]);
668 hp
->nscount
= htons(counts
[2]);
669 hp
->arcount
= htons(counts
[3]);
675 * Get a whitespace delimited word from a string (not file)
676 * into buf. modify the start pointer to point after the
677 * word in the string.
680 getword_str(char *buf
, int size
, const u_char
**startpp
, const u_char
*endp
) {
684 for (cp
= buf
; *startpp
<= endp
; ) {
686 if (isspace(c
) || c
== '\0') {
687 if (cp
!= buf
) /* trailing whitespace */
689 else { /* leading whitespace */
695 if (cp
>= buf
+size
-1)
704 * Get a phrase - possibly containing blanks - from a string (not file)
705 * into buf. modify the start pointer to point after the
706 * phrase in the string.
709 getphrase_str(char *buf
, int size
, const u_char
**startpp
, const u_char
*endp
) {
713 for (cp
= buf
; *startpp
<= endp
; ) {
715 if (isspace(c
) && cp
== buf
) {
716 /* leading whitespace */
720 else if ( c
== '\0' ) {
724 if (cp
>= buf
+size
-1)
733 * get a white spae delimited string from memory. Process quoted strings
734 * and \DDD escapes. Return length or -1 on error. Returned string may
737 static char digits
[] = "0123456789";
739 getstr_str(char *buf
, int size
, const u_char
**startpp
, const u_char
*endp
) {
747 for (cp
= buf
; *startpp
<= endp
; ) {
748 if ((c
= **startpp
) == '\0')
750 /* leading white space */
751 if ((cp
== buf
) && !seen_quote
&& isspace(c
)) {
789 (strchr(digits
, c
) - digits
);
799 } else if (!inquote
&& isspace(c
))
801 if (cp
>= buf
+size
-1)
809 return ((cp
== buf
)? (seen_quote
? 0: -1): (cp
- buf
));
812 * Get a whitespace delimited base 16 number from a string (not file) into buf
813 * update the start pointer to point after the number in the string.
816 gethexnum_str(const u_char
**startpp
, const u_char
*endp
) {
821 if (*startpp
+ 2 >= endp
||
822 strncasecmp((const char *)*startpp
, "0x", 2) != 0)
823 return getnum_str(startpp
, endp
);
825 for (n
= 0; *startpp
<= endp
; ) {
827 if (isspace(c
) || c
== '\0') {
828 if (seendigit
) /* trailing whitespace */
830 else { /* leading whitespace */
836 while ((*startpp
<= endp
) &&
837 ((c
= **startpp
) != '\n'))
844 if (c
== ')' && seendigit
) {
852 n
= n
* 16 + (c
- '0');
854 n
= n
* 16 + (tolower(c
) - 'a' + 10);
861 * Get a whitespace delimited base 16 number from a string (not file) into buf
862 * update the start pointer to point after the number in the string.
865 getnum_str(const u_char
**startpp
, const u_char
*endp
) {
870 for (n
= 0; *startpp
<= endp
; ) {
872 if (isspace(c
) || c
== '\0') {
873 if (seendigit
) /* trailing whitespace */
875 else { /* leading whitespace */
881 while ((*startpp
<= endp
) &&
882 ((c
= **startpp
) != '\n'))
889 if (c
== ')' && seendigit
) {
896 n
= n
* 10 + (c
- '0');
903 * Allocate a resource record buffer & save rr info.
906 res_mkupdrec(int section
, const char *dname
,
907 u_int
class, u_int type
, u_long ttl
) {
908 ns_updrec
*rrecp
= (ns_updrec
*)calloc(1, sizeof(ns_updrec
));
910 if (!rrecp
|| !(rrecp
->r_dname
= strdup(dname
))) {
915 rrecp
->r_class
= class;
916 rrecp
->r_type
= type
;
918 rrecp
->r_section
= section
;
923 * Free a resource record buffer created by res_mkupdrec.
926 res_freeupdrec(ns_updrec
*rrecp
) {
927 /* Note: freeing r_dp is the caller's responsibility. */
928 if (rrecp
->r_dname
!= NULL
)
929 free(rrecp
->r_dname
);
933 static struct valuelist
*servicelist
, *protolist
;
936 res_buildservicelist() {
937 __unused
struct servent
*sp
;
938 __unused
struct valuelist
*slp
;
940 #ifndef SET_SERVENT_MISSING
948 while ((sp
= getservent()) != NULL
) {
949 slp
= (struct valuelist
*)malloc(sizeof(struct valuelist
));
952 slp
->name
= strdup(sp
->s_name
);
953 slp
->proto
= strdup(sp
->s_proto
);
954 if ((slp
->name
== NULL
) || (slp
->proto
== NULL
)) {
955 if (slp
->name
) free(slp
->name
);
956 if (slp
->proto
) free(slp
->proto
);
960 slp
->port
= ntohs((u_int16_t
)sp
->s_port
); /* host byt order */
961 slp
->next
= servicelist
;
964 servicelist
->prev
= slp
;
972 res_destroyservicelist() {
973 struct valuelist
*slp
, *slp_next
;
975 for (slp
= servicelist
; slp
!= NULL
; slp
= slp_next
) {
976 slp_next
= slp
->next
;
981 servicelist
= (struct valuelist
*)0;
985 res_buildprotolist() {
987 struct valuelist
*slp
;
989 #ifndef SET_PROTOENT_MISSING
996 while ((pp
= getprotoent()) != NULL
) {
997 slp
= (struct valuelist
*)malloc(sizeof(struct valuelist
));
1000 slp
->name
= strdup(pp
->p_name
);
1001 if (slp
->name
== NULL
) {
1005 slp
->port
= pp
->p_proto
; /* host byte order */
1006 slp
->next
= protolist
;
1009 protolist
->prev
= slp
;
1016 res_destroyprotolist() {
1017 struct valuelist
*plp
, *plp_next
;
1019 for (plp
= protolist
; plp
!= NULL
; plp
= plp_next
) {
1020 plp_next
= plp
->next
;
1024 protolist
= (struct valuelist
*)0;
1028 findservice(const char *s
, struct valuelist
**list
) {
1029 struct valuelist
*lp
= *list
;
1032 for (; lp
!= NULL
; lp
= lp
->next
)
1033 if (strcasecmp(lp
->name
, s
) == 0) {
1035 lp
->prev
->next
= lp
->next
;
1037 lp
->next
->prev
= lp
->prev
;
1042 return (lp
->port
); /* host byte order */
1044 if (sscanf(s
, "%d", &n
) != 1 || n
<= 0)
1050 * Convert service name or (ascii) number to int.
1053 res_servicenumber(const char *p
) {
1054 if (servicelist
== (struct valuelist
*)0)
1055 res_buildservicelist();
1056 return (findservice(p
, &servicelist
));
1060 * Convert protocol name or (ascii) number to int.
1063 res_protocolnumber(const char *p
) {
1064 if (protolist
== (struct valuelist
*)0)
1065 res_buildprotolist();
1066 return (findservice(p
, &protolist
));
1069 static struct servent
*
1070 cgetservbyport(unsigned port
, const char *proto
) { /* Host byte order. */
1071 struct valuelist
**list
= &servicelist
;
1072 struct valuelist
*lp
= *list
;
1073 static struct servent serv
;
1076 for (; lp
!= NULL
; lp
= lp
->next
) {
1077 if (port
!= (u_int16_t
)lp
->port
) /* Host byte order. */
1079 if (strcasecmp(lp
->proto
, proto
) == 0) {
1081 lp
->prev
->next
= lp
->next
;
1083 lp
->next
->prev
= lp
->prev
;
1088 serv
.s_name
= lp
->name
;
1089 serv
.s_port
= htons((u_int16_t
)lp
->port
);
1090 serv
.s_proto
= lp
->proto
;
1097 static struct protoent
*
1098 cgetprotobynumber(int proto
) { /* Host byte order. */
1099 struct valuelist
**list
= &protolist
;
1100 struct valuelist
*lp
= *list
;
1101 static struct protoent prot
;
1103 for (; lp
!= NULL
; lp
= lp
->next
)
1104 if (lp
->port
== proto
) { /* Host byte order. */
1106 lp
->prev
->next
= lp
->next
;
1108 lp
->next
->prev
= lp
->prev
;
1113 prot
.p_name
= lp
->name
;
1114 prot
.p_proto
= lp
->port
; /* Host byte order. */
1121 res_protocolname(int num
) {
1122 static char number
[8];
1123 struct protoent
*pp
;
1125 if (protolist
== (struct valuelist
*)0)
1126 res_buildprotolist();
1127 pp
= cgetprotobynumber(num
);
1129 (void) sprintf(number
, "%d", num
);
1132 return (pp
->p_name
);
1136 res_servicename(u_int16_t port
, const char *proto
) { /* Host byte order. */
1137 static char number
[8];
1140 if (servicelist
== (struct valuelist
*)0)
1141 res_buildservicelist();
1142 ss
= cgetservbyport(htons(port
), proto
);
1144 (void) sprintf(number
, "%d", port
);
1147 return (ss
->s_name
);