ipsecctrl: Re-read everything when configuration is reloaded.
[people/teissler/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");
05207d69
MT
81}
82
5fd30232
MT
83/*
84 return values from the vpn config file or false if not 'on'
85*/
86int decode_line (char *s,
69dcc425
CS
87 char **key,
88 char **name,
9f0b5c9f 89 char **type
69dcc425
CS
90 ) {
91 int count = 0;
92 *key = NULL;
93 *name = NULL;
94 *type = NULL;
95
96 if (s[strlen(s) - 1] == '\n')
97 s[strlen(s) - 1] = '\0';
98
99 char *result = strsep(&s, ",");
100 while (result) {
101 if (count == 0)
102 *key = result;
103 if ((count == 1) && strcmp(result, "on") != 0)
104 return 0; // a disabled line
105 if (count == 2)
106 *name = result;
107 if (count == 4)
108 *type = result;
69dcc425
CS
109 count++;
110 result = strsep(&s, ",");
111 }
112
113 // check other syntax
114 if (! *name)
115 return 0;
116
117 if (strspn(*name, LETTERS_NUMBERS) != strlen(*name)) {
118 fprintf(stderr, "Bad connection name: %s\n", *name);
119 return 0;
120 }
121
122 if (! (strcmp(*type, "host") == 0 || strcmp(*type, "net") == 0)) {
123 fprintf(stderr, "Bad connection type: %s\n", *type);
124 return 0;
125 }
126
69dcc425
CS
127 //it's a valid & active line
128 return 1;
5fd30232
MT
129}
130
131/*
132 issue ipsec commmands to turn on connection 'name'
133*/
9f0b5c9f
MT
134void turn_connection_on(char *name, char *type) {
135 /*
136 * To bring up a connection, we need to reload the configuration
137 * and issue ipsec up afterwards. To make sure the connection
138 * is not established from the start, we bring it down in advance.
139 */
6e2ba31b 140 char command[STRING_SIZE];
6e2ba31b 141
9f0b5c9f 142 // Bring down the connection (if established).
6e2ba31b 143 snprintf(command, STRING_SIZE - 1,
9f0b5c9f 144 "/usr/sbin/ipsec down %s >/dev/null", name);
6e2ba31b 145 safe_system(command);
6e2ba31b 146
e0cdf670
MT
147 // Reload the configuration into the daemon (#10339).
148 ipsec_reload();
6e2ba31b 149
9f0b5c9f
MT
150 // Bring the connection up again.
151 snprintf(command, STRING_SIZE - 1,
152 "/usr/sbin/ipsec up %s >/dev/null", name);
153 safe_system(command);
5fd30232 154}
9f0b5c9f 155
5fd30232
MT
156/*
157 issue ipsec commmands to turn off connection 'name'
158*/
159void turn_connection_off (char *name) {
9f0b5c9f
MT
160 /*
161 * To turn off a connection, all SAs must be turned down.
162 * After that, the configuration must be reloaded.
163 */
69dcc425 164 char command[STRING_SIZE];
9f0b5c9f
MT
165
166 // Bring down the connection.
3e077ef3 167 snprintf(command, STRING_SIZE - 1,
9f0b5c9f 168 "/usr/sbin/ipsec down %s >/dev/null", name);
3e077ef3 169 safe_system(command);
6e2ba31b 170
9f0b5c9f 171 // Reload, so the connection is dropped.
e0cdf670
MT
172 ipsec_reload();
173}
174
175void ipsec_reload() {
176 /* Re-read all configuration files and secrets and
177 * reload the daemon (#10339).
178 */
179 safe_system("/usr/sbin/ipsec rereadall >/dev/null 2>&1");
180 safe_system("/usr/sbin/ipsec reload >/dev/null 2>&1");
5fd30232
MT
181}
182
05207d69 183int main(int argc, char *argv[]) {
69dcc425
CS
184 char configtype[STRING_SIZE];
185 char redtype[STRING_SIZE] = "";
186 struct keyvalue *kv = NULL;
187
188 if (argc < 2) {
189 usage();
190 exit(1);
191 }
192 if (!(initsetuid()))
193 exit(1);
194
fe6cda92 195 FILE *file = NULL;
69dcc425 196
ba149d47
AF
197
198 if (strcmp(argv[1], "I") == 0) {
9f0b5c9f 199 safe_system("/usr/sbin/ipsec status");
ba149d47
AF
200 exit(0);
201 }
202
203 if (strcmp(argv[1], "R") == 0) {
e0cdf670 204 ipsec_reload();
ba149d47
AF
205 exit(0);
206 }
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) {
9f0b5c9f 215 safe_system("/usr/sbin/ipsec stop >/dev/null 2>&1");
1f324fd7 216 ipsec_norules();
69dcc425
CS
217 exit(0);
218 }
69dcc425
CS
219 }
220
69dcc425
CS
221 /* read vpn config */
222 kv=initkeyvalues();
223 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
224 {
225 fprintf(stderr, "Cannot read vpn settings\n");
226 exit(1);
227 }
228
229 /* check is the vpn system is enabled */
230 {
231 char s[STRING_SIZE];
232 findkey(kv, "ENABLED", s);
233 freekeyvalues(kv);
234 if (strcmp (s, "on") != 0)
235 exit(0);
236 }
237
238 /* read interface settings */
239 kv=initkeyvalues();
240 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
241 {
242 fprintf(stderr, "Cannot read ethernet settings\n");
243 exit(1);
244 }
245 if (!findkey(kv, "CONFIG_TYPE", configtype))
246 {
247 fprintf(stderr, "Cannot read CONFIG_TYPE\n");
248 exit(1);
249 }
250 findkey(kv, "RED_TYPE", redtype);
251
252
253 /* Loop through the config file to find physical interface that will accept IPSEC */
254 int enable_red=0; // states 0: not used
255 int enable_green=0; // 1: error condition
256 int enable_orange=0; // 2: good
257 int enable_blue=0;
258 char if_red[STRING_SIZE] = "";
259 char if_green[STRING_SIZE] = "";
260 char if_orange[STRING_SIZE] = "";
261 char if_blue[STRING_SIZE] = "";
262 char s[STRING_SIZE];
263
9f0b5c9f
MT
264 // when RED is up, find interface name in special file
265 FILE *ifacefile = NULL;
266 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r"))) {
267 if (fgets(if_red, STRING_SIZE, ifacefile)) {
268 if (if_red[strlen(if_red) - 1] == '\n')
269 if_red[strlen(if_red) - 1] = '\0';
69dcc425 270 }
9f0b5c9f 271 fclose (ifacefile);
69dcc425 272
9f0b5c9f
MT
273 if (VALID_DEVICE(if_red))
274 enable_red++;
275 }
69dcc425 276
9f0b5c9f
MT
277 // Check if GREEN is enabled.
278 findkey(kv, "GREEN_DEV", if_green);
279 if (VALID_DEVICE(if_green))
280 enable_green++;
9f0b5c9f
MT
281
282 // Check if ORANGE is enabled.
283 findkey(kv, "ORANGE_DEV", if_orange);
284 if (VALID_DEVICE(if_orange))
285 enable_orange++;
9f0b5c9f
MT
286
287 // Check if BLUE is enabled.
288 findkey(kv, "BLUE_DEV", if_blue);
289 if (VALID_DEVICE(if_blue))
290 enable_blue++;
69dcc425 291
69dcc425
CS
292 freekeyvalues(kv);
293
69dcc425 294 // exit if nothing to do
9f0b5c9f 295 if ((enable_red+enable_green+enable_orange+enable_blue) == 0)
69dcc425
CS
296 exit(0);
297
298 // open needed ports
9f0b5c9f 299 if (enable_red > 0)
69dcc425
CS
300 open_physical(if_red, 4500);
301
9f0b5c9f 302 if (enable_green > 0)
69dcc425
CS
303 open_physical(if_green, 4500);
304
9f0b5c9f 305 if (enable_orange > 0)
69dcc425
CS
306 open_physical(if_orange, 4500);
307
9f0b5c9f 308 if (enable_blue > 0)
69dcc425
CS
309 open_physical(if_blue, 4500);
310
69dcc425
CS
311 // start the system
312 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
9f0b5c9f 313 safe_system("/usr/sbin/ipsec restart >/dev/null");
69dcc425
CS
314 exit(0);
315 }
316
317 // it is a selective start or stop
318 // second param is only a number 'key'
319 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
9f0b5c9f 320 fprintf(stderr, "Bad arg: %s\n", argv[2]);
69dcc425
CS
321 usage();
322 exit(1);
323 }
324
325 // search the vpn pointed by 'key'
326 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
69dcc425
CS
327 fprintf(stderr, "Couldn't open vpn settings file");
328 exit(1);
329 }
330 while (fgets(s, STRING_SIZE, file) != NULL) {
331 char *key;
332 char *name;
333 char *type;
9f0b5c9f 334 if (!decode_line(s,&key,&name,&type))
69dcc425
CS
335 continue;
336
69dcc425
CS
337 // is it the 'key' requested ?
338 if (strcmp(argv[2], key) != 0)
339 continue;
9f0b5c9f 340
69dcc425
CS
341 // Start or Delete this Connection
342 if (strcmp(argv[1], "S") == 0)
343 turn_connection_on (name, type);
9f0b5c9f 344 else if (strcmp(argv[1], "D") == 0)
69dcc425
CS
345 turn_connection_off (name);
346 else {
69dcc425
CS
347 fprintf(stderr, "Bad command\n");
348 exit(1);
349 }
350 }
351 fclose(file);
9f0b5c9f 352
69dcc425 353 return 0;
05207d69 354}