Skip to content

Commit

Permalink
Initial commit of lwipovpn
Browse files Browse the repository at this point in the history
  • Loading branch information
schwabe committed Sep 16, 2024
1 parent 2942142 commit 23c9d18
Show file tree
Hide file tree
Showing 12 changed files with 1,663 additions and 0 deletions.
37 changes: 37 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
name: CI

on:
push:
pull_request:

jobs:
build:
strategy:
matrix:
os: [ ubuntu-20.04, ubuntu-22.04, ubuntu-24.04 ]
compiler: [clang, gcc]
installdeps: 'sudo apt install -y ninja-build cmake'
include:
- os: macos-latest
installdeps: 'brew install cmake'
compiler: clang
runs-on: ${{matrix.os}}
name: "${{matrix.os}} - ${{matrix.compiler}}"

env:
CC: ${{ matrix.compiler }}
LSAN_OPTIONS: verbosity=1:log_threads=1

steps:
- uses: actions/checkout@v4
with:
submodules: recursive

- name: Install deps
run: ${{matrix.installdeps }}

- name: Run cmake
run: cmake -B lwipovpn-build

- name: Build with cmake
run: cmake --build lwipovpn-build
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
cmake-build-*
70 changes: 70 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
cmake_minimum_required(VERSION 3.14)

include(CheckSymbolExists)

set (CMAKE_CONFIGURATION_TYPES "Debug;Release;ASAN")

# AddressSanitize - use CXX=clang++ CC=clang cmake -DCMAKE_BUILD_TYPE=asan to build with ASAN
set(CMAKE_C_FLAGS_ASAN
"-fsanitize=address,undefined -fno-sanitize-recover=all -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1"
CACHE STRING "Flags used by the C compiler during AddressSanitizer builds."
FORCE)
set(CMAKE_CXX_FLAGS_ASAN
"-fsanitize=address,undefined -fno-sanitize-recover=all -fno-optimize-sibling-calls -fsanitize-address-use-after-scope -fno-omit-frame-pointer -g -O1"
CACHE STRING "Flags used by the C++ compiler during AddressSanitizer builds."
FORCE)

project(lwipovpn)

set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED TRUE)

set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lwip)
set(LWIP_CONTRIB_DIR ${LWIP_DIR}/contrib/)

set (LWIP_INCLUDE_DIRS
"${LWIP_DIR}/src/include"
"${LWIP_DIR}/contrib"
"${LWIP_DIR}/contrib/ports/unix/port/include"
"${CMAKE_CURRENT_SOURCE_DIR}/conf"
)

include(${LWIP_DIR}/src/Filelists.cmake)
include(${LWIP_DIR}/contrib/Filelists.cmake)
include(${LWIP_DIR}/contrib/ports/unix/Filelists.cmake)
include(${LWIP_DIR}/contrib/ports/CMakeCommon.cmake)

set (LWIP_DEFINITIONS LWIP_DEBUG=1)

set(LWIP_OVPN_INCLUDE_DIRS
"${CMAKE_CURRENT_SOURCE_DIR}/app"
"${CMAKE_CURRENT_SOURCE_DIR}/netif"
)

set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)

add_executable(lwipovpn
app/unixaf_app.c
netif/unixaf.c
netif/unixaf.h
netif/unixaf_host.c
netif/unixaf_host.h
)

# C doesn't seem to have a good easy to use random function. Use arc4random if available otherwise rand
check_symbol_exists(arc4random stdlib.h HAVE_ARC4RANDOM)

# we do not care about C90 compatibility in lwipovpn since OpenVPN itself requires C11
set(LWIP_COMPILER_FLAGS_OVPN ${LWIP_COMPILER_FLAGS})
LIST(REMOVE_ITEM LWIP_COMPILER_FLAGS_OVPN $<$<COMPILE_LANGUAGE:C>:-Wc90-c99-compat>)
LIST(REMOVE_ITEM LWIP_COMPILER_FLAGS_OVPN -Waggregate-return)

