moved resolve plugin from libcharon to libhydra
[strongswan.git] / src / libhydra / 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 <hydra.h>
21 #include <debug.h>
22 #include <threading/mutex.h>
23
24 typedef struct private_resolve_handler_t private_resolve_handler_t;
25
26 /**
27 * Private data of an resolve_handler_t object.
28 */
29 struct private_resolve_handler_t {
30
31 /**
32 * Public resolve_handler_t interface.
33 */
34 resolve_handler_t public;
35
36 /**
37 * resolv.conf file to use
38 */
39 char *file;
40
41 /**
42 * Mutex to access file exclusively
43 */
44 mutex_t *mutex;
45 };
46
47 /**
48 * Implementation of attribute_handler_t.handle
49 */
50 static bool handle(private_resolve_handler_t *this, identification_t *server,
51 configuration_attribute_type_t type, chunk_t data)
52 {
53 FILE *in, *out;
54 char buf[1024];
55 host_t *addr;
56 size_t len;
57 bool handled = FALSE;
58
59 switch (type)
60 {
61 case INTERNAL_IP4_DNS:
62 addr = host_create_from_chunk(AF_INET, data, 0);
63 break;
64 case INTERNAL_IP6_DNS:
65 addr = host_create_from_chunk(AF_INET6, data, 0);
66 break;
67 default:
68 return FALSE;
69 }
70
71 if (!addr || addr->is_anyaddr(addr))
72 {
73 DESTROY_IF(addr);
74 return FALSE;
75 }
76 this->mutex->lock(this->mutex);
77
78 in = fopen(this->file, "r");
79 /* allows us to stream from in to out */
80 unlink(this->file);
81 out = fopen(this->file, "w");
82 if (out)
83 {
84 fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr, 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 this->mutex->unlock(this->mutex);
103 addr->destroy(addr);
104
105 if (!handled)
106 {
107 DBG1(DBG_IKE, "adding DNS server failed", this->file);
108 }
109 return handled;
110 }
111
112 /**
113 * Implementation of attribute_handler_t.release
114 */
115 static void release(private_resolve_handler_t *this, identification_t *server,
116 configuration_attribute_type_t type, chunk_t data)
117 {
118 FILE *in, *out;
119 char line[1024], matcher[512], *pos;
120 host_t *addr;
121 int family;
122
123 switch (type)
124 {
125 case INTERNAL_IP4_DNS:
126 family = AF_INET;
127 break;
128 case INTERNAL_IP6_DNS:
129 family = AF_INET6;
130 break;
131 default:
132 return;
133 }
134
135 this->mutex->lock(this->mutex);
136
137 in = fopen(this->file, "r");
138 if (in)
139 {
140 /* allows us to stream from in to out */
141 unlink(this->file);
142 out = fopen(this->file, "w");
143 if (out)
144 {
145 addr = host_create_from_chunk(family, data, 0);
146 snprintf(matcher, sizeof(matcher),
147 "nameserver %H # by strongSwan, from %Y\n",
148 addr, server);
149
150 /* copy all, but matching line */
151 while ((pos = fgets(line, sizeof(line), in)))
152 {
153 if (strneq(line, matcher, strlen(matcher)))
154 {
155 DBG1(DBG_IKE, "removing DNS server %H from %s",
156 addr, this->file);
157 }
158 else
159 {
160 fputs(line, out);
161 }
162 }
163 addr->destroy(addr);
164 fclose(out);
165 }
166 fclose(in);
167 }
168
169 this->mutex->unlock(this->mutex);
170 }
171
172 /**
173 * Attribute enumerator implementation
174 */
175 typedef struct {
176 /** implements enumerator_t interface */
177 enumerator_t public;
178 /** virtual IP we are requesting */
179 host_t *vip;
180 } attribute_enumerator_t;
181
182 /**
183 * Implementation of create_attribute_enumerator().enumerate()
184 */
185 static bool attribute_enumerate(attribute_enumerator_t *this,
186 configuration_attribute_type_t *type, chunk_t *data)
187 {
188 switch (this->vip->get_family(this->vip))
189 {
190 case AF_INET:
191 *type = INTERNAL_IP4_DNS;
192 break;
193 case AF_INET6:
194 *type = INTERNAL_IP6_DNS;
195 break;
196 default:
197 return FALSE;
198 }
199 *data = chunk_empty;
200 /* enumerate only once */
201 this->public.enumerate = (void*)return_false;
202 return TRUE;
203 }
204
205 /**
206 * Implementation of attribute_handler_t.create_attribute_enumerator
207 */
208 static enumerator_t* create_attribute_enumerator(private_resolve_handler_t *this,
209 identification_t *server, host_t *vip)
210 {
211 if (vip)
212 {
213 attribute_enumerator_t *enumerator;
214
215 enumerator = malloc_thing(attribute_enumerator_t);
216 enumerator->public.enumerate = (void*)attribute_enumerate;
217 enumerator->public.destroy = (void*)free;
218 enumerator->vip = vip;
219
220 return &enumerator->public;
221 }
222 return enumerator_create_empty();
223 }
224
225 /**
226 * Implementation of resolve_handler_t.destroy.
227 */
228 static void destroy(private_resolve_handler_t *this)
229 {
230 this->mutex->destroy(this->mutex);
231 free(this);
232 }
233
234 /**
235 * See header
236 */
237 resolve_handler_t *resolve_handler_create()
238 {
239 private_resolve_handler_t *this = malloc_thing(private_resolve_handler_t);
240
241 this->public.handler.handle = (bool(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))handle;
242 this->public.handler.release = (void(*)(attribute_handler_t*, identification_t*, configuration_attribute_type_t, chunk_t))release;
243 this->public.handler.create_attribute_enumerator = (enumerator_t*(*)(attribute_handler_t*, identification_t *server, host_t *vip))create_attribute_enumerator;
244 this->public.destroy = (void(*)(resolve_handler_t*))destroy;
245
246 this->mutex = mutex_create(MUTEX_TYPE_DEFAULT);
247 this->file = lib->settings->get_str(lib->settings,
248 "%s.plugins.resolve.file", RESOLV_CONF, hydra->daemon);
249
250 return &this->public;
251 }
252