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