target_include_directories(lwipovpn PRIVATE ${LWIP_INCLUDE_DIRS} ${LWIP_OVPN_INCLUDE_DIRS})
target_compile_options(lwipovpn PRIVATE ${LWIP_COMPILER_FLAGS_OVPN})
target_compile_definitions(lwipovpn PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
if (NOT "${HAVE_ARC4RANDOM}")
target_compile_definitions(lwipovpn PRIVATE -DARC4RANDOM_MISSING)
endif()
target_link_libraries(lwipovpn PRIVATE ${LWIP_SANITIZER_LIBS} lwipcontribexamples lwipcontribapps lwipcontribaddons lwipallapps lwipcontribportunix lwipcore lwipmbedtls)
target_link_libraries(lwipovpn PRIVATE Threads::Threads)
26 changes: 26 additions & 0 deletions COPYING
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Copyright (c) 2001, 2002 Swedish Institute of Computer Science.
Copyright (c) 2024 Arne Schwabe
All rights reserved.

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. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.

77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
OpenVPN lwipovpn tun/tap emulator
=================================
Overview
--------
This is a small helper tool based on [lwIP - A Lightweight TCP/IP stack](https://savannah.nongnu.org/projects/lwip/)
to emulate a tun/tap device in userspace without having an effect on the system that the lwip is running on.

This allows:

- testing a VPN connection without root
- pinging the connected client
- running tests against the client and the lwip stack
- using lwip example applications
- lwip http server
- lwip iperf server
- ...
- better automated testing

Features
--------
- IPv4 Support
- IPv6 Support
- automatic configuration of IPv4 and IPv6 addresses
- tap or tun emulation


Enabled apps
------------
lwip comes a number of demo/default apps. lwipovpn has enabled most of them to be helpful in testing. Further apps
can be enabled/implemented to allow even more testing.

- netio (https://www.nwlab.net/art/netio/netio.html)
- iperf 2 (https://iperf.fr/)
- http server
- shell (a simple shell that can be used with telnet to make some network diagnostics)
- tcp echo (port 7)
- udp echo (port 7)
-

Limitations
-----------
- Data through is limited. Iperf performance is at 20 MBit/s. This is not a problem for the indented purpose of
this tool which is for testing.
- Windows port is currently missing. It should be possible to use pipes instead of a socketpair with
AF_UNIX/SOCK_DGRAM to support Windows. This might also require adding a length header to ensure that always
full packets are read/written.

Building
--------
This project uses the CMake build system.

cmake -B lwipovpnbuild -S lwipovpn
cmake --build lwipovpnbuild

This should result in a `lwipovpnbuild/lwipovpn` binary that can be used with OpenVPN master and
OpenVPN 2.7.x like this:

openvpn --config client.ovpn --dev-node unix:lwipovpnbuild/lwipovpn

Implementation
--------------
The OpenVPN process will call `(socketpair(AF_UNIX, SOCK_DGRAM, 0, fds)` for connection between OpenVPN and lwipovpn
and execute ovpnlwip and pass the second fd to the process. The rest of the configuration is passed as environment
variables.
- TUNTAP_SOCKET_FD: the fd number of the AF_UNIX socket
- TUN_UNIXAF_PATH: alternative to TUNTAP_SOCKET_FD containing a unix domain socket file path.
- TUNTAP_DEV_TYPE: the type of device to emulate: tap or tun
- TUNTAP_MTU: MTU of the emulated devices
- ifconfig_local, ifconfig_netmask, ifconfig_remote, ifconfig_ipv6_local, ifconfig_ipv6_netbits as described in the
openvpn manual page.

Both the OpenVPN --dev-node unix: and the lwipovpn can be used for other purposes but especially lwipovpn is currently
very OpenVPN specific as it uses the OpenVPN environment variables names.

License
-------
This tool is under the same (3-Clause BSD License)[COPYING] as lwIP itself.
65 changes: 65 additions & 0 deletions app/afunix_config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* Additional settings for the afunix app.
* Copy this to lwipcfg.h and make the config changes you need.
*/

/* configuration for this port, not used */
#define PPP_USERNAME "Admin"
#define PPP_PASSWORD "pass"



/* remember to change this MAC address to suit your needs!
the last octet will be increased by netif->num for each netif */
#define LWIP_MAC_ADDR_BASE {0x00,0x01,0x02,0x03,0x04,0x05}

/* #define USE_SLIPIF 0 */
/* #define SIO_USE_COMPORT 0 */
#ifdef USE_SLIPIF
#if USE_SLIPIF
#define LWIP_PORT_INIT_SLIP1_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 2)
#define LWIP_PORT_INIT_SLIP1_GW(addr) IP4_ADDR((addr), 192, 168, 2, 1)
#define LWIP_PORT_INIT_SLIP1_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0)
#if USE_SLIPIF > 1
#define LWIP_PORT_INIT_SLIP2_IPADDR(addr) IP4_ADDR((addr), 192, 168, 2, 1)
#define LWIP_PORT_INIT_SLIP2_GW(addr) IP4_ADDR((addr), 0, 0, 0, 0)
#define LWIP_PORT_INIT_SLIP2_NETMASK(addr) IP4_ADDR((addr), 255, 255, 255, 0)*/
#endif /* USE_SLIPIF > 1 */
#endif /* USE_SLIPIF */
#endif /* USE_SLIPIF */

/* configuration for applications */

#define LWIP_CHARGEN_APP 0
#define LWIP_DNS_APP 0
#define LWIP_HTTPD_APP 1
/* Set this to 1 to use the netconn http server,
* otherwise the raw api server will be used. */
#define LWIP_HTTPD_APP_NETCONN 0
#define LWIP_HTTPD_EXAMPLE_CUSTOMFILES_ROOTDIR 1
#define LWIP_HTTPD_EXAMPLE_CGI_SIMPLE 0
#define LWIP_HTTPD_EXAMPLE_SSI_SIMPLE 0
#define LWIP_NETBIOS_APP 0
#define LWIP_NETIO_APP 1
#define LWIP_MDNS_APP 0
#define LWIP_MQTT_APP 0
#define LWIP_PING_APP 0
#define LWIP_RTP_APP 0
#define LWIP_SHELL_APP 1
#define LWIP_SNMP_APP 1
#define LWIP_SNTP_APP 1
#define LWIP_SOCKET_EXAMPLES_APP 0
#define LWIP_TCPECHO_APP 1
/* Set this to 1 to use the netconn tcpecho server,
* otherwise the raw api server will be used. */
/*#define LWIP_TCPECHO_APP_NETCONN */
#define LWIP_TFTP_APP 0
#define LWIP_TFTP_CLIENT_APP 0
#define LWIP_UDPECHO_APP 1
#define LWIP_LWIPERF_APP 1

#define USE_DHCP 0
/*#define USE_AUTOIP 1*/

/* define this to your custom application-init function */
/* #define LWIP_APP_INIT my_app_init() */
Loading

0 comments on commit 23c9d18

Please sign in to comment.