]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/misc-progs/ipsecctrl.c
Fix ipsectrl I and ipsectrl R terminate vpn-watch.
[people/pmueller/ipfire-2.x.git] / src / misc-progs / ipsecctrl.c
CommitLineData
05207d69
MT
1/*
2 *
3 * File originally from the Smoothwall project
4 * (c) 2001 Smoothwall Team
5 *
05207d69
MT
6 */
7
8#include "libsmooth.h"
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <unistd.h>
13#include <sys/types.h>
14#include <sys/stat.h>
15#include <signal.h>
16#include "setuid.h"
17
5fd30232
MT
18/*
19 This module is responsible for start stop of the vpn system.
20
21 1) it allows AH & ESP to get in from interface where a vpn is mounted
69dcc425 22 The NAT traversal is used on the udp 4500 port.
5fd30232
MT
23
24 2) it starts the ipsec daemon
69dcc425
CS
25 The RED interface is a problem because it can be up or down a startup.
26 Then, the state change and it must not affect other VPN mounted on
27 other interface.
28 Unfortunatly, openswan 1 cannot do that correctly. It cannot use an
29 interface without restarting everything.
5fd30232
MT
30
31*/
32
05207d69 33void usage() {
69dcc425
CS
34 fprintf (stderr, "Usage:\n");
35 fprintf (stderr, "\tipsecctrl S [connectionkey]\n");
36 fprintf (stderr, "\tipsecctrl D [connectionkey]\n");
37 fprintf (stderr, "\tipsecctrl R\n");
db073a10 38 fprintf (stderr, "\tipsecctrl I\n");
69dcc425
CS
39 fprintf (stderr, "\t\tS : Start/Restart Connection\n");
40 fprintf (stderr, "\t\tD : Stop Connection\n");
41 fprintf (stderr, "\t\tR : Reload Certificates and Secrets\n");
db073a10 42 fprintf (stderr, "\t\tI : Print Statusinfo\n");
05207d69
MT
43}
44
5fd30232 45/*
69dcc425 46 ACCEPT the ipsec protocol ah, esp & udp (for nat traversal) on the specified interface
5fd30232
MT
47*/
48void open_physical (char *interface, int nat_traversal_port) {
69dcc425
CS
49 char str[STRING_SIZE];
50
51 // GRE ???
db073a10 52// sprintf(str, "/sbin/iptables -A " phystable " -p 47 -i %s -j ACCEPT", interface);
6652626c 53// safe_system(str);
69dcc425 54 // ESP
db073a10 55// sprintf(str, "/sbin/iptables -A " phystable " -p 50 -i %s -j ACCEPT", interface);
6652626c 56// safe_system(str);
69dcc425 57 // AH
db073a10 58// sprintf(str, "/sbin/iptables -A " phystable " -p 51 -i %s -j ACCEPT", interface);
6652626c 59// safe_system(str);
69dcc425 60 // IKE
db073a10
AF
61 sprintf(str, "/sbin/iptables -A IPSECINPUT -p udp -i %s --sport 500 --dport 500 -j ACCEPT", interface);
62 safe_system(str);
69dcc425
CS
63
64 if (! nat_traversal_port)
65 return;
66
db073a10
AF
67 sprintf(str, "/sbin/iptables -A IPSECINPUT -p udp -i %s --dport %i -j ACCEPT", interface, nat_traversal_port);
68 safe_system(str);
5fd30232
MT
69}
70
71void ipsec_norules() {
69dcc425 72 /* clear input rules */
db073a10
AF
73 safe_system("/sbin/iptables -F IPSECINPUT");
74 safe_system("/sbin/iptables -F IPSECFORWARD");
75 safe_system("/sbin/iptables -F IPSECOUTPUT");
69dcc425 76
05207d69
MT
77}
78
5fd30232
MT
79/*
80 return values from the vpn config file or false if not 'on'
81*/
82int decode_line (char *s,
69dcc425
CS
83 char **key,
84 char **name,
85 char **type,
86 char **interface
87 ) {
88 int count = 0;
89 *key = NULL;
90 *name = NULL;
91 *type = NULL;
92
93 if (s[strlen(s) - 1] == '\n')
94 s[strlen(s) - 1] = '\0';
95
96 char *result = strsep(&s, ",");
97 while (result) {
98 if (count == 0)
99 *key = result;
100 if ((count == 1) && strcmp(result, "on") != 0)
101 return 0; // a disabled line
102 if (count == 2)
103 *name = result;
104 if (count == 4)
105 *type = result;
106 if (count == 27)
107 *interface = result;
108 count++;
109 result = strsep(&s, ",");
110 }
111
112 // check other syntax
113 if (! *name)
114 return 0;
115
116 if (strspn(*name, LETTERS_NUMBERS) != strlen(*name)) {
117 fprintf(stderr, "Bad connection name: %s\n", *name);
118 return 0;
119 }
120
121 if (! (strcmp(*type, "host") == 0 || strcmp(*type, "net") == 0)) {
122 fprintf(stderr, "Bad connection type: %s\n", *type);
123 return 0;
124 }
125
126 if (! (strcmp(*interface, "RED") == 0 || strcmp(*interface, "GREEN") == 0 ||
127 strcmp(*interface, "ORANGE") == 0 || strcmp(*interface, "BLUE") == 0)) {
128 fprintf(stderr, "Bad interface name: %s\n", *interface);
129 return 0;
130 }
131 //it's a valid & active line
132 return 1;
5fd30232
MT
133}
134
135/*
136 issue ipsec commmands to turn on connection 'name'
137*/
138void turn_connection_on (char *name, char *type) {
69dcc425
CS
139 char command[STRING_SIZE];
140
98065e83 141 safe_system("/usr/sbin/ipsec reload >/dev/null");
331699d5
AF
142 memset(command, 0, STRING_SIZE);
143 snprintf(command, STRING_SIZE - 1,
144 "/usr/sbin/ipsec up %s >/dev/null", name);
69dcc425 145 safe_system(command);
5fd30232
MT
146}
147/*
148 issue ipsec commmands to turn off connection 'name'
149*/
150void turn_connection_off (char *name) {
69dcc425 151 char command[STRING_SIZE];
69dcc425
CS
152 memset(command, 0, STRING_SIZE);
153 snprintf(command, STRING_SIZE - 1,
98065e83 154 "/usr/sbin/ipsec whack --delete --name %s >/dev/null", name);
69dcc425 155 safe_system(command);
98065e83 156 safe_system("/usr/sbin/ipsec whack --rereadall >/dev/null");
5fd30232
MT
157}
158
159
05207d69 160int main(int argc, char *argv[]) {
5fd30232 161
69dcc425
CS
162 char configtype[STRING_SIZE];
163 char redtype[STRING_SIZE] = "";
164 struct keyvalue *kv = NULL;
165
166 if (argc < 2) {
167 usage();
168 exit(1);
169 }
170 if (!(initsetuid()))
171 exit(1);
172
fe6cda92 173 FILE *file = NULL;
69dcc425 174
ba149d47
AF
175
176 if (strcmp(argv[1], "I") == 0) {
177 safe_system("/usr/sbin/ipsec whack --status");
178 exit(0);
179 }
180
181 if (strcmp(argv[1], "R") == 0) {
182 safe_system("/usr/sbin/ipsec whack --rereadall >/dev/null");
183 exit(0);
184 }
185
dced81b2 186 /* Get vpnwatch pid */
fe6cda92 187
0f57633b 188 if ( (argc == 2) && (file = fopen("/var/run/vpn-watch.pid", "r"))) {
7dbf47dc 189 safe_system("kill -9 $(cat /var/run/vpn-watch.pid)");
05882fff 190 safe_system("unlink /var/run/vpn-watch.pid");
7dbf47dc 191 close(file);
0f57633b 192 }
fe6cda92 193
69dcc425
CS
194 /* FIXME: workaround for pclose() issue - still no real idea why
195 * this is happening */
196 signal(SIGCHLD, SIG_DFL);
197
198 /* handle operations that doesn't need start the ipsec system */
199 if (argc == 2) {
200 if (strcmp(argv[1], "D") == 0) {
201 ipsec_norules();
202 /* Only shutdown pluto if it really is running */
203 /* Get pluto pid */
204 if (file = fopen("/var/run/pluto.pid", "r")) {
205 safe_system("/etc/rc.d/init.d/ipsec stop 2> /dev/null >/dev/null");
206 close(file);
207 }
208 exit(0);
209 }
210
69dcc425
CS
211 }
212
213 /* clear iptables vpn rules */
214 ipsec_norules();
215
216 /* read vpn config */
217 kv=initkeyvalues();
218 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
219 {
220 fprintf(stderr, "Cannot read vpn settings\n");
221 exit(1);
222 }
223
224 /* check is the vpn system is enabled */
225 {
226 char s[STRING_SIZE];
227 findkey(kv, "ENABLED", s);
228 freekeyvalues(kv);
229 if (strcmp (s, "on") != 0)
230 exit(0);
231 }
232
233 /* read interface settings */
234 kv=initkeyvalues();
235 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
236 {
237 fprintf(stderr, "Cannot read ethernet settings\n");
238 exit(1);
239 }
240 if (!findkey(kv, "CONFIG_TYPE", configtype))
241 {
242 fprintf(stderr, "Cannot read CONFIG_TYPE\n");
243 exit(1);
244 }
245 findkey(kv, "RED_TYPE", redtype);
246
247
248 /* Loop through the config file to find physical interface that will accept IPSEC */
249 int enable_red=0; // states 0: not used
250 int enable_green=0; // 1: error condition
251 int enable_orange=0; // 2: good
252 int enable_blue=0;
253 char if_red[STRING_SIZE] = "";
254 char if_green[STRING_SIZE] = "";
255 char if_orange[STRING_SIZE] = "";
256 char if_blue[STRING_SIZE] = "";
257 char s[STRING_SIZE];
258
259 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
260 fprintf(stderr, "Couldn't open vpn settings file");
261 exit(1);
262 }
263 while (fgets(s, STRING_SIZE, file) != NULL) {
264 char *key;
265 char *name;
266 char *type;
267 char *interface;
268 if (!decode_line(s,&key,&name,&type,&interface))
269 continue;
270 /* search interface */
271 if (!enable_red && strcmp (interface, "RED") == 0) {
272 // when RED is up, find interface name in special file
273 FILE *ifacefile = NULL;
274 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r"))) {
275 if (fgets(if_red, STRING_SIZE, ifacefile)) {
276 if (if_red[strlen(if_red) - 1] == '\n')
277 if_red[strlen(if_red) - 1] = '\0';
278 }
279 fclose (ifacefile);
280
281 if (VALID_DEVICE(if_red))
282 enable_red+=2; // present and running
283 }
284 }
285
286 if (!enable_green && strcmp (interface, "GREEN") == 0) {
287 enable_green = 1;
288 findkey(kv, "GREEN_DEV", if_green);
289 if (VALID_DEVICE(if_green))
290 enable_green++;
291 else
292 fprintf(stderr, "IPSec enabled on green but green interface is invalid or not found\n");
293 }
294
295 if (!enable_orange && strcmp (interface, "ORANGE") == 0) {
296 enable_orange = 1;
297 findkey(kv, "ORANGE_DEV", if_orange);
298 if (VALID_DEVICE(if_orange))
299 enable_orange++;
300 else
301 fprintf(stderr, "IPSec enabled on orange but orange interface is invalid or not found\n");
302 }
303
304 if (!enable_blue && strcmp (interface, "BLUE") == 0) {
305 enable_blue++;
306 findkey(kv, "BLUE_DEV", if_blue);
307 if (VALID_DEVICE(if_blue))
308 enable_blue++;
309 else
310 fprintf(stderr, "IPSec enabled on blue but blue interface is invalid or not found\n");
311
312 }
313 }
314 fclose(file);
315 freekeyvalues(kv);
316
317 // do nothing if something is in error condition
318 if ((enable_red==1) || (enable_green==1) || (enable_orange==1) || (enable_blue==1) )
319 exit(1);
320
321 // exit if nothing to do
322 if ( (enable_red+enable_green+enable_orange+enable_blue) == 0 )
323 exit(0);
324
325 // open needed ports
326 // todo: read a nat_t indicator to allow or not openning UDP/4500
327 if (enable_red==2)
328 open_physical(if_red, 4500);
329
330 if (enable_green==2)
331 open_physical(if_green, 4500);
332
333 if (enable_orange==2)
334 open_physical(if_orange, 4500);
335
336 if (enable_blue==2)
337 open_physical(if_blue, 4500);
338
69dcc425
CS
339 // start the system
340 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
69dcc425 341 safe_system("/etc/rc.d/init.d/ipsec restart >/dev/null");
0f57633b 342 safe_system("/usr/local/bin/vpn-watch &");
69dcc425
CS
343 exit(0);
344 }
345
346 // it is a selective start or stop
347 // second param is only a number 'key'
348 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
349 ipsec_norules();
350 fprintf(stderr, "Bad arg\n");
351 usage();
352 exit(1);
353 }
354
355 // search the vpn pointed by 'key'
356 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
357 ipsec_norules();
358 fprintf(stderr, "Couldn't open vpn settings file");
359 exit(1);
360 }
361 while (fgets(s, STRING_SIZE, file) != NULL) {
362 char *key;
363 char *name;
364 char *type;
365 char *interface;
366 if (!decode_line(s,&key,&name,&type,&interface))
367 continue;
368
369 // start/stop a vpn if belonging to specified interface
370 if (strcmp(argv[1], interface) == 0 ) {
371 if (strcmp(argv[2], "0")==0)
372 turn_connection_off (name);
373 else
374 turn_connection_on (name, type);
375 continue;
376 }
377 // is it the 'key' requested ?
378 if (strcmp(argv[2], key) != 0)
379 continue;
380 // Start or Delete this Connection
381 if (strcmp(argv[1], "S") == 0)
382 turn_connection_on (name, type);
383 else
384 if (strcmp(argv[1], "D") == 0)
385 turn_connection_off (name);
386 else {
387 ipsec_norules();
388 fprintf(stderr, "Bad command\n");
389 exit(1);
390 }
391 }
392 fclose(file);
69dcc425 393 return 0;
05207d69 394}