time values in strongswan.conf can be optionally specified in days (d), hours (h...
[strongswan.git] / src / manager / gateway.c
1 /*
2 * Copyright (C) 2007 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 * $Id$
16 */
17
18 #include "gateway.h"
19
20 #include <sys/types.h>
21 #include <sys/socket.h>
22 #include <unistd.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <sys/un.h>
26
27 #include <xml.h>
28
29 typedef struct private_gateway_t private_gateway_t;
30
31 /**
32 * private data of gateway
33 */
34 struct private_gateway_t {
35
36 /**
37 * public functions
38 */
39 gateway_t public;
40
41 /**
42 * name of the gateway
43 */
44 char *name;
45
46 /**
47 * host to connect using tcp
48 */
49 host_t *host;
50
51 /**
52 * socket file descriptor, > 0 if connected
53 */
54 int fd;
55
56 /**
57 * unique id assigned to each xml message
58 */
59 int xmlid;
60 };
61
62 struct sockaddr_un unix_addr = { AF_UNIX, IPSEC_PIDDIR "/charon.xml"};
63
64 /**
65 * establish connection to gateway
66 */
67 static bool connect_(private_gateway_t *this)
68 {
69 int family, len;
70 struct sockaddr *addr;
71
72 if (this->fd >= 0)
73 {
74 close(this->fd);
75 }
76 if (this->host)
77 {
78 family = AF_INET;
79 addr = this->host->get_sockaddr(this->host);
80 len = *this->host->get_sockaddr_len(this->host);
81 }
82 else
83 {
84 family = AF_UNIX;
85 addr = (struct sockaddr*)&unix_addr;
86 len = sizeof(unix_addr);
87 }
88
89 this->fd = socket(family, SOCK_STREAM, 0);
90 if (this->fd < 0)
91 {
92 return FALSE;
93 }
94 if (connect(this->fd, addr, len) != 0)
95 {
96 close(this->fd);
97 this->fd = -1;
98 return FALSE;
99 }
100 return TRUE;
101 }
102
103 /**
104 * Implementation of gateway_t.request.
105 */
106 static char* request(private_gateway_t *this, char *xml, ...)
107 {
108 if (this->fd < 0)
109 {
110 if (!connect_(this))
111 {
112 return NULL;
113 }
114 }
115 while (TRUE)
116 {
117 char buf[8096];
118 ssize_t len;
119 va_list args;
120
121 va_start(args, xml);
122 len = vsnprintf(buf, sizeof(buf), xml, args);
123 va_end(args);
124 if (len < 0 || len >= sizeof(buf))
125 {
126 return NULL;
127 }
128 if (send(this->fd, buf, len, 0) != len)
129 {
130 if (!connect_(this))
131 {
132 return NULL;
133 }
134 continue;
135 }
136 len = recv(this->fd, buf, sizeof(buf) - 1, 0);
137 if (len <= 0)
138 {
139 if (!connect_(this))
140 {
141 return NULL;
142 }
143 continue;
144 }
145 buf[len] = 0;
146 return strdup(buf);
147 }
148 }
149
150 /**
151 * Implementation of gateway_t.query_ikesalist.
152 */
153 static enumerator_t* query_ikesalist(private_gateway_t *this)
154 {
155 char *str, *name, *value;
156 xml_t *xml;
157 enumerator_t *e1, *e2, *e3, *e4 = NULL;
158
159 str = request(this, "<message type=\"request\" id=\"%d\">"
160 "<query>"
161 "<ikesalist/>"
162 "</query>"
163 "</message>", this->xmlid++);
164 if (str == NULL)
165 {
166 return NULL;
167 }
168 xml = xml_create(str);
169 if (xml == NULL)
170 {
171 return NULL;
172 }
173
174 e1 = xml->children(xml);
175 free(str);
176 while (e1->enumerate(e1, &xml, &name, &value))
177 {
178 if (streq(name, "message"))
179 {
180 e2 = xml->children(xml);
181 while (e2->enumerate(e2, &xml, &name, &value))
182 {
183 if (streq(name, "query"))
184 {
185 e3 = xml->children(xml);
186 while (e3->enumerate(e3, &xml, &name, &value))
187 {
188 if (streq(name, "ikesalist"))
189 {
190 e4 = xml->children(xml);
191 e1->destroy(e1);
192 e2->destroy(e2);
193 e3->destroy(e3);
194 return e4;
195 }
196 }
197 e3->destroy(e3);
198 }
199 }
200 e2->destroy(e2);
201 }
202 }
203 e1->destroy(e1);
204 return NULL;
205 }
206
207
208 /**
209 * Implementation of gateway_t.query_configlist.
210 */
211 static enumerator_t* query_configlist(private_gateway_t *this)
212 {
213 char *str, *name, *value;
214 xml_t *xml;
215 enumerator_t *e1, *e2, *e3, *e4 = NULL;
216
217 str = request(this, "<message type=\"request\" id=\"%d\">"
218 "<query>"
219 "<configlist/>"
220 "</query>"
221 "</message>", this->xmlid++);
222 if (str == NULL)
223 {
224 return NULL;
225 }
226 xml = xml_create(str);
227 if (xml == NULL)
228 {
229 return NULL;
230 }
231
232 e1 = xml->children(xml);
233 free(str);
234 while (e1->enumerate(e1, &xml, &name, &value))
235 {
236 if (streq(name, "message"))
237 {
238 e2 = xml->children(xml);
239 while (e2->enumerate(e2, &xml, &name, &value))
240 {
241 if (streq(name, "query"))
242 {
243 e3 = xml->children(xml);
244 while (e3->enumerate(e3, &xml, &name, &value))
245 {
246 if (streq(name, "configlist"))
247 {
248 e4 = xml->children(xml);
249 e1->destroy(e1);
250 e2->destroy(e2);
251 e3->destroy(e3);
252 return e4;
253 }
254 }
255 e3->destroy(e3);
256 }
257 }
258 e2->destroy(e2);
259 }
260 }
261 e1->destroy(e1);
262 return NULL;
263 }
264
265 /**
266 * create enumerator over control elements children of a control response
267 */
268 static enumerator_t* read_result(private_gateway_t *this, char *res)
269 {
270 char *name, *value;
271 xml_t *xml;
272 enumerator_t *e1, *e2, *e3;
273
274 if (res == NULL)
275 {
276 return NULL;
277 }
278 xml = xml_create(res);
279 if (xml == NULL)
280 {
281 return NULL;
282 }
283 e1 = xml->children(xml);
284 free(res);
285 while (e1->enumerate(e1, &xml, &name, &value))
286 {
287 if (streq(name, "message"))
288 {
289 e2 = xml->children(xml);
290 while (e2->enumerate(e2, &xml, &name, &value))
291 {
292 if (streq(name, "control"))
293 {
294 e3 = xml->children(xml);
295 e1->destroy(e1);
296 e2->destroy(e2);
297 return e3;
298 }
299 }
300 e2->destroy(e2);
301 }
302 }
303 e1->destroy(e1);
304 return NULL;
305 }
306
307 /**
308 * Implementation of gateway_t.initiate.
309 */
310 static enumerator_t* initiate(private_gateway_t *this, bool ike, char *name)
311 {
312 char *str, *kind;
313
314 if (ike)
315 {
316 kind = "ike";
317 }
318 else
319 {
320 kind = "child";
321 }
322 str = request(this, "<message type=\"request\" id=\"%d\">"
323 "<control>"
324 "<%ssainitiate>%s</%ssainitiate>"
325 "</control>"
326 "</message>", this->xmlid++, kind, name, kind);
327 return read_result(this, str);
328 }
329
330 /**
331 * Implementation of gateway_t.terminate.
332 */
333 static enumerator_t* terminate(private_gateway_t *this, bool ike, u_int32_t id)
334 {
335 char *str, *kind;
336
337 if (ike)
338 {
339 kind = "ike";
340 }
341 else
342 {
343 kind = "child";
344 }
345 str = request(this, "<message type=\"request\" id=\"%d\">"
346 "<control>"
347 "<%ssaterminate>%d</%ssaterminate>"
348 "</control>"
349 "</message>", this->xmlid++, kind, id, kind);
350 return read_result(this, str);
351 }
352
353 /**
354 * Implementation of gateway_t.destroy
355 */
356 static void destroy(private_gateway_t *this)
357 {
358 if (this->fd >= 0)
359 {
360 close(this->fd);
361 }
362 if (this->host) this->host->destroy(this->host);
363 free(this->name);
364 free(this);
365 }
366
367 /**
368 * generic constructor
369 */
370 static private_gateway_t *gateway_create(char *name)
371 {
372 private_gateway_t *this = malloc_thing(private_gateway_t);
373
374 this->public.request = (char*(*)(gateway_t*, char *xml))request;
375 this->public.query_ikesalist = (enumerator_t*(*)(gateway_t*))query_ikesalist;
376 this->public.query_configlist = (enumerator_t*(*)(gateway_t*))query_configlist;
377 this->public.initiate = (enumerator_t*(*)(gateway_t*, bool ike, char *name))initiate;
378 this->public.terminate = (enumerator_t*(*)(gateway_t*, bool ike, u_int32_t id))terminate;
379 this->public.destroy = (void(*)(gateway_t*))destroy;
380
381 this->name = strdup(name);
382 this->host = NULL;
383 this->fd = -1;
384 this->xmlid = 1;
385
386 return this;
387 }
388
389 /**
390 * see header
391 */
392 gateway_t *gateway_create_tcp(char *name, host_t *host)
393 {
394 private_gateway_t *this = gateway_create(name);
395
396 this->host = host;
397
398 return &this->public;
399 }
400
401 /**
402 * see header
403 */
404 gateway_t *gateway_create_unix(char *name)
405 {
406 private_gateway_t *this = gateway_create(name);
407
408 return &this->public;
409 }
410