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