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