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