]> git.ipfire.org Git - people/teissler/ipfire-2.x.git/blob - src/misc-progs/openvpnctrl.c
Merge branch 'master' into next
[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.1";
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(" -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");
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");
74 printf(" starts OpenVPN daemon only\n");
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
82 connection *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[STRING_SIZE] = "";
92 char *resultptr;
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;
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
128 if (count == 2) {
129 strcpy(conn_curr->name, result);
130 } else if (count == 4) {
131 strcpy(conn_curr->type, result);
132 } else if (count == 29) {
133 strcpy(conn_curr->proto, result);
134 } else if (count == 30) {
135 conn_curr->port = atoi(result);
136 }
137
138 count++;
139 }
140 }
141
142 fclose(fp);
143
144 return conn_first;
145 }
146
147 int 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
161 void 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
228 void 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
235 void setChainRules(char *chain, char *interface, char *protocol, char *port)
236 {
237 char str[STRING_SIZE];
238
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
247 void 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
257 void 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
268 void 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
277 void 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
290 void 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
298 void 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
306 void createAllChains(void) {
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);
315 }
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);
325 }
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);
335 }
336 }
337 }
338
339 void setFirewallRules(void) {
340 char protocol[STRING_SIZE] = "";
341 char dport[STRING_SIZE] = "";
342 char dovpnip[STRING_SIZE] = "";
343
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
368 // Flush all chains.
369 flushChain(OVPNRED);
370 flushChain(OVPNBLUE);
371 flushChain(OVPNORANGE);
372
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);
380
381 // read connection configuration
382 connection *conn = getConnections();
383
384 // set firewall rules for n2n connections
385 char command[STRING_SIZE];
386 while (conn != NULL) {
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
393 conn = conn->next;
394 }
395 }
396
397 void stopDaemon(void) {
398 char command[STRING_SIZE];
399
400 int pid = readPidFile("/var/run/openvpn.pid");
401 if (!pid > 0) {
402 exit(1);
403 }
404
405 fprintf(stderr, "Killing PID %d.\n", pid);
406 kill(pid, SIGTERM);
407
408 snprintf(command, STRING_SIZE - 1, "/bin/rm -f /var/run/openvpn.pid");
409 executeCommand(command);
410 }
411
412 void 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 {
419 snprintf(command, STRING_SIZE-1, "/sbin/modprobe tun");
420 executeCommand(command);
421 snprintf(command, STRING_SIZE-1, "/usr/sbin/openvpn --config /var/ipfire/ovpn/server.conf");
422 executeCommand(command);
423 }
424 }
425
426 void startNet2Net(char *name) {
427 connection *conn = NULL;
428 connection *conn_iter;
429
430 conn_iter = getConnections();
431
432 while (conn_iter) {
433 if ((strcmp(conn_iter->type, "net") == 0) && (strcmp(conn_iter->name, name) == 0)) {
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
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
457 // Make sure all firewall rules are up to date.
458 setFirewallRules();
459
460 char command[STRING_SIZE];
461 snprintf(command, STRING_SIZE-1, "/sbin/modprobe tun");
462 executeCommand(command);
463 snprintf(command, STRING_SIZE-1, "/usr/sbin/openvpn --config %s", configfile);
464 executeCommand(command);
465 }
466
467 void 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];
487 snprintf(pidfile, STRING_SIZE - 1, "/var/run/%sn2n.pid", conn->name);
488
489 int pid = readPidFile(pidfile);
490 if (!pid > 0) {
491 exit(1);
492 }
493
494 fprintf(stderr, "Killing PID %d.\n", pid);
495 kill(pid, SIGTERM);
496
497 char command[STRING_SIZE];
498 snprintf(command, STRING_SIZE - 1, "/bin/rm -f %s", pidfile);
499 executeCommand(command);
500
501 exit(0);
502 }
503
504 void startAllNet2Net() {
505 connection *conn = getConnections();
506
507 while(conn) {
508 startNet2Net(conn->name);
509 conn = conn->next;
510 }
511
512 exit(0);
513 }
514
515 void killAllNet2Net() {
516 connection *conn = getConnections();
517
518 while(conn) {
519 killNet2Net(conn->name);
520 conn = conn->next;
521 }
522
523 exit(0);
524 }
525
526 void displayopenvpn(void) {
527 char command[STRING_SIZE];
528
529 snprintf(command, STRING_SIZE - 1, "/bin/killall -sSIGUSR2 openvpn");
530 executeCommand(command);
531 }
532
533 int main(int argc, char *argv[]) {
534 if (!(initsetuid()))
535 exit(1);
536 if(argc < 2)
537 usage();
538
539 if(argc == 3) {
540 ovpnInit();
541
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) {
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 }
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 }
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 }
618 return 0;
619 }
620