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