ipsec: change ipsecctrl for status and reload of charon.
[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
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) {
44b5666b
AF
144/*
145 if you find a way to start a single connection without changing all add it
146 here. Change also vpn-watch.
147*/
734b67d2 148 safe_system("/etc/rc.d/init.d/ipsec restart >/dev/null");
5fd30232
MT
149}
150/*
151 issue ipsec commmands to turn off connection 'name'
152*/
153void turn_connection_off (char *name) {
69dcc425 154 char command[STRING_SIZE];
69dcc425
CS
155 memset(command, 0, STRING_SIZE);
156 snprintf(command, STRING_SIZE - 1,
98065e83 157 "/usr/sbin/ipsec whack --delete --name %s >/dev/null", name);
69dcc425 158 safe_system(command);
98065e83 159 safe_system("/usr/sbin/ipsec whack --rereadall >/dev/null");
5fd30232
MT
160}
161
162
05207d69 163int main(int argc, char *argv[]) {
5fd30232 164
69dcc425
CS
165 char configtype[STRING_SIZE];
166 char redtype[STRING_SIZE] = "";
167 struct keyvalue *kv = NULL;
168
169 if (argc < 2) {
170 usage();
171 exit(1);
172 }
173 if (!(initsetuid()))
174 exit(1);
175
fe6cda92 176 FILE *file = NULL;
69dcc425 177
ba149d47
AF
178
179 if (strcmp(argv[1], "I") == 0) {
180 safe_system("/usr/sbin/ipsec whack --status");
0d181206 181 safe_system("/usr/sbin/ipsec stroke status");
ba149d47
AF
182 exit(0);
183 }
184
185 if (strcmp(argv[1], "R") == 0) {
186 safe_system("/usr/sbin/ipsec whack --rereadall >/dev/null");
0d181206 187 safe_system("/usr/sbin/ipsec stroke rereadall >/dev/null");
ba149d47
AF
188 exit(0);
189 }
190
dced81b2 191 /* Get vpnwatch pid */
fe6cda92 192
44b5666b
AF
193
194 if ((argc == 2) && (file = fopen("/var/run/vpn-watch.pid", "r"))) {
195 safe_system("kill -9 $(cat /var/run/vpn-watch.pid)");
196 safe_system("unlink /var/run/vpn-watch.pid");
197 close(file);
198 }
fe6cda92 199
69dcc425
CS
200 /* FIXME: workaround for pclose() issue - still no real idea why
201 * this is happening */
202 signal(SIGCHLD, SIG_DFL);
203
204 /* handle operations that doesn't need start the ipsec system */
205 if (argc == 2) {
206 if (strcmp(argv[1], "D") == 0) {
69dcc425
CS
207 /* Only shutdown pluto if it really is running */
208 /* Get pluto pid */
209 if (file = fopen("/var/run/pluto.pid", "r")) {
210 safe_system("/etc/rc.d/init.d/ipsec stop 2> /dev/null >/dev/null");
211 close(file);
212 }
1f324fd7 213 ipsec_norules();
69dcc425
CS
214 exit(0);
215 }
216
69dcc425
CS
217 }
218
69dcc425
CS
219 /* read vpn config */
220 kv=initkeyvalues();
221 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
222 {
223 fprintf(stderr, "Cannot read vpn settings\n");
224 exit(1);
225 }
226
227 /* check is the vpn system is enabled */
228 {
229 char s[STRING_SIZE];
230 findkey(kv, "ENABLED", s);
231 freekeyvalues(kv);
232 if (strcmp (s, "on") != 0)
233 exit(0);
234 }
235
236 /* read interface settings */
237 kv=initkeyvalues();
238 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
239 {
240 fprintf(stderr, "Cannot read ethernet settings\n");
241 exit(1);
242 }
243 if (!findkey(kv, "CONFIG_TYPE", configtype))
244 {
245 fprintf(stderr, "Cannot read CONFIG_TYPE\n");
246 exit(1);
247 }
248 findkey(kv, "RED_TYPE", redtype);
249
250
251 /* Loop through the config file to find physical interface that will accept IPSEC */
252 int enable_red=0; // states 0: not used
253 int enable_green=0; // 1: error condition
254 int enable_orange=0; // 2: good
255 int enable_blue=0;
256 char if_red[STRING_SIZE] = "";
257 char if_green[STRING_SIZE] = "";
258 char if_orange[STRING_SIZE] = "";
259 char if_blue[STRING_SIZE] = "";
260 char s[STRING_SIZE];
261
262 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
263 fprintf(stderr, "Couldn't open vpn settings file");
264 exit(1);
265 }
266 while (fgets(s, STRING_SIZE, file) != NULL) {
267 char *key;
268 char *name;
269 char *type;
270 char *interface;
271 if (!decode_line(s,&key,&name,&type,&interface))
272 continue;
273 /* search interface */
274 if (!enable_red && strcmp (interface, "RED") == 0) {
275 // when RED is up, find interface name in special file
276 FILE *ifacefile = NULL;
277 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r"))) {
278 if (fgets(if_red, STRING_SIZE, ifacefile)) {
279 if (if_red[strlen(if_red) - 1] == '\n')
280 if_red[strlen(if_red) - 1] = '\0';
281 }
282 fclose (ifacefile);
283
284 if (VALID_DEVICE(if_red))
285 enable_red+=2; // present and running
286 }
287 }
288
289 if (!enable_green && strcmp (interface, "GREEN") == 0) {
290 enable_green = 1;
291 findkey(kv, "GREEN_DEV", if_green);
292 if (VALID_DEVICE(if_green))
293 enable_green++;
294 else
295 fprintf(stderr, "IPSec enabled on green but green interface is invalid or not found\n");
296 }
297
298 if (!enable_orange && strcmp (interface, "ORANGE") == 0) {
299 enable_orange = 1;
300 findkey(kv, "ORANGE_DEV", if_orange);
301 if (VALID_DEVICE(if_orange))
302 enable_orange++;
303 else
304 fprintf(stderr, "IPSec enabled on orange but orange interface is invalid or not found\n");
305 }
306
307 if (!enable_blue && strcmp (interface, "BLUE") == 0) {
308 enable_blue++;
309 findkey(kv, "BLUE_DEV", if_blue);
310 if (VALID_DEVICE(if_blue))
311 enable_blue++;
312 else
313 fprintf(stderr, "IPSec enabled on blue but blue interface is invalid or not found\n");
314
315 }
316 }
317 fclose(file);
318 freekeyvalues(kv);
319
320 // do nothing if something is in error condition
321 if ((enable_red==1) || (enable_green==1) || (enable_orange==1) || (enable_blue==1) )
322 exit(1);
323
324 // exit if nothing to do
325 if ( (enable_red+enable_green+enable_orange+enable_blue) == 0 )
326 exit(0);
327
328 // open needed ports
329 // todo: read a nat_t indicator to allow or not openning UDP/4500
330 if (enable_red==2)
331 open_physical(if_red, 4500);
332
333 if (enable_green==2)
334 open_physical(if_green, 4500);
335
336 if (enable_orange==2)
337 open_physical(if_orange, 4500);
338
339 if (enable_blue==2)
340 open_physical(if_blue, 4500);
341
69dcc425
CS
342 // start the system
343 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
44b5666b
AF
344 safe_system("/etc/rc.d/init.d/ipsec restart >/dev/null");
345 safe_system("/usr/local/bin/vpn-watch &");
69dcc425
CS
346 exit(0);
347 }
348
349 // it is a selective start or stop
350 // second param is only a number 'key'
351 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
69dcc425
CS
352 fprintf(stderr, "Bad arg\n");
353 usage();
354 exit(1);
355 }
356
357 // search the vpn pointed by 'key'
358 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
69dcc425
CS
359 fprintf(stderr, "Couldn't open vpn settings file");
360 exit(1);
361 }
362 while (fgets(s, STRING_SIZE, file) != NULL) {
363 char *key;
364 char *name;
365 char *type;
366 char *interface;
367 if (!decode_line(s,&key,&name,&type,&interface))
368 continue;
369
370 // start/stop a vpn if belonging to specified interface
371 if (strcmp(argv[1], interface) == 0 ) {
372 if (strcmp(argv[2], "0")==0)
373 turn_connection_off (name);
374 else
375 turn_connection_on (name, type);
376 continue;
377 }
378 // is it the 'key' requested ?
379 if (strcmp(argv[2], key) != 0)
380 continue;
381 // Start or Delete this Connection
382 if (strcmp(argv[1], "S") == 0)
383 turn_connection_on (name, type);
384 else
385 if (strcmp(argv[1], "D") == 0)
386 turn_connection_off (name);
387 else {
69dcc425
CS
388 fprintf(stderr, "Bad command\n");
389 exit(1);
390 }
391 }
392 fclose(file);
69dcc425 393 return 0;
05207d69 394}