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