2 * Copyright (C) 2008 Martin Willi
3 * Hochschule fuer Technik Rapperswil
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>.
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
21 #include "updown_plugin.h"
24 #include <config/child_cfg.h>
26 typedef struct private_updown_plugin_t private_updown_plugin_t
;
29 * private data of updown plugin
31 struct private_updown_plugin_t
{
34 * implements plugin interface
36 updown_plugin_t
public;
39 * Listener interface, listens to CHILD_SA state changes
45 * Run the up/down script
47 static void updown(ike_sa_t
*ike_sa
, child_sa_t
*child_sa
, bool up
)
49 traffic_selector_t
*my_ts
, *other_ts
;
50 enumerator_t
*enumerator
;
52 host_t
*vip
, *me
, *other
;
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
);
66 enumerator
= child_sa
->create_policy_enumerator(child_sa
);
67 while (enumerator
->enumerate(enumerator
, &my_ts
, &other_ts
))
70 char *my_client
, *other_client
, *my_client_mask
, *other_client_mask
;
71 char *pos
, *virtual_ip
, *iface
;
74 /* get subnet/bits from string */
75 if (asprintf(&my_client
, "%R", my_ts
) < 0)
79 pos
= strchr(my_client
, '/');
81 my_client_mask
= pos
+ 1;
82 pos
= strchr(my_client_mask
, '[');
87 if (asprintf(&other_client
, "%R", other_ts
) < 0)
91 pos
= strchr(other_client
, '/');
93 other_client_mask
= pos
+ 1;
94 pos
= strchr(other_client_mask
, '[');
102 if (asprintf(&virtual_ip
, "PLUTO_MY_SOURCEIP='%H' ", vip
) < 0)
109 if (asprintf(&virtual_ip
, "") < 0)
115 iface
= charon
->kernel_interface
->get_interface(
116 charon
->kernel_interface
, me
);
118 /* build the command with all env variables.
119 * TODO: PLUTO_PEER_CA and PLUTO_NEXT_HOP are currently missing
121 snprintf(command
, sizeof(command
),
123 "PLUTO_VERSION='1.1' "
124 "PLUTO_VERB='%s%s%s' "
125 "PLUTO_CONNECTION='%s' "
126 "PLUTO_INTERFACE='%s' "
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' "
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' "
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
),
162 config
->get_hostaccess(config
) ?
"PLUTO_HOST_ACCESS='1' " : "",
169 DBG3(DBG_CHD
, "running updown script: %s", command
);
170 shell
= popen(command
, "r");
174 DBG1(DBG_CHD
, "could not execute updown script '%s'", script
);
182 if (fgets(resp
, sizeof(resp
), shell
) == NULL
)
186 DBG1(DBG_CHD
, "error reading output from updown script");
196 char *e
= resp
+ strlen(resp
);
197 if (e
> resp
&& e
[-1] == '\n')
198 { /* trim trailing '\n' */
201 DBG1(DBG_CHD
, "updown: %s", resp
);
206 enumerator
->destroy(enumerator
);
210 * Listener implementation
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
)
215 child_sa_state_t old
;
219 old
= child_sa
->get_state(child_sa
);
221 if ((old
== CHILD_INSTALLED
&& state
!= CHILD_REKEYING
) ||
222 (old
== CHILD_DELETING
&& state
== CHILD_DESTROYING
))
224 updown(ike_sa
, child_sa
, FALSE
);
226 else if (state
== CHILD_INSTALLED
)
228 updown(ike_sa
, child_sa
, TRUE
);
235 * Implementation of plugin_t.destroy
237 static void destroy(private_updown_plugin_t
*this)
239 charon
->bus
->remove_listener(charon
->bus
, &this->listener
);
246 plugin_t
*plugin_create()
248 private_updown_plugin_t
*this = malloc_thing(private_updown_plugin_t
);
250 this->public.plugin
.destroy
= (void(*)(plugin_t
*))destroy
;
252 memset(&this->listener
, 0, sizeof(listener_t
));
253 this->listener
.child_state_change
= child_state_change
;
255 charon
->bus
->add_listener(charon
->bus
, &this->listener
);
257 return &this->public.plugin
;