fixed some compiler warnings
[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 asprintf(&my_client, "%R", my_ts);
76 pos = strchr(my_client, '/');
77 *pos = '\0';
78 my_client_mask = pos + 1;
79 pos = strchr(my_client_mask, '[');
80 if (pos)
81 {
82 *pos = '\0';
83 }
84 asprintf(&other_client, "%R", other_ts);
85 pos = strchr(other_client, '/');
86 *pos = '\0';
87 other_client_mask = pos + 1;
88 pos = strchr(other_client_mask, '[');
89 if (pos)
90 {
91 *pos = '\0';
92 }
93
94 if (vip)
95 {
96 asprintf(&virtual_ip, "PLUTO_MY_SOURCEIP='%H' ", vip);
97 }
98 else
99 {
100 asprintf(&virtual_ip, "");
101 }
102
103 iface = charon->kernel_interface->get_interface(
104 charon->kernel_interface, me);
105
106 /* build the command with all env variables.
107 * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
108 */
109 snprintf(command, sizeof(command),
110 "2>&1 "
111 "PLUTO_VERSION='1.1' "
112 "PLUTO_VERB='%s%s%s' "
113 "PLUTO_CONNECTION='%s' "
114 "PLUTO_INTERFACE='%s' "
115 "PLUTO_REQID='%u' "
116 "PLUTO_ME='%H' "
117 "PLUTO_MY_ID='%D' "
118 "PLUTO_MY_CLIENT='%s/%s' "
119 "PLUTO_MY_CLIENT_NET='%s' "
120 "PLUTO_MY_CLIENT_MASK='%s' "
121 "PLUTO_MY_PORT='%u' "
122 "PLUTO_MY_PROTOCOL='%u' "
123 "PLUTO_PEER='%H' "
124 "PLUTO_PEER_ID='%D' "
125 "PLUTO_PEER_CLIENT='%s/%s' "
126 "PLUTO_PEER_CLIENT_NET='%s' "
127 "PLUTO_PEER_CLIENT_MASK='%s' "
128 "PLUTO_PEER_PORT='%u' "
129 "PLUTO_PEER_PROTOCOL='%u' "
130 "%s"
131 "%s"
132 "%s",
133 up ? "up" : "down",
134 my_ts->is_host(my_ts, me) ? "-host" : "-client",
135 me->get_family(me) == AF_INET ? "" : "-v6",
136 config->get_name(config),
137 iface ? iface : "unknown",
138 child_sa->get_reqid(child_sa),
139 me, ike_sa->get_my_id(ike_sa),
140 my_client, my_client_mask,
141 my_client, my_client_mask,
142 my_ts->get_from_port(my_ts),
143 my_ts->get_protocol(my_ts),
144 other, ike_sa->get_other_id(ike_sa),
145 other_client, other_client_mask,
146 other_client, other_client_mask,
147 other_ts->get_from_port(other_ts),
148 other_ts->get_protocol(other_ts),
149 virtual_ip,
150 config->get_hostaccess(config) ? "PLUTO_HOST_ACCESS='1' " : "",
151 script);
152 free(my_client);
153 free(other_client);
154 free(virtual_ip);
155 free(iface);
156
157 DBG3(DBG_CHD, "running updown script: %s", command);
158 shell = popen(command, "r");
159
160 if (shell == NULL)
161 {
162 DBG1(DBG_CHD, "could not execute updown script '%s'", script);
163 return;
164 }
165
166 while (TRUE)
167 {
168 char resp[128];
169
170 if (fgets(resp, sizeof(resp), shell) == NULL)
171 {
172 if (ferror(shell))
173 {
174 DBG1(DBG_CHD, "error reading output from updown script");
175 return;
176 }
177 else
178 {
179 break;
180 }
181 }
182 else
183 {
184 char *e = resp + strlen(resp);
185 if (e > resp && e[-1] == '\n')
186 { /* trim trailing '\n' */
187 e[-1] = '\0';
188 }
189 DBG1(DBG_CHD, "updown: %s", resp);
190 }
191 }
192 pclose(shell);
193 }
194 enumerator->destroy(enumerator);
195 }
196
197 /**
198 * Listener implementation
199 */
200 static bool child_state_change(listener_t *this, ike_sa_t *ike_sa,
201 child_sa_t *child_sa, child_sa_state_t state)
202 {
203 child_sa_state_t old;
204
205 if (ike_sa)
206 {
207 old = child_sa->get_state(child_sa);
208
209 if ((old == CHILD_INSTALLED && state != CHILD_REKEYING ) ||
210 (old == CHILD_DELETING && state == CHILD_DESTROYING))
211 {
212 updown(ike_sa, child_sa, FALSE);
213 }
214 else if (state == CHILD_INSTALLED)
215 {
216 updown(ike_sa, child_sa, TRUE);
217 }
218 }
219 return TRUE;
220 }
221
222 /**
223 * Implementation of plugin_t.destroy
224 */
225 static void destroy(private_updown_plugin_t *this)
226 {
227 charon->bus->remove_listener(charon->bus, &this->listener);
228 free(this);
229 }
230
231 /*
232 * see header file
233 */
234 plugin_t *plugin_create()
235 {
236 private_updown_plugin_t *this = malloc_thing(private_updown_plugin_t);
237
238 this->public.plugin.destroy = (void(*)(plugin_t*))destroy;
239
240 memset(&this->listener, 0, sizeof(listener_t));
241 this->listener.child_state_change = child_state_change;
242
243 charon->bus->add_listener(charon->bus, &this->listener);
244
245 return &this->public.plugin;
246 }
247