X-Git-Url: http://git.ipfire.org/?a=blobdiff_plain;f=src%2Fmisc-progs%2Fopenvpnctrl.c;h=e366294b572ab796e54fc6deb196e920af27365d;hb=e0cdf670a3d79b6d607f7eade6d99743f5cd5769;hp=ddda6125d22490e08f7c75fc9d55df87da7e9b02;hpb=d4c8b6bec26d2b45112e129f99921558058c4b18;p=people%2Fteissler%2Fipfire-2.x.git diff --git a/src/misc-progs/openvpnctrl.c b/src/misc-progs/openvpnctrl.c index ddda6125d..e366294b5 100644 --- a/src/misc-progs/openvpnctrl.c +++ b/src/misc-progs/openvpnctrl.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include "setuid.h" #include "libsmooth.h" @@ -25,11 +27,17 @@ char enableorange[STRING_SIZE] = "off"; char OVPNRED[STRING_SIZE] = "OVPN"; char OVPNBLUE[STRING_SIZE] = "OVPN_BLUE_"; char OVPNORANGE[STRING_SIZE] = "OVPN_ORANGE_"; -char WRAPPERVERSION[STRING_SIZE] = "ipfire-2.1.2"; +char OVPNNAT[STRING_SIZE] = "OVPNNAT"; +char WRAPPERVERSION[STRING_SIZE] = "ipfire-2.2.3"; struct connection_struct { char name[STRING_SIZE]; + char type[STRING_SIZE]; char proto[STRING_SIZE]; + char status[STRING_SIZE]; + char local_subnet[STRING_SIZE]; + char transfer_subnet[STRING_SIZE]; + char role[STRING_SIZE]; int port; struct connection_struct *next; }; @@ -59,6 +67,12 @@ void usage(void) printf(" kills/stops OpenVPN\n"); printf(" -r --restart\n"); printf(" restarts OpenVPN (implicitly creates chains and firewall rules)\n"); + printf(" -sn2n --start-net-2-net\n"); + printf(" starts all net2net connections\n"); + printf(" you may pass a connection name to the switch to only start a specific one\n"); + printf(" -kn2n --kill-net-2-net\n"); + printf(" kills all net2net connections\n"); + printf(" you may pass a connection name to the switch to only start a specific one\n"); printf(" -d --display\n"); printf(" displays OpenVPN status to syslog\n"); printf(" -fwr --firewall-rules\n"); @@ -81,7 +95,8 @@ connection *getConnections() { } char line[STRING_SIZE] = ""; - char *result; + char result[STRING_SIZE] = ""; + char *resultptr; int count; connection *conn_first = NULL; connection *conn_last = NULL; @@ -102,17 +117,39 @@ connection *getConnections() { conn_last = conn_curr; count = 0; - result = strtok(line, ","); - while (result) { - if (count == 2) { + char *lineptr = &line; + while (1) { + if (*lineptr == NULL) + break; + + resultptr = result; + while (*lineptr != NULL) { + if (*lineptr == ',') { + lineptr++; + break; + } + *resultptr++ = *lineptr++; + } + *resultptr = '\0'; + + if (count == 1) { + strcpy(conn_curr->status, result); + } else if (count == 2) { strcpy(conn_curr->name, result); - } else if (count == 12) { + } else if (count == 4) { + strcpy(conn_curr->type, result); + } else if (count == 7) { + strcpy(conn_curr->role, result); + } else if (count == 9) { + strcpy(conn_curr->local_subnet, result); + } else if (count == 28) { + strcpy(conn_curr->transfer_subnet, result); + } else if (count == 29) { strcpy(conn_curr->proto, result); - } else if (count == 13) { + } else if (count == 30) { conn_curr->port = atoi(result); } - result = strtok(NULL, ","); count++; } } @@ -232,6 +269,13 @@ void flushChain(char *chain) { safe_system(str); } +void flushChainNAT(char *chain) { + char str[STRING_SIZE]; + + sprintf(str, "/sbin/iptables -t nat -F %s", chain); + executeCommand(str); +} + void deleteChainReference(char *chain) { char str[STRING_SIZE]; @@ -314,6 +358,85 @@ void createAllChains(void) { } } +char* calcTransferNetAddress(const connection* conn) { + char *subnetmask = strdup(conn->transfer_subnet); + char *address = strsep(&subnetmask, "/"); + + in_addr_t _address = inet_addr(address); + in_addr_t _subnetmask = inet_addr(subnetmask); + _address &= _subnetmask; + + if (strcmp(conn->role, "server") == 0) { + _address += 1 << 24; + } else if (strcmp(conn->role, "client") == 0) { + _address += 2 << 24; + } else { + goto ERROR; + } + + struct in_addr address_info; + address_info.s_addr = _address; + + return inet_ntoa(address_info); + +ERROR: + fprintf(stderr, "Could not determine transfer net address: %s\n", conn->name); + + free(address); + return NULL; +} + +char* getLocalSubnetAddress(const connection* conn) { + kv = initkeyvalues(); + if (!readkeyvalues(kv, CONFIG_ROOT "/ethernet/settings")) { + fprintf(stderr, "Cannot read ethernet settings\n"); + exit(1); + } + + const char *zones[] = {"GREEN", "BLUE", "ORANGE", NULL}; + char *zone = NULL; + + // Get net address of the local openvpn subnet. + char *subnetmask = strdup(conn->local_subnet); + char *address = strsep(&subnetmask, "/"); + + if ((address == NULL) || (subnetmask == NULL)) { + goto ERROR; + } + + in_addr_t _address = inet_addr(address); + in_addr_t _subnetmask = inet_addr(subnetmask); + + in_addr_t _netaddr = (_address & _subnetmask); + in_addr_t _broadcast = (_address | ~_subnetmask); + + char zone_address_key[STRING_SIZE]; + char zone_address[STRING_SIZE]; + in_addr_t zone_addr; + + int i = 0; + while (zones[i]) { + zone = zones[i++]; + snprintf(zone_address_key, STRING_SIZE, "%s_ADDRESS", zone); + + if (!findkey(kv, zone_address_key, zone_address)) + continue; + + zone_addr = inet_addr(zone_address); + if ((zone_addr > _netaddr) && (zone_addr < _broadcast)) { + freekeyvalues(kv); + + return strdup(zone_address); + } + } + +ERROR: + fprintf(stderr, "Could not determine local subnet address: %s\n", conn->name); + + freekeyvalues(kv); + return NULL; +} + void setFirewallRules(void) { char protocol[STRING_SIZE] = ""; char dport[STRING_SIZE] = ""; @@ -343,13 +466,11 @@ void setFirewallRules(void) { } freekeyvalues(kv); - // read connection configuration - connection *conn = getConnections(); - // Flush all chains. flushChain(OVPNRED); flushChain(OVPNBLUE); flushChain(OVPNORANGE); + flushChainNAT(OVPNNAT); // set firewall rules if (!strcmp(enablered, "on") && strlen(redif)) @@ -359,11 +480,30 @@ void setFirewallRules(void) { if (!strcmp(enableorange, "on") && strlen(orangeif)) setChainRules(OVPNORANGE, orangeif, protocol, dport); + // read connection configuration + connection *conn = getConnections(); + // set firewall rules for n2n connections - char *port; - while (conn) { - sprintf(port, "%d", conn->port); - setChainRules(OVPNRED, redif, conn->proto, port); + char command[STRING_SIZE]; + char *local_subnet_address = NULL; + char *transfer_subnet_address = NULL; + while (conn != NULL) { + if (strcmp(conn->type, "net") == 0) { + sprintf(command, "/sbin/iptables -A %sINPUT -i %s -p %s --dport %d -j ACCEPT", + OVPNRED, redif, conn->proto, conn->port); + executeCommand(command); + + local_subnet_address = getLocalSubnetAddress(conn); + transfer_subnet_address = calcTransferNetAddress(conn); + + if ((!local_subnet_address) || (!transfer_subnet_address)) + continue; + + snprintf(command, STRING_SIZE, "/sbin/iptables -t nat -A %s -s %s -j SNAT --to-source %s", + OVPNNAT, transfer_subnet_address, local_subnet_address); + executeCommand(command); + } + conn = conn->next; } } @@ -397,14 +537,14 @@ void startDaemon(void) { } } -void startNet2Net(char *name) { +int startNet2Net(char *name) { connection *conn = NULL; connection *conn_iter; conn_iter = getConnections(); while (conn_iter) { - if (strcmp(conn_iter->name, name) == 0) { + if ((strcmp(conn_iter->type, "net") == 0) && (strcmp(conn_iter->name, name) == 0)) { conn = conn_iter; break; } @@ -413,9 +553,16 @@ void startNet2Net(char *name) { if (conn == NULL) { fprintf(stderr, "Connection not found.\n"); - exit(1); + return 1; } + if (strcmp(conn->status, "on") != 0) { + fprintf(stderr, "Connection '%s' is not enabled.\n", conn->name); + return 1; + } + + fprintf(stderr, "Starting connection %s...\n", conn->name); + char configfile[STRING_SIZE]; snprintf(configfile, STRING_SIZE - 1, CONFIG_ROOT "/ovpn/n2nconf/%s/%s.conf", conn->name, conn->name); @@ -424,7 +571,7 @@ void startNet2Net(char *name) { if (fp == NULL) { fprintf(stderr, "Could not find configuration file for connection '%s' at '%s'.\n", conn->name, configfile); - exit(2); + return 2; } fclose(fp); @@ -432,11 +579,15 @@ void startNet2Net(char *name) { setFirewallRules(); char command[STRING_SIZE]; - sprintf(command, "/usr/sbin/openvpn --config %s", configfile); + snprintf(command, STRING_SIZE-1, "/sbin/modprobe tun"); executeCommand(command); + snprintf(command, STRING_SIZE-1, "/usr/sbin/openvpn --config %s", configfile); + executeCommand(command); + + return 0; } -void killNet2Net(char *name) { +int killNet2Net(char *name) { connection *conn = NULL; connection *conn_iter; @@ -452,7 +603,7 @@ void killNet2Net(char *name) { if (conn == NULL) { fprintf(stderr, "Connection not found.\n"); - exit(1); + return 1; } char pidfile[STRING_SIZE]; @@ -460,17 +611,64 @@ void killNet2Net(char *name) { int pid = readPidFile(pidfile); if (!pid > 0) { - exit(1); + fprintf(stderr, "Could not read pid file of connection %s.", conn->name); + return 1; } - fprintf(stderr, "Killing PID %d.\n", pid); + fprintf(stderr, "Killing connection %s (PID %d)...\n", conn->name, pid); kill(pid, SIGTERM); char command[STRING_SIZE]; snprintf(command, STRING_SIZE - 1, "/bin/rm -f %s", pidfile); executeCommand(command); - exit(0); + return 0; +} + +void startAllNet2Net() { + int exitcode = 0, _exitcode = 0; + + connection *conn = getConnections(); + + while(conn) { + /* Skip all connections that are not of type "net" or disabled. */ + if ((strcmp(conn->type, "net") != 0) || (strcmp(conn->status, "on") != 0)) { + conn = conn->next; + continue; + } + + _exitcode = startNet2Net(conn->name); + conn = conn->next; + + if (_exitcode > exitcode) { + exitcode = _exitcode; + } + } + + exit(exitcode); +} + +void killAllNet2Net() { + int exitcode = 0, _exitcode = 0; + + connection *conn = getConnections(); + + while(conn) { + /* Skip all connections that are not of type "net". */ + if (strcmp(conn->type, "net") != 0) { + conn = conn->next; + continue; + } + + _exitcode = killNet2Net(conn->name); + conn = conn->next; + + if (_exitcode > exitcode) { + exitcode = _exitcode; + } + } + + exit(exitcode); } void displayopenvpn(void) { @@ -487,6 +685,8 @@ int main(int argc, char *argv[]) { usage(); if(argc == 3) { + ovpnInit(); + if( (strcmp(argv[1], "-sn2n") == 0) || (strcmp(argv[1], "--start-net-2-net") == 0) ) { startNet2Net(argv[2]); return 0; @@ -522,6 +722,14 @@ int main(int argc, char *argv[]) { startDaemon(); return 0; } + else if( (strcmp(argv[1], "-sn2n") == 0) || (strcmp(argv[1], "--start-net-2-net") == 0) ) { + startAllNet2Net(); + return 0; + } + else if( (strcmp(argv[1], "-kn2n") == 0) || (strcmp(argv[1], "--kill-net-2-net") == 0) ) { + killAllNet2Net(); + return 0; + } else if( (strcmp(argv[1], "-sdo") == 0) || (strcmp(argv[1], "--start-daemon-only") == 0) ) { startDaemon(); return 0;