]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/misc-progs/ipsecctrl.c
logwatch: Update to 7.4.3
[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>
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
MT
175 ipsec_reload();
176}
177
05207d69 178int main(int argc, char *argv[]) {
69dcc425
CS
179 char configtype[STRING_SIZE];
180 char redtype[STRING_SIZE] = "";
181 struct keyvalue *kv = NULL;
182
183 if (argc < 2) {
184 usage();
185 exit(1);
186 }
187 if (!(initsetuid()))
188 exit(1);
189
fe6cda92 190 FILE *file = NULL;
69dcc425 191
ba149d47
AF
192
193 if (strcmp(argv[1], "I") == 0) {
9f0b5c9f 194 safe_system("/usr/sbin/ipsec status");
ba149d47
AF
195 exit(0);
196 }
197
198 if (strcmp(argv[1], "R") == 0) {
8e2683f7 199 ipsec_reload();
ba149d47
AF
200 exit(0);
201 }
202
69dcc425
CS
203 /* FIXME: workaround for pclose() issue - still no real idea why
204 * this is happening */
205 signal(SIGCHLD, SIG_DFL);
206
207 /* handle operations that doesn't need start the ipsec system */
208 if (argc == 2) {
209 if (strcmp(argv[1], "D") == 0) {
9f0b5c9f 210 safe_system("/usr/sbin/ipsec stop >/dev/null 2>&1");
1f324fd7 211 ipsec_norules();
69dcc425
CS
212 exit(0);
213 }
69dcc425
CS
214 }
215
69dcc425
CS
216 /* read vpn config */
217 kv=initkeyvalues();
218 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
219 {
220 fprintf(stderr, "Cannot read vpn settings\n");
221 exit(1);
222 }
223
224 /* check is the vpn system is enabled */
225 {
226 char s[STRING_SIZE];
227 findkey(kv, "ENABLED", s);
228 freekeyvalues(kv);
229 if (strcmp (s, "on") != 0)
230 exit(0);
231 }
232
233 /* read interface settings */
234 kv=initkeyvalues();
235 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
236 {
237 fprintf(stderr, "Cannot read ethernet settings\n");
238 exit(1);
239 }
240 if (!findkey(kv, "CONFIG_TYPE", configtype))
241 {
242 fprintf(stderr, "Cannot read CONFIG_TYPE\n");
243 exit(1);
244 }
245 findkey(kv, "RED_TYPE", redtype);
246
247
248 /* Loop through the config file to find physical interface that will accept IPSEC */
249 int enable_red=0; // states 0: not used
250 int enable_green=0; // 1: error condition
251 int enable_orange=0; // 2: good
252 int enable_blue=0;
253 char if_red[STRING_SIZE] = "";
254 char if_green[STRING_SIZE] = "";
255 char if_orange[STRING_SIZE] = "";
256 char if_blue[STRING_SIZE] = "";
257 char s[STRING_SIZE];
258
9f0b5c9f
MT
259 // when RED is up, find interface name in special file
260 FILE *ifacefile = NULL;
261 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r"))) {
262 if (fgets(if_red, STRING_SIZE, ifacefile)) {
263 if (if_red[strlen(if_red) - 1] == '\n')
264 if_red[strlen(if_red) - 1] = '\0';
69dcc425 265 }
9f0b5c9f 266 fclose (ifacefile);
69dcc425 267
9f0b5c9f
MT
268 if (VALID_DEVICE(if_red))
269 enable_red++;
270 }
69dcc425 271
9f0b5c9f
MT
272 // Check if GREEN is enabled.
273 findkey(kv, "GREEN_DEV", if_green);
274 if (VALID_DEVICE(if_green))
275 enable_green++;
9f0b5c9f
MT
276
277 // Check if ORANGE is enabled.
278 findkey(kv, "ORANGE_DEV", if_orange);
279 if (VALID_DEVICE(if_orange))
280 enable_orange++;
9f0b5c9f
MT
281
282 // Check if BLUE is enabled.
283 findkey(kv, "BLUE_DEV", if_blue);
284 if (VALID_DEVICE(if_blue))
285 enable_blue++;
69dcc425 286
69dcc425
CS
287 freekeyvalues(kv);
288
69dcc425 289 // exit if nothing to do
9f0b5c9f 290 if ((enable_red+enable_green+enable_orange+enable_blue) == 0)
69dcc425
CS
291 exit(0);
292
293 // open needed ports
9f0b5c9f 294 if (enable_red > 0)
69dcc425
CS
295 open_physical(if_red, 4500);
296
9f0b5c9f 297 if (enable_green > 0)
69dcc425
CS
298 open_physical(if_green, 4500);
299
9f0b5c9f 300 if (enable_orange > 0)
69dcc425
CS
301 open_physical(if_orange, 4500);
302
9f0b5c9f 303 if (enable_blue > 0)
69dcc425
CS
304 open_physical(if_blue, 4500);
305
69dcc425
CS
306 // start the system
307 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
80fbd899 308 safe_system("/usr/lib/firewall/ipsec-block >/dev/null");
9f0b5c9f 309 safe_system("/usr/sbin/ipsec restart >/dev/null");
69dcc425
CS
310 exit(0);
311 }
312
313 // it is a selective start or stop
314 // second param is only a number 'key'
315 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
9f0b5c9f 316 fprintf(stderr, "Bad arg: %s\n", argv[2]);
69dcc425
CS
317 usage();
318 exit(1);
319 }
320
321 // search the vpn pointed by 'key'
322 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
69dcc425
CS
323 fprintf(stderr, "Couldn't open vpn settings file");
324 exit(1);
325 }
326 while (fgets(s, STRING_SIZE, file) != NULL) {
327 char *key;
328 char *name;
329 char *type;
9f0b5c9f 330 if (!decode_line(s,&key,&name,&type))
69dcc425
CS
331 continue;
332
69dcc425
CS
333 // is it the 'key' requested ?
334 if (strcmp(argv[2], key) != 0)
335 continue;
9f0b5c9f 336
69dcc425
CS
337 // Start or Delete this Connection
338 if (strcmp(argv[1], "S") == 0)
339 turn_connection_on (name, type);
9f0b5c9f 340 else if (strcmp(argv[1], "D") == 0)
69dcc425
CS
341 turn_connection_off (name);
342 else {
69dcc425
CS
343 fprintf(stderr, "Bad command\n");
344 exit(1);
345 }
346 }
347 fclose(file);
9f0b5c9f 348
69dcc425 349 return 0;
05207d69 350}