]>
Commit | Line | Data |
---|---|---|
352f4ff9 | 1 | /* Temporary, thread-local resolver state. |
04277e02 | 2 | Copyright (C) 2017-2019 Free Software Foundation, Inc. |
352f4ff9 FW |
3 | This file is part of the GNU C Library. |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <resolv_context.h> | |
f30a54b2 | 20 | #include <resolv_conf.h> |
352f4ff9 FW |
21 | #include <resolv-internal.h> |
22 | ||
23 | #include <assert.h> | |
f30a54b2 | 24 | #include <errno.h> |
352f4ff9 FW |
25 | #include <stdlib.h> |
26 | #include <stdio.h> | |
27 | ||
28 | /* Currently active struct resolv_context object. This pointer forms | |
29 | the start of a single-linked list, using the __next member of | |
30 | struct resolv_context. This list serves two purposes: | |
31 | ||
32 | (a) A subsequent call to __resolv_context_get will only increment | |
33 | the reference counter and will not allocate a new object. The | |
34 | _res state freshness check is skipped in this case, too. | |
35 | ||
36 | (b) The per-thread cleanup function defined by the resolver calls | |
37 | __resolv_context_freeres, which will deallocate all the context | |
38 | objects. This avoids the need for cancellation handlers and | |
39 | the complexity they bring, but it requires heap allocation of | |
40 | the context object because the per-thread cleanup functions run | |
41 | only after the stack has been fully unwound (and all on-stack | |
42 | objects have been deallocated at this point). | |
43 | ||
44 | The TLS variable current is updated even in | |
45 | __resolv_context_get_override, to support case (b) above. This does | |
46 | not override the per-thread resolver state (as obtained by the | |
47 | non-res_state function such as __resolv_context_get) in an | |
48 | observable way because the wrapped context is only used to | |
49 | implement the res_n* functions in the resolver, and those do not | |
50 | call back into user code which could indirectly use the per-thread | |
51 | resolver state. */ | |
52 | static __thread struct resolv_context *current attribute_tls_model_ie; | |
53 | ||
aef16cc8 FW |
54 | /* The resolv_conf handling will gives us a ctx->conf pointer even if |
55 | these fields do not match because a mis-match does not cause a loss | |
56 | of state (_res objects can store the full information). This | |
57 | function checks to ensure that there is a full patch, to prevent | |
58 | overwriting a patched configuration. */ | |
59 | static bool | |
60 | replicated_configuration_matches (const struct resolv_context *ctx) | |
61 | { | |
62 | return ctx->resp->options == ctx->conf->options | |
63 | && ctx->resp->retrans == ctx->conf->retrans | |
64 | && ctx->resp->retry == ctx->conf->retry | |
65 | && ctx->resp->ndots == ctx->conf->ndots; | |
66 | } | |
67 | ||
352f4ff9 FW |
68 | /* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if |
69 | res_init in some other thread requested re-initializing. */ | |
70 | static __attribute__ ((warn_unused_result)) bool | |
f30a54b2 | 71 | maybe_init (struct resolv_context *ctx, bool preinit) |
352f4ff9 | 72 | { |
f30a54b2 | 73 | struct __res_state *resp = ctx->resp; |
352f4ff9 FW |
74 | if (resp->options & RES_INIT) |
75 | { | |
aef16cc8 FW |
76 | if (resp->options & RES_NORELOAD) |
77 | /* Configuration reloading was explicitly disabled. */ | |
78 | return true; | |
79 | ||
f30a54b2 FW |
80 | /* If there is no associated resolv_conf object despite the |
81 | initialization, something modified *ctx->resp. Do not | |
82 | override those changes. */ | |
aef16cc8 | 83 | if (ctx->conf != NULL && replicated_configuration_matches (ctx)) |
352f4ff9 | 84 | { |
aef16cc8 FW |
85 | struct resolv_conf *current = __resolv_conf_get_current (); |
86 | if (current == NULL) | |
87 | return false; | |
88 | ||
89 | /* Check if the configuration changed. */ | |
90 | if (current != ctx->conf) | |
f30a54b2 | 91 | { |
aef16cc8 FW |
92 | /* This call will detach the extended resolver state. */ |
93 | if (resp->nscount > 0) | |
94 | __res_iclose (resp, true); | |
95 | /* Reattach the current configuration. */ | |
96 | if (__resolv_conf_attach (ctx->resp, current)) | |
97 | { | |
98 | __resolv_conf_put (ctx->conf); | |
99 | /* ctx takes ownership, so we do not release current. */ | |
100 | ctx->conf = current; | |
101 | } | |
f30a54b2 | 102 | } |
aef16cc8 FW |
103 | else |
104 | /* No change. Drop the reference count for current. */ | |
105 | __resolv_conf_put (current); | |
352f4ff9 FW |
106 | } |
107 | return true; | |
108 | } | |
109 | ||
f30a54b2 | 110 | assert (ctx->conf == NULL); |
352f4ff9 FW |
111 | if (preinit) |
112 | { | |
113 | if (!resp->retrans) | |
114 | resp->retrans = RES_TIMEOUT; | |
115 | if (!resp->retry) | |
116 | resp->retry = RES_DFLRETRY; | |
117 | resp->options = RES_DEFAULT; | |
118 | if (!resp->id) | |
119 | resp->id = res_randomid (); | |
120 | } | |
f30a54b2 FW |
121 | |
122 | if (__res_vinit (resp, preinit) < 0) | |
123 | return false; | |
124 | ctx->conf = __resolv_conf_get (ctx->resp); | |
125 | return true; | |
352f4ff9 FW |
126 | } |
127 | ||
128 | /* Allocate a new context object and initialize it. The object is put | |
129 | on the current list. */ | |
130 | static struct resolv_context * | |
131 | context_alloc (struct __res_state *resp) | |
132 | { | |
133 | struct resolv_context *ctx = malloc (sizeof (*ctx)); | |
134 | if (ctx == NULL) | |
135 | return NULL; | |
136 | ctx->resp = resp; | |
f30a54b2 | 137 | ctx->conf = __resolv_conf_get (resp); |
352f4ff9 FW |
138 | ctx->__refcount = 1; |
139 | ctx->__from_res = true; | |
140 | ctx->__next = current; | |
141 | current = ctx; | |
142 | return ctx; | |
143 | } | |
144 | ||
145 | /* Deallocate the context object and all the state within. */ | |
146 | static void | |
147 | context_free (struct resolv_context *ctx) | |
148 | { | |
f30a54b2 | 149 | int error_code = errno; |
352f4ff9 | 150 | current = ctx->__next; |
f30a54b2 | 151 | __resolv_conf_put (ctx->conf); |
352f4ff9 | 152 | free (ctx); |
f30a54b2 | 153 | __set_errno (error_code); |
352f4ff9 FW |
154 | } |
155 | ||
156 | /* Reuse the current context object. */ | |
157 | static struct resolv_context * | |
158 | context_reuse (void) | |
159 | { | |
160 | /* A context object created by __resolv_context_get_override cannot | |
161 | be reused. */ | |
162 | assert (current->__from_res); | |
163 | ||
164 | ++current->__refcount; | |
165 | ||
166 | /* Check for reference counter wraparound. This can only happen if | |
167 | the get/put functions are not properly paired. */ | |
168 | assert (current->__refcount > 0); | |
169 | ||
170 | return current; | |
171 | } | |
172 | ||
173 | /* Backing function for the __resolv_context_get family of | |
174 | functions. */ | |
175 | static struct resolv_context * | |
176 | context_get (bool preinit) | |
177 | { | |
178 | if (current != NULL) | |
179 | return context_reuse (); | |
180 | ||
181 | struct resolv_context *ctx = context_alloc (&_res); | |
182 | if (ctx == NULL) | |
183 | return NULL; | |
f30a54b2 | 184 | if (!maybe_init (ctx, preinit)) |
352f4ff9 FW |
185 | { |
186 | context_free (ctx); | |
187 | return NULL; | |
188 | } | |
189 | return ctx; | |
190 | } | |
191 | ||
192 | struct resolv_context * | |
193 | __resolv_context_get (void) | |
194 | { | |
195 | return context_get (false); | |
196 | } | |
197 | libc_hidden_def (__resolv_context_get) | |
198 | ||
199 | struct resolv_context * | |
200 | __resolv_context_get_preinit (void) | |
201 | { | |
202 | return context_get (true); | |
203 | } | |
204 | libc_hidden_def (__resolv_context_get_preinit) | |
205 | ||
206 | struct resolv_context * | |
207 | __resolv_context_get_override (struct __res_state *resp) | |
208 | { | |
209 | /* NB: As explained asbove, context_alloc will put the context on | |
210 | the current list. */ | |
211 | struct resolv_context *ctx = context_alloc (resp); | |
212 | if (ctx == NULL) | |
213 | return NULL; | |
214 | ||
215 | ctx->__from_res = false; | |
216 | return ctx; | |
217 | } | |
218 | libc_hidden_def (__resolv_context_get_override) | |
219 | ||
220 | void | |
221 | __resolv_context_put (struct resolv_context *ctx) | |
222 | { | |
223 | if (ctx == NULL) | |
224 | return; | |
225 | ||
226 | /* NB: Callers assume that this function preserves errno and | |
227 | h_errno. */ | |
228 | ||
229 | assert (current == ctx); | |
230 | assert (ctx->__refcount > 0); | |
231 | ||
232 | if (ctx->__from_res && --ctx->__refcount > 0) | |
233 | /* Do not pop this context yet. */ | |
234 | return; | |
235 | ||
236 | context_free (ctx); | |
237 | } | |
238 | libc_hidden_def (__resolv_context_put) | |
239 | ||
240 | void | |
241 | __resolv_context_freeres (void) | |
242 | { | |
243 | /* Deallocate the entire chain of context objects. */ | |
244 | struct resolv_context *ctx = current; | |
245 | current = NULL; | |
246 | while (ctx != NULL) | |
247 | { | |
248 | struct resolv_context *next = ctx->__next; | |
249 | context_free (ctx); | |
250 | ctx = next; | |
251 | } | |
252 | } |