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