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