[PATCH] tools: Add ovpn application

  • From: "Sander Vrijders" <dmarc-noreply@xxxxxxxxxxxxx> (Redacted sender "sander" for DMARC)
  • To: ouroboros@xxxxxxxxxxxxx
  • Date: Sat, 20 Oct 2018 15:03:58 +0200

This adds the ovpn application which allows to send TCP/IP traffic
over Ouroboros. This is done by opening a TUN interface and allocating
a flow to another ovpn application so that applications using TCP/IP
can be used over Ouroboros as well.

Signed-off-by: Sander Vrijders <sander@xxxxxxxxxxxxxxx>
---
 src/tools/CMakeLists.txt      |   3 +
 src/tools/ovpn/CMakeLists.txt |  21 +++
 src/tools/ovpn/ovpn.c         | 275 ++++++++++++++++++++++++++++++++++
 3 files changed, 299 insertions(+)
 create mode 100644 src/tools/ovpn/CMakeLists.txt
 create mode 100644 src/tools/ovpn/ovpn.c

diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index b81e543..d7a4d17 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -3,3 +3,6 @@ add_subdirectory(ocbr)
 add_subdirectory(oecho)
 add_subdirectory(oping)
 add_subdirectory(operf)
+if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
+  add_subdirectory(ovpn)
+endif ()
diff --git a/src/tools/ovpn/CMakeLists.txt b/src/tools/ovpn/CMakeLists.txt
new file mode 100644
index 0000000..f3a2cac
--- /dev/null
+++ b/src/tools/ovpn/CMakeLists.txt
@@ -0,0 +1,21 @@
+include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+include_directories(${CMAKE_CURRENT_BINARY_DIR})
+
+include_directories(${CMAKE_SOURCE_DIR}/include)
+include_directories(${CMAKE_BINARY_DIR}/include)
+
+get_filename_component(CURRENT_SOURCE_PARENT_DIR
+  ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
+
+include_directories(${CURRENT_SOURCE_PARENT_DIR})
+
+set(SOURCE_FILES
+  # Add source files here
+  ovpn.c
+  )
+
+add_executable(ovpn ${SOURCE_FILES})
+
+target_link_libraries(ovpn LINK_PUBLIC ouroboros-dev)
+
+install(TARGETS ovpn RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
diff --git a/src/tools/ovpn/ovpn.c b/src/tools/ovpn/ovpn.c
new file mode 100644
index 0000000..8422243
--- /dev/null
+++ b/src/tools/ovpn/ovpn.c
@@ -0,0 +1,275 @@
+/*
+ * Ouroboros - Copyright (C) 2016 - 2018
+ *
+ * Ouroboros VPN
+ *
+ *    Dimitri Staessens <dimitri.staessens@xxxxxxxx>
+ *    Sander Vrijders   <sander.vrijders@xxxxxxxx>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define _POSIX_C_SOURCE 200109L
+
+#include <ouroboros/dev.h>
+
+#include <stdio.h>
+#include <pthread.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <signal.h>
+
+#define BUF_SIZE 4096
+
+int t_fd;
+int o_fd;
+
+static void usage(void)
+{
+        printf("Usage: ovpn [OPTION]...\n"
+               "Sends TCP/IP traffic over Ouroboros\n\n"
+               "  -n, --name                Run as client, name of ovpn "
+               "server to connect to\n"
+               "  -i, --ip                  IP address to give to TUN device\n"
+               "  -m, --mask                Subnet mask to give to TUN 
device\n"
+               "\n"
+               "      --help                Display this help text and 
exit\n");
+}
+
+static int tun_open(char *   dev,
+                    uint32_t ip,
+                    uint32_t mask)
+{
+        struct ifreq         ifr;
+        int                  fd;
+        int                  s;
+        int                  ret;
+        char *               clonedev = "/dev/net/tun";
+        struct sockaddr_in * addr;
+
+        fd = open(clonedev, O_RDWR);
+        if (fd < 0)
+                return -1;
+
+        memset(&ifr, 0, sizeof(ifr));
+
+        ifr.ifr_flags = IFF_TUN;
+
+        ret = ioctl(fd, TUNSETIFF, (void *) &ifr);
+        if (ret < 0)
+                goto fail;
+
+        strcpy(dev, ifr.ifr_name);
+
+        /* Now get the i/f up and running. */
+        s = socket(AF_INET, SOCK_DGRAM, 0);
+        if (s < 0)
+                goto fail;
+
+        /* Set IP address. */
+        ifr.ifr_addr.sa_family = AF_INET;
+        addr = (struct sockaddr_in *) &ifr.ifr_addr;
+        addr->sin_addr.s_addr = ip;
+
+        if (ioctl(s, SIOCSIFADDR, &ifr))
+                goto fail;
+
+        /* Set subnet mask. */
+        addr->sin_addr.s_addr = mask;
+        if (ioctl(s, SIOCSIFNETMASK, &ifr))
+                goto fail;
+
+        /* Bring interface up */
+        if (ioctl(s, SIOCGIFFLAGS, &ifr))
+                goto fail;
+        ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
+        if (ioctl(s, SIOCSIFFLAGS, &ifr))
+                goto fail;
+
+        return fd;
+
+ fail:
+        close(fd);
+        return -1;
+}
+
+void * o_reader(void * o)
+{
+        char buf[BUF_SIZE];
+        int  len = 0;
+
+        (void) o;
+
+        while (true) {
+                len = flow_read(o_fd, buf, BUF_SIZE);
+                if (len <= 0) {
+                        printf("Bad ouroboros read.\n");
+                        continue;
+                }
+
+                if (write(t_fd, buf, len)) {
+                        printf("Bad tun write.\n");
+                        continue;
+                }
+        }
+}
+
+void * t_reader(void * o)
+{
+        char buf[BUF_SIZE];
+        int  len = 0;
+
+        (void) o;
+
+        while (true) {
+                len = read(t_fd, buf, BUF_SIZE);
+                if (len <= 0) {
+                        printf("Bad tun read.\n");
+                        continue;
+                }
+
+                if (flow_write(o_fd, buf, len)) {
+                        printf("Bad ouroboros write.\n");
+                        continue;
+                }
+        }
+}
+
+int main(int     argc,
+         char ** argv)
+{
+        char *    name = NULL;
+        uint32_t  ip   = 0;
+        uint32_t  mask = 0;
+        char      dev[IFNAMSIZ];
+        pthread_t t_thr;
+        pthread_t o_thr;
+        sigset_t  sigset;
+        int       sig;
+
+        sigemptyset(&sigset);
+        sigaddset(&sigset, SIGINT);
+        sigaddset(&sigset, SIGQUIT);
+        sigaddset(&sigset, SIGHUP);
+        sigaddset(&sigset, SIGTERM);
+
+        pthread_sigmask(SIG_BLOCK, &sigset, NULL);
+
+        argc--;
+        argv++;
+
+        if (geteuid() != 0) {
+                printf("ovpn must be run as root.\n");
+                exit(EXIT_FAILURE);
+        }
+
+        while (argc > 0) {
+                if (strcmp(*argv, "-i") == 0 ||
+                    strcmp(*argv, "--ip") == 0) {
+                        if (inet_pton(AF_INET, *(++argv), &ip) != 1)
+                                goto unknown_param;
+                        --argc;
+                } else if (strcmp(*argv, "-m") == 0 ||
+                           strcmp(*argv, "--mask") == 0) {
+                        if (inet_pton(AF_INET, *(++argv), &mask) != 1)
+                                goto unknown_param;
+                        --argc;
+                } else if (strcmp(*argv, "-n") == 0 ||
+                           strcmp(*argv, "--name") == 0) {
+                        name = *(++argv);
+                        --argc;
+                } else {
+                        goto fail;
+                }
+                argc--;
+                argv++;
+        }
+
+        if (ip == 0 || mask == 0)
+                goto fail;
+
+        t_fd = tun_open(dev, ip, mask);
+        if (t_fd < 0)
+                exit(EXIT_FAILURE);
+
+        printf("Tunnel device name is %s.\n", dev);
+
+        if (name != NULL) {
+                o_fd = flow_alloc(name, NULL, NULL);
+                if (o_fd < 0) {
+                        printf("Failed to allocate flow.\n");
+                        exit(EXIT_FAILURE);
+                }
+        } else {
+                o_fd = flow_accept(NULL, NULL);
+                if (o_fd < 0) {
+                        printf("Failed to accept flow.\n");
+                        exit(EXIT_FAILURE);
+                }
+        }
+
+        pthread_create(&o_thr, NULL, o_reader, NULL);
+        pthread_create(&t_thr, NULL, t_reader, NULL);
+
+        while (true) {
+                if (sigwait(&sigset, &sig) != 0) {
+                        printf("Bad signal\n.");
+                        continue;
+                }
+
+                printf("Shutting down...\n");
+                break;
+        }
+
+        pthread_cancel(o_thr);
+        pthread_cancel(t_thr);
+
+        pthread_join(o_thr, NULL);
+        pthread_join(t_thr, NULL);
+
+        pthread_sigmask(SIG_UNBLOCK, &sigset, NULL);
+
+        exit(EXIT_SUCCESS);
+
+ unknown_param:
+        printf("Unknown parameter for %s: \"%s\".\n", *argv, *(argv + 1));
+        exit(EXIT_FAILURE);
+ fail:
+        usage();
+        exit(EXIT_FAILURE);
+}
-- 
2.19.1


Other related posts: