]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libcharon/plugins/updown/updown_listener.c
fix html error in scenario description
[thirdparty/strongswan.git] / src / libcharon / plugins / updown / updown_listener.c
CommitLineData
49653b6b
MW
1/*
2 * Copyright (C) 2008 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.
49653b6b
MW
14 */
15
16#define _GNU_SOURCE
17#include <stdio.h>
18
19#include "updown_listener.h"
20
21#include <daemon.h>
22#include <config/child_cfg.h>
23
24typedef struct private_updown_listener_t private_updown_listener_t;
25
26/**
27 * Private data of an updown_listener_t object.
28 */
29struct private_updown_listener_t {
7daf5226 30
49653b6b
MW
31 /**
32 * Public updown_listener_t interface.
33 */
34 updown_listener_t public;
7daf5226 35
49653b6b
MW
36 /**
37 * List of cached interface names
38 */
39 linked_list_t *iface_cache;
40};
41
42typedef struct cache_entry_t cache_entry_t;
43
44/**
45 * Cache line in the interface name cache.
46 */
47struct cache_entry_t {
48 /** requid of the CHILD_SA */
49 u_int32_t reqid;
50 /** cached interface name */
51 char *iface;
52};
53
54/**
55 * Insert an interface name to the cache
56 */
57static void cache_iface(private_updown_listener_t *this, u_int32_t reqid,
58 char *iface)
59{
60 cache_entry_t *entry = malloc_thing(cache_entry_t);
7daf5226 61
49653b6b
MW
62 entry->reqid = reqid;
63 entry->iface = strdup(iface);
7daf5226 64
49653b6b
MW
65 this->iface_cache->insert_first(this->iface_cache, entry);
66}
67
68/**
69 * Remove a cached interface name and return it.
70 */
71static char* uncache_iface(private_updown_listener_t *this, u_int32_t reqid)
72{
73 enumerator_t *enumerator;
74 cache_entry_t *entry;
75 char *iface = NULL;
7daf5226 76
49653b6b
MW
77 enumerator = this->iface_cache->create_enumerator(this->iface_cache);
78 while (enumerator->enumerate(enumerator, &entry))
79 {
80 if (entry->reqid == reqid)
81 {
82 this->iface_cache->remove_at(this->iface_cache, enumerator);
83 iface = entry->iface;
84 free(entry);
85 break;
86 }
87 }
88 enumerator->destroy(enumerator);
89 return iface;
90}
91
7481f964
MW
92METHOD(listener_t, child_updown, bool,
93 private_updown_listener_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
94 bool up)
49653b6b
MW
95{
96 traffic_selector_t *my_ts, *other_ts;
97 enumerator_t *enumerator;
98 child_cfg_t *config;
99 host_t *vip, *me, *other;
100 char *script;
7daf5226 101
49653b6b
MW
102 config = child_sa->get_config(child_sa);
103 vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
104 script = config->get_updown(config);
105 me = ike_sa->get_my_host(ike_sa);
106 other = ike_sa->get_other_host(ike_sa);
7daf5226 107
49653b6b
MW
108 if (script == NULL)
109 {
7481f964 110 return TRUE;
49653b6b 111 }
7daf5226 112
49653b6b
MW
113 enumerator = child_sa->create_policy_enumerator(child_sa);
114 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
115 {
116 char command[1024];
117 char *my_client, *other_client, *my_client_mask, *other_client_mask;
14665981
AS
118 char *pos, *virtual_ip, *iface, *mark_in, *mark_out;
119 mark_t mark;
9789d3a9 120 bool is_host, is_ipv6;
49653b6b
MW
121 FILE *shell;
122
123 /* get subnet/bits from string */
124 if (asprintf(&my_client, "%R", my_ts) < 0)
125 {
126 my_client = NULL;
127 }
128 pos = strchr(my_client, '/');
129 *pos = '\0';
130 my_client_mask = pos + 1;
131 pos = strchr(my_client_mask, '[');
132 if (pos)
133 {
134 *pos = '\0';
135 }
136 if (asprintf(&other_client, "%R", other_ts) < 0)
137 {
138 other_client = NULL;
139 }
140 pos = strchr(other_client, '/');
141 *pos = '\0';
142 other_client_mask = pos + 1;
143 pos = strchr(other_client_mask, '[');
144 if (pos)
145 {
146 *pos = '\0';
147 }
148
149 if (vip)
150 {
151 if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0)
152 {
153 virtual_ip = NULL;
154 }
155 }
156 else
157 {
158 if (asprintf(&virtual_ip, "") < 0)
159 {
160 virtual_ip = NULL;
161 }
162 }
7daf5226 163
14665981
AS
164 /* check for the presence of an inbound mark */
165 mark = config->get_mark(config, TRUE);
166 if (mark.value)
167 {
168 if (asprintf(&mark_in, "PLUTO_MARK_IN='%u/0x%08x' ",
169 mark.value, mark.mask ) < 0)
170 {
171 mark_in = NULL;
172 }
173 }
174 else
175 {
176 if (asprintf(&mark_in, "") < 0)
177 {
178 mark_in = NULL;
179 }
180 }
181
182 /* check for the presence of an outbound mark */
183 mark = config->get_mark(config, FALSE);
184 if (mark.value)
185 {
186 if (asprintf(&mark_out, "PLUTO_MARK_OUT='%u/0x%08x' ",
187 mark.value, mark.mask ) < 0)
188 {
189 mark_out = NULL;
190 }
191 }
192 else
193 {
194 if (asprintf(&mark_out, "") < 0)
195 {
196 mark_out = NULL;
197 }
198 }
199
49653b6b
MW
200 if (up)
201 {
202 iface = charon->kernel_interface->get_interface(
203 charon->kernel_interface, me);
204 if (iface)
205 {
206 cache_iface(this, child_sa->get_reqid(child_sa), iface);
207 }
208 }
209 else
210 {
211 iface = uncache_iface(this, child_sa->get_reqid(child_sa));
212 }
7daf5226 213
9789d3a9
AS
214 /* determine IPv4/IPv6 and client/host situation */
215 is_host = my_ts->is_host(my_ts, me);
216 is_ipv6 = is_host ? (me->get_family(me) == AF_INET6) :
217 (my_ts->get_type(my_ts) == TS_IPV6_ADDR_RANGE);
218
49653b6b
MW
219 /* build the command with all env variables.
220 * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
221 */
222 snprintf(command, sizeof(command),
223 "2>&1 "
224 "PLUTO_VERSION='1.1' "
225 "PLUTO_VERB='%s%s%s' "
226 "PLUTO_CONNECTION='%s' "
227 "PLUTO_INTERFACE='%s' "
228 "PLUTO_REQID='%u' "
229 "PLUTO_ME='%H' "
d24a74c5 230 "PLUTO_MY_ID='%Y' "
49653b6b
MW
231 "PLUTO_MY_CLIENT='%s/%s' "
232 "PLUTO_MY_CLIENT_NET='%s' "
233 "PLUTO_MY_CLIENT_MASK='%s' "
234 "PLUTO_MY_PORT='%u' "
235 "PLUTO_MY_PROTOCOL='%u' "
236 "PLUTO_PEER='%H' "
d24a74c5 237 "PLUTO_PEER_ID='%Y' "
49653b6b
MW
238 "PLUTO_PEER_CLIENT='%s/%s' "
239 "PLUTO_PEER_CLIENT_NET='%s' "
240 "PLUTO_PEER_CLIENT_MASK='%s' "
241 "PLUTO_PEER_PORT='%u' "
242 "PLUTO_PEER_PROTOCOL='%u' "
243 "%s"
244 "%s"
14665981
AS
245 "%s"
246 "%s"
49653b6b
MW
247 "%s",
248 up ? "up" : "down",
9789d3a9
AS
249 is_host ? "-host" : "-client",
250 is_ipv6 ? "-v6" : "",
49653b6b
MW
251 config->get_name(config),
252 iface ? iface : "unknown",
253 child_sa->get_reqid(child_sa),
254 me, ike_sa->get_my_id(ike_sa),
255 my_client, my_client_mask,
256 my_client, my_client_mask,
257 my_ts->get_from_port(my_ts),
258 my_ts->get_protocol(my_ts),
259 other, ike_sa->get_other_id(ike_sa),
260 other_client, other_client_mask,
261 other_client, other_client_mask,
262 other_ts->get_from_port(other_ts),
263 other_ts->get_protocol(other_ts),
264 virtual_ip,
14665981
AS
265 mark_in,
266 mark_out,
49653b6b
MW
267 config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "",
268 script);
269 free(my_client);
270 free(other_client);
271 free(virtual_ip);
14665981
AS
272 free(mark_in);
273 free(mark_out);
49653b6b 274 free(iface);
7daf5226 275
49653b6b
MW
276 DBG3(DBG_CHD, "running updown script: %s", command);
277 shell = popen(command, "r");
278
279 if (shell == NULL)
280 {
281 DBG1(DBG_CHD, "could not execute updown script '%s'", script);
7481f964 282 return TRUE;
49653b6b 283 }
7daf5226 284
49653b6b
MW
285 while (TRUE)
286 {
287 char resp[128];
7daf5226 288
49653b6b
MW
289 if (fgets(resp, sizeof(resp), shell) == NULL)
290 {
291 if (ferror(shell))
292 {
293 DBG1(DBG_CHD, "error reading output from updown script");
49653b6b 294 }
7481f964 295 break;
49653b6b
MW
296 }
297 else
298 {
299 char *e = resp + strlen(resp);
300 if (e > resp && e[-1] == '\n')
301 { /* trim trailing '\n' */
302 e[-1] = '\0';
303 }
304 DBG1(DBG_CHD, "updown: %s", resp);
305 }
306 }
307 pclose(shell);
308 }
309 enumerator->destroy(enumerator);
49653b6b
MW
310 return TRUE;
311}
312
7481f964
MW
313METHOD(updown_listener_t, destroy, void,
314 private_updown_listener_t *this)
49653b6b
MW
315{
316 this->iface_cache->destroy(this->iface_cache);
317 free(this);
318}
319
320/**
321 * See header
322 */
323updown_listener_t *updown_listener_create()
324{
7481f964
MW
325 private_updown_listener_t *this;
326
327 INIT(this,
328 .public = {
6f52d3b0
TB
329 .listener = {
330 .child_updown = _child_updown,
331 },
7481f964
MW
332 .destroy = _destroy,
333 },
334 .iface_cache = linked_list_create(),
335 );
7daf5226 336
49653b6b
MW
337 return &this->public;
338}
339