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