implemented IKE/CHILD_SA close through manager
[strongswan.git] / src / manager / gateway.c
1 /**
2 * @file gateway.c
3 *
4 * @brief Implementation of gateway_t.
5 *
6 */
7
8 /*
9 * Copyright (C) 2007 Martin Willi
10 * Hochschule fuer Technik Rapperswil
11 *
12 * This program is free software; you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 2 of the License, or (at your
15 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
19 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
20 * for more details.
21 */
22
23 #include "gateway.h"
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <unistd.h>
28 #include <string.h>
29 #include <sys/socket.h>
30 #include <sys/un.h>
31
32 #include <lib/xml.h>
33
34 typedef struct private_gateway_t private_gateway_t;
35
36 /**
37 * private data of gateway
38 */
39 struct private_gateway_t {
40
41 /**
42 * public functions
43 */
44 gateway_t public;
45
46 /**
47 * name of the gateway
48 */
49 char *name;
50
51 /**
52 * host to connect using tcp
53 */
54 host_t *host;
55
56 /**
57 * socket file descriptor, > 0 if connected
58 */
59 int fd;
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 return NULL;
131 }
132 len = recv(this->fd, buf, sizeof(buf) - 1, 0);
133 if (len < 0)
134 {
135 return NULL;
136 }
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=\"1\">"
160 "<query>"
161 "<ikesalist/>"
162 "</query>"
163 "</message>");
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 * Implementation of gateway_t.terminate.
209 */
210 static bool terminate(private_gateway_t *this, bool ike, u_int32_t id)
211 {
212 char *str, *kind;
213 xml_t *xml;
214
215 if (ike)
216 {
217 kind = "ike";
218 }
219 else
220 {
221 kind = "child";
222 }
223
224 str = request(this, "<message type=\"request\" id=\"1\">"
225 "<control>"
226 "<%ssaterminate><id>%d</id></%ssaterminate>"
227 "</control>"
228 "</message>", kind, id, kind);
229 if (str == NULL)
230 {
231 return FALSE;
232 }
233 free(str);
234 return TRUE;
235 }
236
237 /**
238 * Implementation of gateway_t.destroy
239 */
240 static void destroy(private_gateway_t *this)
241 {
242 if (this->fd >= 0)
243 {
244 close(this->fd);
245 }
246 if (this->host) this->host->destroy(this->host);
247 free(this->name);
248 free(this);
249 }
250
251 /**
252 * generic constructor
253 */
254 static private_gateway_t *gateway_create(char *name)
255 {
256 private_gateway_t *this = malloc_thing(private_gateway_t);
257
258 this->public.request = (char*(*)(gateway_t*, char *xml))request;
259 this->public.query_ikesalist = (enumerator_t*(*)(gateway_t*))query_ikesalist;
260 this->public.terminate = (bool(*)(gateway_t*, bool ike, u_int32_t id))terminate;
261 this->public.destroy = (void(*)(gateway_t*))destroy;
262
263 this->name = strdup(name);
264 this->host = NULL;
265 this->fd = -1;
266
267 return this;
268 }
269
270 /**
271 * see header
272 */
273 gateway_t *gateway_create_tcp(char *name, host_t *host)
274 {
275 private_gateway_t *this = gateway_create(name);
276
277 this->host = host;
278
279 return &this->public;
280 }
281
282 /**
283 * see header
284 */
285 gateway_t *gateway_create_unix(char *name)
286 {
287 private_gateway_t *this = gateway_create(name);
288
289 return &this->public;
290 }
291