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