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