fixed compiler warnings issued by:
[strongswan.git] / src / charon / plugins / updown / updown_plugin.c
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.
14 *
15 * $Id$
16 */
17
18 #define _GNU_SOURCE
19 #include <stdio.h>
20
21 #include "updown_plugin.h"
22
23 #include <daemon.h>
24 #include <config/child_cfg.h>
25
26 typedef struct private_updown_plugin_t private_updown_plugin_t;
27
28 /**
29 * private data of updown plugin
30 */
31 struct private_updown_plugin_t {
32
33 /**
34 * implements plugin interface
35 */
36 updown_plugin_t public;
37
38 /**
39 * Listener interface, listens to CHILD_SA state changes
40 */
41 listener_t listener;
42 };
43
44 /**
45 * Run the up/down script
46 */
47 static void updown(ike_sa_t *ike_sa, child_sa_t *child_sa, bool up)
48 {
49 traffic_selector_t *my_ts, *other_ts;
50 enumerator_t *enumerator;
51 child_cfg_t *config;
52 host_t *vip, *me, *other;
53 char *script;
54
55 config = child_sa->get_config(child_sa);
56 vip = ike_sa->get_virtual_ip(ike_sa, TRUE);
57 script = config->get_updown(config);
58 me = ike_sa->get_my_host(ike_sa);
59 other = ike_sa->get_other_host(ike_sa);
60
61 if (script == NULL)
62 {
63 return;
64 }
65
66 enumerator = child_sa->create_policy_enumerator(child_sa);
67 while (enumerator->enumerate(enumerator, &my_ts, &other_ts))
68 {
69 char command[1024];
70 char *my_client, *other_client, *my_client_mask, *other_client_mask;
71 char *pos, *virtual_ip, *iface;
72 FILE *shell;
73
74 /* get subnet/bits from string */
75 if (asprintf(&my_client, "%R", my_ts) < 0)
76 {
77 my_client = NULL;
78 }
79 pos = strchr(my_client, '/');
80 *pos = '\0';
81 my_client_mask = pos + 1;
82 pos = strchr(my_client_mask, '[');
83 if (pos)
84 {
85 *pos = '\0';
86 }
87 if (asprintf(&other_client, "%R", other_ts) < 0)
88 {
89 other_client = NULL;
90 }
91 pos = strchr(other_client, '/');
92 *pos = '\0';
93 other_client_mask = pos + 1;
94 pos = strchr(other_client_mask, '[');
95 if (pos)
96 {
97 *pos = '\0';
98 }
99
100 if (vip)
101 {
102 if (asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip) < 0)
103 {
104 virtual_ip = NULL;
105 }
106 }
107 else
108 {
109 if (asprintf(&virtual_ip, "") < 0)
110 {
111 virtual_ip = NULL;
112 }
113 }
114
115 iface = charon->kernel_interface->get_interface(
116 charon->kernel_interface, me);
117
118 /* build the command with all env variables.
119 * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
120 */
121 snprintf(command, sizeof(command),
122 "2>&1 "
123 "PLUTO_VERSION='1.1' "
124 "PLUTO_VERB='%s%s%s' "
125 "PLUTO_CONNECTION='%s' "
126 "PLUTO_INTERFACE='%s' "
127 "PLUTO_REQID='%u' "
128 "PLUTO_ME='%H' "
129 "PLUTO_MY_ID='%D' "
130 "PLUTO_MY_CLIENT='%s/%s' "
131 "PLUTO_MY_CLIENT_NET='%s' "
132 "PLUTO_MY_CLIENT_MASK='%s' "
133 "PLUTO_MY_PORT='%u' "
134 "PLUTO_MY_PROTOCOL='%u' "
135 "PLUTO_PEER='%H' "
136 "PLUTO_PEER_ID='%D' "
137 "PLUTO_PEER_CLIENT='%s/%s' "
138 "PLUTO_PEER_CLIENT_NET='%s' "
139 "PLUTO_PEER_CLIENT_MASK='%s' "
140 "PLUTO_PEER_PORT='%u' "
141 "PLUTO_PEER_PROTOCOL='%u' "
142 "%s"
143 "%s"
144 "%s",
145 up ? "up" : "down",
146 my_ts->is_host(my_ts, me) ? "-host" : "-client",
147 me->get_family(me) == AF_INET ? "" : "-v6",
148 config->get_name(config),
149 iface ? iface : "unknown",
150 child_sa->get_reqid(child_sa),
151 me, ike_sa->get_my_id(ike_sa),
152 my_client, my_client_mask,
153 my_client, my_client_mask,
154 my_ts->get_from_port(my_ts),
155 my_ts->get_protocol(my_ts),
156 other, ike_sa->get_other_id(ike_sa),
157 other_client, other_client_mask,
158 other_client, other_client_mask,
159 other_ts->get_from_port(other_ts),
160 other_ts->get_protocol(other_ts),
161 virtual_ip,
162 config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "",
163 script);
164 free(my_client);
165 free(other_client);
166 free(virtual_ip);
167 free(iface);
168
169 DBG3(DBG_CHD, "running updown script: %s", command);
170 shell = popen(command, "r");
171
172 if (shell == NULL)
173 {
174 DBG1(DBG_CHD, "could not execute updown script '%s'", script);
175 return;
176 }
177
178 while (TRUE)
179 {
180 char resp[128];
181
182 if (fgets(resp, sizeof(resp), shell) == NULL)
183 {
184 if (ferror(shell))
185 {
186 DBG1(DBG_CHD, "error reading output from updown script");
187 return;
188 }
189 else
190 {
191 break;
192 }
193 }
194 else
195 {
196 char *e = resp + strlen(resp);
197 if (e > resp && e[-1] == '\n')
198 { /* trim trailing '\n' */
199 e[-1] = '\0';
200 }
201 DBG1(DBG_CHD, "updown: %s", resp);
202 }
203 }
204 pclose(shell);
205 }
206 enumerator->destroy(enumerator);
207 }
208
209 /**
210 * Listener implementation
211 */
212 static bool child_state_change(listener_t *this, ike_sa_t *ike_sa,
213 child_sa_t *child_sa, child_sa_state_t state)
214 {
215 child_sa_state_t old;
216
217 if (ike_sa)
218 {
219 old = child_sa->get_state(child_sa);
220
221 if ((old == CHILD_INSTALLED && state != CHILD_REKEYING ) ||
222 (old == CHILD_DELETING && state == CHILD_DESTROYING))
223 {
224 updown(ike_sa, child_sa, FALSE);
225 }
226 else if (state == CHILD_INSTALLED)
227 {
228 updown(ike_sa, child_sa, TRUE);
229 }
230 }
231 return TRUE;
232 }
233
234 /**
235 * Implementation of plugin_t.destroy
236 */
237 static void destroy(private_updown_plugin_t *this)
238 {
239 charon->bus->remove_listener(charon->bus, &this->listener);
240 free(this);
241 }
242
243 /*
244 * see header file
245 */
246 plugin_t *plugin_create()
247 {
248 private_updown_plugin_t *this = malloc_thing(private_updown_plugin_t);
249
250 this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
251
252 memset(&this->listener, 0, sizeof(listener_t));
253 this->listener.child_state_change = child_state_change;
254
255 charon->bus->add_listener(charon->bus, &this->listener);
256
257 return &this->public.plugin;
258 }
259