child-rekey: Uninstall old outbound SA earlier on initiator/winner
[strongswan.git] / src / libhydra / plugins / resolve / resolve_handler.c
1 /*
2 * Copyright (C) 2012 Tobias Brunner
3 * Copyright (C) 2009 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "resolve_handler.h"
18
19 #include <sys/types.h>
20 #include <sys/stat.h>
21 #include <unistd.h>
22
23 #include <hydra.h>
24 #include <debug.h>
25 #include <threading/mutex.h>
26
27 /* path to resolvconf executable */
28 #define RESOLVCONF_EXEC "/sbin/resolvconf"
29
30 /* default prefix used for resolvconf interfaces (should have high prio) */
31 #define RESOLVCONF_PREFIX "lo.inet.ipsec."
32
33 typedef struct private_resolve_handler_t private_resolve_handler_t;
34
35 /**
36 * Private data of an resolve_handler_t object.
37 */
38 struct private_resolve_handler_t {
39
40 /**
41 * Public resolve_handler_t interface.
42 */
43 resolve_handler_t public;
44
45 /**
46 * resolv.conf file to use
47 */
48 char *file;
49
50 /**
51 * use resolvconf instead of writing directly to resolv.conf
52 */
53 bool use_resolvconf;
54
55 /**
56 * prefix to be used for interface names sent to resolvconf
57 */
58 char *iface_prefix;
59
60 /**
61 * Mutex to access file exclusively
62 */
63 mutex_t *mutex;
64 };
65
66 /**
67 * Writes the given nameserver to resolv.conf
68 */
69 static bool write_nameserver(private_resolve_handler_t *this,
70 identification_t *server, host_t *addr)
71 {
72 FILE *in, *out;
73 char buf[1024];
74 size_t len;
75 bool handled = FALSE;
76
77 in = fopen(this->file, "r");
78 /* allows us to stream from in to out */
79 unlink(this->file);
80 out = fopen(this->file, "w");
81 if (out)
82 {
83 fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
84 server);
85 DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
86 handled = TRUE;
87
88 /* copy rest of the file */
89 if (in)
90 {
91 while ((len = fread(buf, 1, sizeof(buf), in)))
92 {
93 ignore_result(fwrite(buf, 1, len, out));
94 }
95 }
96 fclose(out);
97 }
98 if (in)
99 {
100 fclose(in);
101 }
102 return handled;
103 }
104
105 /**
106 * Removes the given nameserver from resolv.conf
107 */
108 static void remove_nameserver(private_resolve_handler_t *this,
109 identification_t *server, host_t *addr)
110 {
111 FILE *in, *out;
112 char line[1024], matcher[512];
113
114 in = fopen(this->file, "r");
115 if (in)
116 {
117 /* allows us to stream from in to out */
118 unlink(this->file);
119 out = fopen(this->file, "w");
120 if (out)
121 {
122 snprintf(matcher, sizeof(matcher),
123 "nameserver %H # by strongSwan, from %Y\n",
124 addr, server);
125
126 /* copy all, but matching line */
127 while (fgets(line, sizeof(line), in))
128 {
129 if (strneq(line, matcher, strlen(matcher)))
130 {
131 DBG1(DBG_IKE, "removing DNS server %H from %s",
132 addr, this->file);
133 }
134 else
135 {
136 fputs(line, out);
137 }
138 }
139 fclose(out);
140 }
141 fclose(in);
142 }
143 }
144
145 /**
146 * Add or remove the given nameserver by invoking resolvconf.
147 */
148 static bool invoke_resolvconf(private_resolve_handler_t *this,
149 identification_t *server, host_t *addr,
150 bool install)
151 {
152 char cmd[128];
153
154 /* we use the nameserver's IP address as part of the interface name to
155 * make them unique */
156 if (snprintf(cmd, sizeof(cmd), "%s %s %s%H", RESOLVCONF_EXEC,
157 install ? "-a" : "-d", this->iface_prefix, addr) >= sizeof(cmd))
158 {
159 return FALSE;
160 }
161
162 if (install)
163 {
164 FILE *out;
165
166 out = popen(cmd, "w");
167 if (!out)
168 {
169 return FALSE;
170 }
171 DBG1(DBG_IKE, "installing DNS server %H via resolvconf", addr);
172 fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr,
173 server);
174 if (ferror(out) || pclose(out))
175 {
176 return FALSE;
177 }
178 }
179 else
180 {
181 ignore_result(system(cmd));
182 }
183 return TRUE;
184 }
185
186 METHOD(attribute_handler_t, handle, bool,
187 private_resolve_handler_t *this, identification_t *server,
188 configuration_attribute_type_t type, chunk_t data)
189 {
190 host_t *addr;
191 bool handled;
192
193 switch (type)
194 {
195 case INTERNAL_IP4_DNS:
196 addr = host_create_from_chunk(AF_INET, data, 0);
197 break;
198 case INTERNAL_IP6_DNS:
199 addr = host_create_from_chunk(AF_INET6, data, 0);
200 break;
201 default:
202 return FALSE;
203 }
204
205 if (!addr || addr->is_anyaddr(addr))
206 {
207 DESTROY_IF(addr);
208 return FALSE;
209 }
210
211 this->mutex->lock(this->mutex);
212 if (this->use_resolvconf)
213 {
214 handled = invoke_resolvconf(this, server, addr, TRUE);
215 }
216 else
217 {
218 handled = write_nameserver(this, server, addr);
219 }
220 this->mutex->unlock(this->mutex);
221 addr->destroy(addr);
222
223 if (!handled)
224 {
225 DBG1(DBG_IKE, "adding DNS server failed");
226 }
227 return handled;
228 }
229
230 METHOD(attribute_handler_t, release, void,
231 private_resolve_handler_t *this, identification_t *server,
232 configuration_attribute_type_t type, chunk_t data)
233 {
234 host_t *addr;
235 int family;
236
237 switch (type)
238 {
239 case INTERNAL_IP4_DNS:
240 family = AF_INET;
241 break;
242 case INTERNAL_IP6_DNS:
243 family = AF_INET6;
244 break;
245 default:
246 return;
247 }
248 addr = host_create_from_chunk(family, data, 0);
249
250 this->mutex->lock(this->mutex);
251 if (this->use_resolvconf)
252 {
253 invoke_resolvconf(this, server, addr, FALSE);
254 }
255 else
256 {
257 remove_nameserver(this, server, addr);
258 }
259 this->mutex->unlock(this->mutex);
260
261 addr->destroy(addr);
262 }
263
264 /**
265 * Attribute enumerator implementation
266 */
267 typedef struct {
268 /** implements enumerator_t interface */
269 enumerator_t public;
270 /** virtual IP we are requesting */
271 host_t *vip;
272 } attribute_enumerator_t;
273
274 static bool attribute_enumerate(attribute_enumerator_t *this,
275 configuration_attribute_type_t *type,
276 chunk_t *data)
277 {
278 switch (this->vip->get_family(this->vip))
279 {
280 case AF_INET:
281 *type = INTERNAL_IP4_DNS;
282 break;
283 case AF_INET6:
284 *type = INTERNAL_IP6_DNS;
285 break;
286 default:
287 return FALSE;
288 }
289 *data = chunk_empty;
290 /* enumerate only once */
291 this->public.enumerate = (void*)return_false;
292 return TRUE;
293 }
294
295 METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
296 private_resolve_handler_t *this, identification_t *server, host_t *vip)
297 {
298 if (vip)
299 {
300 attribute_enumerator_t *enumerator;
301
302 enumerator = malloc_thing(attribute_enumerator_t);
303 enumerator->public.enumerate = (void*)attribute_enumerate;
304 enumerator->public.destroy = (void*)free;
305 enumerator->vip = vip;
306
307 return &enumerator->public;
308 }
309 return enumerator_create_empty();
310 }
311
312 METHOD(resolve_handler_t, destroy, void,
313 private_resolve_handler_t *this)
314 {
315 this->mutex->destroy(this->mutex);
316 free(this);
317 }
318
319 /**
320 * See header
321 */
322 resolve_handler_t *resolve_handler_create()
323 {
324 private_resolve_handler_t *this;
325 struct stat st;
326
327 INIT(this,
328 .public = {
329 .handler = {
330 .handle = _handle,
331 .release = _release,
332 .create_attribute_enumerator = _create_attribute_enumerator,
333 },
334 .destroy = _destroy,
335 },
336 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
337 .file = lib->settings->get_str(lib->settings, "%s.plugins.resolve.file",
338 RESOLV_CONF, hydra->daemon),
339 );
340
341 if (stat(RESOLVCONF_EXEC, &st) == 0)
342 {
343 this->use_resolvconf = TRUE;
344 this->iface_prefix = lib->settings->get_str(lib->settings,
345 "%s.plugins.resolve.resolvconf.iface_prefix",
346 RESOLVCONF_PREFIX, hydra->daemon);
347 }
348
349 return &this->public;
350 }
351