Migrated resolve_handler to INIT/METHOD macros
[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 METHOD(attribute_handler_t, handle, bool,
48 private_resolve_handler_t *this, identification_t *server,
49 configuration_attribute_type_t type, chunk_t data)
50 {
51 FILE *in, *out;
52 char buf[1024];
53 host_t *addr;
54 size_t len;
55 bool handled = FALSE;
56
57 switch (type)
58 {
59 case INTERNAL_IP4_DNS:
60 addr = host_create_from_chunk(AF_INET, data, 0);
61 break;
62 case INTERNAL_IP6_DNS:
63 addr = host_create_from_chunk(AF_INET6, data, 0);
64 break;
65 default:
66 return FALSE;
67 }
68
69 if (!addr || addr->is_anyaddr(addr))
70 {
71 DESTROY_IF(addr);
72 return FALSE;
73 }
74 this->mutex->lock(this->mutex);
75
76 in = fopen(this->file, "r");
77 /* allows us to stream from in to out */
78 unlink(this->file);
79 out = fopen(this->file, "w");
80 if (out)
81 {
82 fprintf(out, "nameserver %H # by strongSwan, from %Y\n", addr, server);
83 DBG1(DBG_IKE, "installing DNS server %H to %s", addr, this->file);
84 handled = TRUE;
85
86 /* copy rest of the file */
87 if (in)
88 {
89 while ((len = fread(buf, 1, sizeof(buf), in)))
90 {
91 ignore_result(fwrite(buf, 1, len, out));
92 }
93 }
94 fclose(out);
95 }
96 if (in)
97 {
98 fclose(in);
99 }
100 this->mutex->unlock(this->mutex);
101 addr->destroy(addr);
102
103 if (!handled)
104 {
105 DBG1(DBG_IKE, "adding DNS server failed", this->file);
106 }
107 return handled;
108 }
109
110 METHOD(attribute_handler_t, release,void,
111 private_resolve_handler_t *this, identification_t *server,
112 configuration_attribute_type_t type, chunk_t data)
113 {
114 FILE *in, *out;
115 char line[1024], matcher[512];
116 host_t *addr;
117 int family;
118
119 switch (type)
120 {
121 case INTERNAL_IP4_DNS:
122 family = AF_INET;
123 break;
124 case INTERNAL_IP6_DNS:
125 family = AF_INET6;
126 break;
127 default:
128 return;
129 }
130
131 this->mutex->lock(this->mutex);
132
133 in = fopen(this->file, "r");
134 if (in)
135 {
136 /* allows us to stream from in to out */
137 unlink(this->file);
138 out = fopen(this->file, "w");
139 if (out)
140 {
141 addr = host_create_from_chunk(family, data, 0);
142 snprintf(matcher, sizeof(matcher),
143 "nameserver %H # by strongSwan, from %Y\n",
144 addr, server);
145
146 /* copy all, but matching line */
147 while (fgets(line, sizeof(line), in))
148 {
149 if (strneq(line, matcher, strlen(matcher)))
150 {
151 DBG1(DBG_IKE, "removing DNS server %H from %s",
152 addr, this->file);
153 }
154 else
155 {
156 fputs(line, out);
157 }
158 }
159 addr->destroy(addr);
160 fclose(out);
161 }
162 fclose(in);
163 }
164
165 this->mutex->unlock(this->mutex);
166 }
167
168 /**
169 * Attribute enumerator implementation
170 */
171 typedef struct {
172 /** implements enumerator_t interface */
173 enumerator_t public;
174 /** virtual IP we are requesting */
175 host_t *vip;
176 } attribute_enumerator_t;
177
178 static bool attribute_enumerate(attribute_enumerator_t *this,
179 configuration_attribute_type_t *type,
180 chunk_t *data)
181 {
182 switch (this->vip->get_family(this->vip))
183 {
184 case AF_INET:
185 *type = INTERNAL_IP4_DNS;
186 break;
187 case AF_INET6:
188 *type = INTERNAL_IP6_DNS;
189 break;
190 default:
191 return FALSE;
192 }
193 *data = chunk_empty;
194 /* enumerate only once */
195 this->public.enumerate = (void*)return_false;
196 return TRUE;
197 }
198
199 METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
200 private_resolve_handler_t *this, identification_t *server, host_t *vip)
201 {
202 if (vip)
203 {
204 attribute_enumerator_t *enumerator;
205
206 enumerator = malloc_thing(attribute_enumerator_t);
207 enumerator->public.enumerate = (void*)attribute_enumerate;
208 enumerator->public.destroy = (void*)free;
209 enumerator->vip = vip;
210
211 return &enumerator->public;
212 }
213 return enumerator_create_empty();
214 }
215
216 METHOD(resolve_handler_t, destroy, void,
217 private_resolve_handler_t *this)
218 {
219 this->mutex->destroy(this->mutex);
220 free(this);
221 }
222
223 /**
224 * See header
225 */
226 resolve_handler_t *resolve_handler_create()
227 {
228 private_resolve_handler_t *this;
229
230 INIT(this,
231 .public = {
232 .handler = {
233 .handle = _handle,
234 .release = _release,
235 .create_attribute_enumerator = _create_attribute_enumerator,
236 },
237 .destroy = _destroy,
238 },
239 .mutex = mutex_create(MUTEX_TYPE_DEFAULT),
240 .file = lib->settings->get_str(lib->settings, "%s.plugins.resolve.file",
241 RESOLV_CONF, hydra->daemon),
242 );
243
244 return &this->public;
245 }
246