Moving charon to libcharon.
[strongswan.git] / src / libcharon / plugins / resolve / resolve_handler.c
1 /*
2 * Copyright (C) 2009 Martin Willi
3 * Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "resolve_handler.h"
17
18 #include <unistd.h>
19
20 #include <daemon.h>
21 #include <threading/mutex.h>
22
23 typedef struct private_resolve_handler_t private_resolve_handler_t;
24
25 /**
26 * Private data of an resolve_handler_t object.
27 */
28 struct private_resolve_handler_t {
29
30 /**
31 * Public resolve_handler_t interface.
32 */
33 resolve_handler_t public;
34
35 /**
36 * resolv.conf file to use
37 */
38 char *file;
39
40 /**
41 * Mutex to access file exclusively
42 */
43 mutex_t *mutex;
44 };
45
46 /**
47 * Implementation of attribute_handler_t.handle
48 */
49 static bool handle(private_resolve_handler_t *this, identification_t *server,
50 configuration_attribute_type_t type, chunk_t data)
51 {
52 FILE *in, *out;
53 char buf[1024];
54 host_t *addr;
55 size_t len;
56 bool handled = FALSE;
57
58 switch (type)
59 {
60 case INTERNAL_IP4_DNS:
61 addr = host_create_from_chunk(AF_INET, data, 0);
62 break;
63 case INTERNAL_IP6_DNS:
64 addr = host_create_from_chunk(AF_INET6, data, 0);
65 break;
66 default:
67 return FALSE;
68 }
69
70 if (!addr || addr->is_anyaddr(addr))
71 {
72 DESTROY_IF(addr);
73 return FALSE;
74 }
75 this->mutex->lock(this->mutex);
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, server);
84 DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
85 handled = TRUE;
86
87 /* copy rest of the file */
88 if (in)
89 {
90 while ((len = fread(buf, 1, sizeof(buf), in)))
91 {
92 ignore_result(fwrite(buf, 1, len, out));
93 }
94 }
95 fclose(out);
96 }
97 if (in)
98 {
99 fclose(in);
100 }
101 this->mutex->unlock(this->mutex);
102 addr->destroy(addr);
103
104 if (!handled)
105 {
106 DBG1(DBG_IKE, "adding DNS server failed", this->file);
107 }
108 return handled;
109 }
110
111 /**
112 * Implementation of attribute_handler_t.release
113 */
114 static void release(private_resolve_handler_t *this, identification_t *server,
115 configuration_attribute_type_t type, chunk_t data)
116 {
117 FILE *in, *out;
118 char line[1024], matcher[512], *pos;
119 host_t *addr;
120 int family;
121
122 switch (type)
123 {
124 case INTERNAL_IP4_DNS:
125 family = AF_INET;
126 break;
127 case INTERNAL_IP6_DNS:
128 family = AF_INET6;
129 break;
130 default:
131 return;
132 }
133
134 this->mutex->lock(this->mutex);
135
136 in = fopen(this->file, "r");
137 if (in)
138 {
139 /* allows us to stream from in to out */
140 unlink(this->file);
141 out = fopen(this->file, "w");
142 if (out)
143 {
144 addr = host_create_from_chunk(family, data, 0);
145 snprintf(matcher, sizeof(matcher),
146 "nameserver %H # by strongSwan, from %Y\n",
147 addr, server);
148
149 /* copy all, but matching line */
150 while ((pos = fgets(line, sizeof(line), in)))
151 {
152 if (strneq(line, matcher, strlen(matcher)))
153 {
154 DBG1(DBG_IKE, "removing DNS server %H from %s",
155 addr, this->file);
156 }
157 else
158 {
159 fputs(line, out);
160 }
161 }
162 addr->destroy(addr);
163 fclose(out);
164 }
165 fclose(in);
166 }
167
168 this->mutex->unlock(this->mutex);
169 }
170
171 /**
172 * Attribute enumerator implementation
173 */
174 typedef struct {
175 /** implements enumerator_t interface */
176 enumerator_t public;
177 /** virtual IP we are requesting */
178 host_t *vip;
179 } attribute_enumerator_t;
180
181 /**
182 * Implementation of create_attribute_enumerator().enumerate()
183 */
184 static bool attribute_enumerate(attribute_enumerator_t *this,
185 configuration_attribute_type_t *type, chunk_t *data)
186 {
187 switch (this->vip->get_family(this->vip))
188 {
189 case AF_INET:
190 *type = INTERNAL_IP4_DNS;
191 break;
192 case AF_INET6:
193 *type = INTERNAL_IP6_DNS;
194 break;
195 default:
196 return FALSE;
197 }
198 *data = chunk_empty;
199 /* enumerate only once */
200 this->public.enumerate = (void*)return_false;
201 return TRUE;
202 }
203
204 /**
205 * Implementation of attribute_handler_t.create_attribute_enumerator
206 */
207 static enumerator_t* create_attribute_enumerator(private_resolve_handler_t *this,
208 identification_t *server, host_t *vip)
209 {
210 if (vip)
211 {
212 attribute_enumerator_t *enumerator;
213
214 enumerator = malloc_thing(attribute_enumerator_t);
215 enumerator->public.enumerate = (void*)attribute_enumerate;
216 enumerator->public.destroy = (void*)free;
217 enumerator->vip = vip;
218
219 return &enumerator->public;
220 }
221 return enumerator_create_empty();
222 }
223
224 /**
225 * Implementation of resolve_handler_t.destroy.
226 */
227 static void destroy(private_resolve_handler_t *this)
228 {
229 this->mutex->destroy(this->mutex);
230 free(this);
231 }
232
233 /**
234 * See header
235 */
236 resolve_handler_t *resolve_handler_create()
237 {
238 private_resolve_handler_t *this = malloc_thing(private_resolve_handler_t);
239
240 this->public.handler.handle = (bool(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))handle;
241 this->public.handler.release = (void(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
242 this->public.handler.create_attribute_enumerator = (enumerator_t*(*)(attribute_handler_t*, identification_t *server, host_t *vip))create_attribute_enumerator;
243 this->public.destroy = (void(*)(resolve_handler_t*))destroy;
244
245 this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
246 this->file = lib->settings->get_str(lib->settings,
247 "charon.plugins.resolve.file", RESOLV_CONF);
248
249 return &this->public;
250 }
251