├── .clang-format ├── .github └── workflows │ ├── build.yaml │ └── code-format.yaml ├── .gitignore ├── .gitmodules ├── Android.mk ├── Application.mk ├── License ├── Makefile ├── README.md ├── build-apple.sh ├── build.mk ├── conf ├── auth.txt └── main.yml ├── docker ├── Dockerfile ├── README.md └── entrypoint.sh ├── module.modulemap └── src ├── hev-config-const.h ├── hev-config.c ├── hev-config.h ├── hev-jni.c ├── hev-jni.h ├── hev-main.c ├── hev-main.h ├── hev-socket-factory.c ├── hev-socket-factory.h ├── hev-socks5-proxy.c ├── hev-socks5-proxy.h ├── hev-socks5-session.c ├── hev-socks5-session.h ├── hev-socks5-user-mark.c ├── hev-socks5-user-mark.h ├── hev-socks5-worker.c ├── hev-socks5-worker.h └── misc ├── hev-compiler.h ├── hev-list.c ├── hev-list.h ├── hev-logger.c ├── hev-logger.h ├── hev-misc.c └── hev-misc.h /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | AccessModifierOffset: -4 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignEscapedNewlines: Left 8 | AlignOperands: true 9 | AlignTrailingComments: false 10 | AllowAllParametersOfDeclarationOnNextLine: false 11 | AllowShortBlocksOnASingleLine: false 12 | AllowShortCaseLabelsOnASingleLine: false 13 | AllowShortFunctionsOnASingleLine: None 14 | AllowShortIfStatementsOnASingleLine: false 15 | AllowShortLoopsOnASingleLine: false 16 | AlwaysBreakAfterDefinitionReturnType: TopLevel 17 | AlwaysBreakAfterReturnType: None 18 | AlwaysBreakBeforeMultilineStrings: false 19 | AlwaysBreakTemplateDeclarations: MultiLine 20 | BinPackArguments: true 21 | BinPackParameters: true 22 | BraceWrapping: 23 | AfterClass: true 24 | AfterControlStatement: false 25 | AfterEnum: true 26 | AfterFunction: true 27 | AfterNamespace: true 28 | AfterObjCDeclaration: false 29 | AfterStruct: true 30 | AfterUnion: true 31 | AfterExternBlock: false 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: None 39 | BreakBeforeBraces: Custom 40 | BreakBeforeInheritanceComma: false 41 | BreakInheritanceList: BeforeColon 42 | BreakBeforeTernaryOperators: false 43 | BreakConstructorInitializersBeforeComma: false 44 | BreakAfterJavaFieldAnnotations: false 45 | BreakStringLiterals: false 46 | ColumnLimit: 80 47 | CommentPragmas: '^ IWYU pragma:' 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 50 | ConstructorInitializerIndentWidth: 4 51 | ContinuationIndentWidth: 4 52 | Cpp11BracedListStyle: false 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: false 57 | ForEachMacros: 58 | - foreach 59 | - Q_FOREACH 60 | - BOOST_FOREACH 61 | IncludeBlocks: Preserve 62 | IncludeCategories: 63 | - Regex: '.*' 64 | Priority: 1 65 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 66 | Priority: 3 67 | - Regex: '.*' 68 | Priority: 1 69 | IncludeIsMainRegex: '(Test)?$' 70 | IndentCaseLabels: false 71 | IndentPPDirectives: None 72 | IndentWidth: 4 73 | IndentWrappedFunctionNames: false 74 | JavaScriptQuotes: Leave 75 | JavaScriptWrapImports: true 76 | KeepEmptyLinesAtTheStartOfBlocks: false 77 | MacroBlockBegin: '' 78 | MacroBlockEnd: '' 79 | MaxEmptyLinesToKeep: 1 80 | NamespaceIndentation: Inner 81 | ObjCBinPackProtocolList: Auto 82 | ObjCBlockIndentWidth: 4 83 | ObjCSpaceAfterProperty: true 84 | ObjCSpaceBeforeProtocolList: true 85 | PenaltyBreakAssignment: 10 86 | PenaltyBreakBeforeFirstCallParameter: 30 87 | PenaltyBreakComment: 10 88 | PenaltyBreakFirstLessLess: 0 89 | PenaltyBreakString: 10 90 | PenaltyBreakTemplateDeclaration: 10 91 | PenaltyExcessCharacter: 100 92 | PenaltyReturnTypeOnItsOwnLine: 60 93 | PointerAlignment: Right 94 | ReflowComments: false 95 | SortIncludes: false 96 | SortUsingDeclarations: false 97 | SpaceAfterCStyleCast: false 98 | SpaceAfterTemplateKeyword: true 99 | SpaceBeforeAssignmentOperators: true 100 | SpaceBeforeCpp11BracedList: false 101 | SpaceBeforeCtorInitializerColon: true 102 | SpaceBeforeInheritanceColon: true 103 | SpaceBeforeParens: Always 104 | SpaceBeforeRangeBasedForLoopColon: true 105 | SpaceInEmptyParentheses: false 106 | SpacesBeforeTrailingComments: 1 107 | SpacesInAngles: false 108 | SpacesInContainerLiterals: false 109 | SpacesInCStyleCastParentheses: false 110 | SpacesInParentheses: false 111 | SpacesInSquareBrackets: false 112 | Standard: Cpp03 113 | TabWidth: 4 114 | UseTab: Never 115 | ... 116 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | name: "Build" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | release: 9 | types: 10 | - published 11 | workflow_dispatch: 12 | 13 | jobs: 14 | source: 15 | name: Source 16 | runs-on: ubuntu-22.04 17 | steps: 18 | - name: Checkout 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 1 22 | submodules: true 23 | - name: Gen Source 24 | run: | 25 | REV_ID=$(git rev-parse --short HEAD) 26 | mkdir -p hev-socks5-server-${{ github.ref_name }} 27 | git ls-files --recurse-submodules | tar c -O -T- | tar x -C hev-socks5-server-${{ github.ref_name }} 28 | echo ${REV_ID} > hev-socks5-server-${{ github.ref_name }}/.rev-id 29 | tar cJf hev-socks5-server-${{ github.ref_name }}.tar.xz hev-socks5-server-${{ github.ref_name }} 30 | - name: Upload source 31 | uses: actions/upload-artifact@v4 32 | with: 33 | name: hev-socks5-server-${{ github.ref_name }}.tar.xz 34 | path: hev-socks5-server-${{ github.ref_name }}.tar.xz 35 | if-no-files-found: error 36 | retention-days: 1 37 | 38 | linux: 39 | name: Linux 40 | runs-on: ubuntu-22.04 41 | strategy: 42 | matrix: 43 | include: 44 | - name: arm64 45 | tool: aarch64-unknown-linux-musl 46 | - name: arm32 47 | tool: arm-unknown-linux-musleabi 48 | - name: arm32hf 49 | tool: arm-unknown-linux-musleabihf 50 | - name: arm32v7 51 | tool: armv7-unknown-linux-musleabi 52 | - name: arm32v7hf 53 | tool: armv7-unknown-linux-musleabihf 54 | - name: i586 55 | tool: i586-unknown-linux-musl 56 | - name: i686 57 | tool: i686-unknown-linux-musl 58 | - name: loong64 59 | tool: loongarch64-unknown-linux-musl 60 | - name: m68k 61 | tool: m68k-unknown-linux-musl 62 | - name: microblazeel 63 | tool: microblazeel-xilinx-linux-musl 64 | - name: microblaze 65 | tool: microblaze-xilinx-linux-musl 66 | - name: mips64el 67 | tool: mips64el-unknown-linux-musl 68 | - name: mips64 69 | tool: mips64-unknown-linux-musl 70 | - name: mips32el 71 | tool: mipsel-unknown-linux-musl 72 | - name: mips32elsf 73 | tool: mipsel-unknown-linux-muslsf 74 | - name: mips32 75 | tool: mips-unknown-linux-musl 76 | - name: mips32sf 77 | tool: mips-unknown-linux-muslsf 78 | - name: powerpc64 79 | tool: powerpc64-unknown-linux-musl 80 | - name: powerpc 81 | tool: powerpc-unknown-linux-musl 82 | - name: riscv32 83 | tool: riscv32-unknown-linux-musl 84 | - name: riscv64 85 | tool: riscv64-unknown-linux-musl 86 | - name: s390x 87 | tool: s390x-ibm-linux-musl 88 | - name: sh 89 | tool: sh-multilib-linux-musl 90 | - name: sheb 91 | tool: sh-multilib-linux-musl 92 | env: 93 | CFLAGS: "-mb" 94 | - name: x86_64 95 | tool: x86_64-unknown-linux-musl 96 | steps: 97 | - name: Checkout 98 | uses: actions/checkout@v4 99 | with: 100 | fetch-depth: 1 101 | submodules: true 102 | - name: Build ${{ matrix.name }} 103 | run: | 104 | sudo mkdir -p /opt/x-tools 105 | wget https://github.com/musl-cross/musl-cross/releases/download/20250206/${{ matrix.tool }}.tar.xz 106 | sudo tar xf ${{ matrix.tool }}.tar.xz -C /opt/x-tools 107 | make CROSS_PREFIX=/opt/x-tools/${{ matrix.tool }}/bin/${{ matrix.tool }}- CFLAGS=${{ matrix.env.CFLAGS }} ENABLE_STATIC=1 -j`nproc` 108 | cp bin/hev-socks5-server hev-socks5-server-linux-${{ matrix.name }} 109 | - name: Upload ${{ matrix.name }} 110 | uses: actions/upload-artifact@v4 111 | with: 112 | name: hev-socks5-server-linux-${{ matrix.name }} 113 | path: hev-socks5-server-linux-${{ matrix.name }} 114 | if-no-files-found: error 115 | retention-days: 1 116 | 117 | windows: 118 | name: Windows 119 | runs-on: windows-latest 120 | defaults: 121 | run: 122 | shell: cmd 123 | steps: 124 | - name: Checkout 125 | uses: actions/checkout@v4 126 | with: 127 | fetch-depth: 1 128 | submodules: true 129 | - name: Setup MSYS2 130 | uses: msys2/setup-msys2@v2 131 | with: 132 | msystem: MSYS 133 | location: D:\msys2 134 | update: true 135 | install: >- 136 | gcc 137 | git 138 | make 139 | wget 140 | zip 141 | openssl-devel 142 | - name: Build 143 | shell: msys2 {0} 144 | run: | 145 | export MSYS=winsymlinks:native 146 | git clone --depth=1 --recursive file://`pwd` work; cd work 147 | make LFLAGS="-lmsys-2.0 -lws2_32" -j`nproc` 148 | mkdir hev-socks5-server 149 | cp bin/hev-socks5-server* hev-socks5-server 150 | wget -P hev-socks5-server https://github.com/heiher/msys2/releases/latest/download/msys-2.0.dll 151 | zip -r ../hev-socks5-server-win64.zip hev-socks5-server 152 | - name: Upload ${{ matrix.name }} 153 | uses: actions/upload-artifact@v4 154 | with: 155 | name: hev-socks5-server-win64.zip 156 | path: hev-socks5-server-win64.zip 157 | if-no-files-found: error 158 | retention-days: 1 159 | 160 | macos: 161 | name: macOS 162 | runs-on: macos-14 163 | strategy: 164 | matrix: 165 | include: 166 | - name: arm64 167 | flags: -arch arm64 -mmacosx-version-min=11.0 168 | - name: x86_64 169 | flags: -arch x86_64 -mmacosx-version-min=10.6 170 | steps: 171 | - name: Checkout 172 | uses: actions/checkout@v4 173 | with: 174 | fetch-depth: 1 175 | submodules: true 176 | - name: Build ${{ matrix.name }} 177 | run: | 178 | make CC=clang CFLAGS="${{ matrix.flags }}" LFLAGS="${{ matrix.flags }}" -j $(sysctl -n hw.logicalcpu) 179 | cp bin/hev-socks5-server hev-socks5-server-darwin-${{ matrix.name }} 180 | - name: Upload ${{ matrix.name }} 181 | uses: actions/upload-artifact@v4 182 | with: 183 | name: hev-socks5-server-darwin-${{ matrix.name }} 184 | path: hev-socks5-server-darwin-${{ matrix.name }} 185 | if-no-files-found: error 186 | retention-days: 1 187 | 188 | freebsd: 189 | name: FreeBSD 190 | runs-on: ubuntu-22.04 191 | steps: 192 | - name: Checkout 193 | uses: actions/checkout@v4 194 | with: 195 | fetch-depth: 1 196 | submodules: true 197 | - name: Build 198 | uses: vmactions/freebsd-vm@v1 199 | with: 200 | usesh: true 201 | prepare: | 202 | pkg install -y gmake gcc 203 | run: | 204 | gmake 205 | cp bin/hev-socks5-server hev-socks5-server-freebsd-x86_64 206 | - name: Upload 207 | uses: actions/upload-artifact@v4 208 | with: 209 | name: hev-socks5-server-freebsd-x86_64 210 | path: hev-socks5-server-freebsd-x86_64 211 | if-no-files-found: error 212 | retention-days: 1 213 | 214 | release: 215 | name: Release 216 | runs-on: ubuntu-22.04 217 | needs: 218 | - source 219 | - linux 220 | - macos 221 | - freebsd 222 | - windows 223 | if: github.event_name == 'release' 224 | steps: 225 | - name: Checkout 226 | uses: actions/checkout@v4 227 | with: 228 | fetch-depth: 1 229 | - name: Download artifacts 230 | uses: actions/download-artifact@v4 231 | with: 232 | path: release 233 | pattern: "hev-*" 234 | merge-multiple: true 235 | - name: Upload artifacts 236 | env: 237 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 238 | run: | 239 | for i in release/hev-*; do 240 | gh release upload ${{ github.event.release.tag_name }} $i 241 | done 242 | 243 | apple: 244 | name: Apple 245 | runs-on: macos-14 246 | if: github.event_name != 'release' 247 | steps: 248 | - name: Checkout 249 | uses: actions/checkout@v4 250 | with: 251 | fetch-depth: 1 252 | submodules: true 253 | - name: Build 254 | run: | 255 | ./build-apple.sh 256 | 257 | android: 258 | name: Android 259 | runs-on: ubuntu-22.04 260 | if: github.event_name != 'release' 261 | steps: 262 | - name: Checkout 263 | uses: actions/checkout@v4 264 | with: 265 | fetch-depth: 1 266 | submodules: true 267 | - name: Prepare 268 | run: | 269 | wget https://dl.google.com/android/repository/android-ndk-r27b-linux.zip 270 | unzip android-ndk-r27b-linux.zip 271 | ln -sf . jni 272 | - name: Build 273 | run: | 274 | ./android-ndk-r27b/ndk-build 275 | 276 | llvm: 277 | name: LLVM 278 | runs-on: ubuntu-24.04 279 | if: github.event_name != 'release' 280 | steps: 281 | - name: Checkout 282 | uses: actions/checkout@v4 283 | with: 284 | fetch-depth: 1 285 | submodules: true 286 | - name: Prepare 287 | run: | 288 | sudo apt install -y clang 289 | - name: Build 290 | run: | 291 | make CC=clang ENABLE_STATIC=1 -j`nproc` 292 | -------------------------------------------------------------------------------- /.github/workflows/code-format.yaml: -------------------------------------------------------------------------------- 1 | name: "Check code formatting" 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | 9 | jobs: 10 | checker: 11 | runs-on: ubuntu-24.04 12 | steps: 13 | - name: Checkout 14 | uses: actions/checkout@v4 15 | with: 16 | fetch-depth: 1 17 | - name: Prepare 18 | run: | 19 | sudo apt install -y clang-format 20 | - name: Format 21 | run: | 22 | find src -iname "*.[h,c]" -exec clang-format -i {} \; 23 | - name: Check 24 | run: | 25 | git status 26 | git diff --quiet 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | build 3 | HevSocks5Server.xcframework 4 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "third-part/hev-task-system"] 2 | path = third-part/hev-task-system 3 | url = https://github.com/heiher/hev-task-system 4 | [submodule "third-part/yaml"] 5 | path = third-part/yaml 6 | url = https://github.com/heiher/yaml 7 | [submodule "src/core"] 8 | path = src/core 9 | url = https://github.com/heiher/hev-socks5-core 10 | -------------------------------------------------------------------------------- /Android.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Android Open Source Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | TOP_PATH := $(call my-dir) 17 | 18 | ifeq ($(filter $(modules-get-list),yaml),) 19 | include $(TOP_PATH)/third-part/yaml/Android.mk 20 | endif 21 | ifeq ($(filter $(modules-get-list),hev-task-system),) 22 | include $(TOP_PATH)/third-part/hev-task-system/Android.mk 23 | endif 24 | 25 | LOCAL_PATH = $(TOP_PATH) 26 | SRCDIR := $(LOCAL_PATH)/src 27 | 28 | include $(CLEAR_VARS) 29 | include $(LOCAL_PATH)/build.mk 30 | LOCAL_MODULE := hev-socks5-server 31 | LOCAL_SRC_FILES := $(patsubst $(SRCDIR)/%,src/%,$(SRCFILES)) 32 | LOCAL_C_INCLUDES := \ 33 | $(LOCAL_PATH)/src/misc \ 34 | $(LOCAL_PATH)/src/core/include \ 35 | $(LOCAL_PATH)/third-part/yaml/include \ 36 | $(LOCAL_PATH)/third-part/hev-task-system/include 37 | LOCAL_CFLAGS += $(VERSION_CFLAGS) 38 | ifeq ($(TARGET_ARCH_ABI),armeabi-v7a) 39 | LOCAL_CFLAGS += -mfpu=neon 40 | endif 41 | LOCAL_STATIC_LIBRARIES := yaml hev-task-system 42 | include $(BUILD_SHARED_LIBRARY) 43 | -------------------------------------------------------------------------------- /Application.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2024 The Android Open Source Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | 16 | APP_OPTIM := release 17 | APP_PLATFORM := android-21 18 | APP_ABI := armeabi-v7a arm64-v8a 19 | APP_CFLAGS := -O3 20 | NDK_TOOLCHAIN_VERSION := clang 21 | -------------------------------------------------------------------------------- /License: -------------------------------------------------------------------------------- 1 | Copyright (c) 2024 hev 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for hev-socks5-server 2 | 3 | PROJECT=hev-socks5-server 4 | 5 | CROSS_PREFIX := 6 | PP=$(CROSS_PREFIX)cpp 7 | CC=$(CROSS_PREFIX)gcc 8 | STRIP=$(CROSS_PREFIX)strip 9 | CCFLAGS=-O3 -pipe -Wall -Werror $(CFLAGS) \ 10 | -I$(SRCDIR)/misc \ 11 | -I$(SRCDIR)/core/include \ 12 | -I$(THIRDPARTDIR)/yaml/src \ 13 | -I$(THIRDPARTDIR)/hev-task-system/include 14 | LDFLAGS=-L$(THIRDPARTDIR)/yaml/bin -lyaml \ 15 | -L$(THIRDPARTDIR)/hev-task-system/bin -lhev-task-system 16 | 17 | SRCDIR=src 18 | BINDIR=bin 19 | CONFDIR=conf 20 | BUILDDIR=build 21 | INSTDIR=/usr/local 22 | THIRDPARTDIR=third-part 23 | 24 | CONFIG=$(CONFDIR)/main.yml 25 | EXEC_TARGET=$(BINDIR)/hev-socks5-server 26 | STATIC_TARGET=$(BINDIR)/lib$(PROJECT).a 27 | SHARED_TARGET=$(BINDIR)/lib$(PROJECT).so 28 | THIRDPARTS=$(THIRDPARTDIR)/yaml $(THIRDPARTDIR)/hev-task-system 29 | 30 | $(SHARED_TARGET) : CCFLAGS+=-fPIC 31 | $(SHARED_TARGET) : LDFLAGS+=-shared -pthread 32 | 33 | -include build.mk 34 | CCFLAGS+=$(VERSION_CFLAGS) 35 | CCSRCS=$(filter %.c,$(SRCFILES)) 36 | ASSRCS=$(filter %.S,$(SRCFILES)) 37 | LDOBJS=$(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(CCSRCS)) \ 38 | $(patsubst $(SRCDIR)/%.S,$(BUILDDIR)/%.o,$(ASSRCS)) 39 | DEPEND=$(LDOBJS:.o=.dep) 40 | 41 | BUILDMSG="\e[1;31mBUILD\e[0m %s\n" 42 | LINKMSG="\e[1;34mLINK\e[0m \e[1;32m%s\e[0m\n" 43 | STRIPMSG="\e[1;34mSTRIP\e[0m \e[1;32m%s\e[0m\n" 44 | CLEANMSG="\e[1;34mCLEAN\e[0m %s\n" 45 | INSTMSG="\e[1;34mINST\e[0m %s -> %s\n" 46 | UNINSMSG="\e[1;34mUNINS\e[0m %s\n" 47 | 48 | ENABLE_DEBUG := 49 | ifeq ($(ENABLE_DEBUG),1) 50 | CCFLAGS+=-g -O0 -DENABLE_DEBUG 51 | STRIP=true 52 | endif 53 | 54 | ENABLE_STATIC := 55 | ifeq ($(ENABLE_STATIC),1) 56 | CCFLAGS+=-static 57 | endif 58 | 59 | LDFLAGS+=-lpthread $(LFLAGS) 60 | 61 | V := 62 | ECHO_PREFIX := @ 63 | ifeq ($(V),1) 64 | undefine ECHO_PREFIX 65 | endif 66 | 67 | .PHONY: exec static shared clean install uninstall tp-static tp-shared tp-clean 68 | 69 | exec : $(EXEC_TARGET) 70 | 71 | static : $(STATIC_TARGET) 72 | 73 | shared : $(SHARED_TARGET) 74 | 75 | tp-static : $(THIRDPARTS) 76 | @$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) static;) 77 | 78 | tp-shared : $(THIRDPARTS) 79 | @$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) shared;) 80 | 81 | tp-clean : $(THIRDPARTS) 82 | @$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) clean;) 83 | 84 | clean : tp-clean 85 | $(ECHO_PREFIX) $(RM) -rf $(BINDIR) $(BUILDDIR) 86 | @printf $(CLEANMSG) $(PROJECT) 87 | 88 | install : $(INSTDIR)/bin/$(PROJECT) $(INSTDIR)/etc/$(PROJECT).yml 89 | 90 | uninstall : 91 | $(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/bin/$(PROJECT) 92 | @printf $(UNINSMSG) $(INSTDIR)/bin/$(PROJECT) 93 | $(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/etc/$(PROJECT).yml 94 | @printf $(UNINSMSG) $(INSTDIR)/etc/$(PROJECT).yml 95 | 96 | $(INSTDIR)/bin/$(PROJECT) : $(EXEC_TARGET) 97 | $(ECHO_PREFIX) install -d -m 0755 $(dir $@) 98 | $(ECHO_PREFIX) install -m 0755 $< $@ 99 | @printf $(INSTMSG) $< $@ 100 | 101 | $(INSTDIR)/etc/$(PROJECT).yml : $(CONFIG) 102 | $(ECHO_PREFIX) install -d -m 0755 $(dir $@) 103 | $(ECHO_PREFIX) install -m 0644 $< $@ 104 | @printf $(INSTMSG) $< $@ 105 | 106 | $(EXEC_TARGET) : $(LDOBJS) tp-static 107 | $(ECHO_PREFIX) mkdir -p $(dir $@) 108 | $(ECHO_PREFIX) $(CC) $(CCFLAGS) -o $@ $(LDOBJS) $(LDFLAGS) 109 | @printf $(LINKMSG) $@ 110 | $(ECHO_PREFIX) $(STRIP) $@ 111 | @printf $(STRIPMSG) $@ 112 | 113 | $(STATIC_TARGET) : $(LDOBJS) tp-static 114 | $(ECHO_PREFIX) mkdir -p $(dir $@) 115 | $(ECHO_PREFIX) $(AR) csq $@ $(LDOBJS) 116 | @printf $(LINKMSG) $@ 117 | 118 | $(SHARED_TARGET) : $(LDOBJS) tp-shared 119 | $(ECHO_PREFIX) mkdir -p $(dir $@) 120 | $(ECHO_PREFIX) $(CC) $(CCFLAGS) -o $@ $(LDOBJS) $(LDFLAGS) 121 | @printf $(LINKMSG) $@ 122 | 123 | $(BUILDDIR)/%.dep : $(SRCDIR)/%.c 124 | $(ECHO_PREFIX) mkdir -p $(dir $@) 125 | $(ECHO_PREFIX) $(PP) $(CCFLAGS) -MM -MT$(@:.dep=.o) -MF$@ $< 2>/dev/null 126 | 127 | $(BUILDDIR)/%.o : $(SRCDIR)/%.c 128 | $(ECHO_PREFIX) mkdir -p $(dir $@) 129 | $(ECHO_PREFIX) $(CC) $(CCFLAGS) -c -o $@ $< 130 | @printf $(BUILDMSG) $< 131 | 132 | ifneq ($(MAKECMDGOALS),clean) 133 | -include $(DEPEND) 134 | endif 135 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # HevSocks5Server 2 | 3 | [![status](https://github.com/heiher/hev-socks5-server/actions/workflows/build.yaml/badge.svg?branch=master&event=push)](https://github.com/heiher/hev-socks5-server) 4 | 5 | HevSocks5Server is a simple, lightweight socks5 server. 6 | 7 | ## Features 8 | 9 | * IPv4/IPv6. (dual stack) 10 | * Standard `CONNECT` command. 11 | * Standard `UDP ASSOCIATE` command. [^1] 12 | * Extended `FWD UDP` command. (UDP in TCP) [^2] 13 | * Multiple username/password authentication. 14 | 15 | ## Benchmarks 16 | 17 | See [here](https://github.com/heiher/hev-socks5-server/wiki/Benchmarks) for more details. 18 | 19 | ### Speed 20 | 21 | ![](https://github.com/heiher/hev-socks5-server/wiki/res/upload-speed.png) 22 | ![](https://github.com/heiher/hev-socks5-server/wiki/res/download-speed.png) 23 | 24 | ### CPU usage 25 | 26 | ![](https://github.com/heiher/hev-socks5-server/wiki/res/upload-cpu.png) 27 | ![](https://github.com/heiher/hev-socks5-server/wiki/res/download-cpu.png) 28 | 29 | ### Memory usage 30 | 31 | ![](https://github.com/heiher/hev-socks5-server/wiki/res/upload-mem.png) 32 | ![](https://github.com/heiher/hev-socks5-server/wiki/res/download-mem.png) 33 | 34 | ## How to Build 35 | 36 | ### Unix 37 | 38 | ```bash 39 | git clone --recursive https://github.com/heiher/hev-socks5-server 40 | cd hev-socks5-server 41 | make 42 | 43 | # statically link 44 | make ENABLE_STATIC=1 45 | ``` 46 | 47 | ### Android 48 | 49 | ```bash 50 | mkdir hev-socks5-server 51 | cd hev-socks5-server 52 | git clone --recursive https://github.com/heiher/hev-socks5-server jni 53 | cd jni 54 | ndk-build 55 | ``` 56 | 57 | ### iOS and MacOS 58 | 59 | ```bash 60 | git clone --recursive https://github.com/heiher/hev-socks5-server 61 | cd hev-socks5-server 62 | # will generate HevSocks5Server.xcframework 63 | ./build-apple.sh 64 | ``` 65 | 66 | ### Windows (MSYS2) 67 | 68 | ```bash 69 | export MSYS=winsymlinks:native 70 | git clone --recursive https://github.com/heiher/hev-socks5-server 71 | cd hev-socks5-server 72 | make LFLAGS="-lmsys-2.0 -lws2_32" 73 | ``` 74 | 75 | ## How to Use 76 | 77 | ### Config 78 | 79 | ```yaml 80 | main: 81 | # Worker threads 82 | workers: 4 83 | # Listen port 84 | port: 1080 85 | # Listen address (ipv4|ipv6) 86 | listen-address: '::' 87 | # UDP listen port 88 | udp-port: 1080 89 | # UDP listen address (ipv4|ipv6) 90 | # udp-listen-address: '::1' 91 | # Listen ipv6 only 92 | listen-ipv6-only: false 93 | # Bind source address (ipv4|ipv6) 94 | # It is overridden by bind-address-v{4,6} if specified 95 | bind-address: '' 96 | # Bind source address (ipv4) 97 | bind-address-v4: '' 98 | # Bind source address (ipv6) 99 | bind-address-v6: '' 100 | # Bind source network interface 101 | bind-interface: '' 102 | # Domain address type (ipv4|ipv6|unspec) 103 | domain-address-type: unspec 104 | # Socket mark (hex: 0x1, dec: 1, oct: 01) 105 | mark: 0 106 | 107 | #auth: 108 | # file: conf/auth.txt 109 | # username: 110 | # password: 111 | 112 | #misc: 113 | # task stack size (bytes) 114 | # task-stack-size: 8192 115 | # connect timeout (ms) 116 | # connect-timeout: 5000 117 | # read-write timeout (ms) 118 | # read-write-timeout: 60000 119 | # stdout, stderr or file-path 120 | # log-file: stderr 121 | # debug, info, warn or error 122 | # log-level: warn 123 | # If present, run as a daemon with this pid file 124 | # pid-file: /run/hev-socks5-server.pid 125 | # If present, set rlimit nofile; else use default value 126 | # limit-nofile: 65535 127 | ``` 128 | 129 | ### Authentication file 130 | 131 | ``` 132 | 133 | ``` 134 | 135 | - USERNAME: A string of up to 255 characters 136 | - PASSWORD: A string of up to 255 characters 137 | - MARK: Hexadecimal 138 | 139 | ### Run 140 | 141 | ```bash 142 | bin/hev-socks5-server conf/main.yml 143 | ``` 144 | 145 | ### Live updating authentication file 146 | 147 | Send signal `SIGUSR1` to socks5 server process after the authentication file is updated. 148 | 149 | ```bash 150 | killall -SIGUSR1 hev-socks5-server 151 | ``` 152 | 153 | ### Limit number of connections 154 | 155 | For example, limit the number of connections for `jerry` up to `2`: 156 | 157 | #### Config 158 | 159 | ```yaml 160 | auth: 161 | file: conf/auth.txt 162 | ``` 163 | 164 | #### Auth file 165 | 166 | ``` 167 | jerry pass 1a 168 | ``` 169 | 170 | #### IPtables 171 | 172 | ```bash 173 | iptables -A OUTPUT -p tcp --syn -m mark --mark 0x1a -m connlimit --connlimit-above 2 -j REJECT 174 | ``` 175 | 176 | ## API 177 | 178 | ```c 179 | /** 180 | * hev_socks5_server_main_from_file: 181 | * @config_path: config file path 182 | * 183 | * Start and run the socks5 server, this function will blocks until the 184 | * hev_socks5_server_quit is called or an error occurs. 185 | * 186 | * Returns: returns zero on successful, otherwise returns -1. 187 | * 188 | * Since: 2.6.7 189 | */ 190 | int hev_socks5_server_main_from_file (const char *config_path); 191 | 192 | /** 193 | * hev_socks5_server_main_from_str: 194 | * @config_str: string config 195 | * @config_len: the byte length of string config 196 | * 197 | * Start and run the socks5 server, this function will blocks until the 198 | * hev_socks5_server_quit is called or an error occurs. 199 | * 200 | * Returns: returns zero on successful, otherwise returns -1. 201 | * 202 | * Since: 2.6.7 203 | */ 204 | int hev_socks5_server_main_from_str (const unsigned char *config_str, 205 | unsigned int config_len); 206 | 207 | /** 208 | * hev_socks5_server_quit: 209 | * 210 | * Stop the socks5 server. 211 | * 212 | * Since: 2.6.7 213 | */ 214 | void hev_socks5_server_quit (void); 215 | ``` 216 | 217 | ## Use Cases 218 | 219 | ### Android App 220 | 221 | * [Socks5](https://github.com/heiher/socks5) 222 | 223 | ### iOS App 224 | 225 | * [Socks5](https://github.com/heiher/socks5-ios) 226 | 227 | ## Contributors 228 | 229 | * **ammar faizi** - https://github.com/ammarfaizi2 230 | * **hev** - https://hev.cc 231 | * **pexcn** - 232 | 233 | ## License 234 | 235 | MIT 236 | 237 | [^1]: Windows is not supported at this time. 238 | [^2]: The [hev-socks5-tunnel](https://github.com/heiher/hev-socks5-tunnel) and [hev-socks5-tproxy](https://github.com/heiher/hev-socks5-tproxy) clients support UDP relay over TCP. 239 | -------------------------------------------------------------------------------- /build-apple.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e 4 | 5 | XCFRAMEWORK_DIR="./apple_xcframework" 6 | 7 | # buildStatic iphoneos -mios-version-min=15.0 arm64 8 | buildStatic() 9 | { 10 | echo "build for $1, $2, min version $3" 11 | 12 | local MIN_VERSION="-m$1-version-min=$3" 13 | make PP="xcrun --sdk $1 --toolchain $1 clang" \ 14 | CC="xcrun --sdk $1 --toolchain $1 clang" \ 15 | CFLAGS="-arch $2 $MIN_VERSION" \ 16 | LFLAGS="-arch $2 $MIN_VERSION -Wl,-Bsymbolic-functions" static 17 | 18 | local OUTPUT_DIR="$XCFRAMEWORK_DIR/$1-$2" 19 | mkdir -p $OUTPUT_DIR 20 | local OUTPUT_ARCH_FILE="$OUTPUT_DIR/libhev-socks5-server.a" 21 | 22 | libtool -static -o $OUTPUT_ARCH_FILE \ 23 | bin/libhev-socks5-server.a \ 24 | third-part/yaml/bin/libyaml.a \ 25 | third-part/hev-task-system/bin/libhev-task-system.a 26 | make clean 27 | } 28 | 29 | mergeStatic() 30 | { 31 | echo "merge for $1, $2, $3" 32 | local FIRST_LIB_FILE="$XCFRAMEWORK_DIR/$1-$2/libhev-socks5-server.a" 33 | local SECOND_LIB_FILE="$XCFRAMEWORK_DIR/$1-$3/libhev-socks5-server.a" 34 | local OUTPUT_DIR="$XCFRAMEWORK_DIR/$1-$2-$3" 35 | mkdir -p $OUTPUT_DIR 36 | local OUTPUT_ARCH_FILE="$OUTPUT_DIR/libhev-socks5-server.a" 37 | lipo -create \ 38 | -arch $2 $FIRST_LIB_FILE \ 39 | -arch $3 $SECOND_LIB_FILE \ 40 | -output $OUTPUT_ARCH_FILE 41 | } 42 | 43 | rm -rf $XCFRAMEWORK_DIR 44 | rm -rf HevSocks5Server.xcframework 45 | mkdir $XCFRAMEWORK_DIR 46 | 47 | buildStatic iphoneos arm64 15.0 48 | buildStatic iphonesimulator x86_64 15.0 49 | buildStatic iphonesimulator arm64 15.0 50 | mergeStatic iphonesimulator x86_64 arm64 51 | 52 | # keep same with flutter 53 | buildStatic macosx x86_64 10.14 54 | buildStatic macosx arm64 10.14 55 | mergeStatic macosx x86_64 arm64 56 | 57 | buildStatic appletvos arm64 17.0 58 | buildStatic appletvsimulator x86_64 17.0 59 | buildStatic appletvsimulator arm64 17.0 60 | mergeStatic appletvsimulator x86_64 arm64 61 | 62 | INCLUDE_DIR="$XCFRAMEWORK_DIR/include" 63 | mkdir -p $INCLUDE_DIR 64 | cp ./src/hev-main.h $INCLUDE_DIR 65 | cp ./module.modulemap $INCLUDE_DIR 66 | xcodebuild -create-xcframework \ 67 | -library ./apple_xcframework/iphoneos-arm64/libhev-socks5-server.a -headers $INCLUDE_DIR \ 68 | -library ./apple_xcframework/iphonesimulator-x86_64-arm64/libhev-socks5-server.a -headers $INCLUDE_DIR \ 69 | -library ./apple_xcframework/macosx-x86_64-arm64/libhev-socks5-server.a -headers $INCLUDE_DIR \ 70 | -library ./apple_xcframework/appletvos-arm64/libhev-socks5-server.a -headers $INCLUDE_DIR \ 71 | -library ./apple_xcframework/appletvsimulator-x86_64-arm64/libhev-socks5-server.a -headers $INCLUDE_DIR \ 72 | -output ./HevSocks5Server.xcframework 73 | 74 | rm -rf ./apple_xcframework 75 | -------------------------------------------------------------------------------- /build.mk: -------------------------------------------------------------------------------- 1 | # Build 2 | 3 | rwildcard=$(foreach d,$(wildcard $1*), \ 4 | $(call rwildcard,$d/,$2) \ 5 | $(filter $(subst *,%,$2),$d)) 6 | 7 | SRCFILES=$(call rwildcard,$(SRCDIR)/,*.c *.S) 8 | 9 | ifeq ($(REV_ID),) 10 | ifneq (,$(wildcard .rev-id)) 11 | REV_ID=$(shell cat .rev-id) 12 | endif 13 | ifeq ($(REV_ID),) 14 | REV_ID=$(shell git -C $(SRCDIR) rev-parse --short HEAD) 15 | endif 16 | ifeq ($(REV_ID),) 17 | REV_ID=unknown 18 | endif 19 | endif 20 | VERSION_CFLAGS=-DCOMMIT_ID=\"$(REV_ID)\" 21 | -------------------------------------------------------------------------------- /conf/auth.txt: -------------------------------------------------------------------------------- 1 | tom pass 2 | jerry pass 1a 3 | -------------------------------------------------------------------------------- /conf/main.yml: -------------------------------------------------------------------------------- 1 | # Main configuration for hev-socks5-server 2 | 3 | main: 4 | # Worker threads 5 | workers: 4 6 | # Listen port 7 | port: 1080 8 | # Listen address (ipv4|ipv6) 9 | listen-address: '::' 10 | # UDP listen port 11 | udp-port: 1080 12 | # UDP listen address (ipv4|ipv6) 13 | # udp-listen-address: '::1' 14 | # Listen ipv6 only 15 | listen-ipv6-only: false 16 | # Bind source address (ipv4|ipv6) 17 | # It is overridden by bind-address-v{4,6} if specified 18 | bind-address: '' 19 | # Bind source address (ipv4) 20 | bind-address-v4: '' 21 | # Bind source address (ipv6) 22 | bind-address-v6: '' 23 | # Bind source network interface 24 | bind-interface: '' 25 | # Domain address type (ipv4|ipv6|unspec) 26 | domain-address-type: unspec 27 | # Socket mark (hex: 0x1, dec: 1, oct: 01) 28 | mark: 0 29 | 30 | #auth: 31 | # file: conf/auth.txt 32 | # username: 33 | # password: 34 | 35 | #misc: 36 | # task stack size (bytes) 37 | # task-stack-size: 8192 38 | # udp recv buffer size (bytes) 39 | # udp-recv-buffer-size: 524288 40 | # connect timeout (ms) 41 | # connect-timeout: 5000 42 | # read-write timeout (ms) 43 | # read-write-timeout: 60000 44 | # stdout, stderr or file-path 45 | # log-file: stderr 46 | # debug, info, warn or error 47 | # log-level: warn 48 | # If present, run as a daemon with this pid file 49 | # pid-file: /run/hev-socks5-server.pid 50 | # If present, set rlimit nofile; else use default value 51 | # limit-nofile: 65535 52 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | # 2 | # Dockerfile for hev-socks5-server 3 | # 4 | 5 | # 6 | # Build stage 7 | # 8 | FROM alpine AS builder 9 | 10 | COPY . /tmp/hev-socks5-server 11 | 12 | # build 13 | RUN apk update \ 14 | && apk add --no-cache --virtual .build-deps build-base \ 15 | && cd /tmp/hev-socks5-server \ 16 | && make -j$(nproc) \ 17 | && make install INSTDIR="/app" \ 18 | && make clean \ 19 | && cd / \ 20 | && rm -r /tmp/hev-socks5-server \ 21 | && apk del .build-deps \ 22 | && rm -rf /var/cache/apk/* 23 | 24 | # 25 | # Runtime stage 26 | # 27 | FROM alpine 28 | 29 | ENV TZ=Asia/Taipei 30 | 31 | # add depends 32 | RUN apk update \ 33 | && apk add --no-cache tzdata \ 34 | && rm -rf /var/cache/apk/* 35 | 36 | # copy files 37 | COPY --from=builder /app /app/ 38 | RUN chown nobody:nobody /app/etc 39 | COPY docker/entrypoint.sh /app/entrypoint.sh 40 | 41 | USER nobody 42 | ENTRYPOINT ["/app/entrypoint.sh"] 43 | -------------------------------------------------------------------------------- /docker/README.md: -------------------------------------------------------------------------------- 1 | # hev-socks5-server for docker 2 | 3 | ## Usage 4 | 5 | Available environment variables: 6 | ```bash 7 | PORT 8 | LISTEN_ADDRESS 9 | AUTH 10 | ``` 11 | 12 | ```bash 13 | cd hev-socks5-server 14 | docker build -t hev-socks5-server -f docker/Dockerfile . 15 | docker run -d \ 16 | --name hev-socks5-server \ 17 | --restart always \ 18 | --net host \ 19 | -e PORT=1081 \ 20 | -e AUTH="user:pass" \ 21 | hev-socks5-server 22 | ``` 23 | -------------------------------------------------------------------------------- /docker/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if [[ -n "$PORT" && "$PORT" != 1080 ]]; then 4 | sed -i "s/ port: 1080/ port: $PORT/" /app/etc/hev-socks5-server.yml 5 | fi 6 | 7 | if [[ -n "$LISTEN_ADDRESS" && "$LISTEN_ADDRESS" != '::' ]]; then 8 | sed -i "s/ listen-address: '::'/ listen-address: $LISTEN_ADDRESS/" /app/etc/hev-socks5-server.yml 9 | fi 10 | 11 | if [[ -n "$AUTH" ]]; then 12 | sed -i "s/#auth:/auth:/" /app/etc/hev-socks5-server.yml 13 | sed -i "s/# username:/ username: $(echo $AUTH | cut -d ':' -f 1)/" /app/etc/hev-socks5-server.yml 14 | sed -i "s/# password:/ password: $(echo $AUTH | cut -d ':' -f 2)/" /app/etc/hev-socks5-server.yml 15 | fi 16 | 17 | exec /app/bin/hev-socks5-server /app/etc/hev-socks5-server.yml 18 | -------------------------------------------------------------------------------- /module.modulemap: -------------------------------------------------------------------------------- 1 | module HevSocks5Server { 2 | umbrella header "hev-main.h" 3 | export * 4 | } 5 | -------------------------------------------------------------------------------- /src/hev-config-const.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-config-const.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2023 hev 6 | Description : Config Constants 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_CONFIG_CONST_H__ 11 | #define __HEV_CONFIG_CONST_H__ 12 | 13 | #define MAJOR_VERSION (2) 14 | #define MINOR_VERSION (8) 15 | #define MICRO_VERSION (0) 16 | 17 | #endif /* __HEV_CONFIG_CONST_H__ */ 18 | -------------------------------------------------------------------------------- /src/hev-config.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-config.c 4 | Author : hev 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Config 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "hev-logger.h" 18 | #include "hev-config.h" 19 | 20 | static unsigned int workers; 21 | static int listen_ipv6_only; 22 | static char listen_address[256]; 23 | static char listen_port[8]; 24 | static char udp_listen_address[256]; 25 | static char udp_listen_port[8]; 26 | static char bind_address[2][256]; 27 | static char bind_interface[256]; 28 | static char auth_file[1024]; 29 | static char username[256]; 30 | static char password[256]; 31 | static char log_file[1024]; 32 | static char pid_file[1024]; 33 | static int task_stack_size = 8192; 34 | static int udp_recv_buffer_size = 524288; 35 | static int connect_timeout = 5000; 36 | static int read_write_timeout = 60000; 37 | static int limit_nofile = 65535; 38 | static int log_level = HEV_LOGGER_WARN; 39 | static int addr_family = HEV_SOCKS5_ADDR_FAMILY_UNSPEC; 40 | static unsigned int socket_mark; 41 | 42 | static int 43 | hev_config_parse_main (yaml_document_t *doc, yaml_node_t *base) 44 | { 45 | yaml_node_pair_t *pair; 46 | const char *addr = NULL; 47 | const char *port = NULL; 48 | const char *mark = NULL; 49 | const char *udp_addr = NULL; 50 | const char *udp_port = NULL; 51 | const char *bind_saddr = NULL; 52 | const char *bind_saddr4 = NULL; 53 | const char *bind_saddr6 = NULL; 54 | const char *bind_iface = NULL; 55 | const char *addr_type = NULL; 56 | 57 | if (!base || YAML_MAPPING_NODE != base->type) 58 | return -1; 59 | 60 | for (pair = base->data.mapping.pairs.start; 61 | pair < base->data.mapping.pairs.top; pair++) { 62 | yaml_node_t *node; 63 | const char *key, *value; 64 | 65 | if (!pair->key || !pair->value) 66 | break; 67 | 68 | node = yaml_document_get_node (doc, pair->key); 69 | if (!node || YAML_SCALAR_NODE != node->type) 70 | break; 71 | key = (const char *)node->data.scalar.value; 72 | 73 | node = yaml_document_get_node (doc, pair->value); 74 | if (!node || YAML_SCALAR_NODE != node->type) 75 | break; 76 | value = (const char *)node->data.scalar.value; 77 | 78 | if (0 == strcmp (key, "workers")) 79 | workers = strtoul (value, NULL, 10); 80 | else if (0 == strcmp (key, "port")) 81 | port = value; 82 | else if (0 == strcmp (key, "listen-address")) 83 | addr = value; 84 | else if (0 == strcmp (key, "udp-port")) 85 | udp_port = value; 86 | else if (0 == strcmp (key, "udp-listen-address")) 87 | udp_addr = value; 88 | else if (0 == strcmp (key, "listen-ipv6-only")) 89 | listen_ipv6_only = (0 == strcasecmp (value, "true")) ? 1 : 0; 90 | else if (0 == strcmp (key, "bind-address")) 91 | bind_saddr = value; 92 | else if (0 == strcmp (key, "bind-address-v4")) 93 | bind_saddr4 = value; 94 | else if (0 == strcmp (key, "bind-address-v6")) 95 | bind_saddr6 = value; 96 | else if (0 == strcmp (key, "bind-interface")) 97 | bind_iface = value; 98 | else if (0 == strcmp (key, "domain-address-type")) 99 | addr_type = value; 100 | else if (0 == strcmp (key, "mark")) 101 | mark = value; 102 | } 103 | 104 | if (!workers) { 105 | fprintf (stderr, "Can't found main.workers!\n"); 106 | return -1; 107 | } 108 | 109 | if (!port) { 110 | fprintf (stderr, "Can't found main.port!\n"); 111 | return -1; 112 | } 113 | 114 | if (!addr) { 115 | fprintf (stderr, "Can't found main.listen-address!\n"); 116 | return -1; 117 | } 118 | 119 | #ifdef __MSYS__ 120 | if (workers > 1) { 121 | fprintf (stderr, "Only supports one worker on Windows.\n"); 122 | workers = 1; 123 | } 124 | #endif 125 | 126 | strncpy (listen_port, port, 8 - 1); 127 | strncpy (listen_address, addr, 256 - 1); 128 | 129 | if (udp_port) 130 | strncpy (udp_listen_port, udp_port, 8 - 1); 131 | if (udp_addr) 132 | strncpy (udp_listen_address, udp_addr, 256 - 1); 133 | 134 | if (bind_saddr4 && bind_saddr4[0] != '\0') 135 | strncpy (bind_address[0], bind_saddr4, 256 - 1); 136 | else if (bind_saddr && bind_saddr[0] != '\0') 137 | strncpy (bind_address[0], bind_saddr, 256 - 1); 138 | if (bind_saddr6 && bind_saddr6[0] != '\0') 139 | strncpy (bind_address[1], bind_saddr6, 256 - 1); 140 | else if (bind_saddr && bind_saddr[0] != '\0') 141 | strncpy (bind_address[1], bind_saddr, 256 - 1); 142 | 143 | if (bind_iface) 144 | strncpy (bind_interface, bind_iface, 256 - 1); 145 | 146 | if (addr_type) { 147 | if (0 == strcmp (addr_type, "ipv4")) 148 | addr_family = HEV_SOCKS5_ADDR_FAMILY_IPV4; 149 | else if (0 == strcmp (addr_type, "ipv6")) 150 | addr_family = HEV_SOCKS5_ADDR_FAMILY_IPV6; 151 | } 152 | 153 | if (mark) 154 | socket_mark = strtoul (mark, NULL, 0); 155 | 156 | return 0; 157 | } 158 | 159 | static int 160 | hev_config_parse_auth (yaml_document_t *doc, yaml_node_t *base) 161 | { 162 | yaml_node_pair_t *pair; 163 | const char *user = NULL, *pass = NULL, *file = NULL; 164 | 165 | if (!base || YAML_MAPPING_NODE != base->type) 166 | return -1; 167 | 168 | for (pair = base->data.mapping.pairs.start; 169 | pair < base->data.mapping.pairs.top; pair++) { 170 | yaml_node_t *node; 171 | const char *key, *value; 172 | 173 | if (!pair->key || !pair->value) 174 | break; 175 | 176 | node = yaml_document_get_node (doc, pair->key); 177 | if (!node || YAML_SCALAR_NODE != node->type) 178 | break; 179 | key = (const char *)node->data.scalar.value; 180 | 181 | node = yaml_document_get_node (doc, pair->value); 182 | if (!node || YAML_SCALAR_NODE != node->type) 183 | break; 184 | value = (const char *)node->data.scalar.value; 185 | 186 | if (0 == strcmp (key, "username")) 187 | user = value; 188 | else if (0 == strcmp (key, "password")) 189 | pass = value; 190 | else if (0 == strcmp (key, "file")) 191 | file = value; 192 | } 193 | 194 | if (file) { 195 | strncpy (auth_file, file, 1023); 196 | } else if (user && pass) { 197 | strncpy (username, user, 255); 198 | strncpy (password, pass, 255); 199 | } 200 | 201 | return 0; 202 | } 203 | 204 | static int 205 | hev_config_parse_log_level (const char *value) 206 | { 207 | if (0 == strcmp (value, "debug")) 208 | return HEV_LOGGER_DEBUG; 209 | else if (0 == strcmp (value, "info")) 210 | return HEV_LOGGER_INFO; 211 | else if (0 == strcmp (value, "error")) 212 | return HEV_LOGGER_ERROR; 213 | 214 | return HEV_LOGGER_WARN; 215 | } 216 | 217 | static int 218 | hev_config_parse_misc (yaml_document_t *doc, yaml_node_t *base) 219 | { 220 | yaml_node_pair_t *pair; 221 | 222 | if (!base || YAML_MAPPING_NODE != base->type) 223 | return -1; 224 | 225 | for (pair = base->data.mapping.pairs.start; 226 | pair < base->data.mapping.pairs.top; pair++) { 227 | yaml_node_t *node; 228 | const char *key, *value; 229 | 230 | if (!pair->key || !pair->value) 231 | break; 232 | 233 | node = yaml_document_get_node (doc, pair->key); 234 | if (!node || YAML_SCALAR_NODE != node->type) 235 | break; 236 | key = (const char *)node->data.scalar.value; 237 | 238 | node = yaml_document_get_node (doc, pair->value); 239 | if (!node || YAML_SCALAR_NODE != node->type) 240 | break; 241 | value = (const char *)node->data.scalar.value; 242 | 243 | if (0 == strcmp (key, "task-stack-size")) 244 | task_stack_size = strtoul (value, NULL, 10); 245 | else if (0 == strcmp (key, "udp-recv-buffer-size")) 246 | udp_recv_buffer_size = strtoul (value, NULL, 10); 247 | else if (0 == strcmp (key, "connect-timeout")) 248 | connect_timeout = strtoul (value, NULL, 10); 249 | else if (0 == strcmp (key, "read-write-timeout")) 250 | read_write_timeout = strtoul (value, NULL, 10); 251 | else if (0 == strcmp (key, "pid-file")) 252 | strncpy (pid_file, value, 1024 - 1); 253 | else if (0 == strcmp (key, "log-file")) 254 | strncpy (log_file, value, 1024 - 1); 255 | else if (0 == strcmp (key, "log-level")) 256 | log_level = hev_config_parse_log_level (value); 257 | else if (0 == strcmp (key, "limit-nofile")) 258 | limit_nofile = strtol (value, NULL, 10); 259 | } 260 | 261 | return 0; 262 | } 263 | 264 | static int 265 | hev_config_parse_doc (yaml_document_t *doc) 266 | { 267 | yaml_node_t *root; 268 | yaml_node_pair_t *pair; 269 | 270 | root = yaml_document_get_root_node (doc); 271 | if (!root || YAML_MAPPING_NODE != root->type) 272 | return -1; 273 | 274 | for (pair = root->data.mapping.pairs.start; 275 | pair < root->data.mapping.pairs.top; pair++) { 276 | yaml_node_t *node; 277 | const char *key; 278 | int res = 0; 279 | 280 | if (!pair->key || !pair->value) 281 | break; 282 | 283 | node = yaml_document_get_node (doc, pair->key); 284 | if (!node || YAML_SCALAR_NODE != node->type) 285 | break; 286 | 287 | key = (const char *)node->data.scalar.value; 288 | node = yaml_document_get_node (doc, pair->value); 289 | 290 | if (0 == strcmp (key, "main")) 291 | res = hev_config_parse_main (doc, node); 292 | else if (0 == strcmp (key, "auth")) 293 | res = hev_config_parse_auth (doc, node); 294 | else if (0 == strcmp (key, "misc")) 295 | res = hev_config_parse_misc (doc, node); 296 | 297 | if (res < 0) 298 | return -1; 299 | } 300 | 301 | return 0; 302 | } 303 | 304 | int 305 | hev_config_init_from_file (const char *path) 306 | { 307 | yaml_parser_t parser; 308 | yaml_document_t doc; 309 | FILE *fp; 310 | int res = -1; 311 | 312 | if (!yaml_parser_initialize (&parser)) 313 | goto exit; 314 | 315 | fp = fopen (path, "r"); 316 | if (!fp) { 317 | fprintf (stderr, "Open %s failed!\n", path); 318 | goto exit_free_parser; 319 | } 320 | 321 | yaml_parser_set_input_file (&parser, fp); 322 | if (!yaml_parser_load (&parser, &doc)) { 323 | fprintf (stderr, "Parse %s failed!\n", path); 324 | goto exit_close_fp; 325 | } 326 | 327 | res = hev_config_parse_doc (&doc); 328 | yaml_document_delete (&doc); 329 | 330 | exit_close_fp: 331 | fclose (fp); 332 | exit_free_parser: 333 | yaml_parser_delete (&parser); 334 | exit: 335 | return res; 336 | } 337 | 338 | int 339 | hev_config_init_from_str (const unsigned char *config_str, 340 | unsigned int config_len) 341 | { 342 | yaml_parser_t parser; 343 | yaml_document_t doc; 344 | int res = -1; 345 | 346 | if (!yaml_parser_initialize (&parser)) 347 | goto exit; 348 | 349 | yaml_parser_set_input_string (&parser, config_str, config_len); 350 | if (!yaml_parser_load (&parser, &doc)) { 351 | fprintf (stderr, "Failed to parse config."); 352 | goto exit_free_parser; 353 | } 354 | 355 | res = hev_config_parse_doc (&doc); 356 | yaml_document_delete (&doc); 357 | 358 | exit_free_parser: 359 | yaml_parser_delete (&parser); 360 | exit: 361 | return res; 362 | } 363 | 364 | void 365 | hev_config_fini (void) 366 | { 367 | } 368 | 369 | unsigned int 370 | hev_config_get_workers (void) 371 | { 372 | return workers; 373 | } 374 | 375 | const char * 376 | hev_config_get_listen_address (void) 377 | { 378 | return listen_address; 379 | } 380 | 381 | const char * 382 | hev_config_get_listen_port (void) 383 | { 384 | return listen_port; 385 | } 386 | 387 | const char * 388 | hev_config_get_udp_listen_address (void) 389 | { 390 | if ('\0' == udp_listen_address[0]) 391 | return NULL; 392 | 393 | return udp_listen_address; 394 | } 395 | 396 | const char * 397 | hev_config_get_udp_listen_port (void) 398 | { 399 | if ('\0' == udp_listen_port[0]) 400 | return NULL; 401 | 402 | return udp_listen_port; 403 | } 404 | 405 | int 406 | hev_config_get_listen_ipv6_only (void) 407 | { 408 | return listen_ipv6_only; 409 | } 410 | 411 | const char * 412 | hev_config_get_bind_address (int family) 413 | { 414 | int idx = family == AF_INET6; 415 | 416 | if ('\0' == bind_address[idx][0]) 417 | return NULL; 418 | 419 | return bind_address[idx]; 420 | } 421 | 422 | const char * 423 | hev_config_get_bind_interface (void) 424 | { 425 | if ('\0' == bind_interface[0]) 426 | return NULL; 427 | 428 | return bind_interface; 429 | } 430 | 431 | int 432 | hev_config_get_address_family (void) 433 | { 434 | return addr_family; 435 | } 436 | 437 | unsigned int 438 | hev_config_get_socket_mark (void) 439 | { 440 | return socket_mark; 441 | } 442 | 443 | const char * 444 | hev_config_get_auth_file (void) 445 | { 446 | if ('\0' == auth_file[0]) 447 | return NULL; 448 | 449 | return auth_file; 450 | } 451 | 452 | const char * 453 | hev_config_get_auth_username (void) 454 | { 455 | if ('\0' == username[0]) 456 | return NULL; 457 | 458 | return username; 459 | } 460 | 461 | const char * 462 | hev_config_get_auth_password (void) 463 | { 464 | if ('\0' == password[0]) 465 | return NULL; 466 | 467 | return password; 468 | } 469 | 470 | int 471 | hev_config_get_misc_task_stack_size (void) 472 | { 473 | return task_stack_size; 474 | } 475 | 476 | int 477 | hev_config_get_misc_udp_recv_buffer_size (void) 478 | { 479 | return udp_recv_buffer_size; 480 | } 481 | 482 | int 483 | hev_config_get_misc_connect_timeout (void) 484 | { 485 | return connect_timeout; 486 | } 487 | 488 | int 489 | hev_config_get_misc_read_write_timeout (void) 490 | { 491 | return read_write_timeout; 492 | } 493 | 494 | int 495 | hev_config_get_misc_limit_nofile (void) 496 | { 497 | return limit_nofile; 498 | } 499 | 500 | const char * 501 | hev_config_get_misc_pid_file (void) 502 | { 503 | if ('\0' == pid_file[0]) 504 | return NULL; 505 | 506 | return pid_file; 507 | } 508 | 509 | const char * 510 | hev_config_get_misc_log_file (void) 511 | { 512 | if ('\0' == log_file[0]) 513 | return "stderr"; 514 | 515 | return log_file; 516 | } 517 | 518 | int 519 | hev_config_get_misc_log_level (void) 520 | { 521 | return log_level; 522 | } 523 | -------------------------------------------------------------------------------- /src/hev-config.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-config.h 4 | Author : hev 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Config 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_CONFIG_H__ 11 | #define __HEV_CONFIG_H__ 12 | 13 | int hev_config_init_from_file (const char *config_path); 14 | int hev_config_init_from_str (const unsigned char *config_str, 15 | unsigned int config_len); 16 | void hev_config_fini (void); 17 | 18 | unsigned int hev_config_get_workers (void); 19 | 20 | const char *hev_config_get_listen_address (void); 21 | const char *hev_config_get_listen_port (void); 22 | const char *hev_config_get_udp_listen_address (void); 23 | const char *hev_config_get_udp_listen_port (void); 24 | int hev_config_get_listen_ipv6_only (void); 25 | 26 | const char *hev_config_get_bind_address (int family); 27 | const char *hev_config_get_bind_interface (void); 28 | 29 | int hev_config_get_address_family (void); 30 | unsigned int hev_config_get_socket_mark (void); 31 | 32 | const char *hev_config_get_auth_file (void); 33 | const char *hev_config_get_auth_username (void); 34 | const char *hev_config_get_auth_password (void); 35 | 36 | int hev_config_get_misc_task_stack_size (void); 37 | int hev_config_get_misc_udp_recv_buffer_size (void); 38 | int hev_config_get_misc_connect_timeout (void); 39 | int hev_config_get_misc_read_write_timeout (void); 40 | int hev_config_get_misc_limit_nofile (void); 41 | const char *hev_config_get_misc_pid_file (void); 42 | const char *hev_config_get_misc_log_file (void); 43 | int hev_config_get_misc_log_level (void); 44 | 45 | #endif /* __HEV_CONFIG_H__ */ 46 | -------------------------------------------------------------------------------- /src/hev-jni.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-jni.c 4 | Author : hev 5 | Copyright : Copyright (c) 2019 - 2024 hev 6 | Description : Jave Native Interface 7 | ============================================================================ 8 | */ 9 | 10 | #ifdef ANDROID 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "hev-main.h" 21 | 22 | #include "hev-jni.h" 23 | 24 | /* clang-format off */ 25 | #ifndef PKGNAME 26 | #define PKGNAME hev/socks5 27 | #endif 28 | #ifndef CLSNAME 29 | #define CLSNAME Socks5Service 30 | #endif 31 | /* clang-format on */ 32 | 33 | #define STR(s) STR_ARG (s) 34 | #define STR_ARG(c) #c 35 | #define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0])) 36 | 37 | typedef struct _ThreadData ThreadData; 38 | 39 | struct _ThreadData 40 | { 41 | char *path; 42 | }; 43 | 44 | static JavaVM *java_vm; 45 | static pthread_t work_thread; 46 | static pthread_mutex_t mutex; 47 | static pthread_key_t current_jni_env; 48 | 49 | static void native_start_service (JNIEnv *env, jobject thiz, 50 | jstring config_path); 51 | static void native_stop_service (JNIEnv *env, jobject thiz); 52 | 53 | static JNINativeMethod native_methods[] = { 54 | { "Socks5StartService", "(Ljava/lang/String;)V", 55 | (void *)native_start_service }, 56 | { "Socks5StopService", "()V", (void *)native_stop_service }, 57 | }; 58 | 59 | static void 60 | detach_current_thread (void *env) 61 | { 62 | (*java_vm)->DetachCurrentThread (java_vm); 63 | } 64 | 65 | jint 66 | JNI_OnLoad (JavaVM *vm, void *reserved) 67 | { 68 | JNIEnv *env = NULL; 69 | jclass klass; 70 | 71 | java_vm = vm; 72 | if (JNI_OK != (*vm)->GetEnv (vm, (void **)&env, JNI_VERSION_1_4)) { 73 | return 0; 74 | } 75 | 76 | klass = (*env)->FindClass (env, STR (PKGNAME) "/" STR (CLSNAME)); 77 | (*env)->RegisterNatives (env, klass, native_methods, 78 | N_ELEMENTS (native_methods)); 79 | (*env)->DeleteLocalRef (env, klass); 80 | 81 | pthread_key_create (¤t_jni_env, detach_current_thread); 82 | pthread_mutex_init (&mutex, NULL); 83 | 84 | return JNI_VERSION_1_4; 85 | } 86 | 87 | static void * 88 | thread_handler (void *data) 89 | { 90 | ThreadData *tdata = data; 91 | 92 | hev_socks5_server_main_from_file (tdata->path); 93 | 94 | free (tdata->path); 95 | free (tdata); 96 | 97 | return NULL; 98 | } 99 | 100 | static void 101 | native_start_service (JNIEnv *env, jobject thiz, jstring config_path) 102 | { 103 | const jbyte *bytes; 104 | ThreadData *tdata; 105 | 106 | pthread_mutex_lock (&mutex); 107 | if (work_thread) 108 | goto exit; 109 | 110 | tdata = malloc (sizeof (ThreadData)); 111 | 112 | bytes = (const jbyte *)(*env)->GetStringUTFChars (env, config_path, NULL); 113 | tdata->path = strdup ((const char *)bytes); 114 | (*env)->ReleaseStringUTFChars (env, config_path, (const char *)bytes); 115 | 116 | pthread_create (&work_thread, NULL, thread_handler, tdata); 117 | exit: 118 | pthread_mutex_unlock (&mutex); 119 | } 120 | 121 | static void 122 | native_stop_service (JNIEnv *env, jobject thiz) 123 | { 124 | pthread_mutex_lock (&mutex); 125 | if (!work_thread) 126 | goto exit; 127 | 128 | hev_socks5_server_quit (); 129 | pthread_join (work_thread, NULL); 130 | work_thread = 0; 131 | exit: 132 | pthread_mutex_unlock (&mutex); 133 | } 134 | 135 | #endif /* ANDROID */ 136 | -------------------------------------------------------------------------------- /src/hev-jni.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-jni.h 4 | Author : hev 5 | Copyright : Copyright (c) 2019 - 2024 hev 6 | Description : Java Native Interface 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_JNI_H__ 11 | #define __HEV_JNI_H__ 12 | 13 | #endif /* __HEV_JNI_H__ */ 14 | -------------------------------------------------------------------------------- /src/hev-main.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-main.c 4 | Author : hev 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Main 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | 18 | #include "hev-misc.h" 19 | #include "hev-config.h" 20 | #include "hev-config-const.h" 21 | #include "hev-logger.h" 22 | #include "hev-socks5-proxy.h" 23 | 24 | #include "hev-main.h" 25 | 26 | #ifdef __MSYS__ 27 | #define WEAK 28 | #else 29 | #define WEAK __attribute__ ((weak)) 30 | #endif 31 | 32 | static void 33 | show_help (const char *self_path) 34 | { 35 | printf ("%s CONFIG_PATH\n", self_path); 36 | printf ("Version: %u.%u.%u %s\n", MAJOR_VERSION, MINOR_VERSION, 37 | MICRO_VERSION, COMMIT_ID); 38 | } 39 | 40 | static void 41 | sigint_handler (int signum) 42 | { 43 | hev_socks5_proxy_stop (); 44 | } 45 | 46 | static int 47 | hev_socks5_server_main_inner (void) 48 | { 49 | const char *pid_file; 50 | const char *log_file; 51 | int log_level; 52 | int nofile; 53 | int res; 54 | 55 | log_file = hev_config_get_misc_log_file (); 56 | log_level = hev_config_get_misc_log_level (); 57 | 58 | res = hev_config_get_misc_task_stack_size (); 59 | hev_socks5_set_task_stack_size (res); 60 | 61 | res = hev_config_get_misc_udp_recv_buffer_size (); 62 | hev_socks5_set_udp_recv_buffer_size (res); 63 | 64 | res = hev_logger_init (log_level, log_file); 65 | if (res < 0) 66 | goto exit1; 67 | 68 | res = hev_socks5_logger_init (log_level, log_file); 69 | if (res < 0) 70 | goto exit2; 71 | 72 | nofile = hev_config_get_misc_limit_nofile (); 73 | res = set_limit_nofile (nofile); 74 | if (res < 0) 75 | LOG_W ("set limit nofile"); 76 | 77 | pid_file = hev_config_get_misc_pid_file (); 78 | if (pid_file) 79 | run_as_daemon (pid_file); 80 | 81 | res = hev_socks5_proxy_init (); 82 | if (res < 0) 83 | goto exit3; 84 | 85 | hev_socks5_proxy_run (); 86 | 87 | hev_socks5_proxy_fini (); 88 | exit3: 89 | hev_socks5_logger_fini (); 90 | exit2: 91 | hev_logger_fini (); 92 | exit1: 93 | hev_config_fini (); 94 | return res; 95 | } 96 | 97 | int 98 | hev_socks5_server_main_from_file (const char *config_path) 99 | { 100 | int res = hev_config_init_from_file (config_path); 101 | if (res < 0) 102 | return -1; 103 | 104 | return hev_socks5_server_main_inner (); 105 | } 106 | 107 | int 108 | hev_socks5_server_main_from_str (const unsigned char *config_str, 109 | unsigned int config_len) 110 | { 111 | int res = hev_config_init_from_str (config_str, config_len); 112 | if (res < 0) 113 | return -1; 114 | 115 | return hev_socks5_server_main_inner (); 116 | } 117 | 118 | void 119 | hev_socks5_server_quit (void) 120 | { 121 | hev_socks5_proxy_stop (); 122 | } 123 | 124 | WEAK int 125 | main (int argc, char *argv[]) 126 | { 127 | int res; 128 | 129 | if (argc < 2 || strcmp (argv[1], "--version") == 0) { 130 | show_help (argv[0]); 131 | return -1; 132 | } 133 | 134 | signal (SIGINT, sigint_handler); 135 | 136 | res = hev_socks5_server_main_from_file (argv[1]); 137 | if (res < 0) 138 | return -2; 139 | 140 | return 0; 141 | } 142 | -------------------------------------------------------------------------------- /src/hev-main.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-main.h 4 | Author : hev 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Main 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_MAIN_H__ 11 | #define __HEV_MAIN_H__ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | /** 18 | * hev_socks5_server_main_from_file: 19 | * @config_path: config file path 20 | * 21 | * Start and run the socks5 server, this function will blocks until the 22 | * hev_socks5_server_quit is called or an error occurs. 23 | * 24 | * Returns: returns zero on successful, otherwise returns -1. 25 | * 26 | * Since: 2.6.7 27 | */ 28 | int hev_socks5_server_main_from_file (const char *config_path); 29 | 30 | /** 31 | * hev_socks5_server_main_from_str: 32 | * @config_str: string config 33 | * @config_len: the byte length of string config 34 | * 35 | * Start and run the socks5 server, this function will blocks until the 36 | * hev_socks5_server_quit is called or an error occurs. 37 | * 38 | * Returns: returns zero on successful, otherwise returns -1. 39 | * 40 | * Since: 2.6.7 41 | */ 42 | int hev_socks5_server_main_from_str (const unsigned char *config_str, 43 | unsigned int config_len); 44 | 45 | /** 46 | * hev_socks5_server_quit: 47 | * 48 | * Stop the socks5 server. 49 | * 50 | * Since: 2.6.7 51 | */ 52 | void hev_socks5_server_quit (void); 53 | 54 | #ifdef __cplusplus 55 | } 56 | #endif 57 | 58 | #endif /* __HEV_MAIN_H__ */ 59 | -------------------------------------------------------------------------------- /src/hev-socket-factory.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socket-factory.c 4 | Author : Heiher 5 | Copyright : Copyright (c) 2022 hev 6 | Description : Socket Factory 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "hev-misc.h" 20 | #include "hev-logger.h" 21 | 22 | #include "hev-socket-factory.h" 23 | 24 | struct _HevSocketFactory 25 | { 26 | struct sockaddr_in6 addr; 27 | int ipv6_only; 28 | int fd; 29 | }; 30 | 31 | HevSocketFactory * 32 | hev_socket_factory_new (const char *addr, const char *port, int ipv6_only) 33 | { 34 | HevSocketFactory *self; 35 | int res; 36 | 37 | LOG_D ("socket factory new"); 38 | 39 | self = hev_malloc0 (sizeof (HevSocketFactory)); 40 | if (!self) { 41 | LOG_E ("socket factory alloc"); 42 | return NULL; 43 | } 44 | 45 | res = hev_netaddr_resolve (&self->addr, addr, port); 46 | if (res < 0) { 47 | LOG_E ("socket factory resolve"); 48 | hev_free (self); 49 | return NULL; 50 | } 51 | 52 | self->ipv6_only = ipv6_only; 53 | self->fd = -1; 54 | 55 | return self; 56 | } 57 | 58 | void 59 | hev_socket_factory_destroy (HevSocketFactory *self) 60 | { 61 | LOG_D ("socket factory destroy"); 62 | 63 | if (self->fd >= 0) 64 | close (self->fd); 65 | hev_free (self); 66 | } 67 | 68 | int 69 | hev_socket_factory_get (HevSocketFactory *self) 70 | { 71 | int one = 1; 72 | int res; 73 | int fd; 74 | 75 | LOG_D ("socket factory get"); 76 | 77 | if (self->fd >= 0) 78 | return dup (self->fd); 79 | 80 | fd = hev_task_io_socket_socket (AF_INET6, SOCK_STREAM, 0); 81 | if (fd < 0) { 82 | LOG_E ("socket factory socket"); 83 | goto exit; 84 | } 85 | 86 | res = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (one)); 87 | if (res < 0) { 88 | LOG_E ("socket factory reuse"); 89 | goto exit_close; 90 | } 91 | 92 | res = -1; 93 | #ifdef SO_REUSEPORT 94 | res = setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, &one, sizeof (one)); 95 | #endif 96 | if (res < 0 && self->fd < 0) 97 | self->fd = dup (fd); 98 | 99 | res = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &self->ipv6_only, 100 | sizeof (self->ipv6_only)); 101 | if (res < 0) { 102 | LOG_E ("socket factory ipv6 only"); 103 | goto exit_close; 104 | } 105 | 106 | res = bind (fd, (struct sockaddr *)&self->addr, sizeof (self->addr)); 107 | if (res < 0) { 108 | LOG_E ("socket factory bind"); 109 | goto exit_close; 110 | } 111 | 112 | res = listen (fd, 100); 113 | if (res < 0) { 114 | LOG_E ("socket factory listen"); 115 | goto exit_close; 116 | } 117 | 118 | return fd; 119 | 120 | exit_close: 121 | close (fd); 122 | exit: 123 | return -1; 124 | } 125 | -------------------------------------------------------------------------------- /src/hev-socket-factory.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socket-factory.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2022 hev 6 | Description : Socket Factory 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_SOCKET_FACTORY_H__ 11 | #define __HEV_SOCKET_FACTORY_H__ 12 | 13 | typedef struct _HevSocketFactory HevSocketFactory; 14 | 15 | HevSocketFactory *hev_socket_factory_new (const char *addr, const char *port, 16 | int ipv6_only); 17 | void hev_socket_factory_destroy (HevSocketFactory *self); 18 | 19 | int hev_socket_factory_get (HevSocketFactory *self); 20 | 21 | #endif /* __HEV_SOCKET_FACTORY_H__ */ 22 | -------------------------------------------------------------------------------- /src/hev-socks5-proxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-proxy.c 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Socks5 Proxy 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "hev-config.h" 23 | #include "hev-logger.h" 24 | #include "hev-socks5-worker.h" 25 | #include "hev-socket-factory.h" 26 | #include "hev-socks5-user-mark.h" 27 | 28 | #include "hev-socks5-proxy.h" 29 | 30 | static int listen_fd = -1; 31 | static unsigned int workers; 32 | 33 | static HevTask *task; 34 | static pthread_t *work_threads; 35 | static HevSocketFactory *factory; 36 | static HevSocks5Worker **worker_list; 37 | 38 | static void 39 | hev_socks5_proxy_load_file (HevSocks5Authenticator *auth, const char *file) 40 | { 41 | char *line = NULL; 42 | size_t len = 0; 43 | ssize_t nread; 44 | FILE *fp; 45 | 46 | fp = fopen (file, "r"); 47 | if (!fp) { 48 | hev_object_unref (HEV_OBJECT (auth)); 49 | return; 50 | } 51 | 52 | while ((nread = getline (&line, &len, fp)) != -1) { 53 | HevSocks5UserMark *user; 54 | unsigned int nlen; 55 | unsigned int plen; 56 | char name[256]; 57 | char pass[256]; 58 | long mark = 0; 59 | int res; 60 | 61 | res = sscanf (line, "%255s %255s %lx\n", name, pass, &mark); 62 | if (res < 2) { 63 | LOG_E ("socks5 proxy user/pass format"); 64 | continue; 65 | } 66 | 67 | nlen = strlen (name); 68 | plen = strlen (pass); 69 | user = hev_socks5_user_mark_new (name, nlen, pass, plen, mark); 70 | if (!user) { 71 | LOG_E ("socks5 proxy user new"); 72 | continue; 73 | } 74 | res = hev_socks5_authenticator_add (auth, HEV_SOCKS5_USER (user)); 75 | if (res < 0) { 76 | LOG_E ("socks5 proxy user conflict"); 77 | hev_object_unref (HEV_OBJECT (user)); 78 | } 79 | } 80 | 81 | free (line); 82 | fclose (fp); 83 | } 84 | 85 | static void 86 | hev_socks5_proxy_load (void) 87 | { 88 | HevSocks5Authenticator *auth; 89 | const char *file, *name, *pass; 90 | int i; 91 | 92 | LOG_D ("socks5 proxy load"); 93 | 94 | file = hev_config_get_auth_file (); 95 | name = hev_config_get_auth_username (); 96 | pass = hev_config_get_auth_password (); 97 | 98 | if (!file && !name && !pass) 99 | return; 100 | 101 | auth = hev_socks5_authenticator_new (); 102 | if (!auth) 103 | return; 104 | 105 | if (file) { 106 | hev_socks5_proxy_load_file (auth, file); 107 | } else { 108 | HevSocks5UserMark *user; 109 | 110 | user = hev_socks5_user_mark_new (name, strlen (name), pass, 111 | strlen (pass), 0); 112 | if (user) 113 | hev_socks5_authenticator_add (auth, HEV_SOCKS5_USER (user)); 114 | } 115 | 116 | for (i = 0; i < workers; i++) { 117 | HevSocks5Worker *worker; 118 | 119 | worker = worker_list[i]; 120 | hev_socks5_worker_set_auth (worker, auth); 121 | hev_socks5_worker_reload (worker); 122 | } 123 | 124 | hev_object_unref (HEV_OBJECT (auth)); 125 | } 126 | 127 | static void 128 | sigint_handler (int signum) 129 | { 130 | hev_socks5_proxy_load (); 131 | } 132 | 133 | int 134 | hev_socks5_proxy_init (void) 135 | { 136 | LOG_D ("socks5 proxy init"); 137 | 138 | if (hev_task_system_init () < 0) { 139 | LOG_E ("socks5 proxy task system"); 140 | goto exit; 141 | } 142 | 143 | task = hev_task_new (-1); 144 | if (!task) { 145 | LOG_E ("socks5 proxy task"); 146 | goto exit; 147 | } 148 | 149 | workers = hev_config_get_workers (); 150 | work_threads = hev_malloc0 (sizeof (pthread_t) * workers); 151 | if (!work_threads) { 152 | LOG_E ("socks5 proxy work threads"); 153 | goto exit; 154 | } 155 | 156 | worker_list = hev_malloc0 (sizeof (HevSocks5Worker *) * workers); 157 | if (!worker_list) { 158 | LOG_E ("socks5 proxy worker list"); 159 | goto exit; 160 | } 161 | 162 | factory = hev_socket_factory_new (hev_config_get_listen_address (), 163 | hev_config_get_listen_port (), 164 | hev_config_get_listen_ipv6_only ()); 165 | if (!factory) { 166 | LOG_E ("socks5 proxy socket factory"); 167 | goto exit; 168 | } 169 | 170 | signal (SIGPIPE, SIG_IGN); 171 | signal (SIGUSR1, sigint_handler); 172 | 173 | return 0; 174 | 175 | exit: 176 | hev_socks5_proxy_fini (); 177 | return -1; 178 | } 179 | 180 | void 181 | hev_socks5_proxy_fini (void) 182 | { 183 | LOG_D ("socks5 proxy fini"); 184 | 185 | if (task) 186 | hev_task_unref (task); 187 | if (work_threads) 188 | hev_free (work_threads); 189 | if (worker_list) 190 | hev_free (worker_list); 191 | if (factory) 192 | hev_socket_factory_destroy (factory); 193 | hev_task_system_fini (); 194 | } 195 | 196 | static void * 197 | work_thread_handler (void *data) 198 | { 199 | HevSocks5Worker **worker = data; 200 | int res; 201 | int fd; 202 | 203 | if (hev_task_system_init () < 0) { 204 | LOG_E ("socks5 proxy worker task system"); 205 | goto exit; 206 | } 207 | 208 | fd = hev_socket_factory_get (factory); 209 | if (fd < 0) { 210 | LOG_E ("socks5 proxy worker socket"); 211 | goto free; 212 | } 213 | 214 | res = hev_socks5_worker_init (*worker, fd); 215 | if (res < 0) { 216 | LOG_E ("socks5 proxy worker init"); 217 | goto free; 218 | } 219 | 220 | hev_socks5_worker_start (*worker); 221 | 222 | hev_task_system_run (); 223 | 224 | hev_socks5_worker_destroy (*worker); 225 | *worker = NULL; 226 | 227 | free: 228 | if (fd >= 0) 229 | close (fd); 230 | hev_task_system_fini (); 231 | exit: 232 | return NULL; 233 | } 234 | 235 | static void 236 | hev_socks5_proxy_task_entry (void *data) 237 | { 238 | int res; 239 | int i; 240 | 241 | LOG_D ("socks5 proxy task run"); 242 | 243 | listen_fd = hev_socket_factory_get (factory); 244 | if (listen_fd < 0) 245 | return; 246 | 247 | worker_list[0] = hev_socks5_worker_new (); 248 | if (!worker_list[0]) { 249 | LOG_E ("socks5 proxy worker"); 250 | return; 251 | } 252 | 253 | res = hev_socks5_worker_init (worker_list[0], listen_fd); 254 | if (res < 0) { 255 | LOG_E ("socks5 proxy worker init"); 256 | return; 257 | } 258 | 259 | hev_socks5_worker_start (worker_list[0]); 260 | 261 | for (i = 1; i < workers; i++) { 262 | worker_list[i] = hev_socks5_worker_new (); 263 | if (!worker_list[i]) { 264 | LOG_E ("socks5 proxy worker"); 265 | return; 266 | } 267 | 268 | pthread_create (&work_threads[i], NULL, work_thread_handler, 269 | &worker_list[i]); 270 | } 271 | 272 | hev_socks5_proxy_load (); 273 | 274 | task = NULL; 275 | } 276 | 277 | void 278 | hev_socks5_proxy_run (void) 279 | { 280 | LOG_D ("socks5 proxy run"); 281 | 282 | hev_task_run (task, hev_socks5_proxy_task_entry, NULL); 283 | 284 | hev_task_system_run (); 285 | 286 | if (listen_fd >= 0) 287 | close (listen_fd); 288 | 289 | if (worker_list[0]) { 290 | int i; 291 | 292 | for (i = 1; i < workers; i++) 293 | pthread_join (work_threads[i], NULL); 294 | 295 | hev_socks5_worker_destroy (worker_list[0]); 296 | worker_list[0] = NULL; 297 | } 298 | } 299 | 300 | void 301 | hev_socks5_proxy_stop (void) 302 | { 303 | int i; 304 | 305 | for (i = 0; i < workers; i++) { 306 | HevSocks5Worker *worker; 307 | 308 | worker = worker_list[i]; 309 | if (!worker) 310 | continue; 311 | 312 | hev_socks5_worker_stop (worker); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /src/hev-socks5-proxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-proxy.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2021 hev 6 | Description : Socks5 Proxy 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_SOCKS5_PROXY_H__ 11 | #define __HEV_SOCKS5_PROXY_H__ 12 | 13 | int hev_socks5_proxy_init (void); 14 | void hev_socks5_proxy_fini (void); 15 | 16 | void hev_socks5_proxy_run (void); 17 | void hev_socks5_proxy_stop (void); 18 | 19 | #endif /* __HEV_SOCKS5_PROXY_H__ */ 20 | -------------------------------------------------------------------------------- /src/hev-socks5-session.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-session.c 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Socks5 Session 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | 15 | #include "hev-misc.h" 16 | #include "hev-logger.h" 17 | #include "hev-config.h" 18 | #include "hev-socks5-user-mark.h" 19 | 20 | #include "hev-socks5-session.h" 21 | 22 | HevSocks5Session * 23 | hev_socks5_session_new (int fd) 24 | { 25 | HevSocks5Session *self; 26 | int res; 27 | 28 | self = hev_malloc0 (sizeof (HevSocks5Session)); 29 | if (!self) 30 | return NULL; 31 | 32 | res = hev_socks5_session_construct (self, fd); 33 | if (res < 0) { 34 | hev_free (self); 35 | return NULL; 36 | } 37 | 38 | LOG_D ("%p socks5 session new", self); 39 | 40 | return self; 41 | } 42 | 43 | void 44 | hev_socks5_session_terminate (HevSocks5Session *self) 45 | { 46 | LOG_D ("%p socks5 session terminate", self); 47 | 48 | hev_socks5_set_timeout (HEV_SOCKS5 (self), 0); 49 | hev_task_wakeup (self->task); 50 | } 51 | 52 | static int 53 | hev_socks5_session_bind (HevSocks5 *self, int fd, const struct sockaddr *dest) 54 | { 55 | HevSocks5Server *srv = HEV_SOCKS5_SERVER (self); 56 | const char *saddr; 57 | const char *iface; 58 | int mark = 0; 59 | int family; 60 | int res; 61 | 62 | LOG_D ("%p socks5 session bind", self); 63 | 64 | if (IN6_IS_ADDR_V4MAPPED (&((struct sockaddr_in6 *)dest)->sin6_addr)) 65 | family = AF_INET; 66 | else 67 | family = AF_INET6; 68 | 69 | saddr = hev_config_get_bind_address (family); 70 | iface = hev_config_get_bind_interface (); 71 | 72 | if (saddr) { 73 | struct sockaddr_in6 addr; 74 | 75 | res = hev_netaddr_resolve (&addr, saddr, NULL); 76 | if (res < 0) 77 | return -1; 78 | 79 | res = bind (fd, (struct sockaddr *)&addr, sizeof (addr)); 80 | if (res < 0) 81 | return -1; 82 | } 83 | 84 | if (iface) { 85 | res = set_sock_bind (fd, iface); 86 | if (res < 0) 87 | return -1; 88 | } 89 | 90 | if (srv->user) { 91 | HevSocks5UserMark *user = HEV_SOCKS5_USER_MARK (srv->user); 92 | mark = user->mark; 93 | } 94 | 95 | if (!mark) 96 | mark = hev_config_get_socket_mark (); 97 | 98 | if (mark) { 99 | res = set_sock_mark (fd, mark); 100 | if (res < 0) 101 | return -1; 102 | } 103 | 104 | return 0; 105 | } 106 | 107 | static int 108 | hev_socks5_session_udp_bind (HevSocks5Server *self, int sock, 109 | const struct sockaddr *src) 110 | { 111 | struct sockaddr_in6 addr; 112 | const char *saddr; 113 | const char *sport; 114 | socklen_t alen; 115 | int ipv6_only; 116 | int res; 117 | 118 | LOG_D ("%p socks5 session udp bind", self); 119 | 120 | alen = sizeof (struct sockaddr_in6); 121 | saddr = hev_config_get_udp_listen_address (); 122 | sport = hev_config_get_udp_listen_port (); 123 | ipv6_only = hev_config_get_listen_ipv6_only (); 124 | 125 | if (ipv6_only) { 126 | int one = 1; 127 | 128 | res = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof (one)); 129 | if (res < 0) 130 | return -1; 131 | } 132 | 133 | if (saddr) { 134 | res = hev_netaddr_resolve (&addr, saddr, NULL); 135 | if (res < 0) 136 | return -1; 137 | } else { 138 | int fd; 139 | 140 | fd = HEV_SOCKS5 (self)->fd; 141 | res = getsockname (fd, (struct sockaddr *)&addr, &alen); 142 | if (res < 0) 143 | return -1; 144 | } 145 | 146 | addr.sin6_port = sport ? htons (strtoul (sport, NULL, 10)) : 0; 147 | res = bind (sock, (struct sockaddr *)&addr, alen); 148 | if (res < 0) 149 | return -1; 150 | 151 | if (hev_netaddr_is_any ((struct sockaddr_in6 *)src)) 152 | return 0; 153 | 154 | res = connect (sock, src, sizeof (struct sockaddr_in6)); 155 | if (res < 0) 156 | return -1; 157 | 158 | HEV_SOCKS5 (self)->udp_associated = 1; 159 | 160 | return 0; 161 | } 162 | 163 | int 164 | hev_socks5_session_construct (HevSocks5Session *self, int fd) 165 | { 166 | int read_write_timeout; 167 | int connect_timeout; 168 | int addr_family; 169 | int res; 170 | 171 | res = hev_socks5_server_construct (&self->base, fd); 172 | if (res < 0) 173 | return -1; 174 | 175 | LOG_D ("%p socks5 session construct", self); 176 | 177 | HEV_OBJECT (self)->klass = HEV_SOCKS5_SESSION_TYPE; 178 | 179 | addr_family = hev_config_get_address_family (); 180 | connect_timeout = hev_config_get_misc_connect_timeout (); 181 | read_write_timeout = hev_config_get_misc_read_write_timeout (); 182 | 183 | hev_socks5_set_addr_family (HEV_SOCKS5 (self), addr_family); 184 | hev_socks5_set_timeout (HEV_SOCKS5 (self), read_write_timeout); 185 | hev_socks5_server_set_connect_timeout (&self->base, connect_timeout); 186 | 187 | return 0; 188 | } 189 | 190 | static void 191 | hev_socks5_session_destruct (HevObject *base) 192 | { 193 | HevSocks5Session *self = HEV_SOCKS5_SESSION (base); 194 | 195 | LOG_D ("%p socks5 session destruct", self); 196 | 197 | HEV_SOCKS5_SERVER_TYPE->destruct (base); 198 | } 199 | 200 | HevObjectClass * 201 | hev_socks5_session_class (void) 202 | { 203 | static HevSocks5SessionClass klass; 204 | HevSocks5SessionClass *kptr = &klass; 205 | HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr); 206 | 207 | if (!okptr->name) { 208 | HevSocks5ServerClass *sskptr; 209 | HevSocks5Class *skptr; 210 | 211 | memcpy (kptr, HEV_SOCKS5_SERVER_TYPE, sizeof (HevSocks5ServerClass)); 212 | 213 | okptr->name = "HevSocks5Session"; 214 | okptr->destruct = hev_socks5_session_destruct; 215 | 216 | skptr = HEV_SOCKS5_CLASS (kptr); 217 | skptr->binder = hev_socks5_session_bind; 218 | 219 | sskptr = HEV_SOCKS5_SERVER_CLASS (kptr); 220 | sskptr->binder = hev_socks5_session_udp_bind; 221 | } 222 | 223 | return okptr; 224 | } 225 | -------------------------------------------------------------------------------- /src/hev-socks5-session.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-session.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2021 hev 6 | Description : Socks5 Session 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_SOCKS5_SESSION_H__ 11 | #define __HEV_SOCKS5_SESSION_H__ 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "hev-list.h" 18 | 19 | #define HEV_SOCKS5_SESSION(p) ((HevSocks5Session *)p) 20 | #define HEV_SOCKS5_SESSION_CLASS(p) ((HevSocks5SessionClass *)p) 21 | #define HEV_SOCKS5_SESSION_TYPE (hev_socks5_session_class ()) 22 | 23 | typedef struct _HevSocks5Session HevSocks5Session; 24 | typedef struct _HevSocks5SessionClass HevSocks5SessionClass; 25 | 26 | struct _HevSocks5Session 27 | { 28 | HevSocks5Server base; 29 | 30 | HevListNode node; 31 | HevTask *task; 32 | void *data; 33 | }; 34 | 35 | struct _HevSocks5SessionClass 36 | { 37 | HevSocks5ServerClass base; 38 | }; 39 | 40 | HevObjectClass *hev_socks5_session_class (void); 41 | 42 | int hev_socks5_session_construct (HevSocks5Session *self, int fd); 43 | 44 | HevSocks5Session *hev_socks5_session_new (int fd); 45 | 46 | void hev_socks5_session_terminate (HevSocks5Session *self); 47 | 48 | #endif /* __HEV_SOCKS5_SESSION_H__ */ 49 | -------------------------------------------------------------------------------- /src/hev-socks5-user-mark.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-user-mark.c 4 | Author : Heiher 5 | Copyright : Copyright (c) 2023 hev 6 | Description : Socks5 User with mark 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include "hev-logger.h" 14 | 15 | #include "hev-socks5-user-mark.h" 16 | 17 | HevSocks5UserMark * 18 | hev_socks5_user_mark_new (const char *name, unsigned int name_len, 19 | const char *pass, unsigned int pass_len, 20 | unsigned int mark) 21 | { 22 | HevSocks5UserMark *self; 23 | int res; 24 | 25 | self = calloc (1, sizeof (HevSocks5UserMark)); 26 | if (!self) 27 | return NULL; 28 | 29 | res = hev_socks5_user_mark_construct (self, name, name_len, pass, pass_len, 30 | mark); 31 | if (res < 0) { 32 | free (self); 33 | return NULL; 34 | } 35 | 36 | LOG_D ("%p socks5 user mark new", self); 37 | 38 | return self; 39 | } 40 | 41 | int 42 | hev_socks5_user_mark_construct (HevSocks5UserMark *self, const char *name, 43 | unsigned int name_len, const char *pass, 44 | unsigned int pass_len, unsigned int mark) 45 | { 46 | int res; 47 | 48 | res = 49 | hev_socks5_user_construct (&self->base, name, name_len, pass, pass_len); 50 | if (res < 0) 51 | return res; 52 | 53 | LOG_D ("%p socks5 user mark construct", self); 54 | 55 | HEV_OBJECT (self)->klass = HEV_SOCKS5_USER_MARK_TYPE; 56 | 57 | self->mark = mark; 58 | 59 | return 0; 60 | } 61 | 62 | static void 63 | hev_socks5_user_mark_destruct (HevObject *base) 64 | { 65 | HevSocks5UserMark *self = HEV_SOCKS5_USER_MARK (base); 66 | 67 | LOG_D ("%p socks5 user mark destruct", self); 68 | 69 | HEV_SOCKS5_USER_TYPE->destruct (base); 70 | } 71 | 72 | HevObjectClass * 73 | hev_socks5_user_mark_class (void) 74 | { 75 | static HevSocks5UserMarkClass klass; 76 | HevSocks5UserMarkClass *kptr = &klass; 77 | HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr); 78 | 79 | if (!okptr->name) { 80 | memcpy (kptr, HEV_SOCKS5_USER_TYPE, sizeof (HevSocks5UserClass)); 81 | 82 | okptr->name = "HevSocks5UserMark"; 83 | okptr->destruct = hev_socks5_user_mark_destruct; 84 | } 85 | 86 | return okptr; 87 | } 88 | -------------------------------------------------------------------------------- /src/hev-socks5-user-mark.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-user-mark.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2023 hev 6 | Description : Socks5 User with mark 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_SOCKS5_USER_MARK_H__ 11 | #define __HEV_SOCKS5_USER_MARK_H__ 12 | 13 | #include "hev-socks5-user.h" 14 | 15 | #ifdef __cplusplus 16 | extern "C" { 17 | #endif 18 | 19 | #define HEV_SOCKS5_USER_MARK(p) ((HevSocks5UserMark *)p) 20 | #define HEV_SOCKS5_USER_MARK_CLASS(p) ((HevSocks5UserMarkClass *)p) 21 | #define HEV_SOCKS5_USER_MARK_TYPE (hev_socks5_user_mark_class ()) 22 | 23 | typedef struct _HevSocks5UserMark HevSocks5UserMark; 24 | typedef struct _HevSocks5UserMarkClass HevSocks5UserMarkClass; 25 | 26 | struct _HevSocks5UserMark 27 | { 28 | HevSocks5User base; 29 | 30 | unsigned int mark; 31 | }; 32 | 33 | struct _HevSocks5UserMarkClass 34 | { 35 | HevSocks5UserClass base; 36 | }; 37 | 38 | HevObjectClass *hev_socks5_user_mark_class (void); 39 | 40 | int hev_socks5_user_mark_construct (HevSocks5UserMark *self, const char *name, 41 | unsigned int name_len, const char *pass, 42 | unsigned int pass_len, unsigned int mark); 43 | 44 | HevSocks5UserMark *hev_socks5_user_mark_new (const char *name, 45 | unsigned int name_len, 46 | const char *pass, 47 | unsigned int pass_len, 48 | unsigned int mark); 49 | 50 | #ifdef __cplusplus 51 | } 52 | #endif 53 | 54 | #endif /* __HEV_SOCKS5_USER_MARK_H__ */ 55 | -------------------------------------------------------------------------------- /src/hev-socks5-worker.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-worker.c 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2024 hev 6 | Description : Socks5 Worker 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "hev-config.h" 21 | #include "hev-logger.h" 22 | #include "hev-compiler.h" 23 | #include "hev-socks5-session.h" 24 | 25 | #include "hev-socks5-worker.h" 26 | 27 | struct _HevSocks5Worker 28 | { 29 | int fd; 30 | int quit; 31 | int event_fds[2]; 32 | 33 | HevTask *task_event; 34 | HevTask *task_worker; 35 | HevList session_set; 36 | HevSocks5Authenticator *auth_curr; 37 | HevSocks5Authenticator *auth_next; 38 | }; 39 | 40 | static int 41 | task_io_yielder (HevTaskYieldType type, void *data) 42 | { 43 | HevSocks5Worker *self = data; 44 | 45 | hev_task_yield (type); 46 | 47 | return self->quit ? -1 : 0; 48 | } 49 | 50 | static void 51 | hev_socks5_worker_load (HevSocks5Worker *self) 52 | { 53 | atomic_intptr_t *ptr; 54 | intptr_t prev; 55 | 56 | LOG_D ("%p works worker load", self); 57 | 58 | ptr = (atomic_intptr_t *)&self->auth_next; 59 | prev = atomic_exchange_explicit (ptr, 0, memory_order_relaxed); 60 | if (!prev) 61 | return; 62 | 63 | if (self->auth_curr) 64 | hev_object_unref (HEV_OBJECT (self->auth_curr)); 65 | 66 | self->auth_curr = HEV_SOCKS5_AUTHENTICATOR (prev); 67 | } 68 | 69 | static void 70 | hev_socks5_session_task_entry (void *data) 71 | { 72 | HevSocks5Session *s = data; 73 | HevSocks5Worker *self = s->data; 74 | 75 | hev_socks5_server_run (HEV_SOCKS5_SERVER (s)); 76 | 77 | hev_list_del (&self->session_set, &s->node); 78 | hev_object_unref (HEV_OBJECT (s)); 79 | } 80 | 81 | static void 82 | hev_socks5_worker_task_entry (void *data) 83 | { 84 | HevTask *task = hev_task_self (); 85 | HevSocks5Worker *self = data; 86 | HevListNode *node; 87 | int stack_size; 88 | int fd; 89 | 90 | LOG_D ("socks5 worker task run"); 91 | 92 | fd = self->fd; 93 | hev_task_add_fd (task, fd, POLLIN); 94 | stack_size = hev_config_get_misc_task_stack_size (); 95 | 96 | for (;;) { 97 | HevSocks5Session *s; 98 | HevTask *task; 99 | int nfd; 100 | 101 | nfd = hev_task_io_socket_accept (fd, NULL, NULL, task_io_yielder, self); 102 | if (nfd == -1) { 103 | LOG_E ("socks5 proxy accept"); 104 | continue; 105 | } else if (nfd < 0) { 106 | break; 107 | } 108 | 109 | s = hev_socks5_session_new (nfd); 110 | if (!s) { 111 | close (nfd); 112 | continue; 113 | } 114 | 115 | task = hev_task_new (stack_size); 116 | if (!task) { 117 | hev_object_unref (HEV_OBJECT (s)); 118 | continue; 119 | } 120 | 121 | if (self->auth_curr) 122 | hev_socks5_server_set_auth (HEV_SOCKS5_SERVER (s), self->auth_curr); 123 | 124 | s->task = task; 125 | s->data = self; 126 | hev_list_add_tail (&self->session_set, &s->node); 127 | hev_task_run (task, hev_socks5_session_task_entry, s); 128 | } 129 | 130 | node = hev_list_first (&self->session_set); 131 | for (; node; node = hev_list_node_next (node)) { 132 | HevSocks5Session *s; 133 | 134 | s = container_of (node, HevSocks5Session, node); 135 | hev_socks5_session_terminate (s); 136 | } 137 | 138 | hev_task_del_fd (task, fd); 139 | } 140 | 141 | static void 142 | hev_socks5_event_task_entry (void *data) 143 | { 144 | HevTask *task = hev_task_self (); 145 | HevSocks5Worker *self = data; 146 | int res; 147 | 148 | LOG_D ("socks5 event task run"); 149 | 150 | res = hev_task_io_pipe_pipe (self->event_fds); 151 | if (res < 0) { 152 | LOG_E ("socks5 proxy pipe"); 153 | return; 154 | } 155 | 156 | hev_task_add_fd (task, self->event_fds[0], POLLIN); 157 | 158 | for (;;) { 159 | char val; 160 | 161 | res = hev_task_io_read (self->event_fds[0], &val, sizeof (val), NULL, 162 | NULL); 163 | if (res < sizeof (val)) 164 | continue; 165 | 166 | if (val == 'r') 167 | hev_socks5_worker_load (self); 168 | else 169 | break; 170 | } 171 | 172 | self->quit = 1; 173 | hev_task_wakeup (self->task_worker); 174 | 175 | hev_task_del_fd (task, self->event_fds[0]); 176 | close (self->event_fds[0]); 177 | close (self->event_fds[1]); 178 | } 179 | 180 | HevSocks5Worker * 181 | hev_socks5_worker_new (void) 182 | { 183 | HevSocks5Worker *self; 184 | 185 | self = calloc (1, sizeof (HevSocks5Worker)); 186 | if (!self) 187 | return NULL; 188 | 189 | LOG_D ("%p socks5 worker new", self); 190 | 191 | self->fd = -1; 192 | self->event_fds[0] = -1; 193 | self->event_fds[1] = -1; 194 | 195 | return self; 196 | } 197 | 198 | void 199 | hev_socks5_worker_destroy (HevSocks5Worker *self) 200 | { 201 | LOG_D ("%p works worker destroy", self); 202 | 203 | if (self->auth_curr) 204 | hev_object_unref (HEV_OBJECT (self->auth_curr)); 205 | if (self->auth_next) 206 | hev_object_unref (HEV_OBJECT (self->auth_next)); 207 | 208 | if (self->fd >= 0) 209 | close (self->fd); 210 | 211 | free (self); 212 | } 213 | 214 | int 215 | hev_socks5_worker_init (HevSocks5Worker *self, int fd) 216 | { 217 | LOG_D ("%p works worker init", self); 218 | 219 | self->task_worker = hev_task_new (-1); 220 | if (!self->task_worker) { 221 | LOG_E ("socks5 worker task worker"); 222 | return -1; 223 | } 224 | 225 | self->task_event = hev_task_new (-1); 226 | if (!self->task_event) { 227 | LOG_E ("socks5 worker task event"); 228 | hev_task_unref (self->task_worker); 229 | return -1; 230 | } 231 | 232 | self->fd = fd; 233 | 234 | return 0; 235 | } 236 | 237 | void 238 | hev_socks5_worker_start (HevSocks5Worker *self) 239 | { 240 | LOG_D ("%p works worker start", self); 241 | 242 | hev_task_run (self->task_event, hev_socks5_event_task_entry, self); 243 | hev_task_run (self->task_worker, hev_socks5_worker_task_entry, self); 244 | } 245 | 246 | void 247 | hev_socks5_worker_stop (HevSocks5Worker *self) 248 | { 249 | char val = 's'; 250 | 251 | LOG_D ("%p works worker stop", self); 252 | 253 | if (self->event_fds[1] < 0) 254 | return; 255 | 256 | val = write (self->event_fds[1], &val, sizeof (val)); 257 | if (val < 0) 258 | LOG_E ("socks5 proxy write event"); 259 | } 260 | 261 | void 262 | hev_socks5_worker_reload (HevSocks5Worker *self) 263 | { 264 | char val = 'r'; 265 | 266 | LOG_D ("%p works worker reload", self); 267 | 268 | if (self->event_fds[1] < 0) 269 | return; 270 | 271 | val = write (self->event_fds[1], &val, sizeof (val)); 272 | if (val < 0) 273 | LOG_E ("socks5 proxy write event"); 274 | } 275 | 276 | void 277 | hev_socks5_worker_set_auth (HevSocks5Worker *self, HevSocks5Authenticator *auth) 278 | { 279 | atomic_intptr_t *ptr; 280 | intptr_t prev; 281 | 282 | LOG_D ("%p works worker set auth", self); 283 | 284 | hev_object_ref (HEV_OBJECT (auth)); 285 | 286 | if (self->auth_curr) 287 | ptr = (atomic_intptr_t *)&self->auth_next; 288 | else 289 | ptr = (atomic_intptr_t *)&self->auth_curr; 290 | 291 | prev = atomic_exchange (ptr, (intptr_t)auth); 292 | if (prev) 293 | hev_object_unref (HEV_OBJECT (prev)); 294 | } 295 | -------------------------------------------------------------------------------- /src/hev-socks5-worker.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-socks5-worker.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2017 - 2021 hev 6 | Description : Socks5 Worker 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_SOCKS5_WORKER_H__ 11 | #define __HEV_SOCKS5_WORKER_H__ 12 | 13 | #include 14 | 15 | typedef struct _HevSocks5Worker HevSocks5Worker; 16 | 17 | HevSocks5Worker *hev_socks5_worker_new (void); 18 | void hev_socks5_worker_destroy (HevSocks5Worker *self); 19 | int hev_socks5_worker_init (HevSocks5Worker *self, int fd); 20 | 21 | void hev_socks5_worker_start (HevSocks5Worker *self); 22 | void hev_socks5_worker_stop (HevSocks5Worker *self); 23 | void hev_socks5_worker_reload (HevSocks5Worker *self); 24 | 25 | void hev_socks5_worker_set_auth (HevSocks5Worker *self, 26 | HevSocks5Authenticator *auth); 27 | 28 | #endif /* __HEV_SOCKS5_WORKER_H__ */ 29 | -------------------------------------------------------------------------------- /src/misc/hev-compiler.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-compiler.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2019 everyone. 6 | Description : Compiler 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_COMPILER_H__ 11 | #define __HEV_COMPILER_H__ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | #define ALIGN_UP(addr, align) \ 18 | ((addr + (typeof (addr))align - 1) & ~((typeof (addr))align - 1)) 19 | 20 | #define ALIGN_DOWN(addr, align) ((addr) & ~((typeof (addr))align - 1)) 21 | 22 | #ifndef ARRAY_SIZE 23 | #define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0])) 24 | #endif 25 | 26 | #ifndef EXPORT_SYMBOL 27 | #define EXPORT_SYMBOL __attribute__ ((visibility ("default"))) 28 | #endif 29 | 30 | #define barrier() __asm__ __volatile__ ("" : : : "memory") 31 | 32 | static inline void 33 | __read_once_size (void *dst, const volatile void *src, int size) 34 | { 35 | switch (size) { 36 | case sizeof (char): 37 | *(char *)dst = *(volatile char *)src; 38 | break; 39 | case sizeof (short): 40 | *(short *)dst = *(volatile short *)src; 41 | break; 42 | case sizeof (int): 43 | *(int *)dst = *(volatile int *)src; 44 | break; 45 | default: 46 | barrier (); 47 | __builtin_memcpy ((void *)dst, (const void *)src, size); 48 | barrier (); 49 | } 50 | } 51 | 52 | static inline void 53 | __write_once_size (volatile void *dst, const void *src, int size) 54 | { 55 | switch (size) { 56 | case sizeof (char): 57 | *(volatile char *)dst = *(char *)src; 58 | break; 59 | case sizeof (short): 60 | *(volatile short *)dst = *(short *)src; 61 | break; 62 | case sizeof (int): 63 | *(volatile int *)dst = *(int *)src; 64 | break; 65 | default: 66 | barrier (); 67 | __builtin_memcpy ((void *)dst, (const void *)src, size); 68 | barrier (); 69 | } 70 | } 71 | 72 | #define READ_ONCE(x) \ 73 | ({ \ 74 | union \ 75 | { \ 76 | typeof (x) __val; \ 77 | char __c[1]; \ 78 | } __u; \ 79 | __read_once_size (__u.__c, &(x), sizeof (x)); \ 80 | __u.__val; \ 81 | }) 82 | 83 | #define WRITE_ONCE(x, val) \ 84 | ({ \ 85 | union \ 86 | { \ 87 | typeof (x) __val; \ 88 | char __c[1]; \ 89 | } __u = { .__val = (typeof (x))(val) }; \ 90 | __write_once_size (&(x), __u.__c, sizeof (x)); \ 91 | __u.__val; \ 92 | }) 93 | 94 | #ifndef container_of 95 | #define container_of(ptr, type, member) \ 96 | ({ \ 97 | void *__mptr = (void *)(ptr); \ 98 | ((type *)(__mptr - offsetof (type, member))); \ 99 | }) 100 | #endif 101 | 102 | #ifdef __cplusplus 103 | } 104 | #endif 105 | 106 | #endif /* __HEV_COMPILER_H__ */ 107 | -------------------------------------------------------------------------------- /src/misc/hev-list.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-list.c 4 | Authors : Heiher 5 | Copyright : Copyright (c) 2019 everyone. 6 | Description : Double-linked List 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | 12 | #include "hev-list.h" 13 | 14 | void 15 | hev_list_add_tail (HevList *self, HevListNode *new_) 16 | { 17 | new_->prev = self->tail; 18 | new_->next = NULL; 19 | 20 | if (self->tail) 21 | self->tail->next = new_; 22 | else 23 | self->head = new_; 24 | self->tail = new_; 25 | } 26 | 27 | void 28 | hev_list_del (HevList *self, HevListNode *node) 29 | { 30 | if (node->prev) 31 | node->prev->next = node->next; 32 | else 33 | self->head = node->next; 34 | 35 | if (node->next) 36 | node->next->prev = node->prev; 37 | else 38 | self->tail = node->prev; 39 | } 40 | -------------------------------------------------------------------------------- /src/misc/hev-list.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-list.h 4 | Authors : Heiher 5 | Copyright : Copyright (c) 2019 everyone. 6 | Description : Double-linked List 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_LIST_H__ 11 | #define __HEV_LIST_H__ 12 | 13 | #ifdef __cplusplus 14 | extern "C" { 15 | #endif 16 | 17 | typedef struct _HevList HevList; 18 | typedef struct _HevListNode HevListNode; 19 | 20 | struct _HevList 21 | { 22 | HevListNode *head; 23 | HevListNode *tail; 24 | }; 25 | 26 | struct _HevListNode 27 | { 28 | HevListNode *next; 29 | HevListNode *prev; 30 | }; 31 | 32 | static inline HevListNode * 33 | hev_list_node_prev (HevListNode *node) 34 | { 35 | return node->prev; 36 | } 37 | 38 | static inline HevListNode * 39 | hev_list_node_next (HevListNode *node) 40 | { 41 | return node->next; 42 | } 43 | 44 | static inline HevListNode * 45 | hev_list_first (HevList *self) 46 | { 47 | return self->head; 48 | } 49 | 50 | static inline HevListNode * 51 | hev_list_last (HevList *self) 52 | { 53 | return self->tail; 54 | } 55 | 56 | void hev_list_add_tail (HevList *self, HevListNode *new_); 57 | void hev_list_del (HevList *self, HevListNode *node); 58 | 59 | #ifdef __cplusplus 60 | } 61 | #endif 62 | 63 | #endif /* __HEV_LIST_H__ */ 64 | -------------------------------------------------------------------------------- /src/misc/hev-logger.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-logger.c 4 | Author : Heiher 5 | Copyright : Copyright (c) 2019 - 2021 hev 6 | Description : Logger 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "hev-logger.h" 20 | 21 | static int fd = -1; 22 | static HevLoggerLevel req_level; 23 | 24 | int 25 | hev_logger_init (HevLoggerLevel level, const char *path) 26 | { 27 | req_level = level; 28 | 29 | if (0 == strcmp (path, "stdout")) 30 | fd = dup (1); 31 | else if (0 == strcmp (path, "stderr")) 32 | fd = dup (2); 33 | else 34 | fd = open (path, O_WRONLY | O_APPEND | O_CREAT, 0640); 35 | 36 | if (fd < 0) 37 | return -1; 38 | 39 | return 0; 40 | } 41 | 42 | void 43 | hev_logger_fini (void) 44 | { 45 | close (fd); 46 | } 47 | 48 | int 49 | hev_logger_enabled (HevLoggerLevel level) 50 | { 51 | if (fd >= 0 && level >= req_level) 52 | return 1; 53 | 54 | return 0; 55 | } 56 | 57 | void 58 | hev_logger_log (HevLoggerLevel level, const char *fmt, ...) 59 | { 60 | struct iovec iov[4]; 61 | const char *ts_fmt; 62 | char msg[1024]; 63 | struct tm *ti; 64 | char ts[32]; 65 | time_t now; 66 | va_list ap; 67 | int len; 68 | 69 | if (fd < 0 || level < req_level) 70 | return; 71 | 72 | time (&now); 73 | ti = localtime (&now); 74 | 75 | ts_fmt = "[%04u-%02u-%02u %02u:%02u:%02u] "; 76 | len = snprintf (ts, sizeof (ts), ts_fmt, 1900 + ti->tm_year, 1 + ti->tm_mon, 77 | ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec); 78 | 79 | iov[0].iov_base = ts; 80 | iov[0].iov_len = len; 81 | 82 | switch (level) { 83 | case HEV_LOGGER_DEBUG: 84 | iov[1].iov_base = "[D] "; 85 | break; 86 | case HEV_LOGGER_INFO: 87 | iov[1].iov_base = "[I] "; 88 | break; 89 | case HEV_LOGGER_WARN: 90 | iov[1].iov_base = "[W] "; 91 | break; 92 | case HEV_LOGGER_ERROR: 93 | iov[1].iov_base = "[E] "; 94 | break; 95 | case HEV_LOGGER_UNSET: 96 | iov[1].iov_base = "[?] "; 97 | break; 98 | } 99 | iov[1].iov_len = 4; 100 | 101 | va_start (ap, fmt); 102 | iov[2].iov_base = msg; 103 | iov[2].iov_len = vsnprintf (msg, 1024, fmt, ap); 104 | va_end (ap); 105 | 106 | iov[3].iov_base = "\n"; 107 | iov[3].iov_len = 1; 108 | 109 | if (writev (fd, iov, 4)) { 110 | /* ignore return value */ 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/misc/hev-logger.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-logger.h 4 | Author : Heiher 5 | Copyright : Copyright (c) 2019 - 2021 hev 6 | Description : Logger 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_LOGGER_H__ 11 | #define __HEV_LOGGER_H__ 12 | 13 | #define LOG_D(fmt...) hev_logger_log (HEV_LOGGER_DEBUG, fmt) 14 | #define LOG_I(fmt...) hev_logger_log (HEV_LOGGER_INFO, fmt) 15 | #define LOG_W(fmt...) hev_logger_log (HEV_LOGGER_WARN, fmt) 16 | #define LOG_E(fmt...) hev_logger_log (HEV_LOGGER_ERROR, fmt) 17 | 18 | #define LOG_ON() hev_logger_enabled (HEV_LOGGER_UNSET) 19 | #define LOG_ON_D() hev_logger_enabled (HEV_LOGGER_DEBUG) 20 | #define LOG_ON_I() hev_logger_enabled (HEV_LOGGER_INFO) 21 | #define LOG_ON_W() hev_logger_enabled (HEV_LOGGER_WARN) 22 | #define LOG_ON_E() hev_logger_enabled (HEV_LOGGER_ERROR) 23 | 24 | typedef enum 25 | { 26 | HEV_LOGGER_DEBUG, 27 | HEV_LOGGER_INFO, 28 | HEV_LOGGER_WARN, 29 | HEV_LOGGER_ERROR, 30 | HEV_LOGGER_UNSET, 31 | } HevLoggerLevel; 32 | 33 | int hev_logger_init (HevLoggerLevel level, const char *path); 34 | void hev_logger_fini (void); 35 | 36 | int hev_logger_enabled (HevLoggerLevel level); 37 | void hev_logger_log (HevLoggerLevel level, const char *fmt, ...); 38 | 39 | #endif /* __HEV_LOGGER_H__ */ 40 | -------------------------------------------------------------------------------- /src/misc/hev-misc.c: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-misc.c 4 | Authors : Heiher 5 | Copyright : Copyright (c) 2022 - 2024 everyone. 6 | Description : Misc 7 | ============================================================================ 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #if defined(__APPLE__) 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | #include 24 | 25 | #include "hev-logger.h" 26 | 27 | #include "hev-misc.h" 28 | 29 | int 30 | hev_netaddr_resolve (struct sockaddr_in6 *daddr, const char *addr, 31 | const char *port) 32 | { 33 | struct addrinfo hints = { 0 }; 34 | struct addrinfo *result; 35 | int res; 36 | 37 | hints.ai_family = AF_UNSPEC; 38 | hints.ai_socktype = SOCK_STREAM; 39 | hints.ai_flags = AI_PASSIVE; 40 | 41 | res = hev_task_dns_getaddrinfo (addr, port, &hints, &result); 42 | if (res < 0) 43 | return -1; 44 | 45 | if (result->ai_family == AF_INET) { 46 | struct sockaddr_in *adp; 47 | 48 | adp = (struct sockaddr_in *)result->ai_addr; 49 | daddr->sin6_family = AF_INET6; 50 | daddr->sin6_port = adp->sin_port; 51 | memset (&daddr->sin6_addr, 0, 10); 52 | daddr->sin6_addr.s6_addr[10] = 0xff; 53 | daddr->sin6_addr.s6_addr[11] = 0xff; 54 | memcpy (&daddr->sin6_addr.s6_addr[12], &adp->sin_addr, 4); 55 | } else if (result->ai_family == AF_INET6) { 56 | memcpy (daddr, result->ai_addr, sizeof (struct sockaddr_in6)); 57 | } 58 | 59 | freeaddrinfo (result); 60 | 61 | return 0; 62 | } 63 | 64 | int 65 | hev_netaddr_is_any (struct sockaddr_in6 *addr) 66 | { 67 | if (addr->sin6_port) 68 | return 0; 69 | 70 | if (!IN6_IS_ADDR_V4MAPPED (&addr->sin6_addr)) 71 | return !memcmp (&addr->sin6_addr, &in6addr_any, 16); 72 | 73 | return !memcmp (&addr->sin6_addr.s6_addr[12], &in6addr_any, 4); 74 | } 75 | 76 | void 77 | run_as_daemon (const char *pid_file) 78 | { 79 | FILE *fp; 80 | 81 | fp = fopen (pid_file, "w+"); 82 | if (!fp) { 83 | LOG_E ("open pid file %s", pid_file); 84 | return; 85 | } 86 | 87 | #ifndef TARGET_OS_TV 88 | #pragma GCC diagnostic push 89 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 90 | if (daemon (0, 0)) { 91 | /* ignore return value */ 92 | } 93 | #pragma GCC diagnostic pop 94 | #endif 95 | 96 | fprintf (fp, "%u\n", getpid ()); 97 | fclose (fp); 98 | } 99 | 100 | int 101 | set_limit_nofile (int limit_nofile) 102 | { 103 | struct rlimit limit = { 104 | .rlim_cur = limit_nofile, 105 | .rlim_max = limit_nofile, 106 | }; 107 | 108 | return setrlimit (RLIMIT_NOFILE, &limit); 109 | } 110 | 111 | int 112 | set_sock_bind (int fd, const char *iface) 113 | { 114 | int res = 0; 115 | 116 | #if defined(__linux__) 117 | struct ifreq ifr = { 0 }; 118 | 119 | strncpy (ifr.ifr_name, iface, sizeof (ifr.ifr_name) - 1); 120 | res = setsockopt (fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)); 121 | #elif defined(__APPLE__) || defined(__MACH__) 122 | int i; 123 | 124 | i = if_nametoindex (iface); 125 | if (i == 0) { 126 | return -1; 127 | } 128 | 129 | res = setsockopt (fd, IPPROTO_IPV6, IPV6_BOUND_IF, &i, sizeof (i)); 130 | #endif 131 | 132 | return res; 133 | } 134 | 135 | int 136 | set_sock_mark (int fd, unsigned int mark) 137 | { 138 | #if defined(__linux__) 139 | return setsockopt (fd, SOL_SOCKET, SO_MARK, &mark, sizeof (mark)); 140 | #elif defined(__FreeBSD__) 141 | return setsockopt (fd, SOL_SOCKET, SO_USER_COOKIE, &mark, sizeof (mark)); 142 | #endif 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /src/misc/hev-misc.h: -------------------------------------------------------------------------------- 1 | /* 2 | ============================================================================ 3 | Name : hev-misc.h 4 | Authors : Heiher 5 | Copyright : Copyright (c) 2022 - 2024 everyone. 6 | Description : Misc 7 | ============================================================================ 8 | */ 9 | 10 | #ifndef __HEV_MISC_H__ 11 | #define __HEV_MISC_H__ 12 | 13 | #include 14 | 15 | int hev_netaddr_resolve (struct sockaddr_in6 *daddr, const char *addr, 16 | const char *port); 17 | int hev_netaddr_is_any (struct sockaddr_in6 *addr); 18 | 19 | void run_as_daemon (const char *pid_file); 20 | int set_limit_nofile (int limit_nofile); 21 | 22 | int set_sock_bind (int fd, const char *iface); 23 | int set_sock_mark (int fd, unsigned int mark); 24 | 25 | #endif /* __HEV_MISC_H__ */ 26 | --------------------------------------------------------------------------------