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