diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..7c9383a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,193 @@
+# Created by https://www.toptal.com/developers/gitignore/api/c,cmake,clion
+# Edit at https://www.toptal.com/developers/gitignore?templates=c,cmake,clion
+
+### C ###
+# Prerequisites
+*.d
+
+# Object files
+*.o
+*.ko
+*.obj
+*.elf
+
+# Linker output
+*.ilk
+*.map
+*.exp
+
+# Precompiled Headers
+*.gch
+*.pch
+
+# Libraries
+*.lib
+*.a
+*.la
+*.lo
+
+# Shared objects (inc. Windows DLLs)
+*.dll
+*.so
+*.so.*
+*.dylib
+
+# Executables
+*.exe
+*.out
+*.app
+*.i*86
+*.x86_64
+*.hex
+
+# Debug files
+*.dSYM/
+*.su
+*.idb
+*.pdb
+
+# Kernel Module Compile Results
+*.mod*
+*.cmd
+.tmp_versions/
+modules.order
+Module.symvers
+Mkfile.old
+dkms.conf
+
+### CLion ###
+# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
+# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
+
+# User-specific stuff
+.idea/**/workspace.xml
+.idea/**/tasks.xml
+.idea/**/usage.statistics.xml
+.idea/**/dictionaries
+.idea/**/shelf
+
+# AWS User-specific
+.idea/**/aws.xml
+
+# Generated files
+.idea/**/contentModel.xml
+
+# Sensitive or high-churn files
+.idea/**/dataSources/
+.idea/**/dataSources.ids
+.idea/**/dataSources.local.xml
+.idea/**/sqlDataSources.xml
+.idea/**/dynamic.xml
+.idea/**/uiDesigner.xml
+.idea/**/dbnavigator.xml
+
+# Gradle
+.idea/**/gradle.xml
+.idea/**/libraries
+
+# Gradle and Maven with auto-import
+# When using Gradle or Maven with auto-import, you should exclude module files,
+# since they will be recreated, and may cause churn. Uncomment if using
+# auto-import.
+# .idea/artifacts
+# .idea/compiler.xml
+# .idea/jarRepositories.xml
+# .idea/modules.xml
+# .idea/*.iml
+# .idea/modules
+# *.iml
+# *.ipr
+
+# CMake
+cmake-build-*/
+
+# Mongo Explorer plugin
+.idea/**/mongoSettings.xml
+
+# File-based project format
+*.iws
+
+# IntelliJ
+out/
+
+# mpeltonen/sbt-idea plugin
+.idea_modules/
+
+# JIRA plugin
+atlassian-ide-plugin.xml
+
+# Cursive Clojure plugin
+.idea/replstate.xml
+
+# SonarLint plugin
+.idea/sonarlint/
+
+# Crashlytics plugin (for Android Studio and IntelliJ)
+com_crashlytics_export_strings.xml
+crashlytics.properties
+crashlytics-build.properties
+fabric.properties
+
+# Editor-based Rest Client
+.idea/httpRequests
+
+# Android studio 3.1+ serialized cache file
+.idea/caches/build_file_checksums.ser
+
+### CLion Patch ###
+# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
+
+# *.iml
+# modules.xml
+# .idea/misc.xml
+# *.ipr
+
+# Sonarlint plugin
+# https://plugins.jetbrains.com/plugin/7973-sonarlint
+.idea/**/sonarlint/
+
+# SonarQube Plugin
+# https://plugins.jetbrains.com/plugin/7238-sonarqube-community-plugin
+.idea/**/sonarIssues.xml
+
+# Markdown Navigator plugin
+# https://plugins.jetbrains.com/plugin/7896-markdown-navigator-enhanced
+.idea/**/markdown-navigator.xml
+.idea/**/markdown-navigator-enh.xml
+.idea/**/markdown-navigator/
+
+# Cache file creation bug
+# See https://youtrack.jetbrains.com/issue/JBR-2257
+.idea/$CACHE_FILE$
+
+# CodeStream plugin
+# https://plugins.jetbrains.com/plugin/12206-codestream
+.idea/codestream.xml
+
+# Azure Toolkit for IntelliJ plugin
+# https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij
+.idea/**/azureSettings.xml
+
+### CMake ###
+CMakeLists.txt.user
+CMakeCache.txt
+CMakeFiles
+CMakeScripts
+Testing
+Makefile
+cmake_install.cmake
+install_manifest.txt
+compile_commands.json
+CTestTestfile.cmake
+_deps
+
+### CMake Patch ###
+# External projects
+*-prefix/
+
+# End of https://www.toptal.com/developers/gitignore/api/c,cmake,clion
+
+# CMake Doxygen
+CMakeDoxyfile.in
+CMakeDoxygenDefaults.cmake
+/tcpproxy
\ No newline at end of file
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..5e84c46
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lwip"]
+ path = lwip
+ url = https://git.savannah.nongnu.org/git/lwip.git
diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..79b3c94
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..bbfd58c
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/tcpproxy.iml b/.idea/tcpproxy.iml
new file mode 100644
index 0000000..f08604b
--- /dev/null
+++ b/.idea/tcpproxy.iml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..ed6ec8e
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..4ee89e8
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 3.25)
+
+project(tcpproxy C)
+
+set(LWIP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/lwip)
+set(LWIP_CONTRIB_DIR ${LWIP_DIR}/contrib)
+set (LWIP_INCLUDE_DIRS
+ "${LWIP_DIR}/src/include"
+ "${LWIP_CONTRIB_DIR}"
+ "${LWIP_CONTRIB_DIR}/ports/unix/port/include"
+ "${CMAKE_CURRENT_SOURCE_DIR}/src")
+
+
+include(${LWIP_DIR}/src/Filelists.cmake)
+include(${LWIP_DIR}/contrib/Filelists.cmake)
+include(${LWIP_DIR}/contrib/ports/unix/Filelists.cmake)
+
+set(CMAKE_C_STANDARD 11)
+
+find_library(LIBEVENT event_core)
+
+
+add_executable(tcpproxy src/main.c ${lwipcontribportunix_SRCS})
+target_include_directories(tcpproxy PRIVATE ${LWIP_INCLUDE_DIRS})
+target_compile_options(tcpproxy PRIVATE ${LWIP_COMPILER_FLAGS})
+target_compile_definitions(tcpproxy PRIVATE ${LWIP_DEFINITIONS} ${LWIP_MBEDTLS_DEFINITIONS})
+target_link_libraries(tcpproxy ${LWIP_SANITIZER_LIBS} lwipcontribexamples lwipcontribapps lwipcontribaddons lwipallapps lwipcontribportunix lwipcore lwipmbedtls ${LIBEVENT})
+
diff --git a/Dockerfile b/Dockerfile
index fde198f..da3f18e 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,18 @@
-FROM haproxy:lts
-ENV PORT=3890
-EXPOSE $PORT
-ADD haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg
+FROM debian:bookworm-slim AS builder
+RUN apt-get update && apt-get install -y build-essential cmake 'libevent-dev=2.1.*'
+COPY CMakeLists.txt /app/src/
+COPY NOTICE /app/src/
+COPY lwip /app/src/lwip/
+COPY src /app/src/src/
+RUN mkdir /app/build && cd /app/build && cmake /app/src && make && mv tcpproxy ..
+
+FROM debian:bookworm-slim
+RUN apt-get update && apt-get install -y --no-install-recommends openconnect libevent-core-2.1-7
+COPY --from=builder /app/tcpproxy /app/
+COPY --from=builder /app/src/NOTICE /app/
+COPY --from=builder /app/src/lwip/COPYING /app/
+COPY docker-entrypoint.sh /app/
+ARG HOST
+EXPOSE 1234
+USER nobody
+ENTRYPOINT ["/app/docker-entrypoint.sh"]
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..e0b2444
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,28 @@
+Copyright (c) 2023 Penn Mackintosh
+Adapted from [ocproxy](https://github.com/cernekee/ocproxy) to use upgrade LwIP, remove LDAP functionality
+Copyright (c) 2016 Google Inc.
+Copyright (c) 2012-2014 David Edmondson
+Copyright (c) 2012-2014 Kevin Cernekee
+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.
diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh
new file mode 100755
index 0000000..5de93ca
--- /dev/null
+++ b/docker-entrypoint.sh
@@ -0,0 +1,3 @@
+#!/bin/bash
+echo openconnect --script-tun --script "/app/tcpproxy -L 1234:$HOST" "$@"
+exec openconnect --script-tun --script "/app/tcpproxy -L 1234:$HOST" "$@"
diff --git a/haproxy.cfg b/haproxy.cfg
deleted file mode 100644
index cb38dca..0000000
--- a/haproxy.cfg
+++ /dev/null
@@ -1,11 +0,0 @@
-global
-
-defaults
- mode tcp
- timeout connect 5s
- timeout client 50s
- timeout server 50s
-
-listen tcp-in
- bind "0.0.0.0:${PORT}"
- server server1 "${TARGET}"
diff --git a/lwip b/lwip
new file mode 160000
index 0000000..e29870c
--- /dev/null
+++ b/lwip
@@ -0,0 +1 @@
+Subproject commit e29870c15e8bf28eac9c811dd236c474f3f2008f
diff --git a/src/lwipopts.h b/src/lwipopts.h
new file mode 100644
index 0000000..83d39a4
--- /dev/null
+++ b/src/lwipopts.h
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
+ * 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.
+ *
+ * This file is part of the lwIP TCP/IP stack.
+ *
+ * Author: Adam Dunkels
+ *
+ */
+#ifndef LWIP_LWIPOPTS_H
+#define LWIP_LWIPOPTS_H
+
+#ifdef LWIP_OPTTEST_FILE
+#include "lwipopts_test.h"
+#else /* LWIP_OPTTEST_FILE */
+
+#define LWIP_IPV4 1
+#define LWIP_IPV6 1
+
+#define NO_SYS 0
+#define LWIP_SOCKET 0
+#define LWIP_NETCONN 0
+#define LWIP_NETIF_API (NO_SYS==0)
+
+#define LWIP_IGMP 0
+#define LWIP_ICMP LWIP_IPV4
+
+#define LWIP_SNMP LWIP_UDP
+#ifdef LWIP_HAVE_MBEDTLS
+#define LWIP_SNMP_V3 (LWIP_SNMP)
+#endif
+
+#define LWIP_DNS LWIP_UDP
+#define LWIP_MDNS_RESPONDER LWIP_UDP
+
+#define LWIP_NUM_NETIF_CLIENT_DATA (LWIP_MDNS_RESPONDER)
+
+#define LWIP_HAVE_LOOPIF 1
+#define LWIP_NETIF_LOOPBACK 1
+#define LWIP_SINGLE_NETIF 1
+#define LWIP_LOOPBACK_MAX_PBUFS 10
+
+#define TCP_LISTEN_BACKLOG 1
+
+#define LWIP_COMPAT_SOCKETS 1
+#define LWIP_SO_RCVTIMEO 1
+#define LWIP_SO_RCVBUF 1
+
+#define LWIP_TCPIP_CORE_LOCKING 1
+
+#define LWIP_NETIF_LINK_CALLBACK 1
+#define LWIP_NETIF_STATUS_CALLBACK 1
+#define LWIP_NETIF_EXT_STATUS_CALLBACK 1
+
+#ifdef LWIP_DEBUG
+
+#define LWIP_DBG_MIN_LEVEL 0
+#define PPP_DEBUG LWIP_DBG_OFF
+#define MEM_DEBUG LWIP_DBG_OFF
+#define MEMP_DEBUG LWIP_DBG_OFF
+#define PBUF_DEBUG LWIP_DBG_OFF
+#define API_LIB_DEBUG LWIP_DBG_OFF
+#define API_MSG_DEBUG LWIP_DBG_OFF
+#define TCPIP_DEBUG LWIP_DBG_OFF
+#define NETIF_DEBUG LWIP_DBG_OFF
+#define SOCKETS_DEBUG LWIP_DBG_OFF
+#define DNS_DEBUG LWIP_DBG_OFF
+#define AUTOIP_DEBUG LWIP_DBG_OFF
+#define DHCP_DEBUG LWIP_DBG_OFF
+#define IP_DEBUG LWIP_DBG_OFF
+#define IP_REASS_DEBUG LWIP_DBG_OFF
+#define ICMP_DEBUG LWIP_DBG_OFF
+#define IGMP_DEBUG LWIP_DBG_OFF
+#define UDP_DEBUG LWIP_DBG_OFF
+#define TCP_DEBUG LWIP_DBG_OFF
+#define TCP_INPUT_DEBUG LWIP_DBG_OFF
+#define TCP_OUTPUT_DEBUG LWIP_DBG_OFF
+#define TCP_RTO_DEBUG LWIP_DBG_OFF
+#define TCP_CWND_DEBUG LWIP_DBG_OFF
+#define TCP_WND_DEBUG LWIP_DBG_OFF
+#define TCP_FR_DEBUG LWIP_DBG_OFF
+#define TCP_QLEN_DEBUG LWIP_DBG_OFF
+#define TCP_RST_DEBUG LWIP_DBG_OFF
+#endif
+
+#define LWIP_DBG_TYPES_ON (LWIP_DBG_ON|LWIP_DBG_TRACE|LWIP_DBG_STATE|LWIP_DBG_FRESH|LWIP_DBG_HALT)
+
+
+/* ---------- Memory options ---------- */
+/* MEM_ALIGNMENT: should be set to the alignment of the CPU for which
+ lwIP is compiled. 4 byte alignment -> define MEM_ALIGNMENT to 4, 2
+ byte alignment -> define MEM_ALIGNMENT to 2. */
+/* MSVC port: intel processors don't need 4-byte alignment,
+ but are faster that way! */
+#define MEM_ALIGNMENT 4U
+
+/* MEM_SIZE: the size of the heap memory. If the application will send
+a lot of data that needs to be copied, this should be set high. */
+#define MEM_SIZE 1024000
+
+/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
+ sends a lot of data out of ROM (or other static memory), this
+ should be set high. */
+#define MEMP_NUM_PBUF 1600
+/* MEMP_NUM_RAW_PCB: the number of UDP protocol control blocks. One
+ per active RAW "connection". */
+#define MEMP_NUM_RAW_PCB 3
+/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
+ per active UDP "connection". */
+#define MEMP_NUM_UDP_PCB 8
+/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
+ connections. */
+#define MEMP_NUM_TCP_PCB 1000
+/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
+ connections. */
+#define MEMP_NUM_TCP_PCB_LISTEN 80
+/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
+ segments. */
+#define MEMP_NUM_TCP_SEG 1600
+/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
+ timeouts. */
+#define MEMP_NUM_SYS_TIMEOUT 300
+
+/* The following four are used only with the sequential API and can be
+ set to 0 if the application only will use the raw API. */
+/* MEMP_NUM_NETBUF: the number of struct netbufs. */
+#define MEMP_NUM_NETBUF 200
+/* MEMP_NUM_NETCONN: the number of struct netconns. */
+#define MEMP_NUM_NETCONN 1000
+/* MEMP_NUM_TCPIP_MSG_*: the number of struct tcpip_msg, which is used
+ for sequential API communication and incoming packets. Used in
+ src/api/tcpip.c. */
+#define MEMP_NUM_TCPIP_MSG_API 1600
+#define MEMP_NUM_TCPIP_MSG_INPKT 1600
+
+
+/* ---------- Pbuf options ---------- */
+/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
+#define PBUF_POOL_SIZE 10000
+
+/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
+#define PBUF_POOL_BUFSIZE 2048
+
+/** SYS_LIGHTWEIGHT_PROT
+ * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection
+ * for certain critical regions during buffer allocation, deallocation and memory
+ * allocation and deallocation.
+ */
+#define SYS_LIGHTWEIGHT_PROT (NO_SYS==0)
+
+
+/* ---------- TCP options ---------- */
+#define LWIP_TCP 1
+#define TCP_TTL 255
+
+#define LWIP_ALTCP (LWIP_TCP)
+#ifdef LWIP_HAVE_MBEDTLS
+#define LWIP_ALTCP_TLS (LWIP_TCP)
+#define LWIP_ALTCP_TLS_MBEDTLS (LWIP_TCP)
+#endif
+
+
+/* Controls if TCP should queue segments that arrive out of
+ order. Define to 0 if your device is low on memory. */
+#define TCP_QUEUE_OOSEQ 1
+
+/* TCP Maximum segment size. */
+#define TCP_MSS 1024
+
+/* TCP sender buffer space (bytes). */
+#define TCP_SND_BUF 65534 /* Match TCP_WND. */
+
+/* TCP sender buffer space (pbufs). This must be at least = 2 *
+ TCP_SND_BUF/TCP_MSS for things to work. */
+#define TCP_SND_QUEUELEN (4 * TCP_SND_BUF/TCP_MSS)
+
+/* TCP writable space (bytes). This must be less than or equal
+ to TCP_SND_BUF. It is the amount of space which must be
+ available in the tcp snd_buf for select to return writable */
+#define TCP_SNDLOWAT (TCP_SND_BUF/8)
+
+/* TCP receive window. */
+#define TCP_WND 65534 /* Avoid wrap. */
+
+/* Maximum number of retransmissions of data segments. */
+#define TCP_MAXRTX 12
+
+/* Maximum number of retransmissions of SYN segments. */
+#define TCP_SYNMAXRTX 4
+
+
+/* ---------- ARP options ---------- */
+#define LWIP_ARP 1
+#define ARP_TABLE_SIZE 0
+#define ARP_QUEUEING 1
+
+
+/* ---------- IP options ---------- */
+/* Define IP_FORWARD to 1 if you wish to have the ability to forward
+ IP packets across network interfaces. If you are going to run lwIP
+ on a device with only one network interface, define this to 0. */
+#define IP_FORWARD 0
+
+/* IP reassembly and segmentation.These are orthogonal even
+ * if they both deal with IP fragments */
+#define IP_REASSEMBLY 1
+#define IP_REASS_MAX_PBUFS (10 * ((1500 + PBUF_POOL_BUFSIZE - 1) / PBUF_POOL_BUFSIZE))
+#define MEMP_NUM_REASSDATA IP_REASS_MAX_PBUFS
+#define IP_FRAG 1
+#define IPV6_FRAG_COPYHEADER 1
+
+/* ---------- ICMP options ---------- */
+#define ICMP_TTL 255
+
+
+/* ---------- DHCP options ---------- */
+/* Define LWIP_DHCP to 1 if you want DHCP configuration of
+ interfaces. */
+#define LWIP_DHCP LWIP_UDP
+
+/* 1 if you want to do an ARP check on the offered address
+ (recommended). */
+#define DHCP_DOES_ARP_CHECK (LWIP_DHCP)
+
+
+/* ---------- AUTOIP options ------- */
+#define LWIP_AUTOIP (LWIP_DHCP)
+#define LWIP_DHCP_AUTOIP_COOP (LWIP_DHCP && LWIP_AUTOIP)
+
+
+/* ---------- UDP options ---------- */
+#define LWIP_UDP 0
+#define LWIP_UDPLITE LWIP_UDP
+#define UDP_TTL 255
+
+
+/* ---------- RAW options ---------- */
+#define LWIP_RAW 0
+
+
+/* ---------- Statistics options ---------- */
+
+#define LWIP_STATS 0
+#define LWIP_STATS_DISPLAY 0
+
+#if LWIP_STATS
+#define LINK_STATS 1
+#define IP_STATS 1
+#define ICMP_STATS 1
+#define IGMP_STATS 1
+#define IPFRAG_STATS 1
+#define UDP_STATS 1
+#define TCP_STATS 1
+#define MEM_STATS 1
+#define MEMP_STATS 1
+#define PBUF_STATS 1
+#define SYS_STATS 1
+#endif /* LWIP_STATS */
+
+/* ---------- NETBIOS options ---------- */
+#define LWIP_NETBIOS_RESPOND_NAME_QUERY 0
+
+/* ---------- PPP options ---------- */
+
+#define PPP_SUPPORT 0 /* Set > 0 for PPP */
+
+#if PPP_SUPPORT
+
+#define NUM_PPP 1 /* Max PPP sessions. */
+
+
+/* Select modules to enable. Ideally these would be set in the makefile but
+ * we're limited by the command line length so you need to modify the settings
+ * in this file.
+ */
+#define PPPOE_SUPPORT 1
+#define PPPOS_SUPPORT 1
+
+#define PAP_SUPPORT 1 /* Set > 0 for PAP. */
+#define CHAP_SUPPORT 1 /* Set > 0 for CHAP. */
+#define MSCHAP_SUPPORT 0 /* Set > 0 for MSCHAP */
+#define CBCP_SUPPORT 0 /* Set > 0 for CBCP (NOT FUNCTIONAL!) */
+#define CCP_SUPPORT 0 /* Set > 0 for CCP */
+#define VJ_SUPPORT 0 /* Set > 0 for VJ header compression. */
+#define MD5_SUPPORT 1 /* Set > 0 for MD5 (see also CHAP) */
+
+#endif /* PPP_SUPPORT */
+
+#endif /* LWIP_OPTTEST_FILE */
+
+/* The following defines must be done even in OPTTEST mode: */
+
+#if !defined(NO_SYS) || !NO_SYS /* default is 0 */
+#if 0
+void sys_check_core_locking(void);
+#define LWIP_ASSERT_CORE_LOCKED() sys_check_core_locking()
+#endif
+#endif
+
+#ifndef LWIP_PLATFORM_ASSERT
+#if 0
+/* Define LWIP_PLATFORM_ASSERT to something to catch missing stdio.h includes */
+void lwip_example_app_platform_assert(const char *msg, int line, const char *file);
+#define LWIP_PLATFORM_ASSERT(x) lwip_example_app_platform_assert(x, __LINE__, __FILE__)
+#endif
+#endif
+
+#endif /* LWIP_LWIPOPTS_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..bd12813
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) 2023 Penn Mackintosh
+ * Adapted from [ocproxy](https://github.com/cernekee/ocproxy) to use upgrade LwIP, remove LDAP functionality
+ * Copyright (c) 2016 Google Inc.
+ * Copyright (c) 2012-2014 David Edmondson
+ * Copyright (c) 2012-2014 Kevin Cernekee
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+//#include "lwip/opt.h"
+//#include "lwip/debug.h"
+//#include "lwip/err.h"
+//#include "lwip/init.h"
+#include "lwip/ip.h"
+#include "lwip/tcp.h"
+#include "lwip/init.h"
+//#include "lwip/dns.h"
+//#include "lwip/netif.h"
+//#include "lwip/stats.h"
+//#include "lwip/sys.h"
+//#include "lwip/tcp.h"
+
+enum {
+ STATE_NEW = 0,
+ STATE_DNS,
+ STATE_CONNECTING,
+ STATE_DATA,
+ STATE_DEAD,
+ STATE_MAX
+};
+
+#define CONN_TYPE_REDIR 0
+
+#define SOCKBUF_LEN 2048
+
+#define FL_ACTIVATE 1
+#define FL_DIE_ON_ERROR 2
+
+#define MAX_IOVEC 128
+#define MAX_CONN 1024
+
+struct ocp_sock {
+ /* general */
+ int fd;
+ struct evconnlistener *listener;
+ struct event *ev;
+ struct tcp_pcb *tpcb;
+ int state;
+ int conn_type;
+ struct ocp_sock *next;
+
+ /* for TCP send/receive */
+ int done_len;
+ int lwip_blocked;
+ int sock_pos;
+ int sock_total;
+ char sockbuf[SOCKBUF_LEN];
+
+ /* for all listeners */
+ int lport;
+ char *bind_addr;
+ evconnlistener_cb listen_cb;
+
+ /* for port forwarding */
+ ip_addr_t rhost;
+ int rport;
+
+ /* for lwip_data_cb() */
+ struct netif *netif;
+};
+
+struct socks_auth {
+ u8_t ver;
+ u8_t n_methods;
+ u8_t methods;
+} PACK_STRUCT_STRUCT;
+
+struct socks_req {
+ u8_t ver;
+ u8_t cmd;
+ u8_t rsv;
+ u8_t atyp;
+ union {
+ struct {
+ u32_t dst_addr;
+ u16_t dst_port;
+ u8_t end;
+ } ipv4;
+ struct {
+ u8_t fqdn_len;
+ u8_t fqdn_name[255]; /* variable length */
+ u16_t port;
+ } fqdn;
+ } u;
+} PACK_STRUCT_STRUCT;
+
+struct socks_reply {
+ u8_t ver;
+ u8_t rep;
+ u8_t rsv;
+ u8_t atyp;
+ u32_t bnd_addr;
+ u16_t bnd_port;
+} PACK_STRUCT_STRUCT;
+
+static struct event_base *event_base;
+
+static struct ocp_sock ocp_sock_pool[MAX_CONN];
+static struct ocp_sock *ocp_sock_free_list;
+static struct ocp_sock *ocp_sock_bind_list;
+static int ocp_sock_used;
+static int ocp_sock_max;
+
+/* nonstatic debug cmd option, exported in lwipopts.h */
+unsigned char debug_flags = 0;
+
+static int allow_remote;
+static int tcpdump_enabled;
+static int got_sighup;
+static int got_sigusr1;
+static char *dns_domain;
+
+static void start_connection(struct ocp_sock *s);
+
+/**********************************************************************
+ * Utility functions / libevent wrappers
+ **********************************************************************/
+
+static void die(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fflush(stdout);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ exit(1);
+}
+
+static void warn(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ fflush(stdout);
+ fprintf(stderr, "warning: ");
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+static char *xstrdup(const char *s)
+{
+ char *ret = strdup(s);
+ if (!ret)
+ die("out of memory\n");
+ return ret;
+}
+
+static int ocp_atoi(const char *s)
+{
+ char *p;
+ long val = strtol(s, &p, 0);
+ if (!*s || *p)
+ die("invalid integer: '%s'\n", s);
+ return val;
+}
+
+static struct ocp_sock *ocp_sock_new(int fd, event_callback_fn cb, int flags)
+{
+ struct ocp_sock *s;
+
+ s = ocp_sock_free_list;
+ if (!s) {
+ if (flags & FL_DIE_ON_ERROR)
+ die("%s: ran out of ocp_socks\n", __func__);
+ return NULL;
+ }
+ ocp_sock_free_list = s->next;
+ memset(s, 0, sizeof(*s));
+
+ ocp_sock_used++;
+ if (ocp_sock_used > ocp_sock_max)
+ ocp_sock_max = ocp_sock_used;
+
+ s->next = ocp_sock_bind_list;
+ ocp_sock_bind_list = s;
+
+ if (fd < 0)
+ return s;
+
+ s->fd = fd;
+ s->ev = event_new(event_base, fd, EV_READ, cb, s);
+ if (flags & FL_ACTIVATE)
+ event_add(s->ev, NULL);
+ return s;
+}
+
+static void ocp_sock_del(struct ocp_sock *s)
+{
+ if (s->state == STATE_DNS) {
+ s->state = STATE_DEAD;
+ return;
+ }
+ close(s->fd);
+ if (s->tpcb) {
+ tcp_arg(s->tpcb, NULL);
+ tcp_close(s->tpcb);
+ }
+ event_free(s->ev);
+ memset(s, 0xdd, sizeof(*s));
+ s->next = ocp_sock_free_list;
+ ocp_sock_free_list = s;
+ ocp_sock_used--;
+}
+
+/**********************************************************************
+ * lwIP TCP<->socket TCP traffic
+ **********************************************************************/
+
+/* Called when the local TCP socket has data available (or hung up) */
+static void local_data_cb(evutil_socket_t fd, short what, void *ctx)
+{
+ struct ocp_sock *s = ctx;
+ ssize_t len;
+ int try_len;
+ err_t err;
+
+ try_len = tcp_sndbuf(s->tpcb);
+ if (try_len > SOCKBUF_LEN)
+ try_len = SOCKBUF_LEN;
+ if (!try_len || tcp_sndqueuelen(s->tpcb) > (TCP_SND_QUEUELEN/2)) {
+ s->lwip_blocked = 1;
+ return;
+ }
+
+ len = read(s->fd, s->sockbuf, try_len);
+ if (len <= 0) {
+ ocp_sock_del(s);
+ return;
+ }
+ err = tcp_write(s->tpcb, s->sockbuf, len, TCP_WRITE_FLAG_COPY);
+ if (err == ERR_MEM)
+ die("%s: out of memory\n", __func__);
+ else if (err != ERR_OK)
+ warn("tcp_write returned %d\n", (int)err);
+
+ tcp_output(s->tpcb);
+ event_add(s->ev, NULL);
+}
+
+/* Called when lwIP has sent data to the VPN */
+static err_t sent_cb(void *ctx, struct tcp_pcb *tpcb, u16_t len)
+{
+ struct ocp_sock *s = ctx;
+
+ if (!s)
+ return ERR_OK;
+
+ if (s->lwip_blocked) {
+ s->lwip_blocked = 0;
+ event_add(s->ev, NULL);
+ }
+
+ return ERR_OK;
+}
+
+/* Called when lwIP has new TCP data from the VPN */
+static err_t recv_cb(void *ctx, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
+{
+ struct ocp_sock *s = ctx;
+ struct pbuf *first = p;
+ int offset;
+ ssize_t wlen;
+
+ if (!s)
+ return ERR_ABRT;
+
+ if (!p) {
+ ocp_sock_del(s);
+ return ERR_OK;
+ }
+
+ /*
+ * tcp_tmr() will call this function every 250ms with the same pbuf,
+ * if we refused data during the previous attempt. s->done_len
+ * will reflect the number of bytes we were able to send to the socket
+ * so far (if any).
+ */
+
+ for (offset = s->done_len; p && offset >= p->len; offset -= p->len)
+ p = p->next;
+
+ for (; p; p = p->next) {
+ int try_len = p->len - offset;
+
+ wlen = write(s->fd, (char *)p->payload + offset, try_len);
+ offset = 0;
+
+ if (wlen < 0) {
+ ocp_sock_del(s);
+ return ERR_ABRT;
+ }
+ s->done_len += wlen;
+ tcp_recved(tpcb, wlen);
+ if (wlen < try_len)
+ return ERR_WOULDBLOCK;
+ }
+
+ /* if we got here, then the whole pbuf is done */
+ s->done_len = 0;
+ pbuf_free(first);
+
+ return ERR_OK;
+}
+
+/**********************************************************************
+ * SOCKS protocol
+ **********************************************************************/
+
+/**********************************************************************
+ * Connection setup
+ **********************************************************************/
+
+/* Called on lwIP TCP errors; used to detect connection failure */
+static void tcp_err_cb(void *arg, err_t err)
+{
+ struct ocp_sock *s = arg;
+ warn("%s: called with %d\n", __func__, (int) err);
+
+ if (s) {
+ s->tpcb = NULL;
+ ocp_sock_del(s);
+ }
+}
+
+/* Called when lwIP tcp_connect() is successful */
+static err_t connect_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
+{
+ if (err != ERR_OK)
+ warn("%s: called with %d\n", __func__, (int) err);
+
+ struct ocp_sock *s = arg;
+
+ s->state = STATE_DATA;
+ event_add(s->ev, NULL);
+ tcp_recv(tpcb, recv_cb);
+ tcp_sent(tpcb, sent_cb);
+
+ return ERR_OK;
+}
+
+static void start_connection(struct ocp_sock *s)
+{
+ struct tcp_pcb *tpcb;
+ err_t err;
+
+ s->state = STATE_CONNECTING;
+
+ tpcb = tcp_new();
+ if (!tpcb)
+ die("%s: out of memory\n", __func__);
+ tcp_nagle_disable(tpcb);
+ tcp_arg(tpcb, s);
+ tcp_recv(tpcb, NULL);
+ tcp_err(tpcb, tcp_err_cb);
+ s->tpcb = tpcb;
+
+
+ err = tcp_connect(tpcb, &s->rhost, s->rport, connect_cb);
+ if (err != ERR_OK) {
+ warn("%s: tcp_connect(%s:%d) returned %d\n", __func__, ipaddr_ntoa(&s->rhost), s->rport, (int) err);
+ }
+}
+
+/* Called upon connection to a local TCP socket */
+static void new_conn_cb(struct evconnlistener *listener, evutil_socket_t fd,
+ struct sockaddr *address, int socklen, void *ctx)
+{
+ struct ocp_sock *lsock = ctx, *s;
+
+ s = ocp_sock_new(fd, local_data_cb, 0);
+ if (!s) {
+ warn("too many connections\n");
+ return;
+ }
+
+ s->conn_type = lsock->conn_type;
+ s->rhost = lsock->rhost;
+ s->rport = lsock->rport;
+
+ start_connection(s);
+
+}
+
+/**********************************************************************
+ * lwIP<->VPN traffic
+ **********************************************************************/
+
+static void vpn_conn_down(void)
+{
+ printf("VPN connection has terminated\n");
+ event_base_loopbreak(event_base);
+}
+
+/* Called when the VPN sends us a raw IP packet destined for lwIP */
+static void lwip_data_cb(evutil_socket_t fd, short what, void *ctx)
+{
+ struct ocp_sock *s = ctx;
+ ssize_t len;
+ struct pbuf *p;
+
+ len = read(s->fd, s->sockbuf, SOCKBUF_LEN);
+ if (len <= 0) {
+ /* This might never happen, because s->fd is a DGRAM socket */
+ vpn_conn_down();
+ }
+ if ((p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL)) != NULL) {
+ char *bufptr;
+ struct pbuf *q;
+
+ bufptr = s->sockbuf;
+ q = p;
+ while (len > 0) {
+ int copy = (len > q->len) ? q->len : len;
+
+ memcpy(q->payload, bufptr, copy);
+ len -= copy;
+ bufptr += copy;
+ q = q->next;
+ }
+ LINK_STATS_INC(link.recv);
+ s->netif->input(p, s->netif);
+ } else
+ warn("%s: could not allocate pbuf\n", __func__);
+ event_add(s->ev, NULL);
+}
+
+/* Called when lwIP has data to send up to the VPN */
+static err_t lwip_data_out(struct netif *netif, struct pbuf *p, const ip4_addr_t *ipaddr)
+{
+ struct ocp_sock *s = netif->state;
+ int i = 0, total = 0;
+ ssize_t ret;
+ struct iovec iov[MAX_IOVEC];
+
+
+ for (; p; p = p->next) {
+ if (i >= MAX_IOVEC) {
+ warn("%s: too many chunks, dropping packet\n", __func__);
+ return ERR_OK;
+ }
+ iov[i].iov_base = p->payload;
+ iov[i++].iov_len = p->len;
+ total += p->len;
+ }
+
+ ret = writev(s->fd, iov, i);
+ if (ret < 0) {
+ if (errno == ECONNREFUSED || errno == ENOTCONN)
+ vpn_conn_down();
+ else
+ LINK_STATS_INC(link.drop);
+ } else if (ret != total)
+ LINK_STATS_INC(link.lenerr);
+ else
+ LINK_STATS_INC(link.xmit);
+
+ return ERR_OK;
+}
+
+/**********************************************************************
+ * Periodic tasks
+ **********************************************************************/
+
+static void handle_sig(int sig)
+{
+ if (sig == SIGHUP)
+ got_sighup = 1;
+ else if (sig == SIGUSR1)
+ got_sigusr1 = 1;
+}
+
+static void new_periodic_event(event_callback_fn cb, void *arg, int timeout_ms)
+{
+ struct timeval tv;
+ struct event *ev;
+
+ tv.tv_sec = timeout_ms / 1000;
+ tv.tv_usec = 1000 * (timeout_ms % 1000);
+ ev = event_new(event_base, -1, EV_PERSIST, cb, arg);
+ if (!ev)
+ die("can't create new periodic event\n");
+ evtimer_add(ev, &tv);
+}
+
+static void cb_housekeeping(evutil_socket_t fd, short what, void *ctx)
+{
+ int *vpnfd = ctx;
+
+ /*
+ * OpenConnect will ignore 0-byte datagrams if it's alive, but
+ * we'll get ECONNREFUSED if the peer has died.
+ */
+ if (write(*vpnfd, vpnfd, 0) < 0 &&
+ (errno == ECONNREFUSED || errno == ENOTCONN))
+ vpn_conn_down();
+ else if (got_sighup)
+ vpn_conn_down();
+
+ if (got_sigusr1) {
+ LINK_STATS_DISPLAY();
+ MEM_STATS_DISPLAY();
+ printf("open connections: %d / %d, max %d\n",
+ ocp_sock_used, MAX_CONN, ocp_sock_max);
+ got_sigusr1 = 0;
+ }
+}
+
+/**********************************************************************
+ * Program initialization
+ **********************************************************************/
+
+static err_t init_oc_netif(struct netif *netif)
+{
+ netif->name[0] = 'u';
+ netif->name[1] = 'n';
+ netif->output = lwip_data_out;
+ return ERR_OK;
+}
+
+static void bind_all_listeners(void)
+{
+ struct ocp_sock *s;
+ struct sockaddr_in sock;
+
+ for (s = ocp_sock_bind_list; s; s = s->next) {
+ if (!s->listen_cb)
+ continue;
+ if (s->lport < 1 || s->lport > 65535)
+ die("invalid port number: %d\n", s->lport);
+
+ memset(&sock, 0, sizeof(sock));
+ sock.sin_port = htons(s->lport);
+ sock.sin_family = AF_INET;
+
+ if (s->bind_addr) {
+ /*
+ * TODO: support IPv6 and multiple listening sockets
+ * per hostname
+ */
+ if (!inet_aton(s->bind_addr, &sock.sin_addr))
+ die("can't parse IP: '%s'\n", s->bind_addr);
+
+ } else {
+ sock.sin_addr.s_addr = htonl(allow_remote ?
+ INADDR_ANY : INADDR_LOOPBACK);
+ }
+
+ s->listener = evconnlistener_new_bind(event_base, s->listen_cb,
+ s, LEV_OPT_CLOSE_ON_FREE|LEV_OPT_REUSEABLE, -1,
+ (struct sockaddr *)&sock, sizeof(sock));
+ if (!s->listener)
+ die("can't set up listener on port %d/tcp\n", s->lport);
+ }
+}
+
+static struct ocp_sock *new_listener(int port, evconnlistener_cb cb)
+{
+ struct ocp_sock *s;
+
+ s = ocp_sock_new(-1, NULL, FL_DIE_ON_ERROR);
+ s->lport = port;
+ s->listen_cb = cb;
+
+ return s;
+}
+
+static void fwd_add(const char *opt)
+{
+ char *str = xstrdup(opt), *tmp = str, *p;
+ int lport;
+ struct ocp_sock *s;
+
+ p = strsep(&str, ":");
+ if (!str)
+ goto bad;
+ lport = ocp_atoi(p);
+
+ p = strsep(&str, ":");
+ if (!str)
+ goto bad;
+
+ s = new_listener(lport, new_conn_cb);
+ struct addrinfo *addrinfo;
+
+ int ret = getaddrinfo(p, NULL, NULL, &addrinfo);
+ if (ret != 0) {
+ die("getaddrinfo: %s\n", gai_strerror(ret));
+ }
+ ip_addr_t addr;
+ if (addrinfo->ai_addr->sa_family == AF_INET6) {
+ struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addrinfo->ai_addr;
+ //addr.u_addr.ip6.zone = addr6->sin6_scope_id;
+ addr.u_addr.ip6.addr[0] =
+ addr6->sin6_addr.s6_addr[0] << 24 |
+ addr6->sin6_addr.s6_addr[1] << 16 |
+ addr6->sin6_addr.s6_addr[2] << 8 |
+ addr6->sin6_addr.s6_addr[3] << 0;
+ addr.u_addr.ip6.addr[1] =
+ addr6->sin6_addr.s6_addr[4] << 24 |
+ addr6->sin6_addr.s6_addr[5] << 16 |
+ addr6->sin6_addr.s6_addr[6] << 8 |
+ addr6->sin6_addr.s6_addr[7] << 0;
+ addr.u_addr.ip6.addr[2] =
+ addr6->sin6_addr.s6_addr[8] << 24 |
+ addr6->sin6_addr.s6_addr[9] << 16 |
+ addr6->sin6_addr.s6_addr[10] << 8 |
+ addr6->sin6_addr.s6_addr[11] << 0;
+ addr.u_addr.ip6.addr[3] =
+ addr6->sin6_addr.s6_addr[12] << 24 |
+ addr6->sin6_addr.s6_addr[13] << 16 |
+ addr6->sin6_addr.s6_addr[14] << 8 |
+ addr6->sin6_addr.s6_addr[15] << 0;
+ } else {
+ struct sockaddr_in *addr4 = (struct sockaddr_in *) addrinfo->ai_addr;
+ addr.u_addr.ip4.addr = addr4->sin_addr.s_addr;
+ }
+ s->rhost = addr;
+ s->rport = ocp_atoi(str);
+ s->conn_type = CONN_TYPE_REDIR;
+
+ if (s->rport <= 0)
+ die("Remote port must be a positive integer\n");
+
+ free(tmp);
+
+ return;
+ bad:
+ die("Invalid port forward specifier: '%s'\n", opt);
+}
+
+static struct option longopts[] = {
+ { "ip", 1, NULL, 'I' },
+ { "mtu", 1, NULL, 'M' },
+ { "dns", 1, NULL, 'd' },
+ { "domain", 1, NULL, 'o' },
+ { "localfw", 1, NULL, 'L' },
+ { "dynfw", 1, NULL, 'D' },
+ { "allow-remote", 0, NULL, 'g' },
+ { "verbose", 0, NULL, 'v' },
+ { "tcpdump", 0, NULL, 'T' },
+ { NULL }
+};
+
+int main(int argc, char **argv)
+{
+ int opt, i, vpnfd;
+ char *str;
+ char *ip_str, *mtu_str, *dns_str;
+ ip_addr_t ip, netmask, gw, dns;
+ struct ocp_sock *s;
+ struct netif netif;
+
+ ip_str = mtu_str = dns_str = NULL;
+
+ ocp_sock_free_list = &ocp_sock_pool[0];
+ for (i = 1; i < MAX_CONN; i++)
+ ocp_sock_pool[i - 1].next = &ocp_sock_pool[i];
+
+ event_base = event_base_new();
+ if (!event_base)
+ die("can't initialize libevent\n");
+
+ str = getenv("VPNFD");
+ if (!str)
+ die("VPNFD is not set, aborting\n");
+ vpnfd = ocp_atoi(str);
+
+ /* try to set the IP configuration from the environment, first */
+ ip_str = getenv("INTERNAL_IP4_ADDRESS");
+ mtu_str = getenv("INTERNAL_IP4_MTU");
+
+ dns_domain = getenv("CISCO_DEF_DOMAIN");
+ str = getenv("INTERNAL_IP4_DNS");
+ if (str) {
+ char *p;
+
+ /* this could contain many addresses; just use the first one */
+ dns_str = xstrdup(str);
+ p = strchr(dns_str, ' ');
+ if (p)
+ *p = 0;
+ }
+
+ /* override with command line options */
+ while ((opt = getopt_long(argc, argv,
+ "I:M:d:o:D:k:gL:vT", longopts, NULL)) != -1) {
+ switch (opt) {
+ case 'I':
+ ip_str = optarg;
+ break;
+ case 'M':
+ mtu_str = optarg;
+ break;
+ case 'd':
+ dns_str = optarg;
+ break;
+ case 'o':
+ dns_domain = optarg;
+ break;
+ case 'g':
+ allow_remote = 1;
+ break;
+ case 'L':
+ fwd_add(optarg);
+ break;
+ case 'v':
+ debug_flags = LWIP_DBG_ON | LWIP_DBG_TRACE |
+ LWIP_DBG_STATE | LWIP_DBG_FRESH |
+ LWIP_DBG_HALT;
+ break;
+ case 'T':
+ tcpdump_enabled = 1;
+ break;
+ default:
+ die("unknown option: %c\n", opt);
+ }
+ }
+
+ if (!ip_str || !mtu_str)
+ die("missing -I or -M\n");
+
+ if (!ipaddr_aton(ip_str, &ip))
+ die("Invalid IP address: '%s'\n", ip_str);
+
+ /* Debugging help. */
+ signal(SIGHUP, handle_sig);
+ signal(SIGUSR1, handle_sig);
+ signal(SIGPIPE, SIG_IGN);
+ setlinebuf(stdout);
+ setlinebuf(stderr);
+
+ /* Set up lwIP interface */
+ s = ocp_sock_new(vpnfd, lwip_data_cb, FL_ACTIVATE | FL_DIE_ON_ERROR);
+ memset(&netif, 0, sizeof(netif));
+ s->netif = &netif;
+
+ lwip_init();
+ ip_addr_set_zero(&netmask);
+ ip_addr_set_zero(&gw);
+ netif_add(&netif, &ip.u_addr.ip4, &netmask.u_addr.ip4, &gw.u_addr.ip4, s, init_oc_netif, ip_input);
+ netif.mtu = ocp_atoi(mtu_str);
+
+ netif_set_default(&netif);
+ netif_set_up(&netif);
+ netif_set_link_up(&netif);
+
+ /* bind after all options have been parsed (especially -g) */
+ bind_all_listeners();
+
+
+ new_periodic_event(cb_housekeeping, &vpnfd, 1000);
+
+ event_base_dispatch(event_base);
+
+ return 0;
+}