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