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