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