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