]> git.ipfire.org Git - ipfire-2.x.git/blame - src/misc-progs/ipsecctrl.c
core115: Include captive portal in updater
[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>
52e54c1c 16
05207d69 17#include "setuid.h"
52e54c1c 18#include "netutil.h"
05207d69 19
5fd30232
MT
20/*
21 This module is responsible for start stop of the vpn system.
22
23 1) it allows AH & ESP to get in from interface where a vpn is mounted
69dcc425 24 The NAT traversal is used on the udp 4500 port.
5fd30232
MT
25
26 2) it starts the ipsec daemon
69dcc425
CS
27 The RED interface is a problem because it can be up or down a startup.
28 Then, the state change and it must not affect other VPN mounted on
29 other interface.
30 Unfortunatly, openswan 1 cannot do that correctly. It cannot use an
31 interface without restarting everything.
5fd30232
MT
32
33*/
34
05207d69 35void usage() {
69dcc425
CS
36 fprintf (stderr, "Usage:\n");
37 fprintf (stderr, "\tipsecctrl S [connectionkey]\n");
38 fprintf (stderr, "\tipsecctrl D [connectionkey]\n");
39 fprintf (stderr, "\tipsecctrl R\n");
db073a10 40 fprintf (stderr, "\tipsecctrl I\n");
69dcc425
CS
41 fprintf (stderr, "\t\tS : Start/Restart Connection\n");
42 fprintf (stderr, "\t\tD : Stop Connection\n");
43 fprintf (stderr, "\t\tR : Reload Certificates and Secrets\n");
db073a10 44 fprintf (stderr, "\t\tI : Print Statusinfo\n");
05207d69
MT
45}
46
8fcb9253
MT
47static void ipsec_reload() {
48 /* Re-read all configuration files and secrets and
49 * reload the daemon (#10339).
50 */
51 safe_system("/usr/sbin/ipsec rereadall >/dev/null 2>&1");
52 safe_system("/usr/sbin/ipsec reload >/dev/null 2>&1");
53}
54
5fd30232 55/*
69dcc425 56 ACCEPT the ipsec protocol ah, esp & udp (for nat traversal) on the specified interface
5fd30232
MT
57*/
58void open_physical (char *interface, int nat_traversal_port) {
69dcc425
CS
59 char str[STRING_SIZE];
60
69dcc425 61 // IKE
a9600358 62 sprintf(str, "/sbin/iptables --wait -D IPSECINPUT -p udp -i %s --dport 500 -j ACCEPT >/dev/null 2>&1", interface);
1f324fd7 63 safe_system(str);
a9600358 64 sprintf(str, "/sbin/iptables --wait -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
a9600358 70 sprintf(str, "/sbin/iptables --wait -D IPSECINPUT -p udp -i %s --dport %i -j ACCEPT >/dev/null 2>&1", interface, nat_traversal_port);
1f324fd7 71 safe_system(str);
a9600358 72 sprintf(str, "/sbin/iptables --wait -A IPSECINPUT -p udp -i %s --dport %i -j ACCEPT", interface, nat_traversal_port);
db073a10 73 safe_system(str);
5fd30232
MT
74}
75
76void ipsec_norules() {
69dcc425 77 /* clear input rules */
a9600358
MT
78 safe_system("/sbin/iptables --wait -F IPSECINPUT");
79 safe_system("/sbin/iptables --wait -F IPSECFORWARD");
80 safe_system("/sbin/iptables --wait -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
80fbd899
MT
147 // Reload the IPsec block chain
148 safe_system("/usr/lib/firewall/ipsec-block >/dev/null");
149
8e2683f7
MT
150 // Reload the configuration into the daemon (#10339).
151 ipsec_reload();
6e2ba31b 152
9f0b5c9f
MT
153 // Bring the connection up again.
154 snprintf(command, STRING_SIZE - 1,
155 "/usr/sbin/ipsec up %s >/dev/null", name);
156 safe_system(command);
5fd30232 157}
9f0b5c9f 158
5fd30232
MT
159/*
160 issue ipsec commmands to turn off connection 'name'
161*/
162void turn_connection_off (char *name) {
9f0b5c9f
MT
163 /*
164 * To turn off a connection, all SAs must be turned down.
165 * After that, the configuration must be reloaded.
166 */
69dcc425 167 char command[STRING_SIZE];
9f0b5c9f
MT
168
169 // Bring down the connection.
3e077ef3 170 snprintf(command, STRING_SIZE - 1,
9f0b5c9f 171 "/usr/sbin/ipsec down %s >/dev/null", name);
3e077ef3 172 safe_system(command);
6e2ba31b 173
9f0b5c9f 174 // Reload, so the connection is dropped.
8e2683f7 175 ipsec_reload();
4f6790a7
MT
176
177 // Reload the IPsec block chain
178 safe_system("/usr/lib/firewall/ipsec-block >/dev/null");
8e2683f7
MT
179}
180
05207d69 181int main(int argc, char *argv[]) {
69dcc425
CS
182 char configtype[STRING_SIZE];
183 char redtype[STRING_SIZE] = "";
184 struct keyvalue *kv = NULL;
185
186 if (argc < 2) {
187 usage();
188 exit(1);
189 }
190 if (!(initsetuid()))
191 exit(1);
192
fe6cda92 193 FILE *file = NULL;
69dcc425 194
ba149d47
AF
195
196 if (strcmp(argv[1], "I") == 0) {
9f0b5c9f 197 safe_system("/usr/sbin/ipsec status");
ba149d47
AF
198 exit(0);
199 }
200
201 if (strcmp(argv[1], "R") == 0) {
8e2683f7 202 ipsec_reload();
ba149d47
AF
203 exit(0);
204 }
205
69dcc425
CS
206 /* FIXME: workaround for pclose() issue - still no real idea why
207 * this is happening */
208 signal(SIGCHLD, SIG_DFL);
209
210 /* handle operations that doesn't need start the ipsec system */
211 if (argc == 2) {
212 if (strcmp(argv[1], "D") == 0) {
9f0b5c9f 213 safe_system("/usr/sbin/ipsec stop >/dev/null 2>&1");
1f324fd7 214 ipsec_norules();
69dcc425
CS
215 exit(0);
216 }
69dcc425
CS
217 }
218
69dcc425
CS
219 /* read vpn config */
220 kv=initkeyvalues();
221 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
222 {
223 fprintf(stderr, "Cannot read vpn settings\n");
224 exit(1);
225 }
226
227 /* check is the vpn system is enabled */
228 {
229 char s[STRING_SIZE];
230 findkey(kv, "ENABLED", s);
231 freekeyvalues(kv);
232 if (strcmp (s, "on") != 0)
233 exit(0);
234 }
235
236 /* read interface settings */
237 kv=initkeyvalues();
238 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
239 {
240 fprintf(stderr, "Cannot read ethernet settings\n");
241 exit(1);
242 }
243 if (!findkey(kv, "CONFIG_TYPE", configtype))
244 {
245 fprintf(stderr, "Cannot read CONFIG_TYPE\n");
246 exit(1);
247 }
248 findkey(kv, "RED_TYPE", redtype);
249
250
251 /* Loop through the config file to find physical interface that will accept IPSEC */
252 int enable_red=0; // states 0: not used
253 int enable_green=0; // 1: error condition
254 int enable_orange=0; // 2: good
255 int enable_blue=0;
256 char if_red[STRING_SIZE] = "";
257 char if_green[STRING_SIZE] = "";
258 char if_orange[STRING_SIZE] = "";
259 char if_blue[STRING_SIZE] = "";
260 char s[STRING_SIZE];
261
9f0b5c9f
MT
262 // when RED is up, find interface name in special file
263 FILE *ifacefile = NULL;
264 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r"))) {
265 if (fgets(if_red, STRING_SIZE, ifacefile)) {
266 if (if_red[strlen(if_red) - 1] == '\n')
267 if_red[strlen(if_red) - 1] = '\0';
69dcc425 268 }
9f0b5c9f 269 fclose (ifacefile);
69dcc425 270
9f0b5c9f
MT
271 if (VALID_DEVICE(if_red))
272 enable_red++;
273 }
69dcc425 274
9f0b5c9f
MT
275 // Check if GREEN is enabled.
276 findkey(kv, "GREEN_DEV", if_green);
277 if (VALID_DEVICE(if_green))
278 enable_green++;
9f0b5c9f
MT
279
280 // Check if ORANGE is enabled.
281 findkey(kv, "ORANGE_DEV", if_orange);
282 if (VALID_DEVICE(if_orange))
283 enable_orange++;
9f0b5c9f
MT
284
285 // Check if BLUE is enabled.
286 findkey(kv, "BLUE_DEV", if_blue);
287 if (VALID_DEVICE(if_blue))
288 enable_blue++;
69dcc425 289
69dcc425
CS
290 freekeyvalues(kv);
291
69dcc425 292 // exit if nothing to do
9f0b5c9f 293 if ((enable_red+enable_green+enable_orange+enable_blue) == 0)
69dcc425
CS
294 exit(0);
295
296 // open needed ports
9f0b5c9f 297 if (enable_red > 0)
69dcc425
CS
298 open_physical(if_red, 4500);
299
9f0b5c9f 300 if (enable_green > 0)
69dcc425
CS
301 open_physical(if_green, 4500);
302
9f0b5c9f 303 if (enable_orange > 0)
69dcc425
CS
304 open_physical(if_orange, 4500);
305
9f0b5c9f 306 if (enable_blue > 0)
69dcc425
CS
307 open_physical(if_blue, 4500);
308
69dcc425
CS
309 // start the system
310 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
80fbd899 311 safe_system("/usr/lib/firewall/ipsec-block >/dev/null");
9f0b5c9f 312 safe_system("/usr/sbin/ipsec restart >/dev/null");
69dcc425
CS
313 exit(0);
314 }
315
316 // it is a selective start or stop
317 // second param is only a number 'key'
318 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
9f0b5c9f 319 fprintf(stderr, "Bad arg: %s\n", argv[2]);
69dcc425
CS
320 usage();
321 exit(1);
322 }
323
324 // search the vpn pointed by 'key'
325 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
69dcc425
CS
326 fprintf(stderr, "Couldn't open vpn settings file");
327 exit(1);
328 }
329 while (fgets(s, STRING_SIZE, file) != NULL) {
330 char *key;
331 char *name;
332 char *type;
9f0b5c9f 333 if (!decode_line(s,&key,&name,&type))
69dcc425
CS
334 continue;
335
69dcc425
CS
336 // is it the 'key' requested ?
337 if (strcmp(argv[2], key) != 0)
338 continue;
9f0b5c9f 339
69dcc425
CS
340 // Start or Delete this Connection
341 if (strcmp(argv[1], "S") == 0)
342 turn_connection_on (name, type);
9f0b5c9f 343 else if (strcmp(argv[1], "D") == 0)
69dcc425
CS
344 turn_connection_off (name);
345 else {
69dcc425
CS
346 fprintf(stderr, "Bad command\n");
347 exit(1);
348 }
349 }
350 fclose(file);
9f0b5c9f 351
69dcc425 352 return 0;
05207d69 353}