]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/misc-progs/ipsecctrl.c
ipsecctrl: Don't wait when a connection is to be started
[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
MT
55/*
56 return values from the vpn config file or false if not 'on'
57*/
58int decode_line (char *s,
69dcc425
CS
59 char **key,
60 char **name,
9f0b5c9f 61 char **type
69dcc425
CS
62 ) {
63 int count = 0;
64 *key = NULL;
65 *name = NULL;
66 *type = NULL;
67
68 if (s[strlen(s) - 1] == '\n')
69 s[strlen(s) - 1] = '\0';
70
71 char *result = strsep(&s, ",");
72 while (result) {
73 if (count == 0)
74 *key = result;
75 if ((count == 1) && strcmp(result, "on") != 0)
76 return 0; // a disabled line
77 if (count == 2)
78 *name = result;
79 if (count == 4)
80 *type = result;
69dcc425
CS
81 count++;
82 result = strsep(&s, ",");
83 }
84
85 // check other syntax
86 if (! *name)
87 return 0;
88
89 if (strspn(*name, LETTERS_NUMBERS) != strlen(*name)) {
90 fprintf(stderr, "Bad connection name: %s\n", *name);
91 return 0;
92 }
93
94 if (! (strcmp(*type, "host") == 0 || strcmp(*type, "net") == 0)) {
95 fprintf(stderr, "Bad connection type: %s\n", *type);
96 return 0;
97 }
98
69dcc425
CS
99 //it's a valid & active line
100 return 1;
5fd30232
MT
101}
102
103/*
104 issue ipsec commmands to turn on connection 'name'
105*/
9f0b5c9f
MT
106void turn_connection_on(char *name, char *type) {
107 /*
108 * To bring up a connection, we need to reload the configuration
109 * and issue ipsec up afterwards. To make sure the connection
110 * is not established from the start, we bring it down in advance.
111 */
6e2ba31b 112 char command[STRING_SIZE];
6e2ba31b 113
9f0b5c9f 114 // Bring down the connection (if established).
6e2ba31b 115 snprintf(command, STRING_SIZE - 1,
9f0b5c9f 116 "/usr/sbin/ipsec down %s >/dev/null", name);
6e2ba31b 117 safe_system(command);
6e2ba31b 118
6c920b19
MT
119 // Reload the IPsec firewall policy
120 safe_system("/usr/lib/firewall/ipsec-policy >/dev/null");
80fbd899 121
8e2683f7
MT
122 // Reload the configuration into the daemon (#10339).
123 ipsec_reload();
6e2ba31b 124
9f0b5c9f
MT
125 // Bring the connection up again.
126 snprintf(command, STRING_SIZE - 1,
b89ae1a4 127 "/usr/sbin/ipsec stroke up-nb %s >/dev/null", name);
9f0b5c9f 128 safe_system(command);
5fd30232 129}
9f0b5c9f 130
5fd30232
MT
131/*
132 issue ipsec commmands to turn off connection 'name'
133*/
134void turn_connection_off (char *name) {
9f0b5c9f
MT
135 /*
136 * To turn off a connection, all SAs must be turned down.
137 * After that, the configuration must be reloaded.
138 */
69dcc425 139 char command[STRING_SIZE];
9f0b5c9f
MT
140
141 // Bring down the connection.
3e077ef3 142 snprintf(command, STRING_SIZE - 1,
9f0b5c9f 143 "/usr/sbin/ipsec down %s >/dev/null", name);
3e077ef3 144 safe_system(command);
6e2ba31b 145
9f0b5c9f 146 // Reload, so the connection is dropped.
8e2683f7 147 ipsec_reload();
4f6790a7 148
6c920b19
MT
149 // Reload the IPsec firewall policy
150 safe_system("/usr/lib/firewall/ipsec-policy >/dev/null");
8e2683f7
MT
151}
152
05207d69 153int main(int argc, char *argv[]) {
69dcc425
CS
154 struct keyvalue *kv = NULL;
155
156 if (argc < 2) {
157 usage();
158 exit(1);
159 }
160 if (!(initsetuid()))
161 exit(1);
6cf8bc91
MT
162
163 FILE *file = NULL;
ba149d47
AF
164
165 if (strcmp(argv[1], "I") == 0) {
9f0b5c9f 166 safe_system("/usr/sbin/ipsec status");
ba149d47
AF
167 exit(0);
168 }
169
170 if (strcmp(argv[1], "R") == 0) {
8e2683f7 171 ipsec_reload();
ba149d47
AF
172 exit(0);
173 }
174
69dcc425
CS
175 /* FIXME: workaround for pclose() issue - still no real idea why
176 * this is happening */
177 signal(SIGCHLD, SIG_DFL);
178
179 /* handle operations that doesn't need start the ipsec system */
180 if (argc == 2) {
181 if (strcmp(argv[1], "D") == 0) {
9f0b5c9f 182 safe_system("/usr/sbin/ipsec stop >/dev/null 2>&1");
6cf8bc91 183 safe_system("/usr/lib/firewall/ipsec-policy >/dev/null");
69dcc425
CS
184 exit(0);
185 }
69dcc425
CS
186 }
187
69dcc425
CS
188 /* read vpn config */
189 kv=initkeyvalues();
190 if (!readkeyvalues(kv, CONFIG_ROOT "/vpn/settings"))
191 {
192 fprintf(stderr, "Cannot read vpn settings\n");
193 exit(1);
194 }
195
196 /* check is the vpn system is enabled */
197 {
198 char s[STRING_SIZE];
199 findkey(kv, "ENABLED", s);
200 freekeyvalues(kv);
201 if (strcmp (s, "on") != 0)
202 exit(0);
203 }
204
69dcc425
CS
205 char s[STRING_SIZE];
206
6cf8bc91 207 // start the system
69dcc425 208 if ((argc == 2) && strcmp(argv[1], "S") == 0) {
6c920b19 209 safe_system("/usr/lib/firewall/ipsec-policy >/dev/null");
9f0b5c9f 210 safe_system("/usr/sbin/ipsec restart >/dev/null");
69dcc425
CS
211 exit(0);
212 }
213
214 // it is a selective start or stop
215 // second param is only a number 'key'
216 if ((argc == 2) || strspn(argv[2], NUMBERS) != strlen(argv[2])) {
9f0b5c9f 217 fprintf(stderr, "Bad arg: %s\n", argv[2]);
69dcc425
CS
218 usage();
219 exit(1);
220 }
221
222 // search the vpn pointed by 'key'
223 if (!(file = fopen(CONFIG_ROOT "/vpn/config", "r"))) {
69dcc425
CS
224 fprintf(stderr, "Couldn't open vpn settings file");
225 exit(1);
226 }
227 while (fgets(s, STRING_SIZE, file) != NULL) {
228 char *key;
229 char *name;
230 char *type;
9f0b5c9f 231 if (!decode_line(s,&key,&name,&type))
69dcc425
CS
232 continue;
233
69dcc425
CS
234 // is it the 'key' requested ?
235 if (strcmp(argv[2], key) != 0)
236 continue;
9f0b5c9f 237
69dcc425
CS
238 // Start or Delete this Connection
239 if (strcmp(argv[1], "S") == 0)
240 turn_connection_on (name, type);
9f0b5c9f 241 else if (strcmp(argv[1], "D") == 0)
69dcc425
CS
242 turn_connection_off (name);
243 else {
69dcc425
CS
244 fprintf(stderr, "Bad command\n");
245 exit(1);
246 }
247 }
248 fclose(file);
9f0b5c9f 249
69dcc425 250 return 0;
05207d69 251}