]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/misc-progs/openvpnctrl.c
openvpnctrl: Fix initialization of the program.
[people/teissler/ipfire-2.x.git] / src / misc-progs / openvpnctrl.c
1 #include <signal.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <stdlib.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include "setuid.h"
9 #include "libsmooth.h"
10
11 #define ovpndebug
12
13 // global vars
14 struct keyvalue *kv = NULL;
15 FILE *ifacefile = NULL;
16
17 char redif[STRING_SIZE];
18 char blueif[STRING_SIZE];
19 char orangeif[STRING_SIZE];
20 char enablered[STRING_SIZE] = "off";
21 char enableblue[STRING_SIZE] = "off";
22 char enableorange[STRING_SIZE] = "off";
23
24 // consts
25 char OVPNRED[STRING_SIZE] = "OVPN";
26 char OVPNBLUE[STRING_SIZE] = "OVPN_BLUE_";
27 char OVPNORANGE[STRING_SIZE] = "OVPN_ORANGE_";
28 char WRAPPERVERSION[STRING_SIZE] = "ipfire-2.1.2";
29
30 struct connection_struct {
31 char name[STRING_SIZE];
32 char type[STRING_SIZE];
33 char proto[STRING_SIZE];
34 int port;
35 struct connection_struct *next;
36 };
37
38 typedef struct connection_struct connection;
39
40 void exithandler(void)
41 {
42 if(kv)
43 freekeyvalues(kv);
44 if (ifacefile)
45 fclose(ifacefile);
46 }
47
48 void usage(void)
49 {
50 #ifdef ovpndebug
51 printf("Wrapper for OpenVPN %s-debug\n", WRAPPERVERSION);
52 #else
53 printf("Wrapper for OpenVPN %s\n", WRAPPERVERSION);
54 #endif
55 printf("openvpnctrl <option>\n");
56 printf(" Valid options are:\n");
57 printf(" -s --start\n");
58 printf(" starts OpenVPN (implicitly creates chains and firewall rules)\n");
59 printf(" -k --kill\n");
60 printf(" kills/stops OpenVPN\n");
61 printf(" -r --restart\n");
62 printf(" restarts OpenVPN (implicitly creates chains and firewall rules)\n");
63 printf(" -d --display\n");
64 printf(" displays OpenVPN status to syslog\n");
65 printf(" -fwr --firewall-rules\n");
66 printf(" removes current OpenVPN chains and rules and resets them according to the config\n");
67 printf(" -sdo --start-daemon-only\n");
68 printf(" starts OpenVPN daemon only\n");
69 printf(" -ccr --create-chains-and-rules\n");
70 printf(" creates chains and rules for OpenVPN\n");
71 printf(" -dcr --delete-chains-and-rules\n");
72 printf(" removes all chains for OpenVPN\n");
73 exit(1);
74 }
75
76 connection *getConnections() {
77 FILE *fp = NULL;
78
79 if (!(fp = fopen(CONFIG_ROOT "/ovpn/ovpnconfig", "r"))) {
80 fprintf(stderr, "Could not open openvpn n2n configuration file.\n");
81 exit(1);
82 }
83
84 char line[STRING_SIZE] = "";
85 char *result;
86 int count;
87 connection *conn_first = NULL;
88 connection *conn_last = NULL;
89 connection *conn_curr;
90
91 while ((fgets(line, STRING_SIZE, fp) != NULL)) {
92 if (line[strlen(line) - 1] == '\n')
93 line[strlen(line) - 1] = '\0';
94
95 conn_curr = (connection *)malloc(sizeof(connection));
96 memset(conn_curr, 0, sizeof(connection));
97
98 if (conn_first == NULL) {
99 conn_first = conn_curr;
100 } else {
101 conn_last->next = conn_curr;
102 }
103 conn_last = conn_curr;
104
105 count = 0;
106 result = strtok(line, ",");
107 while (result) {
108 if (count == 2) {
109 strcpy(conn_curr->name, result);
110 } else if (count == 4) {
111 strcpy(conn_curr->type, result);
112 } else if (count == 12) {
113 strcpy(conn_curr->proto, result);
114 } else if (count == 13) {
115 conn_curr->port = atoi(result);
116 }
117
118 result = strtok(NULL, ",");
119 count++;
120 }
121 }
122
123 fclose(fp);
124
125 return conn_first;
126 }
127
128 int readPidFile(const char *pidfile) {
129 FILE *fp = fopen(pidfile, "r");
130 if (fp == NULL) {
131 fprintf(stderr, "PID file not found: '%s'\n", pidfile);
132 exit(1);
133 }
134
135 int pid = 0;
136 fscanf(fp, "%d", &pid);
137 fclose(fp);
138
139 return pid;
140 }
141
142 void ovpnInit(void) {
143
144 // Read OpenVPN configuration
145 kv = initkeyvalues();
146 if (!readkeyvalues(kv, CONFIG_ROOT "/ovpn/settings")) {
147 fprintf(stderr, "Cannot read ovpn settings\n");
148 exit(1);
149 }
150
151 if (!findkey(kv, "ENABLED", enablered)) {
152 fprintf(stderr, "Cannot read ENABLED\n");
153 exit(1);
154 }
155
156 if (!findkey(kv, "ENABLED_BLUE", enableblue)){
157 fprintf(stderr, "Cannot read ENABLED_BLUE\n");
158 exit(1);
159 }
160
161 if (!findkey(kv, "ENABLED_ORANGE", enableorange)){
162 fprintf(stderr, "Cannot read ENABLED_ORANGE\n");
163 exit(1);
164 }
165 freekeyvalues(kv);
166
167 // read interface settings
168
169 // details for the red int
170 memset(redif, 0, STRING_SIZE);
171 if ((ifacefile = fopen(CONFIG_ROOT "/red/iface", "r")))
172 {
173 if (fgets(redif, STRING_SIZE, ifacefile))
174 {
175 if (redif[strlen(redif) - 1] == '\n')
176 redif[strlen(redif) - 1] = '\0';
177 }
178 fclose (ifacefile);
179 ifacefile = NULL;
180
181 if (!VALID_DEVICE(redif))
182 {
183 memset(redif, 0, STRING_SIZE);
184 }
185 }
186
187 kv=initkeyvalues();
188 if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings"))
189 {
190 fprintf(stderr, "Cannot read ethernet settings\n");
191 exit(1);
192 }
193
194 if (strcmp(enableblue, "on")==0){
195 if (!findkey(kv, "BLUE_DEV", blueif)){
196 fprintf(stderr, "Cannot read BLUE_DEV\n");
197 exit(1);
198 }
199 }
200 if (strcmp(enableorange, "on")==0){
201 if (!findkey(kv, "ORANGE_DEV", orangeif)){
202 fprintf(stderr, "Cannot read ORNAGE_DEV\n");
203 exit(1);
204 }
205 }
206 freekeyvalues(kv);
207 }
208
209 void executeCommand(char *command) {
210 #ifdef ovpndebug
211 printf(strncat(command, "\n", 2));
212 #endif
213 safe_system(strncat(command, " >/dev/null 2>&1", 17));
214 }
215
216 void setChainRules(char *chain, char *interface, char *protocol, char *port)
217 {
218 char str[STRING_SIZE];
219
220 sprintf(str, "/sbin/iptables -A %sINPUT -i %s -p %s --dport %s -j ACCEPT", chain, interface, protocol, port);
221 executeCommand(str);
222 sprintf(str, "/sbin/iptables -A %sINPUT -i tun+ -j ACCEPT", chain);
223 executeCommand(str);
224 sprintf(str, "/sbin/iptables -A %sFORWARD -i tun+ -j ACCEPT", chain);
225 executeCommand(str);
226 }
227
228 void flushChain(char *chain) {
229 char str[STRING_SIZE];
230
231 sprintf(str, "/sbin/iptables -F %sINPUT", chain);
232 executeCommand(str);
233 sprintf(str, "/sbin/iptables -F %sFORWARD", chain);
234 executeCommand(str);
235 safe_system(str);
236 }
237
238 void deleteChainReference(char *chain) {
239 char str[STRING_SIZE];
240
241 sprintf(str, "/sbin/iptables -D INPUT -j %sINPUT", chain);
242 executeCommand(str);
243 safe_system(str);
244 sprintf(str, "/sbin/iptables -D FORWARD -j %sFORWARD", chain);
245 executeCommand(str);
246 safe_system(str);
247 }
248
249 void deleteChain(char *chain) {
250 char str[STRING_SIZE];
251
252 sprintf(str, "/sbin/iptables -X %sINPUT", chain);
253 executeCommand(str);
254 sprintf(str, "/sbin/iptables -X %sFORWARD", chain);
255 executeCommand(str);
256 }
257
258 void deleteAllChains(void) {
259 // not an elegant solution, but to avoid timing problems with undeleted chain references
260 deleteChainReference(OVPNRED);
261 deleteChainReference(OVPNBLUE);
262 deleteChainReference(OVPNORANGE);
263 flushChain(OVPNRED);
264 flushChain(OVPNBLUE);
265 flushChain(OVPNORANGE);
266 deleteChain(OVPNRED);
267 deleteChain(OVPNBLUE);
268 deleteChain(OVPNORANGE);
269 }
270
271 void createChainReference(char *chain) {
272 char str[STRING_SIZE];
273 sprintf(str, "/sbin/iptables -I INPUT %s -j %sINPUT", "14", chain);
274 executeCommand(str);
275 sprintf(str, "/sbin/iptables -I FORWARD %s -j %sFORWARD", "12", chain);
276 executeCommand(str);
277 }
278
279 void createChain(char *chain) {
280 char str[STRING_SIZE];
281 sprintf(str, "/sbin/iptables -N %sINPUT", chain);
282 executeCommand(str);
283 sprintf(str, "/sbin/iptables -N %sFORWARD", chain);
284 executeCommand(str);
285 }
286
287 void createAllChains(void) {
288 // create chain and chain references
289 if (!strcmp(enableorange, "on")) {
290 if (strlen(orangeif)) {
291 createChain(OVPNORANGE);
292 createChainReference(OVPNORANGE);
293 } else {
294 fprintf(stderr, "OpenVPN enabled on orange but no orange interface found\n");
295 //exit(1);
296 }
297 }
298
299 if (!strcmp(enableblue, "on")) {
300 if (strlen(blueif)) {
301 createChain(OVPNBLUE);
302 createChainReference(OVPNBLUE);
303 } else {
304 fprintf(stderr, "OpenVPN enabled on blue but no blue interface found\n");
305 //exit(1);
306 }
307 }
308
309 if (!strcmp(enablered, "on")) {
310 if (strlen(redif)) {
311 createChain(OVPNRED);
312 createChainReference(OVPNRED);
313 } else {
314 fprintf(stderr, "OpenVPN enabled on red but no red interface found\n");
315 //exit(1);
316 }
317 }
318 }
319
320 void setFirewallRules(void) {
321 char protocol[STRING_SIZE] = "";
322 char dport[STRING_SIZE] = "";
323 char dovpnip[STRING_SIZE] = "";
324
325 kv = initkeyvalues();
326 if (!readkeyvalues(kv, CONFIG_ROOT "/ovpn/settings"))
327 {
328 fprintf(stderr, "Cannot read ovpn settings\n");
329 exit(1);
330 }
331
332 /* we got one device, so lets proceed further */
333 if (!findkey(kv, "DDEST_PORT", dport)){
334 fprintf(stderr, "Cannot read DDEST_PORT\n");
335 exit(1);
336 }
337
338 if (!findkey(kv, "DPROTOCOL", protocol)){
339 fprintf(stderr, "Cannot read DPROTOCOL\n");
340 exit(1);
341 }
342
343 if (!findkey(kv, "VPN_IP", dovpnip)){
344 fprintf(stderr, "Cannot read VPN_IP\n");
345 // exit(1); step further as we don't need an ip
346 }
347 freekeyvalues(kv);
348
349 // Flush all chains.
350 flushChain(OVPNRED);
351 flushChain(OVPNBLUE);
352 flushChain(OVPNORANGE);
353
354 // set firewall rules
355 if (!strcmp(enablered, "on") && strlen(redif))
356 setChainRules(OVPNRED, redif, protocol, dport);
357 if (!strcmp(enableblue, "on") && strlen(blueif))
358 setChainRules(OVPNBLUE, blueif, protocol, dport);
359 if (!strcmp(enableorange, "on") && strlen(orangeif))
360 setChainRules(OVPNORANGE, orangeif, protocol, dport);
361
362 // read connection configuration
363 connection *conn = getConnections();
364
365 // set firewall rules for n2n connections
366 char command[STRING_SIZE];
367 while (conn != NULL) {
368 if (strcmp(conn->type, "net") == 0) {
369 sprintf(command, "/sbin/iptables -A %sINPUT -i %s -p %s --dport %d -j ACCEPT",
370 OVPNRED, redif, conn->proto, conn->port);
371 executeCommand(command);
372 }
373
374 conn = conn->next;
375 }
376 }
377
378 void stopDaemon(void) {
379 char command[STRING_SIZE];
380
381 int pid = readPidFile("/var/run/openvpn.pid");
382 if (!pid > 0) {
383 exit(1);
384 }
385
386 fprintf(stderr, "Killing PID %d.\n", pid);
387 kill(pid, SIGTERM);
388
389 snprintf(command, STRING_SIZE - 1, "/bin/rm -f /var/run/openvpn.pid");
390 executeCommand(command);
391 }
392
393 void startDaemon(void) {
394 char command[STRING_SIZE];
395
396 if (!((strcmp(enablered, "on")==0) || (strcmp(enableblue, "on")==0) || (strcmp(enableorange, "on")==0))){
397 fprintf(stderr, "OpenVPN is not enabled on any interface\n");
398 exit(1);
399 } else {
400 snprintf(command, STRING_SIZE-1, "/sbin/modprobe tun");
401 executeCommand(command);
402 snprintf(command, STRING_SIZE-1, "/usr/sbin/openvpn --config /var/ipfire/ovpn/server.conf");
403 executeCommand(command);
404 }
405 }
406
407 void startNet2Net(char *name) {
408 connection *conn = NULL;
409 connection *conn_iter;
410
411 conn_iter = getConnections();
412
413 while (conn_iter) {
414 if ((strcmp(conn_iter->type, "net") == 0) && (strcmp(conn_iter->name, name) == 0)) {
415 conn = conn_iter;
416 break;
417 }
418 conn_iter = conn_iter->next;
419 }
420
421 if (conn == NULL) {
422 fprintf(stderr, "Connection not found.\n");
423 exit(1);
424 }
425
426 char configfile[STRING_SIZE];
427 snprintf(configfile, STRING_SIZE - 1, CONFIG_ROOT "/ovpn/n2nconf/%s/%s.conf",
428 conn->name, conn->name);
429
430 FILE *fp = fopen(configfile, "r");
431 if (fp == NULL) {
432 fprintf(stderr, "Could not find configuration file for connection '%s' at '%s'.\n",
433 conn->name, configfile);
434 exit(2);
435 }
436 fclose(fp);
437
438 // Make sure all firewall rules are up to date.
439 setFirewallRules();
440
441 char command[STRING_SIZE];
442 sprintf(command, "/usr/sbin/openvpn --config %s", configfile);
443 executeCommand(command);
444 }
445
446 void killNet2Net(char *name) {
447 connection *conn = NULL;
448 connection *conn_iter;
449
450 conn_iter = getConnections();
451
452 while (conn_iter) {
453 if (strcmp(conn_iter->name, name) == 0) {
454 conn = conn_iter;
455 break;
456 }
457 conn_iter = conn_iter->next;
458 }
459
460 if (conn == NULL) {
461 fprintf(stderr, "Connection not found.\n");
462 exit(1);
463 }
464
465 char pidfile[STRING_SIZE];
466 snprintf(pidfile, STRING_SIZE - 1, "/var/run/%sn2n.pid", conn->name);
467
468 int pid = readPidFile(pidfile);
469 if (!pid > 0) {
470 exit(1);
471 }
472
473 fprintf(stderr, "Killing PID %d.\n", pid);
474 kill(pid, SIGTERM);
475
476 char command[STRING_SIZE];
477 snprintf(command, STRING_SIZE - 1, "/bin/rm -f %s", pidfile);
478 executeCommand(command);
479
480 exit(0);
481 }
482
483 void displayopenvpn(void) {
484 char command[STRING_SIZE];
485
486 snprintf(command, STRING_SIZE - 1, "/bin/killall -sSIGUSR2 openvpn");
487 executeCommand(command);
488 }
489
490 int main(int argc, char *argv[]) {
491 if (!(initsetuid()))
492 exit(1);
493 if(argc < 2)
494 usage();
495
496 if(argc == 3) {
497 ovpnInit();
498
499 if( (strcmp(argv[1], "-sn2n") == 0) || (strcmp(argv[1], "--start-net-2-net") == 0) ) {
500 startNet2Net(argv[2]);
501 return 0;
502 }
503 else if( (strcmp(argv[1], "-kn2n") == 0) || (strcmp(argv[1], "--kill-net-2-net") == 0) ) {
504 killNet2Net(argv[2]);
505 return 0;
506 } else {
507 usage();
508 return 1;
509 }
510 }
511 else if(argc == 2) {
512 if( (strcmp(argv[1], "-k") == 0) || (strcmp(argv[1], "--kill") == 0) ) {
513 stopDaemon();
514 return 0;
515 }
516 else if( (strcmp(argv[1], "-d") == 0) || (strcmp(argv[1], "--display") == 0) ) {
517 displayopenvpn();
518 return 0;
519 }
520 else if( (strcmp(argv[1], "-dcr") == 0) || (strcmp(argv[1], "--delete-chains-and-rules") == 0) ) {
521 deleteAllChains();
522 return 0;
523 }
524 else {
525 ovpnInit();
526
527 if( (strcmp(argv[1], "-s") == 0) || (strcmp(argv[1], "--start") == 0) ) {
528 deleteAllChains();
529 createAllChains();
530 setFirewallRules();
531 startDaemon();
532 return 0;
533 }
534 else if( (strcmp(argv[1], "-sdo") == 0) || (strcmp(argv[1], "--start-daemon-only") == 0) ) {
535 startDaemon();
536 return 0;
537 }
538 else if( (strcmp(argv[1], "-r") == 0) || (strcmp(argv[1], "--restart") == 0) ) {
539 stopDaemon();
540 deleteAllChains();
541 createAllChains();
542 setFirewallRules();
543 startDaemon();
544 return 0;
545 }
546 else if( (strcmp(argv[1], "-fwr") == 0) || (strcmp(argv[1], "--firewall-rules") == 0) ) {
547 deleteAllChains();
548 createAllChains();
549 setFirewallRules();
550 return 0;
551 }
552 else if( (strcmp(argv[1], "-ccr") == 0) || (strcmp(argv[1], "--create-chains-and-rules") == 0) ) {
553 createAllChains();
554 setFirewallRules();
555 return 0;
556 }
557 else {
558 usage();
559 return 0;
560 }
561 }
562 }
563 else {
564 usage();
565 return 0;
566 }
567 return 0;
568 }
569