Migrate to ocproxy-based TCP proxy implementation with VPN integration
This commit is contained in:
parent
0278906574
commit
c767d81251
193
.gitignore
vendored
Normal file
193
.gitignore
vendored
Normal file
@ -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
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "lwip"]
|
||||
path = lwip
|
||||
url = https://git.savannah.nongnu.org/git/lwip.git
|
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -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
|
4
.idea/misc.xml
generated
Normal file
4
.idea/misc.xml
generated
Normal file
@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
|
||||
</project>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/tcpproxy.iml" filepath="$PROJECT_DIR$/.idea/tcpproxy.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
2
.idea/tcpproxy.iml
generated
Normal file
2
.idea/tcpproxy.iml
generated
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module classpath="CMake" type="CPP_MODULE" version="4" />
|
7
.idea/vcs.xml
generated
Normal file
7
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lwip" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
28
CMakeLists.txt
Normal file
28
CMakeLists.txt
Normal file
@ -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})
|
||||
|
22
Dockerfile
22
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"]
|
||||
|
28
NOTICE
Normal file
28
NOTICE
Normal file
@ -0,0 +1,28 @@
|
||||
Copyright (c) 2023 Penn Mackintosh <penn@pennmack.co.uk>
|
||||
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 <dme@dme.org>
|
||||
Copyright (c) 2012-2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
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.
|
3
docker-entrypoint.sh
Executable file
3
docker-entrypoint.sh
Executable file
@ -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" "$@"
|
11
haproxy.cfg
11
haproxy.cfg
@ -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}"
|
1
lwip
Submodule
1
lwip
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit e29870c15e8bf28eac9c811dd236c474f3f2008f
|
330
src/lwipopts.h
Normal file
330
src/lwipopts.h
Normal file
@ -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 <adam@sics.se>
|
||||
*
|
||||
*/
|
||||
#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 */
|
808
src/main.c
Normal file
808
src/main.c
Normal file
@ -0,0 +1,808 @@
|
||||
/*
|
||||
* Copyright (c) 2023 Penn Mackintosh <penn@pennmack.co.uk>
|
||||
* 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 <dme@dme.org>
|
||||
* Copyright (c) 2012-2014 Kevin Cernekee <cernekee@gmail.com>
|
||||
* 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include <event2/event.h>
|
||||
#include <event2/listener.h>
|
||||
|
||||
//#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;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user