2 * Copyright (c) 1996 by Internet Software Consortium.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
17 * $FreeBSD: src/lib/libc/net/res_mkupdate.c,v 1.2.2.1 2001/03/05 10:47:11 obrien Exp $
18 * $DragonFly: src/lib/libc/net/res_mkupdate.c,v 1.3 2005/11/13 02:04:47 swildner Exp $
22 * Based on the Dynamic DNS reference implementation by Viraj Bais
23 * <viraj_bais@ccm.fm.intel.com>
26 #include <sys/types.h>
27 #include <sys/param.h>
29 #include <netinet/in.h>
30 #include <arpa/nameser.h>
31 #include <arpa/inet.h>
42 #include "res_config.h"
44 static int getnum_str(u_char
**, u_char
*);
45 static int getword_str(char *, int, u_char
**, u_char
*);
47 #define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
50 * Form update packets.
51 * Returns the size of the resulting packet if no error
53 * returns -1 if error in reading a word/number in rdata
54 * portion for update packets
55 * -2 if length of buffer passed is insufficient
56 * -3 if zone section is not the first section in
57 * the linked list, or section order has a problem
58 * -4 on a number overflow
59 * -5 unknown operation or no records
62 res_mkupdate(ns_updrec
*rrecp_in
, u_char
*buf
, int buflen
)
64 ns_updrec
*rrecp_start
= rrecp_in
;
66 u_char
*cp
, *sp1
, *sp2
, *startp
, *endp
;
67 int n
, i
, soanum
, multiline
;
71 int section
, numrrs
= 0, counts
[ns_s_max
];
72 u_int16_t rtype
, rclass
;
74 u_char
*dnptrs
[20], **dpp
, **lastdnptr
;
76 if ((_res
.options
& RES_INIT
) == 0 && res_init() == -1) {
77 h_errno
= NETDB_INTERNAL
;
82 * Initialize header fields.
84 if ((buf
== NULL
) || (buflen
< HFIXEDSZ
))
86 memset(buf
, 0, HFIXEDSZ
);
88 hp
->id
= htons(++_res
.id
);
89 hp
->opcode
= ns_o_update
;
91 sp1
= buf
+ 2*INT16SZ
; /* save pointer to zocount */
97 lastdnptr
= dnptrs
+ sizeof dnptrs
/ sizeof dnptrs
[0];
99 if (rrecp_start
== NULL
)
101 else if (rrecp_start
->r_section
!= S_ZONE
)
104 memset(counts
, 0, sizeof counts
);
105 for (rrecp
= rrecp_start
; rrecp
; rrecp
= rrecp
->r_grpnext
) {
107 section
= rrecp
->r_section
;
108 if (section
< 0 || section
>= ns_s_max
)
111 for (i
= section
+ 1; i
< ns_s_max
; i
++)
114 rtype
= rrecp
->r_type
;
115 rclass
= rrecp
->r_class
;
117 /* overload class and type */
118 if (section
== S_PREREQ
) {
120 switch (rrecp
->r_opcode
) {
136 if (rrecp
->r_size
== 0)
141 "res_mkupdate: incorrect opcode: %d\n",
146 } else if (section
== S_UPDATE
) {
147 switch (rrecp
->r_opcode
) {
149 rclass
= rrecp
->r_size
== 0 ? C_ANY
: C_NONE
;
155 "res_mkupdate: incorrect opcode: %d\n",
163 * XXX appending default domain to owner name is omitted,
164 * fqdn must be provided
166 if ((n
= dn_comp(rrecp
->r_dname
, cp
, buflen
, dnptrs
,
170 ShrinkBuffer(n
+ 2*INT16SZ
);
172 PUTSHORT(rclass
, cp
);
173 if (section
== S_ZONE
) {
174 if (numrrs
!= 1 || rrecp
->r_type
!= T_SOA
)
178 ShrinkBuffer(INT32SZ
+ INT16SZ
);
180 sp2
= cp
; /* save pointer to length byte */
182 if (rrecp
->r_size
== 0) {
183 if (section
== S_UPDATE
&& rclass
!= C_ANY
)
190 startp
= rrecp
->r_data
;
191 endp
= startp
+ rrecp
->r_size
- 1;
192 /* XXX this should be done centrally. */
193 switch (rrecp
->r_type
) {
195 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
197 if (!inet_aton(buf2
, &ina
))
199 n1
= ntohl(ina
.s_addr
);
200 ShrinkBuffer(INT32SZ
);
209 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
211 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
220 for (i
= 0; i
< 2; i
++) {
221 if (!getword_str(buf2
, sizeof buf2
, &startp
,
224 n
= dn_comp(buf2
, cp
, buflen
,
231 if (rrecp
->r_type
== T_SOA
) {
232 ShrinkBuffer(5 * INT32SZ
);
233 while (isspace(*startp
) || !*startp
)
235 if (*startp
== '(') {
240 /* serial, refresh, retry, expire, minimum */
241 for (i
= 0; i
< 5; i
++) {
242 soanum
= getnum_str(&startp
, endp
);
248 while (isspace(*startp
) || !*startp
)
258 n
= getnum_str(&startp
, endp
);
262 ShrinkBuffer(INT16SZ
);
263 if (!getword_str(buf2
, sizeof buf2
, &startp
, endp
))
265 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
, lastdnptr
);
272 n
= getnum_str(&startp
, endp
);
276 ShrinkBuffer(INT16SZ
);
277 for (i
= 0; i
< 2; i
++) {
278 if (!getword_str(buf2
, sizeof buf2
, &startp
,
281 n
= dn_comp(buf2
, cp
, buflen
, dnptrs
,
296 /* XXX - more fine tuning needed here */
297 ShrinkBuffer(rrecp
->r_size
);
298 memcpy(cp
, rrecp
->r_data
, rrecp
->r_size
);
304 n
= (u_int16_t
)((cp
- sp2
) - INT16SZ
);
308 hp
->qdcount
= htons(counts
[0]);
309 hp
->ancount
= htons(counts
[1]);
310 hp
->nscount
= htons(counts
[2]);
311 hp
->arcount
= htons(counts
[3]);
316 * Get a whitespace delimited word from a string (not file)
317 * into buf. modify the start pointer to point after the
318 * word in the string.
321 getword_str(char *buf
, int size
, u_char
**startpp
, u_char
*endp
)
326 for (cp
= buf
; *startpp
<= endp
; ) {
328 if (isspace(c
) || c
== '\0') {
329 if (cp
!= buf
) /* trailing whitespace */
331 else { /* leading whitespace */
337 if (cp
>= buf
+size
-1)
346 * Get a whitespace delimited number from a string (not file) into buf
347 * update the start pointer to point after the number in the string.
350 getnum_str(u_char
**startpp
, u_char
*endp
)
356 for (n
= 0; *startpp
<= endp
; ) {
358 if (isspace(c
) || c
== '\0') {
359 if (seendigit
) /* trailing whitespace */
361 else { /* leading whitespace */
367 while ((*startpp
<= endp
) &&
368 ((c
= **startpp
) != '\n'))
375 if (c
== ')' && seendigit
) {
382 n
= n
* 10 + (c
- '0');
389 * Allocate a resource record buffer & save rr info.
392 res_mkupdrec(int section
, const char *dname
,
393 u_int
class, u_int type
, u_long ttl
)
395 ns_updrec
*rrecp
= (ns_updrec
*)calloc(1, sizeof(ns_updrec
));
397 if (!rrecp
|| !(rrecp
->r_dname
= strdup(dname
)))
399 rrecp
->r_class
= class;
400 rrecp
->r_type
= type
;
402 rrecp
->r_section
= section
;
407 * Free a resource record buffer created by res_mkupdrec.
410 res_freeupdrec(ns_updrec
*rrecp
)
412 /* Note: freeing r_dp is the caller's responsibility. */
413 if (rrecp
->r_dname
!= NULL
)
414 free(rrecp
->r_dname
);