]>
Commit | Line | Data |
---|---|---|
3997081b | 1 | #if !defined(lint) && !defined(SABER) |
d758ad8c | 2 | static const char rcsid[] = "$Id: res_update.c,v 1.12 2001/06/27 00:30:38 mellon Exp $"; |
3997081b TL |
3 | #endif /* not lint */ |
4 | ||
5 | /* | |
6 | * Copyright (c) 1996-1999 by Internet Software Consortium. | |
7 | * | |
8 | * Permission to use, copy, modify, and distribute this software for any | |
9 | * purpose with or without fee is hereby granted, provided that the above | |
10 | * copyright notice and this permission notice appear in all copies. | |
11 | * | |
12 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS | |
13 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES | |
14 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE | |
15 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL | |
16 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
17 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
18 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
19 | * SOFTWARE. | |
20 | */ | |
21 | ||
22 | /* | |
23 | * Based on the Dynamic DNS reference implementation by Viraj Bais | |
24 | * <viraj_bais@ccm.fm.intel.com> | |
25 | */ | |
26 | ||
27 | #include <sys/param.h> | |
28 | #include <sys/socket.h> | |
29 | #include <sys/time.h> | |
30 | ||
31 | #include <netinet/in.h> | |
32 | #include <arpa/inet.h> | |
33 | ||
34 | #include <errno.h> | |
35 | #include <limits.h> | |
36 | #include <netdb.h> | |
37 | #include <stdarg.h> | |
38 | #include <stdio.h> | |
39 | #include <stdlib.h> | |
40 | #include <string.h> | |
41 | ||
d758ad8c | 42 | #include <isc-dhcp/list.h> |
3997081b | 43 | #include "minires/minires.h" |
439a9b00 | 44 | #include "arpa/nameser.h" |
3997081b TL |
45 | |
46 | /* | |
47 | * Separate a linked list of records into groups so that all records | |
48 | * in a group will belong to a single zone on the nameserver. | |
49 | * Create a dynamic update packet for each zone and send it to the | |
50 | * nameservers for that zone, and await answer. | |
51 | * Abort if error occurs in updating any zone. | |
52 | * Return the number of zones updated on success, < 0 on error. | |
53 | * | |
54 | * On error, caller must deal with the unsynchronized zones | |
55 | * eg. an A record might have been successfully added to the forward | |
56 | * zone but the corresponding PTR record would be missing if error | |
57 | * was encountered while updating the reverse zone. | |
58 | */ | |
59 | ||
60 | struct zonegrp { | |
61 | char z_origin[MAXDNAME]; | |
62 | ns_class z_class; | |
63 | struct in_addr z_nsaddrs[MAXNS]; | |
64 | int z_nscount; | |
65 | int z_flags; | |
66 | ISC_LIST(ns_updrec) z_rrlist; | |
67 | ISC_LINK(struct zonegrp) z_link; | |
68 | }; | |
69 | ||
70 | #define ZG_F_ZONESECTADDED 0x0001 | |
71 | ||
72 | /* Forward. */ | |
73 | ||
74 | static int nscopy(struct sockaddr_in *, const struct sockaddr_in *, int); | |
75 | static int nsprom(struct sockaddr_in *, const struct in_addr *, int); | |
3997081b | 76 | |
7d9784f6 | 77 | void tkey_free (ns_tsig_key **); |
7d9784f6 | 78 | |
5abf0a44 | 79 | isc_result_t |
7d9784f6 | 80 | res_nupdate(res_state statp, ns_updrec *rrecp_in) { |
3997081b | 81 | ns_updrec *rrecp; |
47082c65 TL |
82 | double answer[PACKETSZ / sizeof (double)]; |
83 | double packet[2*PACKETSZ / sizeof (double)]; | |
3997081b | 84 | struct zonegrp *zptr, tgrp; |
3997081b TL |
85 | int nzones = 0, nscount = 0; |
86 | unsigned n; | |
9e051ac9 | 87 | unsigned rval; |
3997081b | 88 | struct sockaddr_in nsaddrs[MAXNS]; |
7d9784f6 | 89 | ns_tsig_key *key; |
b7137154 TL |
90 | void *zcookie = 0; |
91 | void *zcookp = &zcookie; | |
5abf0a44 | 92 | isc_result_t rcode; |
3997081b | 93 | |
b7137154 | 94 | again: |
e721773f TL |
95 | /* Make sure all the updates are in the same zone, and find out |
96 | what zone they are in. */ | |
97 | zptr = NULL; | |
3997081b TL |
98 | for (rrecp = rrecp_in; rrecp; rrecp = ISC_LIST_NEXT(rrecp, r_link)) { |
99 | /* Find the origin for it if there is one. */ | |
100 | tgrp.z_class = rrecp->r_class; | |
7951fc18 | 101 | rcode = res_findzonecut(statp, rrecp->r_dname, tgrp.z_class, |
3997081b TL |
102 | RES_EXHAUSTIVE, |
103 | tgrp.z_origin, | |
104 | sizeof tgrp.z_origin, | |
7951fc18 TL |
105 | tgrp.z_nsaddrs, MAXNS, &tgrp.z_nscount, |
106 | zcookp); | |
5abf0a44 | 107 | if (rcode != ISC_R_SUCCESS) |
7951fc18 | 108 | goto done; |
3997081b | 109 | if (tgrp.z_nscount <= 0) { |
5abf0a44 | 110 | rcode = ISC_R_NOTZONE; |
3997081b TL |
111 | goto done; |
112 | } | |
3997081b TL |
113 | /* Make a group for it if there isn't one. */ |
114 | if (zptr == NULL) { | |
115 | zptr = malloc(sizeof *zptr); | |
116 | if (zptr == NULL) { | |
5abf0a44 | 117 | rcode = ISC_R_NOMEMORY; |
3997081b TL |
118 | goto done; |
119 | } | |
120 | *zptr = tgrp; | |
121 | zptr->z_flags = 0; | |
122 | ISC_LIST_INIT(zptr->z_rrlist); | |
e721773f TL |
123 | } else if (ns_samename(tgrp.z_origin, zptr->z_origin) == 0 || |
124 | tgrp.z_class != zptr->z_class) { | |
125 | /* Some of the records are in different zones. */ | |
5abf0a44 | 126 | rcode = ISC_R_CROSSZONE; |
e721773f | 127 | goto done; |
3997081b | 128 | } |
e721773f | 129 | /* Thread this rrecp onto the zone group. */ |
3997081b TL |
130 | ISC_LIST_APPEND(zptr->z_rrlist, rrecp, r_glink); |
131 | } | |
132 | ||
e721773f TL |
133 | /* Construct zone section and prepend it. */ |
134 | rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin, | |
135 | zptr->z_class, ns_t_soa, 0); | |
136 | if (rrecp == NULL) { | |
d758ad8c | 137 | rcode = ISC_R_UNEXPECTED; |
e721773f TL |
138 | goto done; |
139 | } | |
140 | ISC_LIST_PREPEND(zptr->z_rrlist, rrecp, r_glink); | |
141 | zptr->z_flags |= ZG_F_ZONESECTADDED; | |
142 | ||
143 | /* Marshall the update message. */ | |
45e52bde | 144 | n = sizeof packet; |
5abf0a44 TL |
145 | rcode = res_nmkupdate(statp, |
146 | ISC_LIST_HEAD(zptr->z_rrlist), packet, &n); | |
147 | if (rcode != ISC_R_SUCCESS) | |
e721773f | 148 | goto done; |
3997081b | 149 | |
e721773f TL |
150 | /* Temporarily replace the resolver's nameserver set. */ |
151 | nscount = nscopy(nsaddrs, statp->nsaddr_list, statp->nscount); | |
152 | statp->nscount = nsprom(statp->nsaddr_list, | |
153 | zptr->z_nsaddrs, zptr->z_nscount); | |
154 | ||
155 | /* Send the update and remember the result. */ | |
7d9784f6 | 156 | key = (ns_tsig_key *)0; |
d758ad8c TL |
157 | rcode = find_tsig_key (&key, zptr->z_origin, zcookie); |
158 | if (rcode == ISC_R_SUCCESS) { | |
5abf0a44 TL |
159 | rcode = res_nsendsigned(statp, packet, n, key, |
160 | answer, sizeof answer, &rval); | |
7d9784f6 | 161 | tkey_free (&key); |
d758ad8c | 162 | } else if (rcode == ISC_R_NOTFOUND || rcode == ISC_R_KEY_UNKNOWN) { |
5abf0a44 TL |
163 | rcode = res_nsend(statp, packet, n, |
164 | answer, sizeof answer, &rval); | |
7d9784f6 | 165 | } |
d758ad8c | 166 | if (rcode != ISC_R_SUCCESS) |
e721773f | 167 | goto undone; |
d758ad8c | 168 | |
5abf0a44 TL |
169 | rcode = ns_rcode_to_isc (((HEADER *)answer)->rcode); |
170 | if (zcookie && rcode == ISC_R_BADSIG) { | |
b7137154 TL |
171 | repudiate_zone (&zcookie); |
172 | } | |
e721773f TL |
173 | |
174 | undone: | |
175 | /* Restore resolver's nameserver set. */ | |
176 | statp->nscount = nscopy(statp->nsaddr_list, nsaddrs, nscount); | |
177 | nscount = 0; | |
3997081b | 178 | done: |
e721773f | 179 | if (zptr) { |
3997081b TL |
180 | if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0) |
181 | res_freeupdrec(ISC_LIST_HEAD(zptr->z_rrlist)); | |
3997081b TL |
182 | free(zptr); |
183 | } | |
3997081b | 184 | |
b7137154 TL |
185 | /* If the update failed because we used a cached zone and it |
186 | didn't work, try it again without the cached zone. */ | |
5abf0a44 | 187 | if (zcookp && (rcode == ISC_R_NOTZONE || rcode == ISC_R_BADSIG)) { |
b7137154 TL |
188 | zcookp = 0; |
189 | goto again; | |
190 | } | |
191 | ||
192 | if (zcookie) | |
193 | forget_zone (&zcookie); | |
e721773f | 194 | return rcode; |
3997081b TL |
195 | } |
196 | ||
197 | /* Private. */ | |
198 | ||
199 | static int | |
200 | nscopy(struct sockaddr_in *dst, const struct sockaddr_in *src, int n) { | |
201 | int i; | |
202 | ||
203 | for (i = 0; i < n; i++) | |
204 | dst[i] = src[i]; | |
205 | return (n); | |
206 | } | |
207 | ||
208 | static int | |
209 | nsprom(struct sockaddr_in *dst, const struct in_addr *src, int n) { | |
210 | int i; | |
211 | ||
212 | for (i = 0; i < n; i++) { | |
213 | memset(&dst[i], 0, sizeof dst[i]); | |
214 | dst[i].sin_family = AF_INET; | |
215 | dst[i].sin_port = htons(NS_DEFAULTPORT); | |
216 | dst[i].sin_addr = src[i]; | |
217 | } | |
218 | return (n); | |
219 | } |