mirror of
https://github.com/bolucat/Archive.git
synced 2026-04-22 16:07:49 +08:00
Update On Tue Aug 5 20:45:24 CEST 2025
This commit is contained in:
@@ -1080,3 +1080,4 @@ Update On Fri Aug 1 20:44:14 CEST 2025
|
||||
Update On Sat Aug 2 20:40:30 CEST 2025
|
||||
Update On Sun Aug 3 20:40:33 CEST 2025
|
||||
Update On Mon Aug 4 20:43:42 CEST 2025
|
||||
Update On Tue Aug 5 20:45:16 CEST 2025
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
"@emotion/styled": "11.14.1",
|
||||
"@juggle/resize-observer": "3.4.0",
|
||||
"@material/material-color-utilities": "0.3.0",
|
||||
"@mui/icons-material": "7.2.0",
|
||||
"@mui/lab": "7.0.0-beta.14",
|
||||
"@mui/material": "7.2.0",
|
||||
"@mui/icons-material": "7.3.0",
|
||||
"@mui/lab": "7.0.0-beta.15",
|
||||
"@mui/material": "7.3.0",
|
||||
"@mui/x-date-pickers": "8.9.2",
|
||||
"@nyanpasu/interface": "workspace:^",
|
||||
"@nyanpasu/ui": "workspace:^",
|
||||
@@ -33,7 +33,7 @@
|
||||
"dayjs": "1.11.13",
|
||||
"framer-motion": "12.23.12",
|
||||
"i18next": "25.3.2",
|
||||
"jotai": "2.12.5",
|
||||
"jotai": "2.13.0",
|
||||
"json-schema": "0.4.0",
|
||||
"material-react-table": "3.2.1",
|
||||
"monaco-editor": "0.52.2",
|
||||
@@ -56,7 +56,7 @@
|
||||
"@csstools/normalize.css": "12.1.1",
|
||||
"@emotion/babel-plugin": "11.13.5",
|
||||
"@emotion/react": "11.14.0",
|
||||
"@iconify/json": "2.2.365",
|
||||
"@iconify/json": "2.2.366",
|
||||
"@monaco-editor/react": "4.7.0",
|
||||
"@tanstack/react-query": "5.84.1",
|
||||
"@tanstack/react-router": "1.130.12",
|
||||
@@ -78,7 +78,7 @@
|
||||
"@vitejs/plugin-react-swc": "3.11.0",
|
||||
"change-case": "5.4.4",
|
||||
"clsx": "2.1.1",
|
||||
"core-js": "3.44.0",
|
||||
"core-js": "3.45.0",
|
||||
"filesize": "11.0.2",
|
||||
"meta-json-schema": "1.19.12",
|
||||
"monaco-yaml": "5.4.0",
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@material/material-color-utilities": "0.3.0",
|
||||
"@mui/icons-material": "7.2.0",
|
||||
"@mui/lab": "7.0.0-beta.14",
|
||||
"@mui/material": "7.2.0",
|
||||
"@mui/icons-material": "7.3.0",
|
||||
"@mui/lab": "7.0.0-beta.15",
|
||||
"@mui/material": "7.3.0",
|
||||
"@radix-ui/react-portal": "1.1.9",
|
||||
"@radix-ui/react-scroll-area": "1.2.9",
|
||||
"@tauri-apps/api": "2.6.0",
|
||||
|
||||
@@ -67,8 +67,8 @@
|
||||
"@types/fs-extra": "11.0.4",
|
||||
"@types/lodash-es": "4.17.12",
|
||||
"@types/node": "22.17.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.38.0",
|
||||
"@typescript-eslint/parser": "8.38.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.39.0",
|
||||
"@typescript-eslint/parser": "8.39.0",
|
||||
"autoprefixer": "10.4.21",
|
||||
"conventional-changelog-conventionalcommits": "9.1.0",
|
||||
"cross-env": "10.0.0",
|
||||
@@ -107,7 +107,7 @@
|
||||
"tailwindcss": "4.1.11",
|
||||
"tsx": "4.20.3",
|
||||
"typescript": "5.9.2",
|
||||
"typescript-eslint": "8.38.0"
|
||||
"typescript-eslint": "8.39.0"
|
||||
},
|
||||
"packageManager": "pnpm@10.14.0",
|
||||
"engines": {
|
||||
|
||||
Generated
+263
-332
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,73 @@
|
||||
#
|
||||
# Copyright (C) 2020-2024 Tony Ambardar <itugrok@yahoo.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=libbpf
|
||||
PKG_VERSION:=1.5.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/libbpf/libbpf
|
||||
PKG_MIRROR_HASH:=ef379723b73175cd1659c5f71cfc5df4e7cb6788d0eb0c8bc5829b3e3997c981
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
|
||||
PKG_ABI_VERSION:=$(firstword $(subst .,$(space),$(PKG_VERSION)))
|
||||
|
||||
PKG_MAINTAINER:=Tony Ambardar <itugrok@yahoo.com>
|
||||
PKG_CPE_ID:=cpe:/a:libbpf_project:libbpf
|
||||
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_FLAGS:=no-mips16 no-gc-sections no-lto
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_INSTALL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/nls.mk
|
||||
|
||||
define Package/libbpf
|
||||
SECTION:=libs
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=libbpf - eBPF helper library
|
||||
LICENSE:=LGPL-2.1 OR BSD-2-Clause
|
||||
ABI_VERSION:=$(PKG_ABI_VERSION)
|
||||
URL:=http://www.kernel.org
|
||||
DEPENDS:=+libelf
|
||||
endef
|
||||
|
||||
define Package/libbpf/description
|
||||
libbpf is a library for loading eBPF programs and reading and manipulating eBPF objects from user-space.
|
||||
endef
|
||||
|
||||
MAKE_FLAGS += \
|
||||
$(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \
|
||||
LIBSUBDIR=lib
|
||||
|
||||
MAKE_PATH = src
|
||||
|
||||
define Build/InstallDev/libbpf
|
||||
$(INSTALL_DIR) $(1)/usr/include/bpf
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/include/bpf/*.h $(1)/usr/include/bpf/
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.{a,so*} \
|
||||
$(1)/usr/lib/
|
||||
$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libbpf.pc \
|
||||
$(1)/usr/lib/pkgconfig/
|
||||
$(SED) 's,/usr/include,$$$${prefix}/include,g' \
|
||||
$(1)/usr/lib/pkgconfig/libbpf.pc
|
||||
$(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \
|
||||
$(1)/usr/lib/pkgconfig/libbpf.pc
|
||||
endef
|
||||
|
||||
Build/InstallDev=$(Build/InstallDev/libbpf)
|
||||
|
||||
define Package/libbpf/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.so.* $(1)/usr/lib/
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,libbpf))
|
||||
@@ -0,0 +1,54 @@
|
||||
--- a/src/libbpf.h
|
||||
+++ b/src/libbpf.h
|
||||
@@ -1291,9 +1291,10 @@ struct bpf_tc_opts {
|
||||
__u32 prog_id;
|
||||
__u32 handle;
|
||||
__u32 priority;
|
||||
+ __u32 classid;
|
||||
size_t :0;
|
||||
};
|
||||
-#define bpf_tc_opts__last_field priority
|
||||
+#define bpf_tc_opts__last_field classid
|
||||
|
||||
LIBBPF_API int bpf_tc_hook_create(struct bpf_tc_hook *hook);
|
||||
LIBBPF_API int bpf_tc_hook_destroy(struct bpf_tc_hook *hook);
|
||||
--- a/src/netlink.c
|
||||
+++ b/src/netlink.c
|
||||
@@ -673,6 +673,8 @@ static int __get_tc_info(void *cookie, s
|
||||
OPTS_SET(info->opts, prog_id, libbpf_nla_getattr_u32(tbb[TCA_BPF_ID]));
|
||||
OPTS_SET(info->opts, handle, tc->tcm_handle);
|
||||
OPTS_SET(info->opts, priority, TC_H_MAJ(tc->tcm_info) >> 16);
|
||||
+ if (tbb[TCA_BPF_CLASSID])
|
||||
+ OPTS_SET(info->opts, classid, libbpf_nla_getattr_u32(tbb[TCA_BPF_CLASSID]));
|
||||
|
||||
info->processed = true;
|
||||
return unicast ? NL_NEXT : NL_DONE;
|
||||
@@ -717,7 +719,7 @@ static int tc_add_fd_and_name(struct lib
|
||||
|
||||
int bpf_tc_attach(const struct bpf_tc_hook *hook, struct bpf_tc_opts *opts)
|
||||
{
|
||||
- __u32 protocol, bpf_flags, handle, priority, parent, prog_id, flags;
|
||||
+ __u32 protocol, bpf_flags, handle, priority, parent, prog_id, flags, classid;
|
||||
int ret, ifindex, attach_point, prog_fd;
|
||||
struct bpf_cb_ctx info = {};
|
||||
struct libbpf_nla_req req;
|
||||
@@ -737,6 +739,7 @@ int bpf_tc_attach(const struct bpf_tc_ho
|
||||
prog_fd = OPTS_GET(opts, prog_fd, 0);
|
||||
prog_id = OPTS_GET(opts, prog_id, 0);
|
||||
flags = OPTS_GET(opts, flags, 0);
|
||||
+ classid = OPTS_GET(opts, classid, 0);
|
||||
|
||||
if (ifindex <= 0 || !prog_fd || prog_id)
|
||||
return libbpf_err(-EINVAL);
|
||||
@@ -776,6 +779,11 @@ int bpf_tc_attach(const struct bpf_tc_ho
|
||||
ret = nlattr_add(&req, TCA_BPF_FLAGS, &bpf_flags, sizeof(bpf_flags));
|
||||
if (ret < 0)
|
||||
return libbpf_err(ret);
|
||||
+ if (classid) {
|
||||
+ ret = nlattr_add(&req, TCA_BPF_CLASSID, &classid, sizeof(classid));
|
||||
+ if (ret < 0)
|
||||
+ return libbpf_err(ret);
|
||||
+ }
|
||||
nlattr_end_nested(&req, nla);
|
||||
|
||||
info.opts = opts;
|
||||
+36
-64
@@ -1,5 +1,5 @@
|
||||
#
|
||||
# Copyright (C) 2020 Tony Ambardar <itugrok@yahoo.com>
|
||||
# Copyright (C) 2020-2024 Tony Ambardar <itugrok@yahoo.com>
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
@@ -7,24 +7,27 @@
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=bpftools
|
||||
PKG_NAME:=bpftool
|
||||
PKG_VERSION:=7.5.0
|
||||
PKG_RELEASE:=1
|
||||
|
||||
PKG_SOURCE_URL:=https://github.com/libbpf/bpftool
|
||||
PKG_MIRROR_HASH:=d2d55ff9cc11490b251105c9e376cbfaa9bcd26d224af779fd58cdcaa8f70ccf
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_DATE:=2022-03-08
|
||||
PKG_SOURCE_VERSION:=04c465fd1f561f67796dc68bbfe1aa7cfa956c3c
|
||||
PKG_MIRROR_HASH:=e22a954cd186f43228a96586bbdc120b11e6c87360ab88ae96ba37afb9c7cb58
|
||||
PKG_ABI_VERSION:=$(call abi_version_str,$(PKG_SOURCE_DATE))
|
||||
PKG_SOURCE_VERSION:=v$(PKG_VERSION)
|
||||
|
||||
PKG_MAINTAINER:=Tony Ambardar <itugrok@yahoo.com>
|
||||
|
||||
PKG_USE_MIPS16:=0
|
||||
PKG_BUILD_FLAGS:=no-mips16 gc-sections lto
|
||||
PKG_BUILD_PARALLEL:=1
|
||||
PKG_INSTALL:=1
|
||||
|
||||
HOST_BUILD_PARALLEL:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
include $(INCLUDE_DIR)/nls.mk
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
|
||||
define Package/bpftool/Default
|
||||
SECTION:=net
|
||||
@@ -63,75 +66,25 @@ define Package/bpftool-full/description
|
||||
eBPF programs and jited code.
|
||||
endef
|
||||
|
||||
define Package/libbpf
|
||||
SECTION:=libs
|
||||
CATEGORY:=Libraries
|
||||
TITLE:=libbpf - eBPF helper library
|
||||
VARIANT:=lib
|
||||
LICENSE:=LGPL-2.1 OR BSD-2-Clause
|
||||
ABI_VERSION:=$(PKG_ABI_VERSION)
|
||||
URL:=http://www.kernel.org
|
||||
DEPENDS:=+libelf
|
||||
endef
|
||||
|
||||
define Package/libbpf/description
|
||||
libbpf is a library for loading eBPF programs and reading and manipulating eBPF objects from user-space.
|
||||
endef
|
||||
|
||||
|
||||
# LTO not compatible with DSO using PIC
|
||||
ifneq ($(BUILD_VARIANT),lib)
|
||||
TARGET_CFLAGS += -ffunction-sections -fdata-sections -flto
|
||||
TARGET_LDFLAGS += -Wl,--gc-sections
|
||||
endif
|
||||
|
||||
ifeq ($(BUILD_VARIANT),full)
|
||||
full:=1
|
||||
else
|
||||
full:=0
|
||||
endif
|
||||
|
||||
MAKE_VARS = \
|
||||
EXTRA_CFLAGS="$(TARGET_CFLAGS) $(TARGET_CPPFLAGS)" \
|
||||
LDFLAGS="$(TARGET_LDFLAGS)"
|
||||
|
||||
MAKE_FLAGS += \
|
||||
OUTPUT="$(PKG_BUILD_DIR)/" \
|
||||
prefix="/usr" \
|
||||
$(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \
|
||||
LIBSUBDIR=lib \
|
||||
check_feat=0 \
|
||||
feature-clang-bpf-co-re=0 \
|
||||
feature-reallocarray=1 \
|
||||
feature-zlib=1 \
|
||||
feature-libbfd=$(full) \
|
||||
feature-llvm=0 \
|
||||
feature-libcap=0 \
|
||||
feature-disassembler-four-args=$(full)
|
||||
feature-disassembler-four-args=1 \
|
||||
feature-disassembler-init-styled=1
|
||||
|
||||
ifeq ($(BUILD_VARIANT),lib)
|
||||
MAKE_PATH = libbpf/src
|
||||
else
|
||||
MAKE_PATH = src
|
||||
endif
|
||||
|
||||
define Build/InstallDev/libbpf
|
||||
$(INSTALL_DIR) $(1)/usr/include/bpf
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/include/bpf/*.h $(1)/usr/include/bpf/
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.{a,so*} \
|
||||
$(1)/usr/lib/
|
||||
$(INSTALL_DIR) $(1)/usr/lib/pkgconfig
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/pkgconfig/libbpf.pc \
|
||||
$(1)/usr/lib/pkgconfig/
|
||||
$(SED) 's,/usr/include,$$$${prefix}/include,g' \
|
||||
$(1)/usr/lib/pkgconfig/libbpf.pc
|
||||
$(SED) 's,/usr/lib,$$$${exec_prefix}/lib,g' \
|
||||
$(1)/usr/lib/pkgconfig/libbpf.pc
|
||||
endef
|
||||
|
||||
ifeq ($(BUILD_VARIANT),lib)
|
||||
Build/InstallDev=$(Build/InstallDev/libbpf)
|
||||
endif
|
||||
MAKE_PATH = src
|
||||
|
||||
define Package/bpftool-$(BUILD_VARIANT)/install
|
||||
$(INSTALL_DIR) $(1)/usr/libexec
|
||||
@@ -139,11 +92,30 @@ define Package/bpftool-$(BUILD_VARIANT)/install
|
||||
$(1)/usr/libexec/bpftool-$(BUILD_VARIANT)
|
||||
endef
|
||||
|
||||
define Package/libbpf/install
|
||||
$(INSTALL_DIR) $(1)/usr/lib
|
||||
$(CP) $(PKG_INSTALL_DIR)/usr/lib/libbpf.so.* $(1)/usr/lib/
|
||||
HOST_MAKE_FLAGS += \
|
||||
OUTPUT="$(HOST_BUILD_DIR)/" \
|
||||
prefix="/usr" \
|
||||
$(if $(findstring c,$(OPENWRT_VERBOSE)),V=1,V='') \
|
||||
check_feat=0 \
|
||||
feature-clang-bpf-co-re=0 \
|
||||
feature-libbfd=0 \
|
||||
feature-llvm=0 \
|
||||
feature-libcap=0 \
|
||||
feature-disassembler-four-args=1 \
|
||||
feature-disassembler-init-styled=1
|
||||
|
||||
HOST_MAKE_PATH = src
|
||||
|
||||
define Host/Install
|
||||
$(INSTALL_DIR) $(STAGING_DIR_HOST)/usr/sbin
|
||||
$(INSTALL_BIN) $(HOST_BUILD_DIR)/bpftool \
|
||||
$(STAGING_DIR_HOST)/usr/sbin/bpftool
|
||||
endef
|
||||
|
||||
define Host/Clean
|
||||
rm -f $(STAGING_DIR_HOST)/usr/sbin/bpftool
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,libbpf))
|
||||
$(eval $(call BuildPackage,bpftool-full))
|
||||
$(eval $(call BuildPackage,bpftool-minimal))
|
||||
$(eval $(call HostBuild))
|
||||
+1
-12
@@ -1,20 +1,9 @@
|
||||
--- a/libbpf/include/linux/list.h
|
||||
+++ b/libbpf/include/linux/list.h
|
||||
@@ -3,6 +3,8 @@
|
||||
#ifndef __LINUX_LIST_H
|
||||
#define __LINUX_LIST_H
|
||||
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = LIST_HEAD_INIT(name)
|
||||
--- a/src/Makefile
|
||||
+++ b/src/Makefile
|
||||
@@ -73,10 +73,10 @@ CFLAGS += -W -Wall -Wextra -Wno-unused-p
|
||||
CFLAGS += $(filter-out -Wswitch-enum -Wnested-externs,$(EXTRA_WARNINGS))
|
||||
CFLAGS += -DPACKAGE='"bpftool"' -D__EXPORTED_HEADERS__ \
|
||||
-I$(if $(OUTPUT),$(OUTPUT),.) \
|
||||
-I$(or $(OUTPUT),.) \
|
||||
- -I$(LIBBPF_INCLUDE) \
|
||||
-I$(srctree)/src/kernel/bpf/ \
|
||||
-I$(srctree)/include \
|
||||
@@ -1,10 +0,0 @@
|
||||
--- a/libbpf/src/Makefile
|
||||
+++ b/libbpf/src/Makefile
|
||||
@@ -25,6 +25,7 @@ ALL_CFLAGS := $(INCLUDES)
|
||||
|
||||
SHARED_CFLAGS += -fPIC -fvisibility=hidden -DSHARED
|
||||
|
||||
+CFLAGS = $(EXTRA_CFLAGS)
|
||||
CFLAGS ?= -g -O2 -Werror -Wall -std=gnu89
|
||||
ALL_CFLAGS += $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
|
||||
ALL_LDFLAGS += $(LDFLAGS)
|
||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=25.8.5
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
|
||||
|
||||
@@ -1580,6 +1580,9 @@ local hysteria2_type = map:get("@global_subscribe[0]", "hysteria2_type") or "sin
|
||||
queryParam[decodeURIComponent(params[0])] = decodeURIComponent(params[1] || '');
|
||||
}
|
||||
}
|
||||
if ((!queryParam.security || queryParam.security == "") && queryParam.sni && queryParam.sni != "") {
|
||||
queryParam.security = "tls";
|
||||
}
|
||||
if (queryParam.security) {
|
||||
if (queryParam.security == "tls") {
|
||||
opt.set(dom_prefix + 'tls', true);
|
||||
|
||||
@@ -1751,7 +1751,7 @@ msgid "Fragmentation interval (ms)"
|
||||
msgstr "分片间隔(ms)"
|
||||
|
||||
msgid "Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first."
|
||||
msgstr 将握手数据拆分为多个 TLS 记录,提升抗封锁能力,几乎不增加延迟,建议优先启用。"
|
||||
msgstr "将握手数据拆分为多个 TLS 记录,提升抗封锁能力,几乎不增加延迟,建议优先启用。"
|
||||
|
||||
msgid "Split handshake into multiple TCP segments. Enhances obfuscation. May increase delay. Use only if needed."
|
||||
msgstr "将 TLS 握手数据分为多个 TCP 包发送,提高伪装性,可能增加延迟,仅在封锁严重时使用。"
|
||||
|
||||
@@ -280,7 +280,7 @@ do
|
||||
if node.balancing_node then
|
||||
for k, node in pairs(node.balancing_node) do
|
||||
currentNodes[#currentNodes + 1] = {
|
||||
log = false,
|
||||
log = true,
|
||||
node = node,
|
||||
currentNode = node and uci:get_all(appname, node) or nil,
|
||||
remarks = node,
|
||||
@@ -328,7 +328,7 @@ do
|
||||
if node.urltest_node then
|
||||
for k, node in pairs(node.urltest_node) do
|
||||
currentNodes[#currentNodes + 1] = {
|
||||
log = false,
|
||||
log = true,
|
||||
node = node,
|
||||
currentNode = node and uci:get_all(appname, node) or nil,
|
||||
remarks = node,
|
||||
@@ -1452,9 +1452,12 @@ local function processData(szType, content, add_mode, add_from)
|
||||
result.address = host_port
|
||||
end
|
||||
result.tls = "0"
|
||||
if (not params.security or params.security == "") and params.sni and params.sni ~= "" then
|
||||
params.security = "tls"
|
||||
end
|
||||
if params.security == "tls" or params.security == "reality" then
|
||||
result.tls = "1"
|
||||
result.tls_serverName = (params.sni and params.sni ~= "") and params.sni or params.host
|
||||
result.tls_serverName = params.sni
|
||||
result.alpn = params.alpn
|
||||
if params.fp and params.fp ~= "" then
|
||||
result.utls = "1"
|
||||
@@ -1566,7 +1569,9 @@ local function select_node(nodes, config, parentConfig)
|
||||
if config.currentNode[".name"] then
|
||||
for index, node in pairs(nodes) do
|
||||
if node[".name"] == config.currentNode[".name"] then
|
||||
log('更新【' .. config.remarks .. '】匹配节点:' .. node.remarks)
|
||||
if config.log == nil or config.log == true then
|
||||
log('更新【' .. config.remarks .. '】匹配节点:' .. node.remarks)
|
||||
end
|
||||
server = node[".name"]
|
||||
break
|
||||
end
|
||||
@@ -1734,6 +1739,9 @@ local function update_node(manual)
|
||||
|
||||
for _, config in pairs(CONFIG) do
|
||||
if config.currentNodes and #config.currentNodes > 0 then
|
||||
if config.remarks and config.currentNodes[1].log ~= false then
|
||||
log('----【' .. config.remarks .. '】----')
|
||||
end
|
||||
for kk, vv in pairs(config.currentNodes) do
|
||||
select_node(nodes, vv, config)
|
||||
end
|
||||
|
||||
Generated
+10
-10
@@ -1024,14 +1024,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.60.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "etherparse"
|
||||
version = "0.18.2"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "54a48e7bdc36cdf86876a6890c0840957029374ea07f6697c96fa15898730375"
|
||||
checksum = "b119b9796ff800751a220394b8b3613f26dd30c48f254f6837e64c464872d1c7"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
]
|
||||
@@ -1977,7 +1977,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.48.5",
|
||||
"windows-targets 0.53.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2741,7 +2741,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"socket2 0.5.10",
|
||||
"tracing",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3062,7 +3062,7 @@ dependencies = [
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3744,7 +3744,7 @@ dependencies = [
|
||||
"getrandom 0.3.3",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -3876,9 +3876,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.47.0"
|
||||
version = "1.47.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35"
|
||||
checksum = "89e49afdadebb872d3145a5638b59eb0691ea23e46ca484037cfab3b76b95038"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -4384,7 +4384,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.48.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -177,7 +177,7 @@ flate2 = { version = "1.0", optional = true }
|
||||
brotli = { version = "8.0", optional = true }
|
||||
zstd = { version = "0.13", optional = true }
|
||||
|
||||
etherparse = { version = "0.18", optional = true }
|
||||
etherparse = { version = "0.19", optional = true }
|
||||
smoltcp = { version = "0.12", optional = true, default-features = false, features = [
|
||||
"std",
|
||||
"log",
|
||||
|
||||
@@ -112,6 +112,8 @@ func buildAndroid() {
|
||||
args = append(args, debugFlags...)
|
||||
}
|
||||
|
||||
args = append(args, "-ldflags", "-checklinkname=0")
|
||||
|
||||
tags := append(sharedTags, memcTags...)
|
||||
if debugEnabled {
|
||||
tags = append(tags, debugTags...)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package libbox
|
||||
|
||||
import (
|
||||
"os"
|
||||
_ "unsafe"
|
||||
)
|
||||
|
||||
// https://github.com/SagerNet/sing-box/issues/3233
|
||||
// https://github.com/golang/go/issues/70508
|
||||
// https://github.com/tailscale/tailscale/issues/13452
|
||||
|
||||
//go:linkname checkPidfdOnce os.checkPidfdOnce
|
||||
var checkPidfdOnce func() error
|
||||
|
||||
func init() {
|
||||
checkPidfdOnce = func() error {
|
||||
return os.ErrInvalid
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-passwall
|
||||
PKG_VERSION:=25.8.5
|
||||
PKG_RELEASE:=1
|
||||
PKG_RELEASE:=2
|
||||
|
||||
PKG_CONFIG_DEPENDS:= \
|
||||
CONFIG_PACKAGE_$(PKG_NAME)_Iptables_Transparent_Proxy \
|
||||
|
||||
@@ -1751,7 +1751,7 @@ msgid "Fragmentation interval (ms)"
|
||||
msgstr "分片间隔(ms)"
|
||||
|
||||
msgid "Split handshake data into multiple TLS records for better censorship evasion. Low overhead. Recommended to enable first."
|
||||
msgstr 将握手数据拆分为多个 TLS 记录,提升抗封锁能力,几乎不增加延迟,建议优先启用。"
|
||||
msgstr "将握手数据拆分为多个 TLS 记录,提升抗封锁能力,几乎不增加延迟,建议优先启用。"
|
||||
|
||||
msgid "Split handshake into multiple TCP segments. Enhances obfuscation. May increase delay. Use only if needed."
|
||||
msgstr "将 TLS 握手数据分为多个 TCP 包发送,提高伪装性,可能增加延迟,仅在封锁严重时使用。"
|
||||
|
||||
@@ -9,7 +9,7 @@ PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
|
||||
PKG_SOURCE_PROTO:=git
|
||||
PKG_SOURCE_URL:=https://github.com/MetaCubeX/mihomo.git
|
||||
PKG_SOURCE_VERSION:=v1.19.12
|
||||
PKG_MIRROR_HASH:=de065d6eb33b84b660d3ecaaee3359c991307ab42345c70e82c5ce65c1ae329e
|
||||
PKG_MIRROR_HASH:=9ca38753d1b76268892cbf22e7d0f1348f58c0c6cff7305e87e41ea8193aba55
|
||||
|
||||
PKG_LICENSE:=GPL3.0+
|
||||
PKG_MAINTAINER:=Joseph Mory <morytyann@gmail.com>
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
# Mixin File
|
||||
# You can set any mihomo profile's config at here, it will mixin to the profile.
|
||||
# Mixin file have lower priority than the LuCI mixin options.
|
||||
#
|
||||
# Mihomo's Wiki: https://wiki.metacubex.one
|
||||
#
|
||||
# For example:
|
||||
#
|
||||
# global-client-fingerprint: chrome # set fingerprint for TLS transport
|
||||
# experimental: # experimental config
|
||||
# quic-go-disable-gso: false # disable quic-go GSO support
|
||||
# quic-go-disable-ecn: false # disable quic-go ECN support
|
||||
# dialer-ip4p-convert: false # IP4P support
|
||||
# proxies: # overwrite proxies
|
||||
# listeners: # overwrite listeners
|
||||
# - name: shadowsocks
|
||||
# type: shadowsocks
|
||||
# listen: "::"
|
||||
# port: 12060
|
||||
# nikki-proxies: # prepend proxies
|
||||
# - name: "PROXY"
|
||||
# type: ss
|
||||
# server: proxy.example.com
|
||||
# port: 443
|
||||
# cipher: chacha20-ietf-poly1305
|
||||
# password: "password"
|
||||
# rules: # overwrite rules
|
||||
# - DOMAIN,google.com,PROXY
|
||||
# - DOMAIN-SUFFIX,google.com,PROXY
|
||||
# - DOMAIN-KEYWORD,google,PROXY
|
||||
# - DOMAIN-REGEX,^google.*com,PROXY
|
||||
# - GEOSITE,google,PROXY
|
||||
# - GEOSITE,cn,DIRECT
|
||||
# - IP-CIDR,8.8.8.8/32,DIRECT,no-resolve
|
||||
# - GEOIP,telegram,DIRECT
|
||||
# - GEOIP,cn,DIRECT
|
||||
# - Match,PROXY
|
||||
# nikki-rules: # prepend rules
|
||||
# - DOMAIN,direct.example.com,DIRECT
|
||||
# - DOMAIN-SUFFIX,proxy.example.com,PROXY
|
||||
@@ -139,9 +139,9 @@ start_service() {
|
||||
yq -M -i 'del(.sniffer.sniff)' "$RUN_PROFILE_PATH"
|
||||
fi
|
||||
if [ "$mixin_file_content" = 0 ]; then
|
||||
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" -
|
||||
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .proxies = .nikki-proxies + .proxies | del(.nikki-proxies) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" -
|
||||
elif [ "$mixin_file_content" = 1 ]; then
|
||||
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" -
|
||||
ucode -S "$MIXIN_UC" | yq -M -p json -o yaml | yq -M -i ea '... comments="" | . as $item ireduce ({}; . * $item ) | .proxies = .nikki-proxies + .proxies | del(.nikki-proxies) | .rules = .nikki-rules + .rules | del(.nikki-rules)' "$RUN_PROFILE_PATH" "$MIXIN_FILE_PATH" -
|
||||
fi
|
||||
fi
|
||||
# test profile
|
||||
|
||||
@@ -12,13 +12,13 @@ PKG_MAINTAINER:=Tianling Shen <cnsztl@immortalwrt.org>
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
GEOIP_VER:=202507050144
|
||||
GEOIP_VER:=202508050201
|
||||
GEOIP_FILE:=geoip.dat.$(GEOIP_VER)
|
||||
define Download/geoip
|
||||
URL:=https://github.com/v2fly/geoip/releases/download/$(GEOIP_VER)/
|
||||
URL_FILE:=geoip.dat
|
||||
FILE:=$(GEOIP_FILE)
|
||||
HASH:=d77289a7465b6e59df39a2d46bd02b30b4fa7dd70939c13d431fd2bd8f448e10
|
||||
HASH:=54761d8691a5756fdb08d2cd4d0a9c889dbaab786e1cf758592e09fb00377f53
|
||||
endef
|
||||
|
||||
GEOSITE_VER:=20250627153051
|
||||
|
||||
@@ -25,6 +25,8 @@ public class CoreHandler
|
||||
Environment.SetEnvironmentVariable(Global.V2RayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.XrayLocalAsset, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
Environment.SetEnvironmentVariable(Global.XrayLocalCert, Utils.GetBinPath(""), EnvironmentVariableTarget.Process);
|
||||
// TODO Temporary addition to support proper use of sing-box v1.12
|
||||
Environment.SetEnvironmentVariable("ENABLE_DEPRECATED_SPECIAL_OUTBOUNDS", "true", EnvironmentVariableTarget.Process);
|
||||
|
||||
//Copy the bin folder to the storage location (for init)
|
||||
if (Environment.GetEnvironmentVariable(Global.LocalAppData) == "1")
|
||||
|
||||
Vendored
+7
-7
@@ -31,31 +31,31 @@ jobs:
|
||||
- name: Install NDK
|
||||
run: |
|
||||
echo "y" | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager \
|
||||
--channel=3 \
|
||||
--install "ndk;29.0.13113456"
|
||||
echo "NDK_HOME=$ANDROID_HOME/ndk/29.0.13113456" >> $GITHUB_ENV
|
||||
--channel=0 \
|
||||
--install "ndk;28.2.13676358"
|
||||
echo "NDK_HOME=$ANDROID_HOME/ndk/28.2.13676358" >> $GITHUB_ENV
|
||||
sed -i '10i\
|
||||
\
|
||||
ndkVersion = "29.0.13113456"' ${{ github.workspace }}/V2rayNG/app/build.gradle.kts
|
||||
ndkVersion = "28.2.13676358"' ${{ github.workspace }}/V2rayNG/app/build.gradle.kts
|
||||
|
||||
- name: Restore cached libtun2socks
|
||||
id: cache-libtun2socks-restore
|
||||
uses: actions/cache/restore@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/libs
|
||||
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
|
||||
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/hev-socks5-tunnel/HEAD') }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
|
||||
|
||||
- name: Build libtun2socks
|
||||
if: steps.cache-libtun2socks-restore.outputs.cache-hit != 'true'
|
||||
run: |
|
||||
bash compile-tun2socks.sh
|
||||
|
||||
|
||||
- name: Save libtun2socks
|
||||
if: steps.cache-libtun2socks-restore.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/libs
|
||||
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
|
||||
key: libtun2socks-${{ runner.os }}-${{ env.NDK_HOME }}-${{ hashFiles('.git/modules/hev-socks5-tunnel/HEAD') }}-${{ hashFiles('.git/modules/badvpn/HEAD') }}-${{ hashFiles('.git/modules/libancillary/HEAD') }}
|
||||
|
||||
- name: Copy libtun2socks
|
||||
run: |
|
||||
|
||||
@@ -10,3 +10,7 @@
|
||||
[submodule "libancillary"]
|
||||
path = libancillary
|
||||
url = https://github.com/shadowsocks/libancillary
|
||||
[submodule "hev-socks5-tunnel"]
|
||||
path = hev-socks5-tunnel
|
||||
url = https://github.com/heiher/hev-socks5-tunnel
|
||||
branch = master
|
||||
|
||||
@@ -248,8 +248,8 @@
|
||||
<string name="title_language">زووݩ</string>
|
||||
<string name="title_ui_settings">سامووا رابت منتوری</string>
|
||||
<string name="title_pref_ui_mode_night">سامووا هالت رابت منتوری</string>
|
||||
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
|
||||
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
|
||||
<string name="title_pref_use_hev_tunnel">فعال کردن ویژیی نۊ TUN</string>
|
||||
<string name="summary_pref_use_hev_tunnel">مجالی ک فعال بۊ، TUN ، hev-socks5-tunnel ن و کار اگره؛ ٱر چینووݩ نبۊ و جاس badvpn-tun2socks و کار گرؽڌه ابۊ.</string>
|
||||
|
||||
<string name="title_logcat">داسووا</string>
|
||||
<string name="logcat_copy">لف گیری</string>
|
||||
|
||||
@@ -245,8 +245,8 @@
|
||||
<string name="title_language">زبان</string>
|
||||
<string name="title_ui_settings">تنظیمات رابط کاربری</string>
|
||||
<string name="title_pref_ui_mode_night">تنظیمات حالت رابط کاربری</string>
|
||||
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
|
||||
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
|
||||
<string name="title_pref_use_hev_tunnel">فعالسازی قابلیت TUN جدید</string>
|
||||
<string name="summary_pref_use_hev_tunnel">در صورت فعال بودن، TUN از hev-socks5-tunnel استفاده میکند؛ در غیر این صورت از badvpn-tun2socks.</string>
|
||||
|
||||
<string name="title_logcat">گزارشات</string>
|
||||
<string name="logcat_copy">کپی</string>
|
||||
|
||||
@@ -247,8 +247,8 @@
|
||||
<string name="title_language">Язык</string>
|
||||
<string name="title_ui_settings">Настройки интерфейса</string>
|
||||
<string name="title_pref_ui_mode_night">Тема интерфейса</string>
|
||||
<string name="title_pref_use_hev_tunnel">Enable New TUN Feature</string>
|
||||
<string name="summary_pref_use_hev_tunnel">When enabled, TUN will use hev-socks5-tunnel; otherwise, it will use badvpn-tun2socks.</string>
|
||||
<string name="title_pref_use_hev_tunnel">Использовать новую версию TUN</string>
|
||||
<string name="summary_pref_use_hev_tunnel">Если включено, TUN будет использовать hev-socks5-tunnel; иначе будет использоваться badvpn-tun2socks.</string>
|
||||
|
||||
<string name="title_logcat">Журнал</string>
|
||||
<string name="logcat_copy">Копировать</string>
|
||||
|
||||
@@ -30,3 +30,29 @@ $NDK_HOME/ndk-build \
|
||||
cp -r $TMPDIR/libs $__dir/
|
||||
popd
|
||||
rm -rf $TMPDIR
|
||||
|
||||
#build hev-socks5-tunnel
|
||||
HEVTUN_TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$HEVTUN_TMP"' EXIT
|
||||
|
||||
mkdir -p "$HEVTUN_TMP/jni"
|
||||
pushd "$HEVTUN_TMP"
|
||||
|
||||
echo 'include $(call all-subdir-makefiles)' > jni/Android.mk
|
||||
|
||||
ln -s "$__dir/hev-socks5-tunnel" jni/hev-socks5-tunnel
|
||||
|
||||
"$NDK_HOME/ndk-build" \
|
||||
NDK_PROJECT_PATH=. \
|
||||
APP_BUILD_SCRIPT=jni/Android.mk \
|
||||
"APP_ABI=armeabi-v7a arm64-v8a x86 x86_64" \
|
||||
APP_PLATFORM=android-21 \
|
||||
NDK_LIBS_OUT="$HEVTUN_TMP/libs" \
|
||||
NDK_OUT="$HEVTUN_TMP/obj" \
|
||||
"APP_CFLAGS=-O3 -DPKGNAME=com/v2ray/ang/service" \
|
||||
"APP_LDFLAGS=-WI,--build-id=none -WI,--hash-style=gnu" \
|
||||
|
||||
cp -r "$HEVTUN_TMP/libs/"* "$__dir/libs/"
|
||||
popd
|
||||
|
||||
rm -rf "$HEVTUN_TMP"
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: Inner
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: Always
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp03
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
@@ -0,0 +1,11 @@
|
||||
/.idea/
|
||||
/.vscode/
|
||||
|
||||
/.git/
|
||||
/.github/
|
||||
/README.md
|
||||
/License
|
||||
|
||||
/Dockerfile
|
||||
|
||||
/conf/
|
||||
@@ -0,0 +1,402 @@
|
||||
name: "Build"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
source:
|
||||
name: Source
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.base_ref || github.ref_name }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Gen Source
|
||||
run: |
|
||||
REV_ID=$(git rev-parse --short HEAD)
|
||||
mkdir -p hev-socks5-tunnel-${{ env.BRANCH_NAME }}
|
||||
git ls-files --recurse-submodules | tar c -O -T- | tar x -C hev-socks5-tunnel-${{ env.BRANCH_NAME }}
|
||||
echo ${REV_ID} > hev-socks5-tunnel-${{ env.BRANCH_NAME }}/.rev-id
|
||||
tar cJf hev-socks5-tunnel-${{ env.BRANCH_NAME }}.tar.xz hev-socks5-tunnel-${{ env.BRANCH_NAME }}
|
||||
- name: Upload source
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hev-socks5-tunnel-${{ env.BRANCH_NAME }}.tar.xz
|
||||
path: hev-socks5-tunnel-${{ env.BRANCH_NAME }}.tar.xz
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
linux:
|
||||
name: Linux
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: arm64
|
||||
tool: aarch64-unknown-linux-musl
|
||||
- name: arm32
|
||||
tool: arm-unknown-linux-musleabi
|
||||
- name: arm32hf
|
||||
tool: arm-unknown-linux-musleabihf
|
||||
- name: arm32v7
|
||||
tool: armv7-unknown-linux-musleabi
|
||||
- name: arm32v7hf
|
||||
tool: armv7-unknown-linux-musleabihf
|
||||
- name: i586
|
||||
tool: i586-unknown-linux-musl
|
||||
- name: i686
|
||||
tool: i686-unknown-linux-musl
|
||||
- name: loong64
|
||||
tool: loongarch64-unknown-linux-musl
|
||||
- name: m68k
|
||||
tool: m68k-unknown-linux-musl
|
||||
- name: microblazeel
|
||||
tool: microblazeel-xilinx-linux-musl
|
||||
- name: microblaze
|
||||
tool: microblaze-xilinx-linux-musl
|
||||
- name: mips64el
|
||||
tool: mips64el-unknown-linux-musl
|
||||
- name: mips64
|
||||
tool: mips64-unknown-linux-musl
|
||||
- name: mips32el
|
||||
tool: mipsel-unknown-linux-musl
|
||||
- name: mips32elsf
|
||||
tool: mipsel-unknown-linux-muslsf
|
||||
- name: mips32
|
||||
tool: mips-unknown-linux-musl
|
||||
- name: mips32sf
|
||||
tool: mips-unknown-linux-muslsf
|
||||
- name: powerpc64
|
||||
tool: powerpc64-unknown-linux-musl
|
||||
- name: powerpc
|
||||
tool: powerpc-unknown-linux-musl
|
||||
- name: riscv32
|
||||
tool: riscv32-unknown-linux-musl
|
||||
- name: riscv64
|
||||
tool: riscv64-unknown-linux-musl
|
||||
- name: s390x
|
||||
tool: s390x-ibm-linux-musl
|
||||
- name: sh4
|
||||
tool: sh4-multilib-linux-musl
|
||||
- name: x86_64
|
||||
tool: x86_64-unknown-linux-musl
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Build ${{ matrix.name }}
|
||||
run: |
|
||||
sudo mkdir -p /opt/x-tools
|
||||
wget https://github.com/cross-tools/musl-cross/releases/download/20250520/${{ matrix.tool }}.tar.xz
|
||||
sudo tar xf ${{ matrix.tool }}.tar.xz -C /opt/x-tools
|
||||
make CROSS_PREFIX=/opt/x-tools/${{ matrix.tool }}/bin/${{ matrix.tool }}- CFLAGS=${{ matrix.env.CFLAGS }} ENABLE_STATIC=1 -j`nproc`
|
||||
cp bin/hev-socks5-tunnel hev-socks5-tunnel-linux-${{ matrix.name }}
|
||||
- name: Upload ${{ matrix.name }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hev-socks5-tunnel-linux-${{ matrix.name }}
|
||||
path: hev-socks5-tunnel-linux-${{ matrix.name }}
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
macos:
|
||||
name: macOS
|
||||
runs-on: macos-latest
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: arm64
|
||||
flags: -arch arm64 -mmacosx-version-min=11.0
|
||||
- name: x86_64
|
||||
flags: -arch x86_64 -mmacosx-version-min=10.6
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Build ${{ matrix.name }}
|
||||
run: |
|
||||
make CC=clang CFLAGS="${{ matrix.flags }}" LFLAGS="${{ matrix.flags }}" -j $(sysctl -n hw.logicalcpu)
|
||||
cp bin/hev-socks5-tunnel hev-socks5-tunnel-darwin-${{ matrix.name }}
|
||||
- name: Upload ${{ matrix.name }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hev-socks5-tunnel-darwin-${{ matrix.name }}
|
||||
path: hev-socks5-tunnel-darwin-${{ matrix.name }}
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
freebsd:
|
||||
name: FreeBSD
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Build
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
with:
|
||||
usesh: true
|
||||
prepare: |
|
||||
pkg install -y gmake gcc
|
||||
run: |
|
||||
gmake
|
||||
cp bin/hev-socks5-tunnel hev-socks5-tunnel-freebsd-x86_64
|
||||
- name: Upload
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hev-socks5-tunnel-freebsd-x86_64
|
||||
path: hev-socks5-tunnel-freebsd-x86_64
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
windows:
|
||||
name: Windows
|
||||
runs-on: windows-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: cmd
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Setup MSYS2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
msystem: MSYS
|
||||
location: D:\msys2
|
||||
update: true
|
||||
install: >-
|
||||
gcc
|
||||
git
|
||||
make
|
||||
wget
|
||||
zip
|
||||
- name: Build
|
||||
shell: msys2 {0}
|
||||
run: |
|
||||
export MSYS=winsymlinks:native
|
||||
git clone --depth=1 --recursive file://`pwd` work; cd work
|
||||
make -j`nproc`
|
||||
mkdir hev-socks5-tunnel
|
||||
cp bin/hev-socks5-tunnel* hev-socks5-tunnel
|
||||
cp third-part/wintun/bin/wintun.dll hev-socks5-tunnel
|
||||
wget -P hev-socks5-tunnel https://github.com/heiher/msys2/releases/latest/download/msys-2.0.dll
|
||||
zip -r ../hev-socks5-tunnel-win64.zip hev-socks5-tunnel
|
||||
- name: Upload ${{ matrix.name }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: hev-socks5-tunnel-win64.zip
|
||||
path: hev-socks5-tunnel-win64.zip
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
needs:
|
||||
- source
|
||||
- linux
|
||||
- macos
|
||||
- freebsd
|
||||
- windows
|
||||
if: github.event_name == 'release'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: release
|
||||
pattern: "hev-*"
|
||||
merge-multiple: true
|
||||
- name: Upload artifacts
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
for i in release/hev-*; do
|
||||
gh release upload ${{ github.event.release.tag_name }} $i
|
||||
done
|
||||
|
||||
apple:
|
||||
name: Apple
|
||||
runs-on: macos-latest
|
||||
if: github.event_name != 'release'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Build
|
||||
run: |
|
||||
./build-apple.sh
|
||||
|
||||
android:
|
||||
name: Android
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'release'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Prepare
|
||||
run: |
|
||||
wget https://dl.google.com/android/repository/android-ndk-r27b-linux.zip
|
||||
unzip android-ndk-r27b-linux.zip
|
||||
ln -sf . jni
|
||||
- name: Build
|
||||
run: |
|
||||
./android-ndk-r27b/ndk-build
|
||||
|
||||
llvm:
|
||||
name: LLVM
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'release'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Prepare
|
||||
run: |
|
||||
sudo apt install -y clang
|
||||
- name: Build
|
||||
run: |
|
||||
make CC=clang ENABLE_STATIC=1 -j`nproc`
|
||||
|
||||
docker:
|
||||
name: Build Docker Image
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
- linux/386
|
||||
- linux/arm64/v8
|
||||
- linux/arm/v7
|
||||
- linux/arm/v6
|
||||
- linux/riscv64
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
submodules: true
|
||||
- name: Prepare QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Prepare Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Prepare Repo Name
|
||||
id: repo
|
||||
run: |
|
||||
echo "repository=${GITHUB_REPOSITORY@L}" >> $GITHUB_OUTPUT
|
||||
- name: Prepare Digest
|
||||
run: |
|
||||
platform=${{ matrix.platform }}
|
||||
echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
|
||||
- name: Login GitHub Packages Docker Image Repository
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build and Push Docker Image
|
||||
id: build
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
platforms: ${{ matrix.platform }}
|
||||
provenance: false
|
||||
outputs: type=image,name=ghcr.io/${{ steps.repo.outputs.repository }},push-by-digest=true,name-canonical=true,push=${{ github.event_name != 'pull_request' }}
|
||||
cache-from: type=gha,scope=${{ matrix.platform }}
|
||||
cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
|
||||
- name: Export Digest
|
||||
if: github.event_name != 'pull_request'
|
||||
run: |
|
||||
mkdir -p /tmp/digests
|
||||
digest="${{ steps.build.outputs.digest }}"
|
||||
touch "/tmp/digests/${digest#sha256:}"
|
||||
- name: Upload Digest
|
||||
uses: actions/upload-artifact@v4
|
||||
if: github.event_name != 'pull_request'
|
||||
with:
|
||||
name: digests-${{ env.PLATFORM_PAIR }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
docker-merge:
|
||||
name: Merge Docker Image Tags
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request'
|
||||
needs:
|
||||
- docker
|
||||
permissions:
|
||||
packages: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Download Digests
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: /tmp/digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
- name: Prepare Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Prepare Repo Name
|
||||
id: repo
|
||||
run: |
|
||||
echo "repository=${GITHUB_REPOSITORY@L}" >> $GITHUB_OUTPUT
|
||||
- name: Login GitHub Packages Docker Image Repository
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Format Docker Image Meta
|
||||
uses: docker/metadata-action@v5
|
||||
id: docker_meta
|
||||
with:
|
||||
images: ghcr.io/${{ steps.repo.outputs.repository }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=ref,event=pr
|
||||
type=semver,pattern={{version}}
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=raw,value=nightly,enable={{is_default_branch}}
|
||||
- name: Create Manifest List and Push
|
||||
working-directory: /tmp/digests
|
||||
run: |
|
||||
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
|
||||
$(printf 'ghcr.io/${{ steps.repo.outputs.repository }}@sha256:%s ' *)
|
||||
- name: Inspect image
|
||||
run: |
|
||||
docker buildx imagetools inspect ghcr.io/${{ steps.repo.outputs.repository }}:${{ steps.docker_meta.outputs.version }}
|
||||
@@ -0,0 +1,26 @@
|
||||
name: "Check code formatting"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
checker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Prepare
|
||||
run: |
|
||||
sudo apt install -y clang-format
|
||||
- name: Format
|
||||
run: |
|
||||
find src -iname "*.[h,c]" -exec clang-format -i {} \;
|
||||
- name: Check
|
||||
run: |
|
||||
git status
|
||||
git diff --quiet
|
||||
@@ -0,0 +1,5 @@
|
||||
bin
|
||||
build
|
||||
HevSocks5Tunnel.xcframework
|
||||
obj
|
||||
libs
|
||||
@@ -0,0 +1,12 @@
|
||||
[submodule "third-part/hev-task-system"]
|
||||
path = third-part/hev-task-system
|
||||
url = https://github.com/heiher/hev-task-system
|
||||
[submodule "third-part/yaml"]
|
||||
path = third-part/yaml
|
||||
url = https://github.com/heiher/yaml
|
||||
[submodule "third-part/lwip"]
|
||||
path = third-part/lwip
|
||||
url = https://github.com/heiher/lwip
|
||||
[submodule "src/core"]
|
||||
path = src/core
|
||||
url = https://github.com/heiher/hev-socks5-core
|
||||
@@ -0,0 +1,51 @@
|
||||
# Copyright (C) 2021 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
TOP_PATH := $(call my-dir)
|
||||
|
||||
ifeq ($(filter $(modules-get-list),yaml),)
|
||||
include $(TOP_PATH)/third-part/yaml/Android.mk
|
||||
endif
|
||||
ifeq ($(filter $(modules-get-list),lwip),)
|
||||
include $(TOP_PATH)/third-part/lwip/Android.mk
|
||||
endif
|
||||
ifeq ($(filter $(modules-get-list),hev-task-system),)
|
||||
include $(TOP_PATH)/third-part/hev-task-system/Android.mk
|
||||
endif
|
||||
|
||||
LOCAL_PATH = $(TOP_PATH)
|
||||
SRCDIR := $(LOCAL_PATH)/src
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
include $(LOCAL_PATH)/build.mk
|
||||
LOCAL_MODULE := hev-socks5-tunnel
|
||||
LOCAL_SRC_FILES := $(patsubst $(SRCDIR)/%,src/%,$(SRCFILES))
|
||||
LOCAL_C_INCLUDES := \
|
||||
$(LOCAL_PATH)/src \
|
||||
$(LOCAL_PATH)/src/misc \
|
||||
$(LOCAL_PATH)/src/core/include \
|
||||
$(LOCAL_PATH)/third-part/yaml/include \
|
||||
$(LOCAL_PATH)/third-part/lwip/src/include \
|
||||
$(LOCAL_PATH)/third-part/lwip/src/ports/include \
|
||||
$(LOCAL_PATH)/third-part/hev-task-system/include
|
||||
LOCAL_CFLAGS += -DFD_SET_DEFINED -DSOCKLEN_T_DEFINED -DENABLE_LIBRARY
|
||||
LOCAL_CFLAGS += $(VERSION_CFLAGS)
|
||||
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
|
||||
LOCAL_CFLAGS += -mfpu=neon
|
||||
endif
|
||||
LOCAL_STATIC_LIBRARIES := yaml lwip hev-task-system
|
||||
LOCAL_LDFLAGS += -Wl,-z,max-page-size=16384
|
||||
LOCAL_LDFLAGS += -Wl,-z,common-page-size=16384
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
@@ -0,0 +1,21 @@
|
||||
# Copyright (C) 2013 The Android Open Source Project
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
|
||||
APP_OPTIM := release
|
||||
APP_PLATFORM := android-21
|
||||
APP_ABI := armeabi-v7a arm64-v8a
|
||||
APP_CFLAGS := -O3
|
||||
APP_SUPPORT_FLEXIBLE_PAGE_SIZES := true
|
||||
NDK_TOOLCHAIN_VERSION := clang
|
||||
@@ -0,0 +1,42 @@
|
||||
FROM alpine:latest AS builder
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
make \
|
||||
git \
|
||||
gcc \
|
||||
linux-headers \
|
||||
musl-dev
|
||||
|
||||
WORKDIR /src
|
||||
COPY . /src
|
||||
|
||||
RUN make
|
||||
|
||||
FROM alpine:latest
|
||||
LABEL org.opencontainers.image.source="https://github.com/heiher/hev-socks5-tunnel"
|
||||
|
||||
RUN apk add --update --no-cache \
|
||||
iproute2
|
||||
|
||||
ENV TUN=tun0 \
|
||||
MTU=8500 \
|
||||
IPV4=198.18.0.1 \
|
||||
IPV6='' \
|
||||
TABLE=20 \
|
||||
MARK=438 \
|
||||
SOCKS5_ADDR=172.17.0.1 \
|
||||
SOCKS5_PORT=1080 \
|
||||
SOCKS5_USERNAME='' \
|
||||
SOCKS5_PASSWORD='' \
|
||||
SOCKS5_UDP_MODE=udp \
|
||||
CONFIG_ROUTES=1 \
|
||||
IPV4_INCLUDED_ROUTES=0.0.0.0/0 \
|
||||
IPV4_EXCLUDED_ROUTES='' \
|
||||
LOG_LEVEL=warn
|
||||
|
||||
HEALTHCHECK --start-period=5s --interval=5s --timeout=2s --retries=3 CMD ["test", "-f", "/success"]
|
||||
|
||||
COPY --chmod=755 docker/entrypoint.sh /entrypoint.sh
|
||||
COPY --from=builder /src/bin/hev-socks5-tunnel /usr/bin/hev-socks5-tunnel
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2022 hev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,146 @@
|
||||
# Makefile for hev-socks5-tunnel
|
||||
|
||||
PROJECT=hev-socks5-tunnel
|
||||
|
||||
CROSS_PREFIX :=
|
||||
PP=$(CROSS_PREFIX)cpp
|
||||
CC=$(CROSS_PREFIX)gcc
|
||||
AR=$(CROSS_PREFIX)ar
|
||||
STRIP=$(CROSS_PREFIX)strip
|
||||
CCFLAGS=-O3 -pipe -Wall -Werror $(CFLAGS) \
|
||||
-I$(SRCDIR) \
|
||||
-I$(SRCDIR)/misc \
|
||||
-I$(SRCDIR)/core/include \
|
||||
-I$(THIRDPARTDIR)/yaml/include \
|
||||
-I$(THIRDPARTDIR)/wintun/include \
|
||||
-I$(THIRDPARTDIR)/lwip/src/include \
|
||||
-I$(THIRDPARTDIR)/lwip/src/ports/include \
|
||||
-I$(THIRDPARTDIR)/hev-task-system/include
|
||||
LDFLAGS=-L$(THIRDPARTDIR)/yaml/bin -lyaml \
|
||||
-L$(THIRDPARTDIR)/lwip/bin -llwip \
|
||||
-L$(THIRDPARTDIR)/hev-task-system/bin -lhev-task-system \
|
||||
-lpthread $(LFLAGS)
|
||||
|
||||
SRCDIR=src
|
||||
BINDIR=bin
|
||||
CONFDIR=conf
|
||||
BUILDDIR=build
|
||||
INSTDIR=/usr/local
|
||||
THIRDPARTDIR=third-part
|
||||
|
||||
CONFIG=$(CONFDIR)/main.yml
|
||||
EXEC_TARGET=$(BINDIR)/hev-socks5-tunnel
|
||||
STATIC_TARGET=$(BINDIR)/lib$(PROJECT).a
|
||||
SHARED_TARGET=$(BINDIR)/lib$(PROJECT).so
|
||||
THIRDPARTS=$(THIRDPARTDIR)/yaml \
|
||||
$(THIRDPARTDIR)/lwip \
|
||||
$(THIRDPARTDIR)/hev-task-system
|
||||
|
||||
$(STATIC_TARGET) : CCFLAGS+=-DENABLE_LIBRARY
|
||||
$(SHARED_TARGET) : CCFLAGS+=-DENABLE_LIBRARY -fPIC
|
||||
$(SHARED_TARGET) : LDFLAGS+=-shared -pthread
|
||||
|
||||
-include build.mk
|
||||
CCFLAGS+=$(VERSION_CFLAGS)
|
||||
CCSRCS=$(filter %.c,$(SRCFILES))
|
||||
ASSRCS=$(filter %.S,$(SRCFILES))
|
||||
LDOBJS=$(patsubst $(SRCDIR)/%.c,$(BUILDDIR)/%.o,$(CCSRCS)) \
|
||||
$(patsubst $(SRCDIR)/%.S,$(BUILDDIR)/%.o,$(ASSRCS))
|
||||
DEPEND=$(LDOBJS:.o=.dep)
|
||||
|
||||
BUILDMSG="\e[1;31mBUILD\e[0m %s\n"
|
||||
LINKMSG="\e[1;34mLINK\e[0m \e[1;32m%s\e[0m\n"
|
||||
STRIPMSG="\e[1;34mSTRIP\e[0m \e[1;32m%s\e[0m\n"
|
||||
CLEANMSG="\e[1;34mCLEAN\e[0m %s\n"
|
||||
INSTMSG="\e[1;34mINST\e[0m %s -> %s\n"
|
||||
UNINSMSG="\e[1;34mUNINS\e[0m %s\n"
|
||||
|
||||
ENABLE_DEBUG :=
|
||||
ifeq ($(ENABLE_DEBUG),1)
|
||||
CCFLAGS+=-g -O0 -DENABLE_DEBUG
|
||||
STRIP=true
|
||||
endif
|
||||
|
||||
ENABLE_STATIC :=
|
||||
ifeq ($(ENABLE_STATIC),1)
|
||||
CCFLAGS+=-static
|
||||
endif
|
||||
|
||||
ifeq ($(MSYSTEM),MSYS)
|
||||
LDFLAGS+=-lmsys-2.0 -lws2_32 -lIphlpapi
|
||||
endif
|
||||
|
||||
V :=
|
||||
ECHO_PREFIX := @
|
||||
ifeq ($(V),1)
|
||||
undefine ECHO_PREFIX
|
||||
endif
|
||||
|
||||
.PHONY: exec static shared clean install uninstall tp-static tp-shared tp-clean
|
||||
|
||||
exec : $(EXEC_TARGET)
|
||||
|
||||
static : $(STATIC_TARGET)
|
||||
|
||||
shared : $(SHARED_TARGET)
|
||||
|
||||
tp-static : $(THIRDPARTS)
|
||||
@$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) static;)
|
||||
|
||||
tp-shared : $(THIRDPARTS)
|
||||
@$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) shared;)
|
||||
|
||||
tp-clean : $(THIRDPARTS)
|
||||
@$(foreach dir,$^,$(MAKE) --no-print-directory -C $(dir) clean;)
|
||||
|
||||
clean : tp-clean
|
||||
$(ECHO_PREFIX) $(RM) -rf $(BINDIR) $(BUILDDIR)
|
||||
@printf $(CLEANMSG) $(PROJECT)
|
||||
|
||||
install : $(INSTDIR)/bin/$(PROJECT) $(INSTDIR)/etc/$(PROJECT).yml
|
||||
|
||||
uninstall :
|
||||
$(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/bin/$(PROJECT)
|
||||
@printf $(UNINSMSG) $(INSTDIR)/bin/$(PROJECT)
|
||||
$(ECHO_PREFIX) $(RM) -rf $(INSTDIR)/etc/$(PROJECT).yml
|
||||
@printf $(UNINSMSG) $(INSTDIR)/etc/$(PROJECT).yml
|
||||
|
||||
$(INSTDIR)/bin/$(PROJECT) : $(EXEC_TARGET)
|
||||
$(ECHO_PREFIX) install -d -m 0755 $(dir $@)
|
||||
$(ECHO_PREFIX) install -m 0755 $< $@
|
||||
@printf $(INSTMSG) $< $@
|
||||
|
||||
$(INSTDIR)/etc/$(PROJECT).yml : $(CONFIG)
|
||||
$(ECHO_PREFIX) install -d -m 0755 $(dir $@)
|
||||
$(ECHO_PREFIX) install -m 0644 $< $@
|
||||
@printf $(INSTMSG) $< $@
|
||||
|
||||
$(EXEC_TARGET) : $(LDOBJS) tp-static
|
||||
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||
$(ECHO_PREFIX) $(CC) $(CCFLAGS) -o $@ $(LDOBJS) $(LDFLAGS)
|
||||
@printf $(LINKMSG) $@
|
||||
$(ECHO_PREFIX) $(STRIP) $@
|
||||
@printf $(STRIPMSG) $@
|
||||
|
||||
$(STATIC_TARGET) : $(LDOBJS) tp-static
|
||||
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||
$(ECHO_PREFIX) $(AR) csq $@ $(LDOBJS)
|
||||
@printf $(LINKMSG) $@
|
||||
|
||||
$(SHARED_TARGET) : $(LDOBJS) tp-shared
|
||||
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||
$(ECHO_PREFIX) $(CC) $(CCFLAGS) -o $@ $(LDOBJS) $(LDFLAGS)
|
||||
@printf $(LINKMSG) $@
|
||||
|
||||
$(BUILDDIR)/%.dep : $(SRCDIR)/%.c
|
||||
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||
$(ECHO_PREFIX) $(PP) $(CCFLAGS) -MM -MT$(@:.dep=.o) -MF$@ $< 2>/dev/null
|
||||
|
||||
$(BUILDDIR)/%.o : $(SRCDIR)/%.c
|
||||
$(ECHO_PREFIX) mkdir -p $(dir $@)
|
||||
$(ECHO_PREFIX) $(CC) $(CCFLAGS) -c -o $@ $<
|
||||
@printf $(BUILDMSG) $<
|
||||
|
||||
ifneq ($(MAKECMDGOALS),clean)
|
||||
-include $(DEPEND)
|
||||
endif
|
||||
@@ -0,0 +1,360 @@
|
||||
# HevSocks5Tunnel
|
||||
|
||||
[](https://github.com/heiher/hev-socks5-tunnel)
|
||||
|
||||
A simple, lightweight tunnel over Socks5 proxy (tun2socks).
|
||||
|
||||
## Features
|
||||
|
||||
* IPv4/IPv6. (dual stack)
|
||||
* Redirect TCP connections.
|
||||
* Redirect UDP packets. (Fullcone NAT, UDP-in-UDP and UDP-in-TCP [^1])
|
||||
* Linux/Android/FreeBSD/macOS/iOS/Windows.
|
||||
|
||||
## Benchmarks
|
||||
|
||||
See [here](https://github.com/heiher/hev-socks5-tunnel/wiki/Benchmarks) for more details.
|
||||
|
||||
### Speed
|
||||
|
||||

|
||||

|
||||
|
||||
### CPU usage
|
||||
|
||||

|
||||

|
||||
|
||||
### Memory usage
|
||||
|
||||

|
||||

|
||||
|
||||
## How to Build
|
||||
|
||||
### Unix
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||
cd hev-socks5-tunnel
|
||||
make
|
||||
```
|
||||
|
||||
### Android
|
||||
|
||||
```bash
|
||||
mkdir hev-socks5-tunnel
|
||||
cd hev-socks5-tunnel
|
||||
git clone --recursive https://github.com/heiher/hev-socks5-tunnel jni
|
||||
ndk-build
|
||||
```
|
||||
|
||||
### iOS and macOS
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||
cd hev-socks5-tunnel
|
||||
# will generate HevSocks5Tunnel.xcframework
|
||||
./build-apple.sh
|
||||
```
|
||||
|
||||
### Windows (MSYS2)
|
||||
```bash
|
||||
export MSYS=winsymlinks:native
|
||||
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||
cd hev-socks5-tunnel
|
||||
make
|
||||
```
|
||||
|
||||
### Library
|
||||
|
||||
```bash
|
||||
git clone --recursive https://github.com/heiher/hev-socks5-tunnel
|
||||
cd hev-socks5-tunnel
|
||||
|
||||
# Static library
|
||||
make static
|
||||
|
||||
# Shared library
|
||||
make shared
|
||||
```
|
||||
|
||||
## How to Use
|
||||
|
||||
### Config
|
||||
|
||||
```yaml
|
||||
tunnel:
|
||||
# Interface name
|
||||
name: tun0
|
||||
# Interface MTU
|
||||
mtu: 8500
|
||||
# Multi-queue
|
||||
multi-queue: false
|
||||
# IPv4 address
|
||||
ipv4: 198.18.0.1
|
||||
# IPv6 address
|
||||
ipv6: 'fc00::1'
|
||||
# Post up script
|
||||
# post-up-script: up.sh
|
||||
# Pre down script
|
||||
# pre-down-script: down.sh
|
||||
|
||||
socks5:
|
||||
# Socks5 server port
|
||||
port: 1080
|
||||
# Socks5 server address (ipv4/ipv6)
|
||||
address: 127.0.0.1
|
||||
# Socks5 UDP relay mode (tcp|udp)
|
||||
udp: 'udp'
|
||||
# Socks5 handshake using pipeline mode
|
||||
# pipeline: false
|
||||
# Socks5 server username
|
||||
# username: 'username'
|
||||
# Socks5 server password
|
||||
# password: 'password'
|
||||
# Socket mark
|
||||
# mark: 0
|
||||
|
||||
#mapdns:
|
||||
# Mapped DNS address
|
||||
# address: 198.18.0.2
|
||||
# Mapped DNS port
|
||||
# port: 53
|
||||
# Mapped IP network base
|
||||
# network: 240.0.0.0
|
||||
# Mapped IP network mask
|
||||
# netmask: 240.0.0.0
|
||||
# Mapped DNS cache size
|
||||
# cache-size: 10000
|
||||
|
||||
#misc:
|
||||
# task stack size (bytes)
|
||||
# task-stack-size: 86016
|
||||
# tcp buffer size (bytes)
|
||||
# tcp-buffer-size: 65536
|
||||
# connect timeout (ms)
|
||||
# connect-timeout: 5000
|
||||
# read-write timeout (ms)
|
||||
# read-write-timeout: 60000
|
||||
# stdout, stderr or file-path
|
||||
# log-file: stderr
|
||||
# debug, info, warn or error
|
||||
# log-level: warn
|
||||
# If present, run as a daemon with this pid file
|
||||
# pid-file: /run/hev-socks5-tunnel.pid
|
||||
# If present, set rlimit nofile; else use default value
|
||||
# limit-nofile: 65535
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
#### Linux
|
||||
|
||||
```bash
|
||||
# Set socks5.mark = 438
|
||||
bin/hev-socks5-tunnel conf/main.yml
|
||||
|
||||
# Bypass upstream socks5 server
|
||||
sudo ip rule add fwmark 438 lookup main pref 10
|
||||
sudo ip -6 rule add fwmark 438 lookup main pref 10
|
||||
|
||||
# Route others
|
||||
sudo ip route add default dev tun0 table 20
|
||||
sudo ip rule add lookup 20 pref 20
|
||||
sudo ip -6 route add default dev tun0 table 20
|
||||
sudo ip -6 rule add lookup 20 pref 20
|
||||
```
|
||||
|
||||
#### FreeBSD/macOS
|
||||
|
||||
```zsh
|
||||
# Bypass upstream socks5 server
|
||||
# 10.0.0.1: socks5 server
|
||||
# 10.0.2.2: default gateway
|
||||
sudo route add -net 10.0.0.1/32 10.0.2.2
|
||||
|
||||
# Route others
|
||||
sudo route change -inet default -interface tun0
|
||||
sudo route change -inet6 default -interface tun0
|
||||
```
|
||||
|
||||
#### Windows
|
||||
|
||||
```zsh
|
||||
# Bypass upstream socks5 server
|
||||
# 10.0.0.1: socks5 server
|
||||
# 10.0.2.2: default gateway
|
||||
route add 10.0.0.1/32 10.0.2.2
|
||||
|
||||
# Route others
|
||||
route change 0.0.0.0/0 0.0.0.0 if tun0
|
||||
route change ::/0 :: if tun0
|
||||
```
|
||||
|
||||
#### Low memory usage
|
||||
|
||||
On low-memory systems like iOS, reducing the size of the TCP buffer
|
||||
and task stack can help prevent out-of-memory issues.
|
||||
|
||||
```yaml
|
||||
misc:
|
||||
# task stack size (bytes)
|
||||
task-stack-size: 24576 # 20480 + tcp-buffer-size
|
||||
# tcp buffer size (bytes)
|
||||
tcp-buffer-size: 4096
|
||||
```
|
||||
|
||||
#### Docker Compose
|
||||
|
||||
```yaml
|
||||
version: "3.9"
|
||||
|
||||
services:
|
||||
client:
|
||||
image: alpine:latest # just for network testing
|
||||
tty: true # you can test network in terminal
|
||||
depends_on:
|
||||
tun:
|
||||
condition: service_healthy
|
||||
network_mode: "service:tun"
|
||||
|
||||
tun:
|
||||
image: ghcr.io/heiher/hev-socks5-tunnel:latest # `latest` for the latest published version; `nightly` for the latest source build; `vX.Y.Z` for the specific version
|
||||
cap_add:
|
||||
- NET_ADMIN # needed
|
||||
devices:
|
||||
- /dev/net/tun:/dev/net/tun # needed
|
||||
environment:
|
||||
TUN: tun0 # optional, tun interface name, default `tun0`
|
||||
MTU: 8500 # optional, MTU is MTU, default `8500`
|
||||
IPV4: 198.18.0.1 # optional, tun interface ip, default `198.18.0.1`
|
||||
TABLE: 20 # optional, ip route table id, default `20`
|
||||
MARK: 438 # optional, ip route rule mark, dec or hex format, default `438`
|
||||
SOCKS5_ADDR: a.b.c.d # socks5 proxy server address
|
||||
SOCKS5_PORT: 1080 # socks5 proxy server port
|
||||
SOCKS5_USERNAME: user # optional, socks5 proxy username, only set when need to auth
|
||||
SOCKS5_PASSWORD: pass # optional, socks5 proxy password, only set when need to auth
|
||||
SOCKS5_UDP_MODE: udp # optional, UDP relay mode, default `udp`, other option `tcp`
|
||||
CONFIG_ROUTES: 1 # optional, set 0 to ignore TABLE, IPV4_INCLUDED_ROUTES and IPV4_EXCLUDED_ROUTES, with MARK defaults to 0
|
||||
IPV4_INCLUDED_ROUTES: 0.0.0.0/0 # optional, demo means proxy all traffic. for multiple network segments, join with `,` or `\n`
|
||||
IPV4_EXCLUDED_ROUTES: a.b.c.d # optional, demo means exclude traffic from the proxy itself. for multiple network segments, join with `,` or `\n`
|
||||
LOG_LEVEL: warn # optional, default `warn`, other option `debug`/`info`/`error`
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
```
|
||||
|
||||
You can also set the route rules with multiple network segments like:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
IPV4_INCLUDED_ROUTES: 10.0.0.0/8,172.16.0.0/12,192.168.0.0/16
|
||||
IPV4_EXCLUDED_ROUTES: |-
|
||||
a.b.c.d/24
|
||||
a.b.c.f/24
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
```c
|
||||
/**
|
||||
* hev_socks5_tunnel_main:
|
||||
* @config_path: config file path
|
||||
* @tun_fd: tunnel file descriptor
|
||||
*
|
||||
* Start and run the socks5 tunnel, this function will blocks until the
|
||||
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||
*
|
||||
* Alias of hev_socks5_tunnel_main_from_file
|
||||
*
|
||||
* Returns: returns zero on successful, otherwise returns -1.
|
||||
*
|
||||
* Since: 2.4.6
|
||||
*/
|
||||
int hev_socks5_tunnel_main (const char *config_path, int tun_fd);
|
||||
|
||||
/**
|
||||
* hev_socks5_tunnel_main_from_file:
|
||||
* @config_path: config file path
|
||||
* @tun_fd: tunnel file descriptor
|
||||
*
|
||||
* Start and run the socks5 tunnel, this function will blocks until the
|
||||
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||
*
|
||||
* Returns: returns zero on successful, otherwise returns -1.
|
||||
*
|
||||
* Since: 2.6.7
|
||||
*/
|
||||
int hev_socks5_tunnel_main_from_file (const char *config_path, int tun_fd);
|
||||
|
||||
/**
|
||||
* hev_socks5_tunnel_main_from_str:
|
||||
* @config_str: string config
|
||||
* @config_len: the byte length of string config
|
||||
* @tun_fd: tunnel file descriptor
|
||||
*
|
||||
* Start and run the socks5 tunnel, this function will blocks until the
|
||||
* hev_socks5_tunnel_quit is called or an error occurs.
|
||||
*
|
||||
* Returns: returns zero on successful, otherwise returns -1.
|
||||
*
|
||||
* Since: 2.6.7
|
||||
*/
|
||||
int hev_socks5_tunnel_main_from_str (const unsigned char *config_str,
|
||||
unsigned int config_len, int tun_fd);
|
||||
|
||||
/**
|
||||
* hev_socks5_tunnel_quit:
|
||||
*
|
||||
* Stop the socks5 tunnel.
|
||||
*
|
||||
* Since: 2.4.6
|
||||
*/
|
||||
void hev_socks5_tunnel_quit (void);
|
||||
|
||||
/**
|
||||
* hev_socks5_tunnel_stats:
|
||||
* @tx_packets (out): transmitted packets
|
||||
* @tx_bytes (out): transmitted bytes
|
||||
* @rx_packets (out): received packets
|
||||
* @rx_bytes (out): received bytes
|
||||
*
|
||||
* Retrieve tunnel interface traffic statistics.
|
||||
*
|
||||
* Since: 2.6.5
|
||||
*/
|
||||
void hev_socks5_tunnel_stats (size_t *tx_packets, size_t *tx_bytes,
|
||||
size_t *rx_packets, size_t *rx_bytes);
|
||||
```
|
||||
|
||||
## Use Cases
|
||||
|
||||
### Android VPN
|
||||
|
||||
* [SocksTun](https://github.com/heiher/sockstun)
|
||||
|
||||
### iOS
|
||||
|
||||
* [Tun2SocksKit](https://github.com/EbrahimTahernejad/Tun2SocksKit)
|
||||
|
||||
## Contributors
|
||||
|
||||
* **arror** - https://github.com/arror
|
||||
* **bazuchan** - https://github.com/bazuchan
|
||||
* **codewithtamim** - https://github.com/codewithtamim
|
||||
* **dovecoteescapee** - https://github.com/dovecoteescapee
|
||||
* **ebrahimtahernejad** - https://github.com/ebrahimtahernejad
|
||||
* **heiby** - https://github.com/heiby
|
||||
* **hev** - https://hev.cc
|
||||
* **pronebird** - https://github.com/pronebird
|
||||
* **saeeddev94** - https://github.com/saeeddev94
|
||||
* **sskaje** - https://github.com/sskaje
|
||||
* **wankkoree** - https://github.com/wankkoree
|
||||
* **xz-dev** - https://github.com/xz-dev
|
||||
* **yiguous** - https://github.com/yiguous
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
[^1]: See [protocol specification](https://github.com/heiher/hev-socks5-core/tree/master?tab=readme-ov-file#udp-in-tcp). The [hev-socks5-server](https://github.com/heiher/hev-socks5-server) supports UDP relay over TCP.
|
||||
Executable
+75
@@ -0,0 +1,75 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
XCFRAMEWORK_DIR="./apple_xcframework"
|
||||
|
||||
# buildStatic iphoneos -mios-version-min=15.0 arm64
|
||||
buildStatic()
|
||||
{
|
||||
echo "build for $1, $2, min version $3"
|
||||
|
||||
local MIN_VERSION="-m$1-version-min=$3"
|
||||
make PP="xcrun --sdk $1 --toolchain $1 clang" \
|
||||
CC="xcrun --sdk $1 --toolchain $1 clang" \
|
||||
CFLAGS="-arch $2 $MIN_VERSION" \
|
||||
LFLAGS="-arch $2 $MIN_VERSION -Wl,-Bsymbolic-functions" static
|
||||
|
||||
local OUTPUT_DIR="$XCFRAMEWORK_DIR/$1-$2"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
local OUTPUT_ARCH_FILE="$OUTPUT_DIR/libhev-socks5-tunnel.a"
|
||||
|
||||
libtool -static -o $OUTPUT_ARCH_FILE \
|
||||
bin/libhev-socks5-tunnel.a \
|
||||
third-part/lwip/bin/liblwip.a \
|
||||
third-part/yaml/bin/libyaml.a \
|
||||
third-part/hev-task-system/bin/libhev-task-system.a
|
||||
make clean
|
||||
}
|
||||
|
||||
mergeStatic()
|
||||
{
|
||||
echo "merge for $1, $2, $3"
|
||||
local FIRST_LIB_FILE="$XCFRAMEWORK_DIR/$1-$2/libhev-socks5-tunnel.a"
|
||||
local SECOND_LIB_FILE="$XCFRAMEWORK_DIR/$1-$3/libhev-socks5-tunnel.a"
|
||||
local OUTPUT_DIR="$XCFRAMEWORK_DIR/$1-$2-$3"
|
||||
mkdir -p $OUTPUT_DIR
|
||||
local OUTPUT_ARCH_FILE="$OUTPUT_DIR/libhev-socks5-tunnel.a"
|
||||
lipo -create \
|
||||
-arch $2 $FIRST_LIB_FILE \
|
||||
-arch $3 $SECOND_LIB_FILE \
|
||||
-output $OUTPUT_ARCH_FILE
|
||||
}
|
||||
|
||||
rm -rf $XCFRAMEWORK_DIR
|
||||
rm -rf HevSocks5Tunnel.xcframework
|
||||
mkdir $XCFRAMEWORK_DIR
|
||||
|
||||
buildStatic iphoneos arm64 15.0
|
||||
buildStatic iphonesimulator x86_64 15.0
|
||||
buildStatic iphonesimulator arm64 15.0
|
||||
mergeStatic iphonesimulator x86_64 arm64
|
||||
|
||||
# keep same with flutter
|
||||
buildStatic macosx x86_64 10.14
|
||||
buildStatic macosx arm64 10.14
|
||||
mergeStatic macosx x86_64 arm64
|
||||
|
||||
buildStatic appletvos arm64 17.0
|
||||
buildStatic appletvsimulator x86_64 17.0
|
||||
buildStatic appletvsimulator arm64 17.0
|
||||
mergeStatic appletvsimulator x86_64 arm64
|
||||
|
||||
INCLUDE_DIR="$XCFRAMEWORK_DIR/include"
|
||||
mkdir -p $INCLUDE_DIR
|
||||
cp ./src/hev-main.h $INCLUDE_DIR
|
||||
cp ./module.modulemap $INCLUDE_DIR
|
||||
xcodebuild -create-xcframework \
|
||||
-library ./apple_xcframework/iphoneos-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||
-library ./apple_xcframework/iphonesimulator-x86_64-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||
-library ./apple_xcframework/macosx-x86_64-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||
-library ./apple_xcframework/appletvos-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||
-library ./apple_xcframework/appletvsimulator-x86_64-arm64/libhev-socks5-tunnel.a -headers $INCLUDE_DIR \
|
||||
-output ./HevSocks5Tunnel.xcframework
|
||||
|
||||
rm -rf ./apple_xcframework
|
||||
@@ -0,0 +1,20 @@
|
||||
# Build
|
||||
|
||||
rwildcard=$(foreach d,$(wildcard $1*), \
|
||||
$(call rwildcard,$d/,$2) \
|
||||
$(filter $(subst *,%,$2),$d))
|
||||
|
||||
SRCFILES=$(call rwildcard,$(SRCDIR)/,*.c *.S)
|
||||
|
||||
ifeq ($(REV_ID),)
|
||||
ifneq (,$(wildcard .rev-id))
|
||||
REV_ID=$(shell cat .rev-id)
|
||||
endif
|
||||
ifeq ($(REV_ID),)
|
||||
REV_ID=$(shell git -C $(SRCDIR) rev-parse --short HEAD)
|
||||
endif
|
||||
ifeq ($(REV_ID),)
|
||||
REV_ID=unknown
|
||||
endif
|
||||
endif
|
||||
VERSION_CFLAGS=-DCOMMIT_ID=\"$(REV_ID)\"
|
||||
@@ -0,0 +1,63 @@
|
||||
# Main configuration for hev-socks5-tunnel
|
||||
|
||||
tunnel:
|
||||
# Interface name
|
||||
name: tun0
|
||||
# Interface MTU
|
||||
mtu: 8500
|
||||
# Multi-queue
|
||||
multi-queue: false
|
||||
# IPv4 address
|
||||
ipv4: 198.18.0.1
|
||||
# IPv6 address
|
||||
ipv6: 'fc00::1'
|
||||
# Post up script
|
||||
# post-up-script: up.sh
|
||||
# Pre down script
|
||||
# pre-down-script: down.sh
|
||||
|
||||
socks5:
|
||||
# Socks5 server port
|
||||
port: 1080
|
||||
# Socks5 server address (ipv4/ipv6)
|
||||
address: 127.0.0.1
|
||||
# Socks5 UDP relay mode (tcp|udp)
|
||||
udp: 'udp'
|
||||
# Socks5 handshake using pipeline mode
|
||||
# pipeline: false
|
||||
# Socks5 server username
|
||||
# username: 'username'
|
||||
# Socks5 server password
|
||||
# password: 'password'
|
||||
# Socket mark
|
||||
# mark: 0
|
||||
|
||||
#mapdns:
|
||||
# Mapped DNS address
|
||||
# address: 198.18.0.2
|
||||
# Mapped DNS port
|
||||
# port: 53
|
||||
# Mapped IP network base
|
||||
# network: 240.0.0.0
|
||||
# Mapped IP network mask
|
||||
# netmask: 240.0.0.0
|
||||
# Mapped DNS cache size
|
||||
# cache-size: 10000
|
||||
|
||||
#misc:
|
||||
# task stack size (bytes)
|
||||
# task-stack-size: 86016
|
||||
# tcp buffer size (bytes)
|
||||
# tcp-buffer-size: 65536
|
||||
# connect timeout (ms)
|
||||
# connect-timeout: 5000
|
||||
# read-write timeout (ms)
|
||||
# read-write-timeout: 60000
|
||||
# stdout, stderr or file-path
|
||||
# log-file: stderr
|
||||
# debug, info, warn or error
|
||||
# log-level: warn
|
||||
# If present, run as a daemon with this pid file
|
||||
# pid-file: /run/hev-socks5-tunnel.pid
|
||||
# If present, set rlimit nofile; else use default value
|
||||
# limit-nofile: 65535
|
||||
@@ -0,0 +1,84 @@
|
||||
#!/bin/sh
|
||||
|
||||
TUN="${TUN:-tun0}"
|
||||
MTU="${MTU:-8500}"
|
||||
IPV4="${IPV4:-198.18.0.1}"
|
||||
IPV6="${IPV6:-}"
|
||||
|
||||
CONFIG_ROUTES="${CONFIG_ROUTES:-1}"
|
||||
|
||||
TABLE="${TABLE:-20}"
|
||||
if [ "${CONFIG_ROUTES}" == "0" ]; then
|
||||
MARK="${MARK:-0}"
|
||||
else
|
||||
MARK="${MARK:-438}"
|
||||
fi
|
||||
|
||||
SOCKS5_ADDR="${SOCKS5_ADDR:-172.17.0.1}"
|
||||
SOCKS5_PORT="${SOCKS5_PORT:-1080}"
|
||||
SOCKS5_USERNAME="${SOCKS5_USERNAME:-}"
|
||||
SOCKS5_PASSWORD="${SOCKS5_PASSWORD:-}"
|
||||
SOCKS5_UDP_MODE="${SOCKS5_UDP_MODE:-udp}"
|
||||
|
||||
IPV4_INCLUDED_ROUTES="${IPV4_INCLUDED_ROUTES:-0.0.0.0/0}"
|
||||
IPV4_EXCLUDED_ROUTES="${IPV4_EXCLUDED_ROUTES:-}"
|
||||
|
||||
LOG_LEVEL="${LOG_LEVEL:-warn}"
|
||||
|
||||
config_file() {
|
||||
cat > /hs5t.yml << EOF
|
||||
misc:
|
||||
log-level: '${LOG_LEVEL}'
|
||||
tunnel:
|
||||
name: '${TUN}'
|
||||
mtu: ${MTU}
|
||||
ipv4: '${IPV4}'
|
||||
ipv6: '${IPV6}'
|
||||
post-up-script: '/route.sh'
|
||||
socks5:
|
||||
address: '${SOCKS5_ADDR}'
|
||||
port: ${SOCKS5_PORT}
|
||||
udp: '${SOCKS5_UDP_MODE}'
|
||||
mark: ${MARK}
|
||||
EOF
|
||||
|
||||
if [ -n "${SOCKS5_USERNAME}" ]; then
|
||||
echo " username: '${SOCKS5_USERNAME}'" >> /hs5t.yml
|
||||
fi
|
||||
|
||||
if [ -n "${SOCKS5_PASSWORD}" ]; then
|
||||
echo " password: '${SOCKS5_PASSWORD}'" >> /hs5t.yml
|
||||
fi
|
||||
}
|
||||
|
||||
config_route() {
|
||||
echo "#!/bin/sh" > /route.sh
|
||||
chmod +x /route.sh
|
||||
|
||||
if [ "${CONFIG_ROUTES}" == "0" ]; then
|
||||
return
|
||||
fi
|
||||
|
||||
echo "ip route add default dev ${TUN} table ${TABLE}" >> /route.sh
|
||||
|
||||
for addr in $(echo ${IPV4_INCLUDED_ROUTES} | tr ',' '\n'); do
|
||||
echo "ip rule add to ${addr} table ${TABLE}" >> /route.sh
|
||||
done
|
||||
|
||||
echo "ip rule add to $(ip -o -f inet address show eth0 | awk '/scope global/ {print $4}') table main" >> /route.sh
|
||||
|
||||
for addr in $(echo ${IPV4_EXCLUDED_ROUTES} | tr ',' '\n'); do
|
||||
echo "ip rule add to ${addr} table main" >> /route.sh
|
||||
done
|
||||
|
||||
echo "ip rule add fwmark ${MARK} table main pref 1" >> /route.sh
|
||||
}
|
||||
|
||||
run() {
|
||||
config_file
|
||||
config_route
|
||||
echo "echo 1 > /success" >> /route.sh
|
||||
hev-socks5-tunnel /hs5t.yml
|
||||
}
|
||||
|
||||
run || exit 1
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-main.h
|
||||
@@ -0,0 +1,4 @@
|
||||
module HevSocks5Tunnel {
|
||||
umbrella header "hev-main.h"
|
||||
export *
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: None
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: TopLevel
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: MultiLine
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterClass: true
|
||||
AfterControlStatement: false
|
||||
AfterEnum: true
|
||||
AfterFunction: true
|
||||
AfterNamespace: true
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: true
|
||||
AfterUnion: true
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: true
|
||||
SplitEmptyRecord: true
|
||||
SplitEmptyNamespace: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: false
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: Inner
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCSpaceAfterProperty: true
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 10
|
||||
PenaltyBreakBeforeFirstCallParameter: 30
|
||||
PenaltyBreakComment: 10
|
||||
PenaltyBreakFirstLessLess: 0
|
||||
PenaltyBreakString: 10
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 100
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Right
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: Always
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp03
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
...
|
||||
@@ -0,0 +1,26 @@
|
||||
name: "Check code formatting"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
checker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 1
|
||||
- name: Prepare
|
||||
run: |
|
||||
sudo apt install -y clang-format
|
||||
- name: Format
|
||||
run: |
|
||||
find src -iname "*.[h,c]" -exec clang-format -i {} \;
|
||||
- name: Check
|
||||
run: |
|
||||
git status
|
||||
git diff --quiet
|
||||
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2022 hev
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,204 @@
|
||||
# HevSocks5Core
|
||||
|
||||
HevSocks5Core is a simple, lightweight socks5 library.
|
||||
|
||||
**Features**
|
||||
* IPv4/IPv6. (dual stack)
|
||||
* Standard `CONNECT` command.
|
||||
* Standard `UDP ASSOCIATE` command.
|
||||
* Extended `FWD UDP` command. (UDP in TCP)
|
||||
* Multiple username/password authentication.
|
||||
|
||||
**Dependencies**
|
||||
* HevTaskSystem - https://github.com/heiher/hev-task-system
|
||||
|
||||
## Examples
|
||||
|
||||
### Server
|
||||
|
||||
```c
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
#include <hev-task-dns.h>
|
||||
#include <hev-task-system.h>
|
||||
|
||||
#include <hev-socks5-server.h>
|
||||
|
||||
static void
|
||||
server_entry (void *data)
|
||||
{
|
||||
HevSocks5Server *server = data;
|
||||
hev_socks5_server_run (server);
|
||||
hev_object_unref (HEV_OBJECT (server));
|
||||
}
|
||||
|
||||
static void
|
||||
listener_entry (void *data)
|
||||
{
|
||||
struct addrinfo hints = { 0 };
|
||||
struct addrinfo *result;
|
||||
int fd;
|
||||
|
||||
hints.ai_family = AF_INET6;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
hev_task_dns_getaddrinfo (NULL, "1080", &hints, &result);
|
||||
fd = hev_task_io_socket_socket (AF_INET6, SOCK_STREAM, 0);
|
||||
bind (fd, result->ai_addr, result->ai_addrlen);
|
||||
freeaddrinfo (result);
|
||||
listen (fd, 5);
|
||||
|
||||
hev_task_add_fd (hev_task_self (), fd, POLLIN);
|
||||
|
||||
for (;;) {
|
||||
HevSocks5Server *server;
|
||||
HevTask *task;
|
||||
int nfd;
|
||||
|
||||
nfd = hev_task_io_socket_accept (fd, NULL, NULL, NULL, NULL);
|
||||
|
||||
task = hev_task_new (-1);
|
||||
server = hev_socks5_server_new (nfd);
|
||||
hev_task_run (task, server_entry, server);
|
||||
}
|
||||
|
||||
close (fd);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
HevTask *task;
|
||||
|
||||
hev_task_system_init ();
|
||||
|
||||
task = hev_task_new (-1);
|
||||
hev_task_run (task, listener_entry, NULL);
|
||||
|
||||
hev_task_system_run ();
|
||||
|
||||
hev_task_system_fini ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### Client
|
||||
|
||||
```c
|
||||
#include <stddef.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-system.h>
|
||||
#include <hev-socks5-client-tcp.h>
|
||||
#include <hev-socks5-client-udp.h>
|
||||
|
||||
static void
|
||||
tcp_client_entry (void *data)
|
||||
{
|
||||
HevSocks5ClientTCP *tcp;
|
||||
|
||||
tcp = hev_socks5_client_tcp_new_name ("www.google.com", 443);
|
||||
hev_socks5_client_connect (HEV_SOCKS5_CLIENT (tcp), "127.0.0.1", 1080);
|
||||
hev_socks5_client_handshake (HEV_SOCKS5_CLIENT (tcp));
|
||||
|
||||
/*
|
||||
* splice data to/from a socket fd:
|
||||
* hev_socks5_tcp_splice (HEV_SOCKS5_TCP (tcp), fd);
|
||||
*/
|
||||
|
||||
hev_object_unref (HEV_OBJECT (tcp));
|
||||
}
|
||||
|
||||
static void
|
||||
udp_client_entry (void *data)
|
||||
{
|
||||
HevSocks5ClientUDP *udp;
|
||||
|
||||
udp = hev_socks5_client_udp_new (HEV_SOCKS5_TYPE_UDP_IN_TCP);
|
||||
hev_socks5_client_connect (HEV_SOCKS5_CLIENT (udp), "127.0.0.1", 1080);
|
||||
hev_socks5_client_handshake (HEV_SOCKS5_CLIENT (udp));
|
||||
|
||||
/*
|
||||
* HevSocks5Addr addr;
|
||||
*
|
||||
* send udp packet:
|
||||
* hev_socks5_udp_sendto (HEV_SOCKS5_UDP (udp), data, len, &addr);
|
||||
*
|
||||
* recv udp packet:
|
||||
* hev_socks5_udp_recvfrom (HEV_SOCKS5_UDP (udp), data, len, &addr);
|
||||
*/
|
||||
|
||||
hev_object_unref (HEV_OBJECT (udp));
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
HevTask *task;
|
||||
|
||||
hev_task_system_init ();
|
||||
|
||||
task = hev_task_new (-1);
|
||||
hev_task_run (task, tcp_client_entry, NULL);
|
||||
|
||||
task = hev_task_new (-1);
|
||||
hev_task_run (task, udp_client_entry, NULL);
|
||||
|
||||
hev_task_system_run ();
|
||||
|
||||
hev_task_system_fini ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
## UDP in TCP
|
||||
|
||||
UDP-in-TCP mode is a proprietary extension based on RFC 1928, designed to
|
||||
forward UDP packets within the primary SOCKS5 TCP stream. The protocol is
|
||||
defined as follows:
|
||||
|
||||
### SOCKS5 Requests
|
||||
|
||||
```
|
||||
+----+-----+-------+------+----------+----------+
|
||||
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
|
||||
+----+-----+-------+------+----------+----------+
|
||||
| 1 | 1 | X'00' | 1 | Variable | 2 |
|
||||
+----+-----+-------+------+----------+----------+
|
||||
```
|
||||
|
||||
* CMD
|
||||
* UDP IN TCP: X'05'
|
||||
|
||||
### UDP Relays
|
||||
|
||||
```
|
||||
+--------+--------+------+----------+----------+----------+
|
||||
| MSGLEN | HDRLEN | ATYP | DST.ADDR | DST.PORT | DATA |
|
||||
+--------+--------+------+----------+----------+----------+
|
||||
| 2 | 1 | 1 | Variable | 2 | Variable |
|
||||
+--------+--------+------+----------+----------+----------+
|
||||
```
|
||||
|
||||
- MSGLEN: The total length of the UDP relay message. `[MSGLEN, DATA]`
|
||||
- HDRLEN: The header length of the UDP relay message. `[MSGLEN, DST.PORT]`
|
||||
- ATYPE/DST.ADDR/DST.PORT: Fields follow the definitions specified in RFC 1928.
|
||||
|
||||
## Users
|
||||
|
||||
* **HevSocks5Server** - https://github.com/heiher/hev-socks5-server
|
||||
* **HevSocks5TProxy** - https://github.com/heiher/hev-socks5-tproxy
|
||||
* **HevSocks5Tunnel** - https://github.com/heiher/hev-socks5-tunnel
|
||||
|
||||
## Contributors
|
||||
* **hev** - https://hev.cc
|
||||
* **spider84** - https://github.com/spider84
|
||||
|
||||
## License
|
||||
MIT
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-rbtree.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-authenticator.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-client-tcp.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-client-udp.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-client.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-logger.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-misc.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-proto.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-server.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-tcp.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-udp.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5-user.h
|
||||
@@ -0,0 +1 @@
|
||||
../src/hev-socks5.h
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-compiler.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 everyone.
|
||||
Description : Compiler
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_COMPILER_H__
|
||||
#define __HEV_COMPILER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define ALIGN_UP(addr, align) \
|
||||
((addr + (typeof (addr))align - 1) & ~((typeof (addr))align - 1))
|
||||
|
||||
#define ALIGN_DOWN(addr, align) ((addr) & ~((typeof (addr))align - 1))
|
||||
|
||||
#ifndef ARRAY_SIZE
|
||||
#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0]))
|
||||
#endif
|
||||
|
||||
#ifndef EXPORT_SYMBOL
|
||||
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
|
||||
#define barrier() __asm__ __volatile__ ("" : : : "memory")
|
||||
|
||||
static inline void
|
||||
__read_once_size (void *dst, const volatile void *src, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case sizeof (char):
|
||||
*(char *)dst = *(volatile char *)src;
|
||||
break;
|
||||
case sizeof (short):
|
||||
*(short *)dst = *(volatile short *)src;
|
||||
break;
|
||||
case sizeof (int):
|
||||
*(int *)dst = *(volatile int *)src;
|
||||
break;
|
||||
default:
|
||||
barrier ();
|
||||
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||
barrier ();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
__write_once_size (volatile void *dst, const void *src, int size)
|
||||
{
|
||||
switch (size) {
|
||||
case sizeof (char):
|
||||
*(volatile char *)dst = *(char *)src;
|
||||
break;
|
||||
case sizeof (short):
|
||||
*(volatile short *)dst = *(short *)src;
|
||||
break;
|
||||
case sizeof (int):
|
||||
*(volatile int *)dst = *(int *)src;
|
||||
break;
|
||||
default:
|
||||
barrier ();
|
||||
__builtin_memcpy ((void *)dst, (const void *)src, size);
|
||||
barrier ();
|
||||
}
|
||||
}
|
||||
|
||||
#define READ_ONCE(x) \
|
||||
({ \
|
||||
union \
|
||||
{ \
|
||||
typeof (x) __val; \
|
||||
char __c[1]; \
|
||||
} __u; \
|
||||
__read_once_size (__u.__c, &(x), sizeof (x)); \
|
||||
__u.__val; \
|
||||
})
|
||||
|
||||
#define WRITE_ONCE(x, val) \
|
||||
({ \
|
||||
union \
|
||||
{ \
|
||||
typeof (x) __val; \
|
||||
char __c[1]; \
|
||||
} __u = { .__val = (typeof (x))(val) }; \
|
||||
__write_once_size (&(x), __u.__c, sizeof (x)); \
|
||||
__u.__val; \
|
||||
})
|
||||
|
||||
#ifndef container_of
|
||||
#define container_of(ptr, type, member) \
|
||||
({ \
|
||||
void *__mptr = (void *)(ptr); \
|
||||
((type *)(__mptr - offsetof (type, member))); \
|
||||
})
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_COMPILER_H__ */
|
||||
@@ -0,0 +1,635 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-rbtree.c
|
||||
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||
David Woodhouse <dwmw2@infradead.org>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : RedBlack Tree
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "hev-rbtree.h"
|
||||
|
||||
typedef enum _HevRBTreeColor HevRBTreeColor;
|
||||
|
||||
enum _HevRBTreeColor
|
||||
{
|
||||
HEV_RBTREE_RED = 0,
|
||||
HEV_RBTREE_BLACK,
|
||||
};
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_color (HevRBTreeNode *node)
|
||||
{
|
||||
return node->__parent_color & 1;
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_is_red (HevRBTreeNode *node)
|
||||
{
|
||||
return !(hev_rbtree_node_color (node) & HEV_RBTREE_BLACK);
|
||||
}
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_is_black (HevRBTreeNode *node)
|
||||
{
|
||||
return hev_rbtree_node_color (node) & HEV_RBTREE_BLACK;
|
||||
}
|
||||
|
||||
static inline int
|
||||
_hev_rbtree_node_is_black (unsigned long pc)
|
||||
{
|
||||
return pc & HEV_RBTREE_BLACK;
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
_hev_rbtree_node_parent (unsigned long pc)
|
||||
{
|
||||
return ((HevRBTreeNode *)(pc & ~3));
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
hev_rbtree_node_red_parent (HevRBTreeNode *node)
|
||||
{
|
||||
return (HevRBTreeNode *)node->__parent_color;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_set_black (HevRBTreeNode *node)
|
||||
{
|
||||
node->__parent_color |= HEV_RBTREE_BLACK;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_set_parent (HevRBTreeNode *node, HevRBTreeNode *parent)
|
||||
{
|
||||
node->__parent_color = hev_rbtree_node_color (node) | (unsigned long)parent;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_set_parent_color (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||
int color)
|
||||
{
|
||||
node->__parent_color = (unsigned long)parent | color;
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_change_child (HevRBTree *self, HevRBTreeNode *old,
|
||||
HevRBTreeNode *new, HevRBTreeNode *parent)
|
||||
{
|
||||
if (parent) {
|
||||
if (parent->left == old)
|
||||
parent->left = new;
|
||||
else
|
||||
parent->right = new;
|
||||
} else {
|
||||
self->root = new;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for rotations:
|
||||
* - old's parent and color get assigned to new
|
||||
* - old gets assigned new as a parent and 'color' as a color.
|
||||
*/
|
||||
static inline void
|
||||
hev_rbtree_rotate_set_parents (HevRBTree *self, HevRBTreeNode *old,
|
||||
HevRBTreeNode *new, int color)
|
||||
{
|
||||
HevRBTreeNode *parent = hev_rbtree_node_parent (old);
|
||||
new->__parent_color = old->__parent_color;
|
||||
hev_rbtree_node_set_parent_color (old, new, color);
|
||||
hev_rbtree_change_child (self, old, new, parent);
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_node_prev (HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *parent;
|
||||
|
||||
if (hev_rbtree_node_empty (node))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If we have a left-hand child, go down and then right as far
|
||||
* as we can.
|
||||
*/
|
||||
if (node->left) {
|
||||
node = node->left;
|
||||
while (node->right)
|
||||
node = node->right;
|
||||
return (HevRBTreeNode *)node;
|
||||
}
|
||||
|
||||
/*
|
||||
* No left-hand children. Go up till we find an ancestor which
|
||||
* is a right-hand child of its parent.
|
||||
*/
|
||||
while ((parent = hev_rbtree_node_parent (node)) && node == parent->left)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_node_next (HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *parent;
|
||||
|
||||
if (hev_rbtree_node_empty (node))
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* If we have a right-hand child, go down and then left as far
|
||||
* as we can.
|
||||
*/
|
||||
if (node->right) {
|
||||
node = node->right;
|
||||
while (node->left)
|
||||
node = node->left;
|
||||
return (HevRBTreeNode *)node;
|
||||
}
|
||||
|
||||
/*
|
||||
* No right-hand children. Everything down and left is smaller than us,
|
||||
* so any 'next' node must be in the general direction of our parent.
|
||||
* Go up the tree; any time the ancestor is a right-hand child of its
|
||||
* parent, keep going up. First time it's a left-hand child of its
|
||||
* parent, said parent is our 'next' node.
|
||||
*/
|
||||
while ((parent = hev_rbtree_node_parent (node)) && node == parent->right)
|
||||
node = parent;
|
||||
|
||||
return parent;
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_first (HevRBTree *self)
|
||||
{
|
||||
HevRBTreeNode *n;
|
||||
|
||||
n = self->root;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->left)
|
||||
n = n->left;
|
||||
return n;
|
||||
}
|
||||
|
||||
HevRBTreeNode *
|
||||
hev_rbtree_last (HevRBTree *self)
|
||||
{
|
||||
HevRBTreeNode *n;
|
||||
|
||||
n = self->root;
|
||||
if (!n)
|
||||
return NULL;
|
||||
while (n->right)
|
||||
n = n->right;
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *parent = hev_rbtree_node_red_parent (node), *gparent, *tmp;
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Loop invariant: node is red.
|
||||
*/
|
||||
if (!parent) {
|
||||
/*
|
||||
* The inserted node is root. Either this is the
|
||||
* first node, or we recursed at Case 1 below and
|
||||
* are no longer violating 4).
|
||||
*/
|
||||
hev_rbtree_node_set_parent_color (node, NULL, HEV_RBTREE_BLACK);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a black parent, we are done.
|
||||
* Otherwise, take some corrective action as,
|
||||
* per 4), we don't want a red root or two
|
||||
* consecutive red nodes.
|
||||
*/
|
||||
if (hev_rbtree_node_is_black (parent))
|
||||
break;
|
||||
|
||||
gparent = hev_rbtree_node_red_parent (parent);
|
||||
|
||||
tmp = gparent->right;
|
||||
if (parent != tmp) { /* parent == gparent->left */
|
||||
if (tmp && hev_rbtree_node_is_red (tmp)) {
|
||||
/*
|
||||
* Case 1 - node's uncle is red (color flips).
|
||||
*
|
||||
* G g
|
||||
* / \ / \
|
||||
* p u --> P U
|
||||
* / /
|
||||
* n n
|
||||
*
|
||||
* However, since g's parent might be red, and
|
||||
* 4) does not allow this, we need to recurse
|
||||
* at g.
|
||||
*/
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
node = gparent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
hev_rbtree_node_set_parent_color (node, parent, HEV_RBTREE_RED);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = parent->right;
|
||||
if (node == tmp) {
|
||||
/*
|
||||
* Case 2 - node's uncle is black and node is
|
||||
* the parent's right child (left rotate at parent).
|
||||
*
|
||||
* G G
|
||||
* / \ / \
|
||||
* p U --> n U
|
||||
* \ /
|
||||
* n p
|
||||
*
|
||||
* This still leaves us in violation of 4), the
|
||||
* continuation into Case 3 will fix that.
|
||||
*/
|
||||
tmp = node->left;
|
||||
parent->right = tmp;
|
||||
node->left = parent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, node, HEV_RBTREE_RED);
|
||||
parent = node;
|
||||
tmp = node->right;
|
||||
}
|
||||
|
||||
/*
|
||||
* Case 3 - node's uncle is black and node is
|
||||
* the parent's left child (right rotate at gparent).
|
||||
*
|
||||
* G P
|
||||
* / \ / \
|
||||
* p U --> n g
|
||||
* / \
|
||||
* n U
|
||||
*/
|
||||
gparent->left = tmp; /* == parent->right */
|
||||
parent->right = gparent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, gparent, parent,
|
||||
HEV_RBTREE_RED);
|
||||
break;
|
||||
} else {
|
||||
tmp = gparent->left;
|
||||
if (tmp && hev_rbtree_node_is_red (tmp)) {
|
||||
/* Case 1 - color flips */
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
node = gparent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
hev_rbtree_node_set_parent_color (node, parent, HEV_RBTREE_RED);
|
||||
continue;
|
||||
}
|
||||
|
||||
tmp = parent->left;
|
||||
if (node == tmp) {
|
||||
/* Case 2 - right rotate at parent */
|
||||
tmp = node->right;
|
||||
parent->left = tmp;
|
||||
node->right = parent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_node_set_parent_color (parent, node, HEV_RBTREE_RED);
|
||||
parent = node;
|
||||
tmp = node->left;
|
||||
}
|
||||
|
||||
/* Case 3 - left rotate at gparent */
|
||||
gparent->right = tmp; /* == parent->left */
|
||||
parent->left = gparent;
|
||||
if (tmp)
|
||||
hev_rbtree_node_set_parent_color (tmp, gparent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, gparent, parent,
|
||||
HEV_RBTREE_RED);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim, HevRBTreeNode *new)
|
||||
{
|
||||
HevRBTreeNode *parent = hev_rbtree_node_parent (victim);
|
||||
|
||||
/* Copy the pointers/colour from the victim to the replacement */
|
||||
*new = *victim;
|
||||
|
||||
/* Set the surrounding nodes to point to the replacement */
|
||||
if (victim->left)
|
||||
hev_rbtree_node_set_parent (victim->left, new);
|
||||
if (victim->right)
|
||||
hev_rbtree_node_set_parent (victim->right, new);
|
||||
hev_rbtree_change_child (self, victim, new, parent);
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
_hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *child = node->right;
|
||||
HevRBTreeNode *tmp = node->left;
|
||||
HevRBTreeNode *parent, *rebalance;
|
||||
unsigned long pc;
|
||||
|
||||
if (!tmp) {
|
||||
/*
|
||||
* Case 1: node to erase has no more than 1 child (easy!)
|
||||
*
|
||||
* Note that if there is one child it must be red due to 5)
|
||||
* and node must be black due to 4). We adjust colors locally
|
||||
* so as to bypass _hev_rbtree_erase_color() later on.
|
||||
*/
|
||||
pc = node->__parent_color;
|
||||
parent = _hev_rbtree_node_parent (pc);
|
||||
hev_rbtree_change_child (self, node, child, parent);
|
||||
if (child) {
|
||||
child->__parent_color = pc;
|
||||
rebalance = NULL;
|
||||
} else
|
||||
rebalance = _hev_rbtree_node_is_black (pc) ? parent : NULL;
|
||||
tmp = parent;
|
||||
} else if (!child) {
|
||||
/* Still case 1, but this time the child is node->left */
|
||||
tmp->__parent_color = pc = node->__parent_color;
|
||||
parent = _hev_rbtree_node_parent (pc);
|
||||
hev_rbtree_change_child (self, node, tmp, parent);
|
||||
rebalance = NULL;
|
||||
tmp = parent;
|
||||
} else {
|
||||
HevRBTreeNode *successor = child, *child2;
|
||||
|
||||
tmp = child->left;
|
||||
if (!tmp) {
|
||||
/*
|
||||
* Case 2: node's successor is its right child
|
||||
*
|
||||
* (n) (s)
|
||||
* / \ / \
|
||||
* (x) (s) -> (x) (c)
|
||||
* \
|
||||
* (c)
|
||||
*/
|
||||
parent = successor;
|
||||
child2 = successor->right;
|
||||
} else {
|
||||
/*
|
||||
* Case 3: node's successor is leftmost under
|
||||
* node's right child subtree
|
||||
*
|
||||
* (n) (s)
|
||||
* / \ / \
|
||||
* (x) (y) -> (x) (y)
|
||||
* / /
|
||||
* (p) (p)
|
||||
* / /
|
||||
* (s) (c)
|
||||
* \
|
||||
* (c)
|
||||
*/
|
||||
do {
|
||||
parent = successor;
|
||||
successor = tmp;
|
||||
tmp = tmp->left;
|
||||
} while (tmp);
|
||||
child2 = successor->right;
|
||||
parent->left = child2;
|
||||
successor->right = child;
|
||||
hev_rbtree_node_set_parent (child, successor);
|
||||
}
|
||||
|
||||
tmp = node->left;
|
||||
successor->left = tmp;
|
||||
hev_rbtree_node_set_parent (tmp, successor);
|
||||
|
||||
pc = node->__parent_color;
|
||||
tmp = _hev_rbtree_node_parent (pc);
|
||||
hev_rbtree_change_child (self, node, successor, tmp);
|
||||
|
||||
if (child2) {
|
||||
hev_rbtree_node_set_parent_color (child2, parent, HEV_RBTREE_BLACK);
|
||||
rebalance = NULL;
|
||||
} else {
|
||||
rebalance = hev_rbtree_node_is_black (successor) ? parent : NULL;
|
||||
}
|
||||
successor->__parent_color = pc;
|
||||
tmp = successor;
|
||||
}
|
||||
|
||||
return rebalance;
|
||||
}
|
||||
|
||||
/*
|
||||
* Inline version for hev_rbtree_erase() use - we want to be able to inline
|
||||
* and eliminate the dummy_rotate callback there
|
||||
*/
|
||||
static inline void
|
||||
_hev_rbtree_erase_color (HevRBTree *self, HevRBTreeNode *parent)
|
||||
{
|
||||
HevRBTreeNode *node = NULL, *sibling, *tmp1, *tmp2;
|
||||
|
||||
while (1) {
|
||||
/*
|
||||
* Loop invariants:
|
||||
* - node is black (or NULL on first iteration)
|
||||
* - node is not the root (parent is not NULL)
|
||||
* - All leaf paths going through parent and node have a
|
||||
* black node count that is 1 lower than other leaf paths.
|
||||
*/
|
||||
sibling = parent->right;
|
||||
if (node != sibling) { /* node == parent->left */
|
||||
if (hev_rbtree_node_is_red (sibling)) {
|
||||
/*
|
||||
* Case 1 - left rotate at parent
|
||||
*
|
||||
* P S
|
||||
* / \ / \
|
||||
* N s --> p Sr
|
||||
* / \ / \
|
||||
* Sl Sr N Sl
|
||||
*/
|
||||
tmp1 = sibling->left;
|
||||
parent->right = tmp1;
|
||||
sibling->left = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_RED);
|
||||
sibling = tmp1;
|
||||
}
|
||||
tmp1 = sibling->right;
|
||||
if (!tmp1 || hev_rbtree_node_is_black (tmp1)) {
|
||||
tmp2 = sibling->left;
|
||||
if (!tmp2 || hev_rbtree_node_is_black (tmp2)) {
|
||||
/*
|
||||
* Case 2 - sibling color flip
|
||||
* (p could be either color here)
|
||||
*
|
||||
* (p) (p)
|
||||
* / \ / \
|
||||
* N S --> N s
|
||||
* / \ / \
|
||||
* Sl Sr Sl Sr
|
||||
*
|
||||
* This leaves us violating 5) which
|
||||
* can be fixed by flipping p to black
|
||||
* if it was red, or by recursing at p.
|
||||
* p is red when coming from Case 1.
|
||||
*/
|
||||
hev_rbtree_node_set_parent_color (sibling, parent,
|
||||
HEV_RBTREE_RED);
|
||||
if (hev_rbtree_node_is_red (parent))
|
||||
hev_rbtree_node_set_black (parent);
|
||||
else {
|
||||
node = parent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
if (parent)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Case 3 - right rotate at sibling
|
||||
* (p could be either color here)
|
||||
*
|
||||
* (p) (p)
|
||||
* / \ / \
|
||||
* N S --> N sl
|
||||
* / \ \
|
||||
* sl Sr S
|
||||
* \
|
||||
* Sr
|
||||
*
|
||||
* Note: p might be red, and then both
|
||||
* p and sl are red after rotation(which
|
||||
* breaks property 4). This is fixed in
|
||||
* Case 4 (in hev_rbtree_rotate_set_parents()
|
||||
* which set sl the color of p
|
||||
* and set p HEV_RBTREE_BLACK)
|
||||
*
|
||||
* (p) (sl)
|
||||
* / \ / \
|
||||
* N sl --> P S
|
||||
* \ / \
|
||||
* S N Sr
|
||||
* \
|
||||
* Sr
|
||||
*/
|
||||
tmp1 = tmp2->right;
|
||||
sibling->left = tmp1;
|
||||
tmp2->right = sibling;
|
||||
parent->right = tmp2;
|
||||
if (tmp1)
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
tmp1 = sibling;
|
||||
sibling = tmp2;
|
||||
}
|
||||
/*
|
||||
* Case 4 - left rotate at parent + color flips
|
||||
* (p and sl could be either color here.
|
||||
* After rotation, p becomes black, s acquires
|
||||
* p's color, and sl keeps its color)
|
||||
*
|
||||
* (p) (s)
|
||||
* / \ / \
|
||||
* N S --> P Sr
|
||||
* / \ / \
|
||||
* (sl) sr N (sl)
|
||||
*/
|
||||
tmp2 = sibling->left;
|
||||
parent->right = tmp2;
|
||||
sibling->left = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling, HEV_RBTREE_BLACK);
|
||||
if (tmp2)
|
||||
hev_rbtree_node_set_parent (tmp2, parent);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
break;
|
||||
} else {
|
||||
sibling = parent->left;
|
||||
if (hev_rbtree_node_is_red (sibling)) {
|
||||
/* Case 1 - right rotate at parent */
|
||||
tmp1 = sibling->right;
|
||||
parent->left = tmp1;
|
||||
sibling->right = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, parent,
|
||||
HEV_RBTREE_BLACK);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_RED);
|
||||
sibling = tmp1;
|
||||
}
|
||||
tmp1 = sibling->left;
|
||||
if (!tmp1 || hev_rbtree_node_is_black (tmp1)) {
|
||||
tmp2 = sibling->right;
|
||||
if (!tmp2 || hev_rbtree_node_is_black (tmp2)) {
|
||||
/* Case 2 - sibling color flip */
|
||||
hev_rbtree_node_set_parent_color (sibling, parent,
|
||||
HEV_RBTREE_RED);
|
||||
if (hev_rbtree_node_is_red (parent))
|
||||
hev_rbtree_node_set_black (parent);
|
||||
else {
|
||||
node = parent;
|
||||
parent = hev_rbtree_node_parent (node);
|
||||
if (parent)
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* Case 3 - left rotate at sibling */
|
||||
tmp1 = tmp2->left;
|
||||
sibling->right = tmp1;
|
||||
tmp2->left = sibling;
|
||||
parent->left = tmp2;
|
||||
if (tmp1)
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
tmp1 = sibling;
|
||||
sibling = tmp2;
|
||||
}
|
||||
/* Case 4 - right rotate at parent + color flips */
|
||||
tmp2 = sibling->right;
|
||||
parent->left = tmp2;
|
||||
sibling->right = parent;
|
||||
hev_rbtree_node_set_parent_color (tmp1, sibling, HEV_RBTREE_BLACK);
|
||||
if (tmp2)
|
||||
hev_rbtree_node_set_parent (tmp2, parent);
|
||||
hev_rbtree_rotate_set_parents (self, parent, sibling,
|
||||
HEV_RBTREE_BLACK);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node)
|
||||
{
|
||||
HevRBTreeNode *rebalance;
|
||||
rebalance = _hev_rbtree_erase (self, node);
|
||||
if (rebalance)
|
||||
_hev_rbtree_erase_color (self, rebalance);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-rbtree.h
|
||||
Authors : Andrea Arcangeli <andrea@suse.de>
|
||||
David Woodhouse <dwmw2@infradead.org>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2018 everyone.
|
||||
Description : RedBlack Tree
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_RBTREE_H__
|
||||
#define __HEV_RBTREE_H__
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct _HevRBTree HevRBTree;
|
||||
typedef struct _HevRBTreeNode HevRBTreeNode;
|
||||
|
||||
struct _HevRBTree
|
||||
{
|
||||
HevRBTreeNode *root;
|
||||
};
|
||||
|
||||
struct _HevRBTreeNode
|
||||
{
|
||||
unsigned long __parent_color;
|
||||
HevRBTreeNode *right;
|
||||
HevRBTreeNode *left;
|
||||
} __attribute__ ((aligned (sizeof (long))));
|
||||
|
||||
static inline int
|
||||
hev_rbtree_node_empty (HevRBTreeNode *node)
|
||||
{
|
||||
return node->__parent_color == (unsigned long)node;
|
||||
}
|
||||
|
||||
static inline HevRBTreeNode *
|
||||
hev_rbtree_node_parent (HevRBTreeNode *node)
|
||||
{
|
||||
return (HevRBTreeNode *)(node->__parent_color & ~3);
|
||||
}
|
||||
|
||||
static inline void
|
||||
hev_rbtree_node_link (HevRBTreeNode *node, HevRBTreeNode *parent,
|
||||
HevRBTreeNode **link)
|
||||
{
|
||||
node->__parent_color = (unsigned long)parent;
|
||||
node->left = node->right = NULL;
|
||||
|
||||
*link = node;
|
||||
}
|
||||
|
||||
HevRBTreeNode *hev_rbtree_node_prev (HevRBTreeNode *node);
|
||||
HevRBTreeNode *hev_rbtree_node_next (HevRBTreeNode *node);
|
||||
|
||||
HevRBTreeNode *hev_rbtree_first (HevRBTree *self);
|
||||
HevRBTreeNode *hev_rbtree_last (HevRBTree *self);
|
||||
|
||||
void hev_rbtree_insert_color (HevRBTree *self, HevRBTreeNode *node);
|
||||
|
||||
void hev_rbtree_replace (HevRBTree *self, HevRBTreeNode *victim,
|
||||
HevRBTreeNode *new);
|
||||
|
||||
void hev_rbtree_erase (HevRBTree *self, HevRBTreeNode *node);
|
||||
|
||||
#endif /* __HEV_RBTREE_H__ */
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-authenticator.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2023 hev
|
||||
Description : Socks5 Authenticator
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hev-compiler.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-authenticator.h"
|
||||
|
||||
HevSocks5Authenticator *
|
||||
hev_socks5_authenticator_new (void)
|
||||
{
|
||||
HevSocks5Authenticator *self;
|
||||
int res;
|
||||
|
||||
self = calloc (1, sizeof (HevSocks5Authenticator));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
res = hev_socks5_authenticator_construct (self);
|
||||
if (res < 0) {
|
||||
free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 authenticator new", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_authenticator_add (HevSocks5Authenticator *self, HevSocks5User *user)
|
||||
{
|
||||
HevRBTreeNode **new = &self->tree.root, *parent = NULL;
|
||||
|
||||
while (*new) {
|
||||
HevSocks5User *this;
|
||||
int res;
|
||||
|
||||
this = container_of (*new, HevSocks5User, node);
|
||||
|
||||
if (this->name_len < user->name_len)
|
||||
res = -1;
|
||||
else if (this->name_len > user->name_len)
|
||||
res = 1;
|
||||
else
|
||||
res = memcmp (this->name, user->name, this->name_len);
|
||||
|
||||
parent = *new;
|
||||
if (res < 0)
|
||||
new = &((*new)->left);
|
||||
else if (res > 0)
|
||||
new = &((*new)->right);
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
hev_rbtree_node_link (&user->node, parent, new);
|
||||
hev_rbtree_insert_color (&self->tree, &user->node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_authenticator_del (HevSocks5Authenticator *self, const char *name,
|
||||
unsigned int name_len)
|
||||
{
|
||||
HevRBTreeNode *node = self->tree.root;
|
||||
|
||||
while (node) {
|
||||
HevSocks5User *this;
|
||||
int res;
|
||||
|
||||
this = container_of (node, HevSocks5User, node);
|
||||
if (this->name_len < name_len)
|
||||
res = -1;
|
||||
else if (this->name_len > name_len)
|
||||
res = 1;
|
||||
else
|
||||
res = memcmp (this->name, name, name_len);
|
||||
|
||||
if (res < 0) {
|
||||
node = node->left;
|
||||
} else if (res > 0) {
|
||||
node = node->right;
|
||||
} else {
|
||||
hev_rbtree_erase (&self->tree, node);
|
||||
hev_object_unref (HEV_OBJECT (this));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
HevSocks5User *
|
||||
hev_socks5_authenticator_get (HevSocks5Authenticator *self, const char *name,
|
||||
unsigned int name_len)
|
||||
{
|
||||
HevRBTreeNode *node = self->tree.root;
|
||||
|
||||
while (node) {
|
||||
HevSocks5User *this;
|
||||
int res;
|
||||
|
||||
this = container_of (node, HevSocks5User, node);
|
||||
if (this->name_len < name_len)
|
||||
res = -1;
|
||||
else if (this->name_len > name_len)
|
||||
res = 1;
|
||||
else
|
||||
res = memcmp (this->name, name, name_len);
|
||||
|
||||
if (res < 0)
|
||||
node = node->left;
|
||||
else if (res > 0)
|
||||
node = node->right;
|
||||
else
|
||||
return this;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_authenticator_clear (HevSocks5Authenticator *self)
|
||||
{
|
||||
HevRBTreeNode *n;
|
||||
|
||||
while ((n = hev_rbtree_first (&self->tree))) {
|
||||
HevSocks5User *t;
|
||||
|
||||
t = container_of (n, HevSocks5User, node);
|
||||
hev_rbtree_erase (&self->tree, n);
|
||||
hev_object_unref (HEV_OBJECT (t));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_authenticator_construct (HevSocks5Authenticator *self)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_object_atomic_construct (&self->base);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_D ("%p socks5 authenticator construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_AUTHENTICATOR_TYPE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_authenticator_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5Authenticator *self = HEV_SOCKS5_AUTHENTICATOR (base);
|
||||
|
||||
LOG_D ("%p socks5 authenticator destruct", self);
|
||||
|
||||
hev_socks5_authenticator_clear (self);
|
||||
|
||||
HEV_OBJECT_ATOMIC_TYPE->destruct (base);
|
||||
free (base);
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_authenticator_class (void)
|
||||
{
|
||||
static HevSocks5AuthenticatorClass klass;
|
||||
HevSocks5AuthenticatorClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
memcpy (kptr, HEV_OBJECT_ATOMIC_TYPE, sizeof (HevObjectAtomicClass));
|
||||
|
||||
okptr->name = "HevSocks5Authenticator";
|
||||
okptr->destruct = hev_socks5_authenticator_destruct;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-authenticator.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2023 hev
|
||||
Description : Socks5 Authenticator
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_AUTHENTICATOR_H__
|
||||
#define __HEV_SOCKS5_AUTHENTICATOR_H__
|
||||
|
||||
#include <hev-object-atomic.h>
|
||||
|
||||
#include "hev-rbtree.h"
|
||||
#include "hev-socks5-user.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_AUTHENTICATOR(p) ((HevSocks5Authenticator *)p)
|
||||
#define HEV_SOCKS5_AUTHENTICATOR_CLASS(p) ((HevSocks5AuthenticatorClass *)p)
|
||||
#define HEV_SOCKS5_AUTHENTICATOR_TYPE (hev_socks5_authenticator_class ())
|
||||
|
||||
typedef struct _HevSocks5Authenticator HevSocks5Authenticator;
|
||||
typedef struct _HevSocks5AuthenticatorClass HevSocks5AuthenticatorClass;
|
||||
typedef enum _HevSocks5AuthenticatorType HevSocks5AuthenticatorType;
|
||||
|
||||
struct _HevSocks5Authenticator
|
||||
{
|
||||
HevObjectAtomic base;
|
||||
|
||||
HevRBTree tree;
|
||||
};
|
||||
|
||||
struct _HevSocks5AuthenticatorClass
|
||||
{
|
||||
HevObjectAtomicClass base;
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_authenticator_class (void);
|
||||
|
||||
int hev_socks5_authenticator_construct (HevSocks5Authenticator *self);
|
||||
|
||||
HevSocks5Authenticator *hev_socks5_authenticator_new (void);
|
||||
|
||||
int hev_socks5_authenticator_add (HevSocks5Authenticator *self,
|
||||
HevSocks5User *user);
|
||||
|
||||
int hev_socks5_authenticator_del (HevSocks5Authenticator *self,
|
||||
const char *name, unsigned int name_len);
|
||||
|
||||
HevSocks5User *hev_socks5_authenticator_get (HevSocks5Authenticator *self,
|
||||
const char *name,
|
||||
unsigned int name_len);
|
||||
|
||||
void hev_socks5_authenticator_clear (HevSocks5Authenticator *self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_AUTHENTICATOR_H__ */
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-client-tcp.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Client TCP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <hev-memory-allocator.h>
|
||||
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-client-tcp.h"
|
||||
|
||||
HevSocks5ClientTCP *
|
||||
hev_socks5_client_tcp_new_name (const char *name, int port)
|
||||
{
|
||||
HevSocks5ClientTCP *self;
|
||||
HevSocks5Addr addr;
|
||||
int res;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevSocks5ClientTCP));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
hev_socks5_addr_from_name (&addr, name, port);
|
||||
res = hev_socks5_client_tcp_construct (self, &addr);
|
||||
if (res < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 client tcp new name", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
HevSocks5ClientTCP *
|
||||
hev_socks5_client_tcp_new_ipv4 (const void *ipv4, int port)
|
||||
{
|
||||
HevSocks5ClientTCP *self;
|
||||
HevSocks5Addr addr;
|
||||
int res;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevSocks5ClientTCP));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
hev_socks5_addr_from_ipv4 (&addr, ipv4, port);
|
||||
res = hev_socks5_client_tcp_construct (self, &addr);
|
||||
if (res < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 client tcp new ipv4", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
HevSocks5ClientTCP *
|
||||
hev_socks5_client_tcp_new_ipv6 (const void *ipv6, int port)
|
||||
{
|
||||
HevSocks5ClientTCP *self;
|
||||
HevSocks5Addr addr;
|
||||
int res;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevSocks5ClientTCP));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
hev_socks5_addr_from_ipv6 (&addr, ipv6, port);
|
||||
res = hev_socks5_client_tcp_construct (self, &addr);
|
||||
if (res < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 client tcp new ipv6", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static HevSocks5Addr *
|
||||
hev_socks5_client_tcp_get_upstream_addr (HevSocks5Client *base)
|
||||
{
|
||||
HevSocks5ClientTCP *self = HEV_SOCKS5_CLIENT_TCP (base);
|
||||
HevSocks5Addr *addr;
|
||||
|
||||
addr = self->addr;
|
||||
self->addr = NULL;
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_tcp_set_upstream_addr (HevSocks5Client *base,
|
||||
HevSocks5Addr *addr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_client_tcp_construct (HevSocks5ClientTCP *self,
|
||||
const HevSocks5Addr *addr)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_socks5_client_construct (&self->base, HEV_SOCKS5_TYPE_TCP);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_D ("%p socks5 client tcp construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_TCP_TYPE;
|
||||
|
||||
res = hev_socks5_addr_len (addr);
|
||||
self->addr = hev_malloc (res);
|
||||
if (!self->addr)
|
||||
return -1;
|
||||
memcpy (self->addr, addr, res);
|
||||
|
||||
if (LOG_ON ()) {
|
||||
const char *str;
|
||||
char buf[272];
|
||||
|
||||
str = hev_socks5_addr_into_str (self->addr, buf, sizeof (buf));
|
||||
LOG_I ("%p socks5 client tcp -> %s", self, str);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_client_tcp_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5ClientTCP *self = HEV_SOCKS5_CLIENT_TCP (base);
|
||||
|
||||
LOG_D ("%p socks5 client tcp destruct", self);
|
||||
|
||||
if (self->addr)
|
||||
hev_free (self->addr);
|
||||
|
||||
HEV_SOCKS5_CLIENT_TYPE->destruct (base);
|
||||
}
|
||||
|
||||
static void *
|
||||
hev_socks5_client_tcp_iface (HevObject *base, void *type)
|
||||
{
|
||||
HevSocks5ClientTCPClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||
|
||||
return &klass->tcp;
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_client_tcp_class (void)
|
||||
{
|
||||
static HevSocks5ClientTCPClass klass;
|
||||
HevSocks5ClientTCPClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
HevSocks5ClientClass *ckptr;
|
||||
HevSocks5TCPIface *tiptr;
|
||||
|
||||
memcpy (kptr, HEV_SOCKS5_CLIENT_TYPE, sizeof (HevSocks5ClientClass));
|
||||
|
||||
okptr->name = "HevSocks5ClientTCP";
|
||||
okptr->destruct = hev_socks5_client_tcp_destruct;
|
||||
okptr->iface = hev_socks5_client_tcp_iface;
|
||||
|
||||
ckptr = HEV_SOCKS5_CLIENT_CLASS (kptr);
|
||||
ckptr->get_upstream_addr = hev_socks5_client_tcp_get_upstream_addr;
|
||||
ckptr->set_upstream_addr = hev_socks5_client_tcp_set_upstream_addr;
|
||||
|
||||
tiptr = &kptr->tcp;
|
||||
memcpy (tiptr, HEV_SOCKS5_TCP_TYPE, sizeof (HevSocks5TCPIface));
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-client-tcp.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Client TCP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_CLIENT_TCP_H__
|
||||
#define __HEV_SOCKS5_CLIENT_TCP_H__
|
||||
|
||||
#include "hev-socks5-tcp.h"
|
||||
#include "hev-socks5-proto.h"
|
||||
|
||||
#include "hev-socks5-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_CLIENT_TCP(p) ((HevSocks5ClientTCP *)p)
|
||||
#define HEV_SOCKS5_CLIENT_TCP_CLASS(p) ((HevSocks5ClientTCPClass *)p)
|
||||
#define HEV_SOCKS5_CLIENT_TCP_TYPE (hev_socks5_client_tcp_class ())
|
||||
|
||||
typedef struct _HevSocks5ClientTCP HevSocks5ClientTCP;
|
||||
typedef struct _HevSocks5ClientTCPClass HevSocks5ClientTCPClass;
|
||||
|
||||
struct _HevSocks5ClientTCP
|
||||
{
|
||||
HevSocks5Client base;
|
||||
|
||||
HevSocks5Addr *addr;
|
||||
};
|
||||
|
||||
struct _HevSocks5ClientTCPClass
|
||||
{
|
||||
HevSocks5ClientClass base;
|
||||
|
||||
HevSocks5TCPIface tcp;
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_client_tcp_class (void);
|
||||
|
||||
int hev_socks5_client_tcp_construct (HevSocks5ClientTCP *self,
|
||||
const HevSocks5Addr *addr);
|
||||
|
||||
HevSocks5ClientTCP *hev_socks5_client_tcp_new_name (const char *name, int port);
|
||||
HevSocks5ClientTCP *hev_socks5_client_tcp_new_ipv4 (const void *ipv4, int port);
|
||||
HevSocks5ClientTCP *hev_socks5_client_tcp_new_ipv6 (const void *ipv6, int port);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_CLIENT_TCP_H__ */
|
||||
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-client-udp.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Client UDP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
#include <hev-memory-allocator.h>
|
||||
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-client-udp.h"
|
||||
|
||||
#define task_io_yielder hev_socks5_task_io_yielder
|
||||
|
||||
HevSocks5ClientUDP *
|
||||
hev_socks5_client_udp_new (HevSocks5Type type)
|
||||
{
|
||||
HevSocks5ClientUDP *self;
|
||||
int res;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevSocks5ClientUDP));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
res = hev_socks5_client_udp_construct (self, type);
|
||||
if (res < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 client udp new", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
static HevSocks5Addr *
|
||||
hev_socks5_client_udp_get_upstream_addr (HevSocks5Client *base)
|
||||
{
|
||||
HevSocks5AddrFamily family;
|
||||
HevSocks5Addr *addr;
|
||||
|
||||
family = hev_socks5_get_addr_family (HEV_SOCKS5 (base));
|
||||
|
||||
switch (family) {
|
||||
case HEV_SOCKS5_ADDR_FAMILY_IPV4:
|
||||
addr = hev_malloc0 (7);
|
||||
if (addr)
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_FAMILY_IPV6:
|
||||
addr = hev_malloc0 (19);
|
||||
if (addr)
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV6;
|
||||
break;
|
||||
default:
|
||||
addr = NULL;
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_udp_set_upstream_addr (HevSocks5Client *base,
|
||||
HevSocks5Addr *addr)
|
||||
{
|
||||
HevSocks5ClientUDP *self = HEV_SOCKS5_CLIENT_UDP (base);
|
||||
struct sockaddr_in6 saddr;
|
||||
struct sockaddr *sadp;
|
||||
HevSocks5Class *klass;
|
||||
int addr_family;
|
||||
int res;
|
||||
int fd;
|
||||
|
||||
if (HEV_SOCKS5 (base)->type != HEV_SOCKS5_TYPE_UDP_IN_UDP)
|
||||
return 0;
|
||||
|
||||
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||
res = hev_socks5_addr_into_sockaddr6 (addr, &saddr, &addr_family);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client udp addr", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = hev_socks5_socket (SOCK_DGRAM);
|
||||
if (fd < 0) {
|
||||
LOG_E ("%p socks5 client udp socket", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sadp = (struct sockaddr *)&saddr;
|
||||
klass = HEV_OBJECT_GET_CLASS (self);
|
||||
res = klass->binder (HEV_SOCKS5 (self), fd, sadp);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client udp bind", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_task_io_socket_connect (fd, sadp, sizeof (saddr), task_io_yielder,
|
||||
self);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client udp connect", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HEV_SOCKS5 (self)->udp_associated = 1;
|
||||
self->fd = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_udp_get_fd (HevSocks5UDP *self)
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (HEV_SOCKS5 (self)->type) {
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||
fd = HEV_SOCKS5 (self)->fd;
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||
fd = HEV_SOCKS5_CLIENT_UDP (self)->fd;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_client_udp_construct (HevSocks5ClientUDP *self, HevSocks5Type type)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_socks5_client_construct (&self->base, type);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_I ("%p socks5 client udp construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_UDP_TYPE;
|
||||
|
||||
self->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_client_udp_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5ClientUDP *self = HEV_SOCKS5_CLIENT_UDP (base);
|
||||
|
||||
LOG_D ("%p socks5 client udp destruct", self);
|
||||
|
||||
if (self->fd >= 0) {
|
||||
hev_task_del_fd (hev_task_self (), self->fd);
|
||||
close (self->fd);
|
||||
}
|
||||
|
||||
HEV_SOCKS5_CLIENT_TYPE->destruct (base);
|
||||
}
|
||||
|
||||
static void *
|
||||
hev_socks5_client_udp_iface (HevObject *base, void *type)
|
||||
{
|
||||
HevSocks5ClientUDPClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||
|
||||
return &klass->udp;
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_client_udp_class (void)
|
||||
{
|
||||
static HevSocks5ClientUDPClass klass;
|
||||
HevSocks5ClientUDPClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
HevSocks5ClientClass *ckptr;
|
||||
HevSocks5UDPIface *uiptr;
|
||||
|
||||
memcpy (kptr, HEV_SOCKS5_CLIENT_TYPE, sizeof (HevSocks5ClientClass));
|
||||
|
||||
okptr->name = "HevSocks5ClientUDP";
|
||||
okptr->destruct = hev_socks5_client_udp_destruct;
|
||||
okptr->iface = hev_socks5_client_udp_iface;
|
||||
|
||||
ckptr = HEV_SOCKS5_CLIENT_CLASS (kptr);
|
||||
ckptr->get_upstream_addr = hev_socks5_client_udp_get_upstream_addr;
|
||||
ckptr->set_upstream_addr = hev_socks5_client_udp_set_upstream_addr;
|
||||
|
||||
uiptr = &kptr->udp;
|
||||
memcpy (uiptr, HEV_SOCKS5_UDP_TYPE, sizeof (HevSocks5UDPIface));
|
||||
uiptr->get_fd = hev_socks5_client_udp_get_fd;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-client-udp.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2023 hev
|
||||
Description : Socks5 Client UDP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_CLIENT_UDP_H__
|
||||
#define __HEV_SOCKS5_CLIENT_UDP_H__
|
||||
|
||||
#include "hev-socks5-udp.h"
|
||||
|
||||
#include "hev-socks5-client.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_CLIENT_UDP(p) ((HevSocks5ClientUDP *)p)
|
||||
#define HEV_SOCKS5_CLIENT_UDP_CLASS(p) ((HevSocks5ClientUDPClass *)p)
|
||||
#define HEV_SOCKS5_CLIENT_UDP_TYPE (hev_socks5_client_udp_class ())
|
||||
|
||||
typedef struct _HevSocks5ClientUDP HevSocks5ClientUDP;
|
||||
typedef struct _HevSocks5ClientUDPClass HevSocks5ClientUDPClass;
|
||||
|
||||
struct _HevSocks5ClientUDP
|
||||
{
|
||||
HevSocks5Client base;
|
||||
|
||||
int fd;
|
||||
};
|
||||
|
||||
struct _HevSocks5ClientUDPClass
|
||||
{
|
||||
HevSocks5ClientClass base;
|
||||
|
||||
HevSocks5UDPIface udp;
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_client_udp_class (void);
|
||||
|
||||
int hev_socks5_client_udp_construct (HevSocks5ClientUDP *self,
|
||||
HevSocks5Type type);
|
||||
|
||||
HevSocks5ClientUDP *hev_socks5_client_udp_new (HevSocks5Type type);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_CLIENT_UDP_H__ */
|
||||
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-client.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Client
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
#include <hev-memory-allocator.h>
|
||||
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-client.h"
|
||||
|
||||
#define task_io_yielder hev_socks5_task_io_yielder
|
||||
|
||||
static int
|
||||
hev_socks5_client_connect_server (HevSocks5Client *self, const char *addr,
|
||||
int port)
|
||||
{
|
||||
HevSocks5Class *klass;
|
||||
struct sockaddr_in6 saddr;
|
||||
struct sockaddr *sap;
|
||||
int addr_family;
|
||||
int fd, res;
|
||||
|
||||
LOG_D ("%p socks5 client connect server", self);
|
||||
|
||||
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||
res = hev_socks5_name_into_sockaddr6 (addr, port, &saddr, &addr_family);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client resolve [%s]:%d", self, addr, port);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = hev_socks5_socket (SOCK_STREAM);
|
||||
if (fd < 0) {
|
||||
LOG_E ("%p socks5 client socket", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
sap = (struct sockaddr *)&saddr;
|
||||
klass = HEV_OBJECT_GET_CLASS (self);
|
||||
res = klass->binder (HEV_SOCKS5 (self), fd, sap);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client bind", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_task_io_socket_connect (fd, sap, sizeof (saddr), task_io_yielder,
|
||||
self);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client connect", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
HEV_SOCKS5 (self)->fd = fd;
|
||||
hev_socks5_set_addr_family (HEV_SOCKS5 (self), addr_family);
|
||||
LOG_D ("%p socks5 client connect server fd %d", self, fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_write_auth_methods (HevSocks5Client *self)
|
||||
{
|
||||
HevSocks5Auth auth;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 client write auth methods", self);
|
||||
|
||||
auth.ver = HEV_SOCKS5_VERSION_5;
|
||||
auth.method_len = 1;
|
||||
if (!self->auth.user || !self->auth.pass)
|
||||
auth.methods[0] = HEV_SOCKS5_AUTH_METHOD_NONE;
|
||||
else
|
||||
auth.methods[0] = HEV_SOCKS5_AUTH_METHOD_USER;
|
||||
|
||||
res = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, &auth, 3, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 client write auth methods", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_write_auth_creds (HevSocks5Client *self)
|
||||
{
|
||||
struct msghdr mh = { 0 };
|
||||
struct iovec iov[4];
|
||||
unsigned char ub[3];
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 client write auth creds", self);
|
||||
|
||||
if (!self->auth.user || !self->auth.pass)
|
||||
return 0;
|
||||
|
||||
ub[0] = HEV_SOCKS5_AUTH_VERSION_1;
|
||||
ub[1] = strlen (self->auth.user);
|
||||
ub[2] = strlen (self->auth.pass);
|
||||
iov[0].iov_base = &ub[0];
|
||||
iov[0].iov_len = 2;
|
||||
iov[1].iov_base = (void *)self->auth.user;
|
||||
iov[1].iov_len = ub[1];
|
||||
iov[2].iov_base = &ub[2];
|
||||
iov[2].iov_len = 1;
|
||||
iov[3].iov_base = (void *)self->auth.pass;
|
||||
iov[3].iov_len = ub[2];
|
||||
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = 4;
|
||||
res = hev_task_io_socket_sendmsg (HEV_SOCKS5 (self)->fd, &mh, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 client write auth creds", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_write_request (HevSocks5Client *self)
|
||||
{
|
||||
HevSocks5ClientClass *klass;
|
||||
struct msghdr mh = { 0 };
|
||||
struct iovec iov[2];
|
||||
HevSocks5Addr *addr;
|
||||
HevSocks5ReqRes req;
|
||||
int addrlen;
|
||||
int ret;
|
||||
|
||||
LOG_D ("%p socks5 client write request", self);
|
||||
|
||||
req.ver = HEV_SOCKS5_VERSION_5;
|
||||
req.rsv = 0;
|
||||
|
||||
switch (HEV_SOCKS5 (self)->type) {
|
||||
case HEV_SOCKS5_TYPE_TCP:
|
||||
req.cmd = HEV_SOCKS5_REQ_CMD_CONNECT;
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||
req.cmd = HEV_SOCKS5_REQ_CMD_FWD_UDP;
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||
req.cmd = HEV_SOCKS5_REQ_CMD_UDP_ASC;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov[0].iov_base = &req;
|
||||
iov[0].iov_len = 3;
|
||||
|
||||
klass = HEV_OBJECT_GET_CLASS (self);
|
||||
addr = klass->get_upstream_addr (self);
|
||||
|
||||
switch (addr->atype) {
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||
addrlen = 7;
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||
addrlen = 19;
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||
addrlen = 4 + addr->domain.len;
|
||||
break;
|
||||
default:
|
||||
LOG_E ("%p socks5 client req.atype %u", self, addr->atype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
iov[1].iov_base = addr;
|
||||
iov[1].iov_len = addrlen;
|
||||
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = 2;
|
||||
ret = hev_task_io_socket_sendmsg (HEV_SOCKS5 (self)->fd, &mh, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (ret <= 0) {
|
||||
LOG_E ("%p socks5 client write request", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hev_free (addr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_read_auth_method (HevSocks5Client *self)
|
||||
{
|
||||
HevSocks5Auth auth;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 client read auth method", self);
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &auth, 2, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 client read auth", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (auth.ver != HEV_SOCKS5_VERSION_5) {
|
||||
LOG_E ("%p socks5 client auth.ver %u", self, auth.ver);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return auth.method;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_read_auth_creds (HevSocks5Client *self)
|
||||
{
|
||||
HevSocks5ReqRes res;
|
||||
int ret;
|
||||
|
||||
LOG_D ("%p socks5 client read auth creds", self);
|
||||
|
||||
ret = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &res, 2, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (ret <= 0) {
|
||||
LOG_E ("%p socks5 client read auth creds", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res.ver != HEV_SOCKS5_AUTH_VERSION_1) {
|
||||
LOG_E ("%p socks5 client auth.res.ver %u", self, res.ver);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res.rep != HEV_SOCKS5_RES_REP_SUCC) {
|
||||
LOG_E ("%p socks5 client auth.res.rep %u", self, res.rep);
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 client auth done", self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_read_response (HevSocks5Client *self)
|
||||
{
|
||||
HevSocks5ClientClass *klass;
|
||||
HevSocks5ReqRes res;
|
||||
int addrlen;
|
||||
int ret;
|
||||
|
||||
LOG_D ("%p socks5 client read response", self);
|
||||
|
||||
ret = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &res, 4, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (ret <= 0) {
|
||||
LOG_E ("%p socks5 client read response", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res.ver != HEV_SOCKS5_VERSION_5) {
|
||||
LOG_E ("%p socks5 client res.ver %u", self, res.ver);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (res.rep != HEV_SOCKS5_RES_REP_SUCC) {
|
||||
LOG_E ("%p socks5 client res.rep %u", self, res.rep);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (res.addr.atype) {
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||
addrlen = 6;
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||
addrlen = 18;
|
||||
break;
|
||||
default:
|
||||
LOG_E ("%p socks5 client res.atype %u", self, res.addr.atype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &res.addr.ipv4,
|
||||
addrlen, MSG_WAITALL, task_io_yielder, self);
|
||||
if (ret <= 0) {
|
||||
LOG_E ("%p socks5 client read addr", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
klass = HEV_OBJECT_GET_CLASS (self);
|
||||
ret = klass->set_upstream_addr (self, &res.addr);
|
||||
if (ret < 0) {
|
||||
LOG_E ("%p socks5 client set upstream addr", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_client_connect (HevSocks5Client *self, const char *addr, int port)
|
||||
{
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 client connect [%s]:%d", self, addr, port);
|
||||
|
||||
res = hev_socks5_client_connect_server (self, addr, port);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 client connect", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_handshake_standard (HevSocks5Client *self)
|
||||
{
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 client handshake standard", self);
|
||||
|
||||
res = hev_socks5_client_write_auth_methods (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_client_read_auth_method (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
if (res == HEV_SOCKS5_AUTH_METHOD_USER) {
|
||||
res = hev_socks5_client_write_auth_creds (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_client_read_auth_creds (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
} else if (res != HEV_SOCKS5_AUTH_METHOD_NONE) {
|
||||
LOG_E ("%p socks5 client auth method %d", self, res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_socks5_client_write_request (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_client_read_response (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_client_handshake_pipeline (HevSocks5Client *self)
|
||||
{
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 client handshake pipeline", self);
|
||||
|
||||
res = hev_socks5_client_write_auth_methods (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_client_write_auth_creds (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_client_write_request (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_client_read_auth_method (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
if (res == HEV_SOCKS5_AUTH_METHOD_USER) {
|
||||
res = hev_socks5_client_read_auth_creds (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
} else if (res != HEV_SOCKS5_AUTH_METHOD_NONE) {
|
||||
LOG_E ("%p socks5 client auth method %d", self, res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_socks5_client_read_response (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_client_handshake (HevSocks5Client *self, int pipeline)
|
||||
{
|
||||
if (pipeline)
|
||||
return hev_socks5_client_handshake_pipeline (self);
|
||||
|
||||
return hev_socks5_client_handshake_standard (self);
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_client_set_auth (HevSocks5Client *self, const char *user,
|
||||
const char *pass)
|
||||
{
|
||||
LOG_D ("%p socks5 client set auth", self);
|
||||
|
||||
self->auth.user = user;
|
||||
self->auth.pass = pass;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_client_construct (HevSocks5Client *self, HevSocks5Type type)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_socks5_construct (&self->base, type);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_D ("%p socks5 client construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_CLIENT_TYPE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_client_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5Client *self = HEV_SOCKS5_CLIENT (base);
|
||||
|
||||
LOG_D ("%p socks5 client destruct", self);
|
||||
|
||||
HEV_SOCKS5_TYPE->destruct (base);
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_client_class (void)
|
||||
{
|
||||
static HevSocks5ClientClass klass;
|
||||
HevSocks5ClientClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
memcpy (kptr, HEV_SOCKS5_TYPE, sizeof (HevSocks5Class));
|
||||
|
||||
okptr->name = "HevSocks5Client";
|
||||
okptr->destruct = hev_socks5_client_destruct;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-client.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2024 hev
|
||||
Description : Socks5 Client
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_CLIENT_H__
|
||||
#define __HEV_SOCKS5_CLIENT_H__
|
||||
|
||||
#include "hev-socks5.h"
|
||||
#include "hev-socks5-proto.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_CLIENT(p) ((HevSocks5Client *)p)
|
||||
#define HEV_SOCKS5_CLIENT_CLASS(p) ((HevSocks5ClientClass *)p)
|
||||
#define HEV_SOCKS5_CLIENT_TYPE (hev_socks5_client_class ())
|
||||
|
||||
typedef struct _HevSocks5Client HevSocks5Client;
|
||||
typedef struct _HevSocks5ClientClass HevSocks5ClientClass;
|
||||
|
||||
struct _HevSocks5Client
|
||||
{
|
||||
HevSocks5 base;
|
||||
|
||||
struct
|
||||
{
|
||||
const char *user;
|
||||
const char *pass;
|
||||
} auth;
|
||||
};
|
||||
|
||||
struct _HevSocks5ClientClass
|
||||
{
|
||||
HevSocks5Class base;
|
||||
|
||||
HevSocks5Addr *(*get_upstream_addr) (HevSocks5Client *self);
|
||||
int (*set_upstream_addr) (HevSocks5Client *self, HevSocks5Addr *addr);
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_client_class (void);
|
||||
|
||||
int hev_socks5_client_construct (HevSocks5Client *self, HevSocks5Type type);
|
||||
|
||||
int hev_socks5_client_connect (HevSocks5Client *self, const char *addr,
|
||||
int port);
|
||||
|
||||
int hev_socks5_client_handshake (HevSocks5Client *self, int pipeline);
|
||||
|
||||
void hev_socks5_client_set_auth (HevSocks5Client *self, const char *user,
|
||||
const char *pass);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_CLIENT_H__ */
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-logger-priv.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 hev
|
||||
Description : Socks5 Logger Private
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_LOGGER_PRIV_H__
|
||||
#define __HEV_SOCKS5_LOGGER_PRIV_H__
|
||||
|
||||
#include "hev-socks5-logger.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define LOG_D(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_DEBUG, fmt)
|
||||
#define LOG_I(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_INFO, fmt)
|
||||
#define LOG_W(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_WARN, fmt)
|
||||
#define LOG_E(fmt...) hev_socks5_logger_log (HEV_SOCKS5_LOGGER_ERROR, fmt)
|
||||
|
||||
#define LOG_ON() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_UNSET)
|
||||
#define LOG_ON_D() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_DEBUG)
|
||||
#define LOG_ON_I() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_INFO)
|
||||
#define LOG_ON_W() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_WARN)
|
||||
#define LOG_ON_E() hev_socks5_logger_enabled (HEV_SOCKS5_LOGGER_ERROR)
|
||||
|
||||
int hev_socks5_logger_enabled (HevSocks5LoggerLevel level);
|
||||
void hev_socks5_logger_log (HevSocks5LoggerLevel level, const char *fmt, ...);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_LOGGER_PRIV_H__ */
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-logger.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 hev
|
||||
Description : Socks5 Logger
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "hev-socks5-logger.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
static int fd = -1;
|
||||
static HevSocks5LoggerLevel req_level;
|
||||
|
||||
int
|
||||
hev_socks5_logger_init (HevSocks5LoggerLevel level, const char *path)
|
||||
{
|
||||
req_level = level;
|
||||
|
||||
if (0 == strcmp (path, "stdout"))
|
||||
fd = dup (1);
|
||||
else if (0 == strcmp (path, "stderr"))
|
||||
fd = dup (2);
|
||||
else
|
||||
fd = open (path, O_WRONLY | O_APPEND | O_CREAT, 0640);
|
||||
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_logger_fini (void)
|
||||
{
|
||||
close (fd);
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_logger_enabled (HevSocks5LoggerLevel level)
|
||||
{
|
||||
if (fd >= 0 && level >= req_level)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_logger_log (HevSocks5LoggerLevel level, const char *fmt, ...)
|
||||
{
|
||||
struct iovec iov[4];
|
||||
const char *ts_fmt;
|
||||
char msg[1024];
|
||||
struct tm *ti;
|
||||
char ts[32];
|
||||
time_t now;
|
||||
va_list ap;
|
||||
int len;
|
||||
|
||||
if (fd < 0 || level < req_level)
|
||||
return;
|
||||
|
||||
time (&now);
|
||||
ti = localtime (&now);
|
||||
|
||||
ts_fmt = "[%04u-%02u-%02u %02u:%02u:%02u] ";
|
||||
len = snprintf (ts, sizeof (ts), ts_fmt, 1900 + ti->tm_year, 1 + ti->tm_mon,
|
||||
ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec);
|
||||
|
||||
iov[0].iov_base = ts;
|
||||
iov[0].iov_len = len;
|
||||
|
||||
switch (level) {
|
||||
case HEV_SOCKS5_LOGGER_DEBUG:
|
||||
iov[1].iov_base = "[D] ";
|
||||
break;
|
||||
case HEV_SOCKS5_LOGGER_INFO:
|
||||
iov[1].iov_base = "[I] ";
|
||||
break;
|
||||
case HEV_SOCKS5_LOGGER_WARN:
|
||||
iov[1].iov_base = "[W] ";
|
||||
break;
|
||||
case HEV_SOCKS5_LOGGER_ERROR:
|
||||
iov[1].iov_base = "[E] ";
|
||||
break;
|
||||
case HEV_SOCKS5_LOGGER_UNSET:
|
||||
iov[1].iov_base = "[?] ";
|
||||
break;
|
||||
}
|
||||
iov[1].iov_len = 4;
|
||||
|
||||
va_start (ap, fmt);
|
||||
iov[2].iov_base = msg;
|
||||
iov[2].iov_len = vsnprintf (msg, 1024, fmt, ap);
|
||||
va_end (ap);
|
||||
|
||||
iov[3].iov_base = "\n";
|
||||
iov[3].iov_len = 1;
|
||||
|
||||
if (writev (fd, iov, 4)) {
|
||||
/* ignore return value */
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-logger.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 hev
|
||||
Description : Socks5 Logger
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_LOGGER_H__
|
||||
#define __HEV_SOCKS5_LOGGER_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum _HevSocks5LoggerLevel HevSocks5LoggerLevel;
|
||||
|
||||
enum _HevSocks5LoggerLevel
|
||||
{
|
||||
HEV_SOCKS5_LOGGER_DEBUG,
|
||||
HEV_SOCKS5_LOGGER_INFO,
|
||||
HEV_SOCKS5_LOGGER_WARN,
|
||||
HEV_SOCKS5_LOGGER_ERROR,
|
||||
HEV_SOCKS5_LOGGER_UNSET,
|
||||
};
|
||||
|
||||
int hev_socks5_logger_init (HevSocks5LoggerLevel level, const char *path);
|
||||
void hev_socks5_logger_fini (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_LOGGER_H__ */
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-misc-priv.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Misc Private
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_MISC_PRIV_H__
|
||||
#define __HEV_SOCKS5_MISC_PRIV_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
|
||||
#include "hev-socks5-misc.h"
|
||||
#include "hev-socks5-proto.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int hev_socks5_socket (int type);
|
||||
|
||||
const char *hev_socks5_addr_into_str (const HevSocks5Addr *addr, char *buf,
|
||||
int len);
|
||||
|
||||
int hev_socks5_get_task_stack_size (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_MISC_PRIV_H__ */
|
||||
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-misc.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Misc
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
#include <hev-task-dns.h>
|
||||
#include <hev-memory-allocator.h>
|
||||
|
||||
#include "hev-socks5.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-misc.h"
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
|
||||
static int task_stack_size = 8192;
|
||||
static int udp_recv_buffer_size = 512 * 1024;
|
||||
|
||||
int
|
||||
hev_socks5_task_io_yielder (HevTaskYieldType type, void *data)
|
||||
{
|
||||
HevSocks5 *self = data;
|
||||
|
||||
if (type == HEV_TASK_YIELD) {
|
||||
hev_task_yield (HEV_TASK_YIELD);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (self->timeout < 0) {
|
||||
hev_task_yield (HEV_TASK_WAITIO);
|
||||
} else {
|
||||
int timeout = self->timeout;
|
||||
timeout = hev_task_sleep (timeout);
|
||||
if (timeout <= 0) {
|
||||
LOG_I ("%p io timeout", self);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_socket (int type)
|
||||
{
|
||||
HevTask *task = hev_task_self ();
|
||||
int fd, res, zero = 0;
|
||||
|
||||
fd = hev_task_io_socket_socket (AF_INET6, type, 0);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
|
||||
res = setsockopt (fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof (zero));
|
||||
if (res < 0) {
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||
if (res < 0)
|
||||
hev_task_mod_fd (task, fd, POLLIN | POLLOUT);
|
||||
|
||||
if (type == SOCK_DGRAM) {
|
||||
res = udp_recv_buffer_size;
|
||||
setsockopt (fd, SOL_SOCKET, SO_RCVBUF, &res, sizeof (res));
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_socks5_addr_into_str (const HevSocks5Addr *addr, char *buf, int len)
|
||||
{
|
||||
const char *res = buf;
|
||||
uint16_t port;
|
||||
char sa[256];
|
||||
|
||||
switch (addr->atype) {
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||
port = ntohs (addr->ipv4.port);
|
||||
inet_ntop (AF_INET, addr->ipv4.addr, sa, sizeof (sa));
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||
port = ntohs (addr->ipv6.port);
|
||||
inet_ntop (AF_INET6, addr->ipv6.addr, sa, sizeof (sa));
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||
memcpy (sa, addr->domain.addr, addr->domain.len);
|
||||
sa[addr->domain.len] = '\0';
|
||||
memcpy (&port, addr->domain.addr + addr->domain.len, 2);
|
||||
port = ntohs (port);
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf (buf, len, "[%s]:%u", sa, port);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_addr_len (const HevSocks5Addr *addr)
|
||||
{
|
||||
switch (addr->atype) {
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||
return 7;
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||
return 19;
|
||||
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||
return 4 + addr->domain.len;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_addr_from_name (HevSocks5Addr *addr, const char *name, int _port)
|
||||
{
|
||||
uint16_t port = _port;
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_NAME;
|
||||
strncpy ((char *)addr->domain.addr, name, 256);
|
||||
addr->domain.len = strlen ((char *)addr->domain.addr);
|
||||
memcpy ((char *)addr->domain.addr + addr->domain.len, &port, 2);
|
||||
return 4 + addr->domain.len;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_addr_from_ipv4 (HevSocks5Addr *addr, const void *ipv4, int port)
|
||||
{
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
|
||||
memcpy (addr->ipv4.addr, ipv4, sizeof (addr->ipv4.addr));
|
||||
addr->ipv4.port = port;
|
||||
return 7;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_addr_from_ipv6 (HevSocks5Addr *addr, const void *ipv6, int port)
|
||||
{
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV6;
|
||||
memcpy (addr->ipv6.addr, ipv6, sizeof (addr->ipv6.addr));
|
||||
addr->ipv6.port = port;
|
||||
return 19;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_addr_from_sockaddr6 (HevSocks5Addr *addr, struct sockaddr_in6 *saddr)
|
||||
{
|
||||
if (IN6_IS_ADDR_V4MAPPED (&saddr->sin6_addr)) {
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV4;
|
||||
addr->ipv4.port = saddr->sin6_port;
|
||||
memcpy (addr->ipv4.addr, &saddr->sin6_addr.s6_addr[12], 4);
|
||||
return 7;
|
||||
}
|
||||
|
||||
addr->atype = HEV_SOCKS5_ADDR_TYPE_IPV6;
|
||||
addr->ipv6.port = saddr->sin6_port;
|
||||
memcpy (addr->ipv6.addr, &saddr->sin6_addr, 16);
|
||||
return 19;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_ipv4_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||
struct sockaddr_in6 *saddr)
|
||||
{
|
||||
saddr->sin6_family = AF_INET6;
|
||||
saddr->sin6_port = addr->ipv4.port;
|
||||
memset (&saddr->sin6_addr, 0, 10);
|
||||
saddr->sin6_addr.s6_addr[10] = 0xff;
|
||||
saddr->sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy (&saddr->sin6_addr.s6_addr[12], addr->ipv4.addr, 4);
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_ipv6_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||
struct sockaddr_in6 *saddr)
|
||||
{
|
||||
saddr->sin6_family = AF_INET6;
|
||||
saddr->sin6_port = addr->ipv6.port;
|
||||
memcpy (&saddr->sin6_addr, addr->ipv6.addr, 16);
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_addr_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||
struct sockaddr_in6 *saddr, int *family)
|
||||
{
|
||||
switch (addr->atype) {
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV4: {
|
||||
hev_socks5_ipv4_into_sockaddr6 (addr, saddr);
|
||||
*family = HEV_SOCKS5_ADDR_FAMILY_IPV4;
|
||||
break;
|
||||
}
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV6: {
|
||||
hev_socks5_ipv6_into_sockaddr6 (addr, saddr);
|
||||
*family = HEV_SOCKS5_ADDR_FAMILY_IPV6;
|
||||
break;
|
||||
}
|
||||
case HEV_SOCKS5_ADDR_TYPE_NAME: {
|
||||
char name[256];
|
||||
uint16_t port;
|
||||
memcpy (name, addr->domain.addr, addr->domain.len);
|
||||
name[addr->domain.len] = '\0';
|
||||
memcpy (&port, addr->domain.addr + addr->domain.len, 2);
|
||||
return hev_socks5_name_into_sockaddr6 (name, ntohs (port), saddr,
|
||||
family);
|
||||
}
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_name_resolve_ipv4 (const char *name, struct sockaddr_in6 *saddr)
|
||||
{
|
||||
int res;
|
||||
|
||||
memset (&saddr->sin6_addr, 0, 10);
|
||||
res = inet_pton (AF_INET, name, &saddr->sin6_addr.s6_addr[12]);
|
||||
if (res == 0)
|
||||
return -1;
|
||||
|
||||
saddr->sin6_addr.s6_addr[10] = 0xff;
|
||||
saddr->sin6_addr.s6_addr[11] = 0xff;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_name_resolve_ipv6 (const char *name, struct sockaddr_in6 *saddr)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = inet_pton (AF_INET6, name, &saddr->sin6_addr);
|
||||
if (res == 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_name_resolve_name (const char *name, struct sockaddr_in6 *saddr,
|
||||
int *family)
|
||||
{
|
||||
struct addrinfo *result = NULL;
|
||||
struct addrinfo hints = { 0 };
|
||||
int res = 0;
|
||||
|
||||
hints.ai_family = *family;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
hev_task_dns_getaddrinfo (name, NULL, &hints, &result);
|
||||
if (!result)
|
||||
return -1;
|
||||
|
||||
switch (result->ai_family) {
|
||||
case AF_INET: {
|
||||
struct sockaddr_in *sa = (struct sockaddr_in *)result->ai_addr;
|
||||
memset (&saddr->sin6_addr, 0, 10);
|
||||
saddr->sin6_addr.s6_addr[10] = 0xff;
|
||||
saddr->sin6_addr.s6_addr[11] = 0xff;
|
||||
memcpy (&saddr->sin6_addr.s6_addr[12], &sa->sin_addr, 4);
|
||||
*family = HEV_SOCKS5_ADDR_FAMILY_IPV4;
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
struct sockaddr_in6 *sa = (struct sockaddr_in6 *)result->ai_addr;
|
||||
memcpy (&saddr->sin6_addr, &sa->sin6_addr, 16);
|
||||
*family = HEV_SOCKS5_ADDR_FAMILY_IPV6;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = -1;
|
||||
}
|
||||
|
||||
freeaddrinfo (result);
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_name_into_sockaddr6 (const char *name, int port,
|
||||
struct sockaddr_in6 *saddr, int *family)
|
||||
{
|
||||
int res;
|
||||
|
||||
saddr->sin6_family = AF_INET6;
|
||||
saddr->sin6_port = htons (port);
|
||||
|
||||
res = hev_socks5_name_resolve_ipv4 (name, saddr);
|
||||
if (res == 0) {
|
||||
*family = HEV_SOCKS5_ADDR_FAMILY_IPV4;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = hev_socks5_name_resolve_ipv6 (name, saddr);
|
||||
if (res == 0) {
|
||||
*family = HEV_SOCKS5_ADDR_FAMILY_IPV6;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = hev_socks5_name_resolve_name (name, saddr, family);
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_set_task_stack_size (int stack_size)
|
||||
{
|
||||
task_stack_size = stack_size;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_get_task_stack_size (void)
|
||||
{
|
||||
return task_stack_size;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_set_udp_recv_buffer_size (int buffer_size)
|
||||
{
|
||||
udp_recv_buffer_size = buffer_size;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-misc.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Misc
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_MISC_H__
|
||||
#define __HEV_SOCKS5_MISC_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
|
||||
#include "hev-socks5-proto.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int hev_socks5_task_io_yielder (HevTaskYieldType type, void *data);
|
||||
|
||||
void hev_socks5_set_task_stack_size (int stack_size);
|
||||
void hev_socks5_set_udp_recv_buffer_size (int buffer_size);
|
||||
|
||||
int hev_socks5_addr_len (const HevSocks5Addr *addr);
|
||||
int hev_socks5_addr_from_name (HevSocks5Addr *addr, const char *name, int port);
|
||||
int hev_socks5_addr_from_ipv4 (HevSocks5Addr *addr, const void *ipv4, int port);
|
||||
int hev_socks5_addr_from_ipv6 (HevSocks5Addr *addr, const void *ipv6, int port);
|
||||
int hev_socks5_addr_from_sockaddr6 (HevSocks5Addr *addr,
|
||||
struct sockaddr_in6 *saddr);
|
||||
int hev_socks5_addr_into_sockaddr6 (const HevSocks5Addr *addr,
|
||||
struct sockaddr_in6 *saddr, int *family);
|
||||
int hev_socks5_name_into_sockaddr6 (const char *host, int port,
|
||||
struct sockaddr_in6 *saddr, int *family);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_MISC_H__ */
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-proto.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2023 hev
|
||||
Description : Socks5 Proto
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_PROTO_H__
|
||||
#define __HEV_SOCKS5_PROTO_H__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum _HevSocks5Version HevSocks5Version;
|
||||
typedef enum _HevSocks5AuthMethod HevSocks5AuthMethod;
|
||||
typedef enum _HevSocks5AuthVersion HevSocks5AuthVersion;
|
||||
typedef enum _HevSocks5ReqCmd HevSocks5ReqCmd;
|
||||
typedef enum _HevSocks5ResRep HevSocks5ResRep;
|
||||
typedef enum _HevSocks5AddrType HevSocks5AddrType;
|
||||
|
||||
typedef struct _HevSocks5Auth HevSocks5Auth;
|
||||
typedef struct _HevSocks5Addr HevSocks5Addr;
|
||||
typedef struct _HevSocks5ReqRes HevSocks5ReqRes;
|
||||
typedef struct _HevSocks5UDPHdr HevSocks5UDPHdr;
|
||||
|
||||
enum _HevSocks5Version
|
||||
{
|
||||
HEV_SOCKS5_VERSION_5 = 5,
|
||||
};
|
||||
|
||||
enum _HevSocks5AuthMethod
|
||||
{
|
||||
HEV_SOCKS5_AUTH_METHOD_NONE = 0,
|
||||
HEV_SOCKS5_AUTH_METHOD_USER = 2,
|
||||
HEV_SOCKS5_AUTH_METHOD_DENY = 255,
|
||||
};
|
||||
|
||||
enum _HevSocks5AuthVersion
|
||||
{
|
||||
HEV_SOCKS5_AUTH_VERSION_1 = 1,
|
||||
};
|
||||
|
||||
enum _HevSocks5ReqCmd
|
||||
{
|
||||
HEV_SOCKS5_REQ_CMD_CONNECT = 1,
|
||||
HEV_SOCKS5_REQ_CMD_UDP_ASC = 3,
|
||||
HEV_SOCKS5_REQ_CMD_FWD_UDP = 5,
|
||||
};
|
||||
|
||||
enum _HevSocks5ResRep
|
||||
{
|
||||
HEV_SOCKS5_RES_REP_SUCC = 0,
|
||||
HEV_SOCKS5_RES_REP_FAIL = 1,
|
||||
HEV_SOCKS5_RES_REP_HOST = 4,
|
||||
HEV_SOCKS5_RES_REP_IMPL = 7,
|
||||
HEV_SOCKS5_RES_REP_ADDR = 8,
|
||||
};
|
||||
|
||||
enum _HevSocks5AddrType
|
||||
{
|
||||
HEV_SOCKS5_ADDR_TYPE_IPV4 = 1,
|
||||
HEV_SOCKS5_ADDR_TYPE_IPV6 = 4,
|
||||
HEV_SOCKS5_ADDR_TYPE_NAME = 3,
|
||||
};
|
||||
|
||||
struct _HevSocks5Auth
|
||||
{
|
||||
uint8_t ver;
|
||||
union
|
||||
{
|
||||
uint8_t method;
|
||||
uint8_t method_len;
|
||||
};
|
||||
uint8_t methods[256];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct _HevSocks5Addr
|
||||
{
|
||||
uint8_t atype;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t addr[4];
|
||||
uint16_t port;
|
||||
} ipv4 __attribute__ ((packed));
|
||||
struct
|
||||
{
|
||||
uint8_t addr[16];
|
||||
uint16_t port;
|
||||
} ipv6 __attribute__ ((packed));
|
||||
struct
|
||||
{
|
||||
uint8_t len;
|
||||
uint8_t addr[256 + 2];
|
||||
} domain;
|
||||
};
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct _HevSocks5ReqRes
|
||||
{
|
||||
uint8_t ver;
|
||||
union
|
||||
{
|
||||
uint8_t cmd;
|
||||
uint8_t rep;
|
||||
};
|
||||
uint8_t rsv;
|
||||
HevSocks5Addr addr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct _HevSocks5UDPHdr
|
||||
{
|
||||
union
|
||||
{
|
||||
uint8_t rsv[3];
|
||||
struct
|
||||
{
|
||||
uint16_t datlen;
|
||||
uint8_t hdrlen;
|
||||
} __attribute__ ((packed));
|
||||
};
|
||||
HevSocks5Addr addr;
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_PROTO_H__ */
|
||||
@@ -0,0 +1,688 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-server.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 Server
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
#include <hev-memory-allocator.h>
|
||||
|
||||
#include "hev-socks5-proto.h"
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-server.h"
|
||||
|
||||
#define task_io_yielder hev_socks5_task_io_yielder
|
||||
|
||||
HevSocks5Server *
|
||||
hev_socks5_server_new (int fd)
|
||||
{
|
||||
HevSocks5Server *self;
|
||||
int res;
|
||||
|
||||
self = hev_malloc0 (sizeof (HevSocks5Server));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
res = hev_socks5_server_construct (self, fd);
|
||||
if (res < 0) {
|
||||
hev_free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 server new", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_server_set_auth (HevSocks5Server *self, HevSocks5Authenticator *auth)
|
||||
{
|
||||
if (self->auth)
|
||||
hev_object_unref (HEV_OBJECT (self->auth));
|
||||
|
||||
hev_object_ref (HEV_OBJECT (auth));
|
||||
self->auth = auth;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_server_set_connect_timeout (HevSocks5Server *self, int timeout)
|
||||
{
|
||||
self->timeout = timeout;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_read_auth_method (HevSocks5Server *self)
|
||||
{
|
||||
HevSocks5Auth auth;
|
||||
HevSocks5AuthMethod method;
|
||||
int res;
|
||||
int i;
|
||||
|
||||
LOG_D ("%p socks5 server read auth method", self);
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &auth, 2, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server read auth method", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (auth.ver != HEV_SOCKS5_VERSION_5) {
|
||||
LOG_E ("%p socks5 server auth.ver %u", self, auth.ver);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &auth.methods,
|
||||
auth.method_len, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server read auth methods", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (self->auth)
|
||||
method = HEV_SOCKS5_AUTH_METHOD_USER;
|
||||
else
|
||||
method = HEV_SOCKS5_AUTH_METHOD_NONE;
|
||||
|
||||
res = -1;
|
||||
for (i = 0; i < auth.method_len; i++) {
|
||||
if (auth.methods[i] == method) {
|
||||
res = method;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_write_auth_method (HevSocks5Server *self, int auth_method)
|
||||
{
|
||||
HevSocks5Auth auth;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 server write auth method", self);
|
||||
|
||||
auth.ver = HEV_SOCKS5_VERSION_5;
|
||||
auth.method = auth_method;
|
||||
|
||||
res = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, &auth, 2, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server write auth method", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_read_auth_user (HevSocks5Server *self)
|
||||
{
|
||||
HevSocks5User *user;
|
||||
uint8_t nlen, plen;
|
||||
uint8_t name[257];
|
||||
uint8_t pass[257];
|
||||
uint8_t head[2];
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 server read auth user", self);
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, head, 2, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server read auth user.ver", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (head[0] != 1) {
|
||||
LOG_E ("%p socks5 server auth user.ver %u", self, head[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlen = head[1];
|
||||
if (nlen == 0) {
|
||||
LOG_E ("%p socks5 server auth user.nlen %u", self, nlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, name, nlen + 1,
|
||||
MSG_WAITALL, task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server read auth user.name", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
plen = name[nlen];
|
||||
if (plen == 0) {
|
||||
LOG_E ("%p socks5 server auth user.plen %u", self, plen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, pass, plen,
|
||||
MSG_WAITALL, task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server read auth user.pass", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
user = hev_socks5_authenticator_get (self->auth, (char *)name, nlen);
|
||||
if (!user) {
|
||||
LOG_E ("%p socks5 server auth user: %s pass: %s", self, name, pass);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = hev_socks5_user_check (user, (char *)pass, plen);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server auth user: %s pass: %s", self, name, pass);
|
||||
return -1;
|
||||
}
|
||||
|
||||
hev_object_ref (HEV_OBJECT (user));
|
||||
hev_object_unref (HEV_OBJECT (self->auth));
|
||||
self->user = user;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_write_auth_user (HevSocks5Server *self, int auth_res)
|
||||
{
|
||||
uint8_t buf[2];
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 server write auth user", self);
|
||||
|
||||
buf[0] = 1;
|
||||
buf[1] = auth_res;
|
||||
|
||||
res = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, buf, 2, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server write auth user", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_auth (HevSocks5Server *self)
|
||||
{
|
||||
int method;
|
||||
int res;
|
||||
|
||||
method = hev_socks5_server_read_auth_method (self);
|
||||
res = hev_socks5_server_write_auth_method (self, method);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
switch (method) {
|
||||
case HEV_SOCKS5_AUTH_METHOD_NONE:
|
||||
break;
|
||||
case HEV_SOCKS5_AUTH_METHOD_USER:
|
||||
res = hev_socks5_server_read_auth_user (self);
|
||||
res |= hev_socks5_server_write_auth_user (self, res);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_read_request (HevSocks5Server *self, int *cmd, int *rep,
|
||||
struct sockaddr_in6 *addr)
|
||||
{
|
||||
HevSocks5ReqRes req;
|
||||
int addr_family;
|
||||
int addrlen;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 server read request", self);
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, &req, 5, MSG_WAITALL,
|
||||
task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
LOG_E ("%p socks5 server read request", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (req.ver != HEV_SOCKS5_VERSION_5) {
|
||||
*rep = HEV_SOCKS5_RES_REP_FAIL;
|
||||
LOG_E ("%p socks5 server req.ver %u", self, req.ver);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (req.addr.atype) {
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV4:
|
||||
addrlen = 5;
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_IPV6:
|
||||
addrlen = 17;
|
||||
break;
|
||||
case HEV_SOCKS5_ADDR_TYPE_NAME:
|
||||
addrlen = 2 + req.addr.domain.len;
|
||||
break;
|
||||
default:
|
||||
*rep = HEV_SOCKS5_RES_REP_ADDR;
|
||||
LOG_E ("%p socks5 server req.atype %u", self, req.addr.atype);
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = hev_task_io_socket_recv (HEV_SOCKS5 (self)->fd, req.addr.domain.addr,
|
||||
addrlen, MSG_WAITALL, task_io_yielder, self);
|
||||
if (res <= 0) {
|
||||
*rep = HEV_SOCKS5_RES_REP_ADDR;
|
||||
LOG_E ("%p socks5 server read addr", self);
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||
res = hev_socks5_addr_into_sockaddr6 (&req.addr, addr, &addr_family);
|
||||
if (res < 0) {
|
||||
*rep = HEV_SOCKS5_RES_REP_ADDR;
|
||||
LOG_I ("%p socks5 server resolve addr", self);
|
||||
return 0;
|
||||
}
|
||||
hev_socks5_set_addr_family (HEV_SOCKS5 (self), addr_family);
|
||||
|
||||
if (LOG_ON ()) {
|
||||
const char *type;
|
||||
const char *str;
|
||||
char buf[272];
|
||||
|
||||
switch (req.cmd) {
|
||||
case HEV_SOCKS5_REQ_CMD_CONNECT:
|
||||
type = "tcp";
|
||||
break;
|
||||
case HEV_SOCKS5_REQ_CMD_UDP_ASC:
|
||||
case HEV_SOCKS5_REQ_CMD_FWD_UDP:
|
||||
type = "udp";
|
||||
break;
|
||||
default:
|
||||
type = "unknown";
|
||||
break;
|
||||
}
|
||||
|
||||
str = hev_socks5_addr_into_str (&req.addr, buf, sizeof (buf));
|
||||
LOG_I ("%p socks5 server %s %s", self, type, str);
|
||||
}
|
||||
|
||||
*cmd = req.cmd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_write_response (HevSocks5Server *self, int rep,
|
||||
struct sockaddr_in6 *addr)
|
||||
{
|
||||
HevSocks5ReqRes res;
|
||||
int ret;
|
||||
|
||||
LOG_D ("%p socks5 server write response", self);
|
||||
|
||||
res.ver = HEV_SOCKS5_VERSION_5;
|
||||
res.rep = rep;
|
||||
res.rsv = 0;
|
||||
|
||||
ret = hev_socks5_addr_from_sockaddr6 (&res.addr, addr);
|
||||
ret = hev_task_io_socket_send (HEV_SOCKS5 (self)->fd, &res, 3 + ret,
|
||||
MSG_WAITALL, task_io_yielder, self);
|
||||
if (ret <= 0) {
|
||||
LOG_E ("%p socks5 server write response", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_connect (HevSocks5Server *self, struct sockaddr_in6 *addr)
|
||||
{
|
||||
HevSocks5Class *klass;
|
||||
int timeout;
|
||||
int res;
|
||||
int fd;
|
||||
|
||||
LOG_D ("%p socks5 server connect", self);
|
||||
|
||||
fd = hev_socks5_socket (SOCK_STREAM);
|
||||
if (fd < 0) {
|
||||
LOG_E ("%p socks5 server socket stream", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
klass = HEV_OBJECT_GET_CLASS (self);
|
||||
res = klass->binder (HEV_SOCKS5 (self), fd, (struct sockaddr *)addr);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server bind", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
timeout = hev_socks5_get_timeout (HEV_SOCKS5 (self));
|
||||
hev_socks5_set_timeout (HEV_SOCKS5 (self), self->timeout);
|
||||
res = hev_task_io_socket_connect (fd, (struct sockaddr *)addr,
|
||||
sizeof (*addr), task_io_yielder, self);
|
||||
hev_socks5_set_timeout (HEV_SOCKS5 (self), timeout);
|
||||
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server connect", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->fds[0] = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_bind (HevSocks5Server *self, struct sockaddr_in6 *addr)
|
||||
{
|
||||
HevSocks5ServerClass *sskptr = HEV_OBJECT_GET_CLASS (self);
|
||||
socklen_t alen;
|
||||
int one = 1;
|
||||
int res;
|
||||
int fd;
|
||||
|
||||
LOG_D ("%p socks5 server bind", self);
|
||||
|
||||
fd = hev_socks5_socket (SOCK_DGRAM);
|
||||
if (fd < 0) {
|
||||
LOG_E ("%p socks5 server socket dgram", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->fds[0] = fd;
|
||||
|
||||
if (!addr)
|
||||
return 0;
|
||||
|
||||
fd = hev_socks5_socket (SOCK_DGRAM);
|
||||
if (fd < 0) {
|
||||
LOG_E ("%p socks5 server socket dgram", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof (one));
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server socket reuse", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = sskptr->binder (self, fd, (struct sockaddr *)addr);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server bind", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
alen = sizeof (struct sockaddr_in6);
|
||||
res = getsockname (fd, (struct sockaddr *)addr, &alen);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server socket name", self);
|
||||
hev_task_del_fd (hev_task_self (), fd);
|
||||
close (fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->fds[1] = fd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_udp_bind (HevSocks5Server *self, int sock,
|
||||
const struct sockaddr *src)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t alen;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 server udp bind", self);
|
||||
|
||||
alen = sizeof (struct sockaddr_in6);
|
||||
res = getsockname (HEV_SOCKS5 (self)->fd, (struct sockaddr *)&addr, &alen);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server socket name", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
addr.sin6_port = 0;
|
||||
res = bind (sock, (struct sockaddr *)&addr, alen);
|
||||
if (res < 0) {
|
||||
LOG_E ("%p socks5 server socket bind", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_handshake (HevSocks5Server *self)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
int cmd;
|
||||
int rep;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 server handshake", self);
|
||||
|
||||
res = hev_socks5_server_auth (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
rep = HEV_SOCKS5_RES_REP_SUCC;
|
||||
res = hev_socks5_server_read_request (self, &cmd, &rep, &addr);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
if (rep == HEV_SOCKS5_RES_REP_SUCC) {
|
||||
switch (cmd) {
|
||||
case HEV_SOCKS5_REQ_CMD_CONNECT:
|
||||
res = hev_socks5_server_connect (self, &addr);
|
||||
if (res < 0)
|
||||
rep = HEV_SOCKS5_RES_REP_HOST;
|
||||
HEV_SOCKS5 (self)->type = HEV_SOCKS5_TYPE_TCP;
|
||||
break;
|
||||
case HEV_SOCKS5_REQ_CMD_UDP_ASC:
|
||||
res = hev_socks5_server_bind (self, &addr);
|
||||
if (res < 0)
|
||||
rep = HEV_SOCKS5_RES_REP_FAIL;
|
||||
HEV_SOCKS5 (self)->type = HEV_SOCKS5_TYPE_UDP_IN_UDP;
|
||||
break;
|
||||
case HEV_SOCKS5_REQ_CMD_FWD_UDP:
|
||||
res = hev_socks5_server_bind (self, NULL);
|
||||
if (res < 0)
|
||||
rep = HEV_SOCKS5_RES_REP_FAIL;
|
||||
HEV_SOCKS5 (self)->type = HEV_SOCKS5_TYPE_UDP_IN_TCP;
|
||||
break;
|
||||
default:
|
||||
rep = HEV_SOCKS5_RES_REP_IMPL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
res = hev_socks5_server_write_response (self, rep, &addr);
|
||||
if ((res < 0) || (rep != HEV_SOCKS5_RES_REP_SUCC))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_service (HevSocks5Server *self)
|
||||
{
|
||||
LOG_D ("%p socks5 server service", self);
|
||||
|
||||
switch (HEV_SOCKS5 (self)->type) {
|
||||
case HEV_SOCKS5_TYPE_TCP:
|
||||
hev_socks5_tcp_splice (HEV_SOCKS5_TCP (self), self->fds[0]);
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||
hev_socks5_udp_splice (HEV_SOCKS5_UDP (self), self->fds[0]);
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||
hev_socks5_udp_splice (HEV_SOCKS5_UDP (self), self->fds[0]);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_server_run (HevSocks5Server *self)
|
||||
{
|
||||
HevTask *task = hev_task_self ();
|
||||
int res;
|
||||
int fd;
|
||||
|
||||
LOG_D ("%p socks5 server run", self);
|
||||
|
||||
fd = HEV_SOCKS5 (self)->fd;
|
||||
res = hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||
if (res < 0)
|
||||
hev_task_mod_fd (task, fd, POLLIN | POLLOUT);
|
||||
|
||||
res = hev_socks5_server_handshake (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_socks5_server_service (self);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_server_get_fd (HevSocks5UDP *self)
|
||||
{
|
||||
int fd;
|
||||
|
||||
switch (HEV_SOCKS5 (self)->type) {
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||
fd = HEV_SOCKS5 (self)->fd;
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||
fd = HEV_SOCKS5_SERVER (self)->fds[1];
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_server_construct (HevSocks5Server *self, int fd)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_socks5_construct (&self->base, HEV_SOCKS5_TYPE_NONE);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_D ("%p socks5 server construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_SERVER_TYPE;
|
||||
|
||||
HEV_SOCKS5 (self)->fd = fd;
|
||||
|
||||
self->fds[0] = -1;
|
||||
self->fds[1] = -1;
|
||||
self->timeout = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_server_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5Server *self = HEV_SOCKS5_SERVER (base);
|
||||
HevTask *task = hev_task_self ();
|
||||
|
||||
LOG_D ("%p socks5 server destruct", self);
|
||||
|
||||
if (self->fds[0] >= 0) {
|
||||
hev_task_del_fd (task, self->fds[0]);
|
||||
close (self->fds[0]);
|
||||
}
|
||||
if (self->fds[1] >= 0) {
|
||||
hev_task_del_fd (task, self->fds[1]);
|
||||
close (self->fds[1]);
|
||||
}
|
||||
|
||||
if (self->obj)
|
||||
hev_object_unref (self->obj);
|
||||
|
||||
HEV_SOCKS5_TYPE->destruct (base);
|
||||
}
|
||||
|
||||
static void *
|
||||
hev_socks5_server_iface (HevObject *base, void *type)
|
||||
{
|
||||
HevSocks5ServerClass *klass = HEV_OBJECT_GET_CLASS (base);
|
||||
|
||||
if (type == HEV_SOCKS5_TCP_TYPE)
|
||||
return &klass->tcp;
|
||||
|
||||
if (type == HEV_SOCKS5_UDP_TYPE)
|
||||
return &klass->udp;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_server_class (void)
|
||||
{
|
||||
static HevSocks5ServerClass klass;
|
||||
HevSocks5ServerClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
HevSocks5TCPIface *tiptr;
|
||||
HevSocks5UDPIface *uiptr;
|
||||
|
||||
memcpy (kptr, HEV_SOCKS5_TYPE, sizeof (HevSocks5Class));
|
||||
|
||||
okptr->name = "HevSocks5Server";
|
||||
okptr->destruct = hev_socks5_server_destruct;
|
||||
okptr->iface = hev_socks5_server_iface;
|
||||
|
||||
kptr->binder = hev_socks5_server_udp_bind;
|
||||
|
||||
tiptr = &kptr->tcp;
|
||||
memcpy (tiptr, HEV_SOCKS5_TCP_TYPE, sizeof (HevSocks5TCPIface));
|
||||
|
||||
uiptr = &kptr->udp;
|
||||
memcpy (uiptr, HEV_SOCKS5_UDP_TYPE, sizeof (HevSocks5UDPIface));
|
||||
uiptr->get_fd = hev_socks5_server_get_fd;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-server.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2023 hev
|
||||
Description : Socks5 Server
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_SERVER_H__
|
||||
#define __HEV_SOCKS5_SERVER_H__
|
||||
|
||||
#include <hev-object.h>
|
||||
|
||||
#include "hev-socks5.h"
|
||||
#include "hev-socks5-tcp.h"
|
||||
#include "hev-socks5-udp.h"
|
||||
#include "hev-socks5-user.h"
|
||||
#include "hev-socks5-authenticator.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_SERVER(p) ((HevSocks5Server *)p)
|
||||
#define HEV_SOCKS5_SERVER_CLASS(p) ((HevSocks5ServerClass *)p)
|
||||
#define HEV_SOCKS5_SERVER_TYPE (hev_socks5_server_class ())
|
||||
|
||||
typedef struct _HevSocks5Server HevSocks5Server;
|
||||
typedef struct _HevSocks5ServerClass HevSocks5ServerClass;
|
||||
|
||||
struct _HevSocks5Server
|
||||
{
|
||||
HevSocks5 base;
|
||||
|
||||
int fds[2];
|
||||
int timeout;
|
||||
|
||||
union
|
||||
{
|
||||
HevObject *obj;
|
||||
HevSocks5User *user;
|
||||
HevSocks5Authenticator *auth;
|
||||
};
|
||||
};
|
||||
|
||||
struct _HevSocks5ServerClass
|
||||
{
|
||||
HevSocks5Class base;
|
||||
|
||||
int (*binder) (HevSocks5Server *self, int sock, const struct sockaddr *src);
|
||||
|
||||
HevSocks5TCPIface tcp;
|
||||
HevSocks5UDPIface udp;
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_server_class (void);
|
||||
|
||||
int hev_socks5_server_construct (HevSocks5Server *self, int fd);
|
||||
|
||||
HevSocks5Server *hev_socks5_server_new (int fd);
|
||||
|
||||
void hev_socks5_server_set_auth (HevSocks5Server *self,
|
||||
HevSocks5Authenticator *auth);
|
||||
void hev_socks5_server_set_connect_timeout (HevSocks5Server *self, int timeout);
|
||||
|
||||
int hev_socks5_server_run (HevSocks5Server *self);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_SERVER_H__ */
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-tcp.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 hev
|
||||
Description : Socks5 TCP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include "hev-socks5.h"
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-tcp.h"
|
||||
|
||||
#define task_io_yielder hev_socks5_task_io_yielder
|
||||
|
||||
static int
|
||||
hev_socks5_tcp_splicer (HevSocks5TCP *self, int fd)
|
||||
{
|
||||
HevTask *task = hev_task_self ();
|
||||
int cfd;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 tcp splicer", self);
|
||||
|
||||
cfd = HEV_SOCKS5 (self)->fd;
|
||||
if (cfd < 0)
|
||||
return -1;
|
||||
|
||||
res = hev_task_add_fd (task, fd, POLLIN | POLLOUT);
|
||||
if (res < 0)
|
||||
hev_task_mod_fd (task, fd, POLLIN | POLLOUT);
|
||||
|
||||
hev_task_io_splice (cfd, cfd, fd, fd, 8192, task_io_yielder, self);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_tcp_splice (HevSocks5TCP *self, int fd)
|
||||
{
|
||||
HevSocks5TCPIface *iface;
|
||||
|
||||
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_TCP_TYPE);
|
||||
return iface->splicer (self, fd);
|
||||
}
|
||||
|
||||
void *
|
||||
hev_socks5_tcp_iface (void)
|
||||
{
|
||||
static HevSocks5TCPIface type = {
|
||||
.splicer = hev_socks5_tcp_splicer,
|
||||
};
|
||||
|
||||
return &type;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-tcp.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 hev
|
||||
Description : Socks5 TCP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_TCP_H__
|
||||
#define __HEV_SOCKS5_TCP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_TCP(p) ((HevSocks5TCP *)p)
|
||||
#define HEV_SOCKS5_TCP_IFACE(p) ((HevSocks5TCPIface *)p)
|
||||
#define HEV_SOCKS5_TCP_TYPE (hev_socks5_tcp_iface ())
|
||||
|
||||
typedef void HevSocks5TCP;
|
||||
typedef struct _HevSocks5TCPIface HevSocks5TCPIface;
|
||||
|
||||
struct _HevSocks5TCPIface
|
||||
{
|
||||
int (*splicer) (HevSocks5TCP *self, int fd);
|
||||
};
|
||||
|
||||
void *hev_socks5_tcp_iface (void);
|
||||
|
||||
int hev_socks5_tcp_splice (HevSocks5TCP *self, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_TCP_H__ */
|
||||
@@ -0,0 +1,420 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-udp.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 UDP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
|
||||
#include "hev-socks5.h"
|
||||
#include "hev-socks5-misc-priv.h"
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-udp.h"
|
||||
|
||||
typedef enum _HevSocks5UDPAlive HevSocks5UDPAlive;
|
||||
typedef struct _HevSocks5UDPSplice HevSocks5UDPSplice;
|
||||
|
||||
enum _HevSocks5UDPAlive
|
||||
{
|
||||
HEV_SOCKS5_UDP_ALIVE_F = (1 << 0),
|
||||
HEV_SOCKS5_UDP_ALIVE_B = (1 << 1),
|
||||
};
|
||||
|
||||
struct _HevSocks5UDPSplice
|
||||
{
|
||||
HevSocks5UDP *udp;
|
||||
HevSocks5UDPAlive alive;
|
||||
int bind;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static int
|
||||
task_io_yielder (HevTaskYieldType type, void *data)
|
||||
{
|
||||
HevSocks5 *self = data;
|
||||
|
||||
if (self->type == HEV_SOCKS5_TYPE_UDP_IN_UDP) {
|
||||
ssize_t res;
|
||||
char buf;
|
||||
|
||||
res = recv (self->fd, &buf, sizeof (buf), 0);
|
||||
if ((res == 0) || ((res < 0) && (errno != EAGAIN))) {
|
||||
hev_socks5_set_timeout (self, 0);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return hev_socks5_task_io_yielder (type, data);
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_udp_get_fd (HevSocks5UDP *self)
|
||||
{
|
||||
HevSocks5UDPIface *iface;
|
||||
|
||||
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_UDP_TYPE);
|
||||
return iface->get_fd (self);
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_udp_sendto (HevSocks5UDP *self, const void *buf, size_t len,
|
||||
const HevSocks5Addr *addr)
|
||||
{
|
||||
HevSocks5UDPHdr udp;
|
||||
struct iovec iov[3];
|
||||
struct msghdr mh;
|
||||
int addrlen;
|
||||
int res;
|
||||
|
||||
LOG_D ("%p socks5 udp sendto", self);
|
||||
|
||||
addrlen = hev_socks5_addr_len (addr);
|
||||
if (addrlen <= 0) {
|
||||
LOG_D ("%p socks5 udp addr", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (HEV_SOCKS5 (self)->type) {
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||
udp.datlen = htons (len);
|
||||
udp.hdrlen = 3 + addrlen;
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||
udp.datlen = 0;
|
||||
udp.hdrlen = 0;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (&mh, 0, sizeof (mh));
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = 3;
|
||||
|
||||
iov[0].iov_base = &udp;
|
||||
iov[0].iov_len = 3;
|
||||
iov[1].iov_base = (void *)addr;
|
||||
iov[1].iov_len = addrlen;
|
||||
iov[2].iov_base = (void *)buf;
|
||||
iov[2].iov_len = len;
|
||||
|
||||
res = hev_task_io_socket_sendmsg (hev_socks5_udp_get_fd (self), &mh,
|
||||
MSG_WAITALL, task_io_yielder, self);
|
||||
if (res <= 0)
|
||||
LOG_D ("%p socks5 udp write udp", self);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_udp_recvfrom_tcp (HevSocks5UDP *self, void *buf, size_t len,
|
||||
HevSocks5Addr *addr)
|
||||
{
|
||||
HevSocks5UDPHdr udp;
|
||||
struct iovec iov[2];
|
||||
struct msghdr mh;
|
||||
int res;
|
||||
int fd;
|
||||
|
||||
LOG_D ("%p socks5 udp recvfrom tcp", self);
|
||||
|
||||
fd = hev_socks5_udp_get_fd (self);
|
||||
res = hev_task_io_socket_recv (fd, &udp, 5, MSG_WAITALL, task_io_yielder,
|
||||
self);
|
||||
if (res <= 0) {
|
||||
LOG_D ("%p socks5 udp read udp head", self);
|
||||
return res;
|
||||
}
|
||||
|
||||
udp.datlen = ntohs (udp.datlen);
|
||||
if (udp.datlen > len) {
|
||||
LOG_D ("%p socks5 udp data len", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset (&mh, 0, sizeof (mh));
|
||||
mh.msg_iov = iov;
|
||||
mh.msg_iovlen = 2;
|
||||
|
||||
iov[0].iov_base = &addr->domain.addr;
|
||||
iov[0].iov_len = udp.hdrlen - 5;
|
||||
iov[1].iov_base = buf;
|
||||
iov[1].iov_len = udp.datlen;
|
||||
|
||||
res = hev_task_io_socket_recvmsg (fd, &mh, MSG_WAITALL, task_io_yielder,
|
||||
self);
|
||||
if (res <= 0) {
|
||||
LOG_D ("%p socks5 udp read udp data", self);
|
||||
return res;
|
||||
}
|
||||
|
||||
addr->atype = udp.addr.atype;
|
||||
addr->domain.len = udp.addr.domain.len;
|
||||
|
||||
return udp.datlen;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_udp_recvfrom_udp (HevSocks5UDP *self, void *buf, size_t len,
|
||||
HevSocks5Addr *addr)
|
||||
{
|
||||
struct sockaddr *saddr = NULL;
|
||||
struct sockaddr_in6 taddr;
|
||||
HevSocks5UDPHdr *udp;
|
||||
uint8_t rbuf[1500];
|
||||
socklen_t alen = 0;
|
||||
ssize_t rlen;
|
||||
int addrlen;
|
||||
int doff;
|
||||
int res;
|
||||
int fd;
|
||||
|
||||
LOG_D ("%p socks5 udp recvfrom udp", self);
|
||||
|
||||
if (!HEV_SOCKS5 (self)->udp_associated) {
|
||||
saddr = (struct sockaddr *)&taddr;
|
||||
alen = sizeof (struct sockaddr_in6);
|
||||
HEV_SOCKS5 (self)->udp_associated = 1;
|
||||
}
|
||||
|
||||
fd = hev_socks5_udp_get_fd (self);
|
||||
rlen = hev_task_io_socket_recvfrom (fd, rbuf, sizeof (rbuf), 0, saddr,
|
||||
&alen, task_io_yielder, self);
|
||||
if (rlen < 4) {
|
||||
LOG_D ("%p socks5 udp read", self);
|
||||
return rlen;
|
||||
}
|
||||
|
||||
if (saddr) {
|
||||
res = connect (fd, saddr, alen);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
udp = (HevSocks5UDPHdr *)rbuf;
|
||||
addrlen = hev_socks5_addr_len (&udp->addr);
|
||||
if (addrlen <= 0) {
|
||||
LOG_D ("%p socks5 udp addr", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
doff = 3 + addrlen;
|
||||
if (doff > rlen) {
|
||||
LOG_D ("%p socks5 udp data len", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rlen -= doff;
|
||||
if (len < rlen)
|
||||
rlen = len;
|
||||
memcpy (buf, rbuf + doff, rlen);
|
||||
memcpy (addr, &udp->addr, addrlen);
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_udp_recvfrom (HevSocks5UDP *self, void *buf, size_t len,
|
||||
HevSocks5Addr *addr)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (HEV_SOCKS5 (self)->type) {
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_TCP:
|
||||
res = hev_socks5_udp_recvfrom_tcp (self, buf, len, addr);
|
||||
break;
|
||||
case HEV_SOCKS5_TYPE_UDP_IN_UDP:
|
||||
res = hev_socks5_udp_recvfrom_udp (self, buf, len, addr);
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_udp_fwd_f (HevSocks5UDP *self, HevSocks5UDPSplice *splice)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
struct sockaddr *saddr;
|
||||
HevSocks5Addr taddr;
|
||||
uint8_t buf[1500];
|
||||
int addr_family;
|
||||
ssize_t res;
|
||||
int ret;
|
||||
|
||||
LOG_D ("%p socks5 udp fwd f", self);
|
||||
|
||||
res = hev_socks5_udp_recvfrom (self, buf, sizeof (buf), &taddr);
|
||||
if (res <= 0) {
|
||||
if (res < -1) {
|
||||
splice->alive &= ~HEV_SOCKS5_UDP_ALIVE_F;
|
||||
if (splice->alive && hev_socks5_get_timeout (HEV_SOCKS5 (self)))
|
||||
return 0;
|
||||
}
|
||||
if (HEV_SOCKS5 (self)->type == HEV_SOCKS5_TYPE_UDP_IN_TCP)
|
||||
hev_socks5_set_timeout (HEV_SOCKS5 (self), 0);
|
||||
LOG_D ("%p socks5 udp fwd f recv", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
saddr = (struct sockaddr *)&addr;
|
||||
addr_family = hev_socks5_get_addr_family (HEV_SOCKS5 (self));
|
||||
ret = hev_socks5_addr_into_sockaddr6 (&taddr, &addr, &addr_family);
|
||||
if (ret < 0) {
|
||||
LOG_D ("%p socks5 udp to sockaddr", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!splice->bind) {
|
||||
HevSocks5Class *skptr = HEV_OBJECT_GET_CLASS (self);
|
||||
ret = skptr->binder (HEV_SOCKS5 (self), splice->fd, saddr);
|
||||
if (ret < 0) {
|
||||
LOG_E ("%p socks5 udp bind", self);
|
||||
return -1;
|
||||
}
|
||||
splice->bind = 1;
|
||||
}
|
||||
|
||||
res = sendto (splice->fd, buf, res, 0, saddr, sizeof (addr));
|
||||
if (res <= 0) {
|
||||
if ((res < 0) && (errno == EAGAIN))
|
||||
return 0;
|
||||
LOG_D ("%p socks5 udp fwd f send", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
splice->alive |= HEV_SOCKS5_UDP_ALIVE_F;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_udp_fwd_b (HevSocks5UDP *self, HevSocks5UDPSplice *splice)
|
||||
{
|
||||
struct sockaddr_in6 addr;
|
||||
socklen_t addrlen;
|
||||
uint8_t buf[1500];
|
||||
ssize_t res;
|
||||
|
||||
LOG_D ("%p socks5 udp fwd b", self);
|
||||
|
||||
addrlen = sizeof (addr);
|
||||
res = hev_task_io_socket_recvfrom (splice->fd, buf, sizeof (buf), 0,
|
||||
(struct sockaddr *)&addr, &addrlen,
|
||||
task_io_yielder, self);
|
||||
if (res > 0) {
|
||||
HevSocks5Addr taddr;
|
||||
hev_socks5_addr_from_sockaddr6 (&taddr, &addr);
|
||||
res = hev_socks5_udp_sendto (self, buf, res, &taddr);
|
||||
}
|
||||
if (res <= 0) {
|
||||
if (res < -1) {
|
||||
splice->alive &= ~HEV_SOCKS5_UDP_ALIVE_B;
|
||||
if (splice->alive && hev_socks5_get_timeout (HEV_SOCKS5 (self)))
|
||||
return 0;
|
||||
}
|
||||
if (HEV_SOCKS5 (self)->type == HEV_SOCKS5_TYPE_UDP_IN_TCP)
|
||||
hev_socks5_set_timeout (HEV_SOCKS5 (self), 0);
|
||||
LOG_D ("%p socks5 udp fwd b recv send", self);
|
||||
return -1;
|
||||
}
|
||||
|
||||
splice->alive |= HEV_SOCKS5_UDP_ALIVE_B;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
splice_task_entry (void *data)
|
||||
{
|
||||
HevSocks5UDPSplice *splice = data;
|
||||
HevSocks5UDP *self = splice->udp;
|
||||
HevTask *task = hev_task_self ();
|
||||
int fd;
|
||||
|
||||
fd = hev_task_io_dup (hev_socks5_udp_get_fd (self));
|
||||
if (fd < 0)
|
||||
return;
|
||||
|
||||
if (hev_task_add_fd (task, fd, POLLIN) < 0)
|
||||
hev_task_mod_fd (task, fd, POLLIN);
|
||||
|
||||
for (;;) {
|
||||
if (hev_socks5_udp_fwd_f (self, splice) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
splice->alive &= ~HEV_SOCKS5_UDP_ALIVE_F;
|
||||
hev_task_del_fd (task, fd);
|
||||
close (fd);
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_udp_splicer (HevSocks5UDP *self, int fd)
|
||||
{
|
||||
HevTask *task = hev_task_self ();
|
||||
HevSocks5UDPSplice splice;
|
||||
int stack_size;
|
||||
int ufd;
|
||||
|
||||
LOG_D ("%p socks5 udp splicer", self);
|
||||
|
||||
splice.udp = self;
|
||||
splice.alive = HEV_SOCKS5_UDP_ALIVE_F | HEV_SOCKS5_UDP_ALIVE_B;
|
||||
splice.bind = 0;
|
||||
splice.fd = fd;
|
||||
|
||||
if (hev_task_add_fd (task, fd, POLLIN) < 0)
|
||||
hev_task_mod_fd (task, fd, POLLIN);
|
||||
|
||||
ufd = hev_socks5_udp_get_fd (self);
|
||||
if (hev_task_mod_fd (task, ufd, POLLOUT) < 0)
|
||||
hev_task_add_fd (task, ufd, POLLOUT);
|
||||
|
||||
stack_size = hev_socks5_get_task_stack_size ();
|
||||
task = hev_task_new (stack_size);
|
||||
hev_task_ref (task);
|
||||
hev_task_run (task, splice_task_entry, &splice);
|
||||
|
||||
for (;;) {
|
||||
if (hev_socks5_udp_fwd_b (self, &splice) < 0)
|
||||
break;
|
||||
}
|
||||
|
||||
splice.alive &= ~HEV_SOCKS5_UDP_ALIVE_B;
|
||||
hev_task_join (task);
|
||||
hev_task_unref (task);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_udp_splice (HevSocks5UDP *self, int fd)
|
||||
{
|
||||
HevSocks5UDPIface *iface;
|
||||
|
||||
iface = HEV_OBJECT_GET_IFACE (self, HEV_SOCKS5_UDP_TYPE);
|
||||
return iface->splicer (self, fd);
|
||||
}
|
||||
|
||||
void *
|
||||
hev_socks5_udp_iface (void)
|
||||
{
|
||||
static HevSocks5UDPIface type = {
|
||||
.splicer = hev_socks5_udp_splicer,
|
||||
};
|
||||
|
||||
return &type;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-udp.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2025 hev
|
||||
Description : Socks5 UDP
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_UDP_H__
|
||||
#define __HEV_SOCKS5_UDP_H__
|
||||
|
||||
#include "hev-socks5-proto.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_UDP(p) ((HevSocks5UDP *)p)
|
||||
#define HEV_SOCKS5_UDP_IFACE(p) ((HevSocks5UDPIface *)p)
|
||||
#define HEV_SOCKS5_UDP_TYPE (hev_socks5_udp_iface ())
|
||||
|
||||
typedef void HevSocks5UDP;
|
||||
typedef struct _HevSocks5UDPIface HevSocks5UDPIface;
|
||||
|
||||
struct _HevSocks5UDPIface
|
||||
{
|
||||
int (*get_fd) (HevSocks5UDP *self);
|
||||
int (*splicer) (HevSocks5UDP *self, int fd);
|
||||
};
|
||||
|
||||
void *hev_socks5_udp_iface (void);
|
||||
|
||||
int hev_socks5_udp_get_fd (HevSocks5UDP *self);
|
||||
|
||||
int hev_socks5_udp_sendto (HevSocks5UDP *self, const void *buf, size_t len,
|
||||
const HevSocks5Addr *addr);
|
||||
|
||||
int hev_socks5_udp_recvfrom (HevSocks5UDP *self, void *buf, size_t len,
|
||||
HevSocks5Addr *addr);
|
||||
|
||||
int hev_socks5_udp_splice (HevSocks5UDP *self, int fd);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_UDP_H__ */
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-user.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2023 hev
|
||||
Description : Socks5 User
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5-user.h"
|
||||
|
||||
HevSocks5User *
|
||||
hev_socks5_user_new (const char *name, unsigned int name_len, const char *pass,
|
||||
unsigned int pass_len)
|
||||
{
|
||||
HevSocks5User *self;
|
||||
int res;
|
||||
|
||||
self = calloc (1, sizeof (HevSocks5User));
|
||||
if (!self)
|
||||
return NULL;
|
||||
|
||||
res = hev_socks5_user_construct (self, name, name_len, pass, pass_len);
|
||||
if (res < 0) {
|
||||
free (self);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D ("%p socks5 user new", self);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_user_check (HevSocks5User *self, const char *pass,
|
||||
unsigned int pass_len)
|
||||
{
|
||||
HevSocks5UserClass *klass = HEV_OBJECT_GET_CLASS (self);
|
||||
|
||||
return klass->checker (self, pass, pass_len);
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_user_checker (HevSocks5User *self, const char *pass,
|
||||
unsigned int pass_len)
|
||||
{
|
||||
LOG_D ("%p socks5 user checker", self);
|
||||
|
||||
if (self->pass_len != pass_len)
|
||||
return -1;
|
||||
|
||||
if (memcmp (self->pass, pass, pass_len) != 0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_user_construct (HevSocks5User *self, const char *name,
|
||||
unsigned int name_len, const char *pass,
|
||||
unsigned int pass_len)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_object_atomic_construct (&self->base);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_D ("%p socks5 user construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_USER_TYPE;
|
||||
|
||||
self->name = malloc (name_len);
|
||||
self->name_len = name_len;
|
||||
memcpy (self->name, name, name_len);
|
||||
|
||||
self->pass = malloc (pass_len);
|
||||
self->pass_len = pass_len;
|
||||
memcpy (self->pass, pass, pass_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_user_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5User *self = HEV_SOCKS5_USER (base);
|
||||
|
||||
LOG_D ("%p socks5 user destruct", self);
|
||||
|
||||
free (self->name);
|
||||
free (self->pass);
|
||||
|
||||
HEV_OBJECT_ATOMIC_TYPE->destruct (base);
|
||||
free (base);
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_user_class (void)
|
||||
{
|
||||
static HevSocks5UserClass klass;
|
||||
HevSocks5UserClass *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
memcpy (kptr, HEV_OBJECT_ATOMIC_TYPE, sizeof (HevObjectAtomicClass));
|
||||
|
||||
okptr->name = "HevSocks5User";
|
||||
okptr->destruct = hev_socks5_user_destruct;
|
||||
|
||||
kptr->checker = hev_socks5_user_checker;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5-user.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2023 hev
|
||||
Description : Socks5 User
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_USER_H__
|
||||
#define __HEV_SOCKS5_USER_H__
|
||||
|
||||
#include <hev-object-atomic.h>
|
||||
|
||||
#include "hev-rbtree.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5_USER(p) ((HevSocks5User *)p)
|
||||
#define HEV_SOCKS5_USER_CLASS(p) ((HevSocks5UserClass *)p)
|
||||
#define HEV_SOCKS5_USER_TYPE (hev_socks5_user_class ())
|
||||
|
||||
typedef struct _HevSocks5User HevSocks5User;
|
||||
typedef struct _HevSocks5UserClass HevSocks5UserClass;
|
||||
|
||||
struct _HevSocks5User
|
||||
{
|
||||
HevObjectAtomic base;
|
||||
|
||||
HevRBTreeNode node;
|
||||
|
||||
char *name;
|
||||
char *pass;
|
||||
unsigned int name_len;
|
||||
unsigned int pass_len;
|
||||
};
|
||||
|
||||
struct _HevSocks5UserClass
|
||||
{
|
||||
HevObjectAtomicClass base;
|
||||
|
||||
int (*checker) (HevSocks5User *self, const char *pass,
|
||||
unsigned int pass_len);
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_user_class (void);
|
||||
|
||||
int hev_socks5_user_construct (HevSocks5User *self, const char *name,
|
||||
unsigned int name_len, const char *pass,
|
||||
unsigned int pass_len);
|
||||
|
||||
HevSocks5User *hev_socks5_user_new (const char *name, unsigned int name_len,
|
||||
const char *pass, unsigned int pass_len);
|
||||
|
||||
int hev_socks5_user_check (HevSocks5User *self, const char *pass,
|
||||
unsigned int pass_len);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_USER_H__ */
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5.c
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2023 hev
|
||||
Description : Socks5
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-io.h>
|
||||
#include <hev-task-io-socket.h>
|
||||
#include <hev-task-dns.h>
|
||||
#include <hev-memory-allocator.h>
|
||||
|
||||
#include "hev-socks5-logger-priv.h"
|
||||
|
||||
#include "hev-socks5.h"
|
||||
|
||||
int
|
||||
hev_socks5_get_timeout (HevSocks5 *self)
|
||||
{
|
||||
return self->timeout;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_set_timeout (HevSocks5 *self, int timeout)
|
||||
{
|
||||
self->timeout = timeout;
|
||||
}
|
||||
|
||||
HevSocks5AddrFamily
|
||||
hev_socks5_get_addr_family (HevSocks5 *self)
|
||||
{
|
||||
return self->addr_family;
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_set_addr_family (HevSocks5 *self, HevSocks5AddrFamily family)
|
||||
{
|
||||
self->addr_family = family;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_socks5_bind (HevSocks5 *self, int sock, const struct sockaddr *dest)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_construct (HevSocks5 *self, HevSocks5Type type)
|
||||
{
|
||||
int res;
|
||||
|
||||
res = hev_object_construct (&self->base);
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
LOG_D ("%p socks5 construct", self);
|
||||
|
||||
HEV_OBJECT (self)->klass = HEV_SOCKS5_TYPE;
|
||||
|
||||
self->fd = -1;
|
||||
self->timeout = -1;
|
||||
self->type = type;
|
||||
self->addr_family = HEV_SOCKS5_ADDR_FAMILY_UNSPEC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
hev_socks5_destruct (HevObject *base)
|
||||
{
|
||||
HevSocks5 *self = HEV_SOCKS5 (base);
|
||||
|
||||
LOG_D ("%p socks5 destruct", self);
|
||||
|
||||
if (self->fd >= 0) {
|
||||
hev_task_del_fd (hev_task_self (), self->fd);
|
||||
close (self->fd);
|
||||
}
|
||||
|
||||
HEV_OBJECT_TYPE->destruct (base);
|
||||
hev_free (base);
|
||||
}
|
||||
|
||||
HevObjectClass *
|
||||
hev_socks5_class (void)
|
||||
{
|
||||
static HevSocks5Class klass;
|
||||
HevSocks5Class *kptr = &klass;
|
||||
HevObjectClass *okptr = HEV_OBJECT_CLASS (kptr);
|
||||
|
||||
if (!okptr->name) {
|
||||
memcpy (kptr, HEV_OBJECT_TYPE, sizeof (HevObjectClass));
|
||||
|
||||
okptr->name = "HevSocks5";
|
||||
okptr->destruct = hev_socks5_destruct;
|
||||
|
||||
kptr->binder = hev_socks5_bind;
|
||||
}
|
||||
|
||||
return okptr;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-socks5.h
|
||||
Author : Heiher <r@hev.cc>
|
||||
Copyright : Copyright (c) 2021 - 2023 hev
|
||||
Description : Socks5
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_SOCKS5_H__
|
||||
#define __HEV_SOCKS5_H__
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include <hev-object.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define HEV_SOCKS5(p) ((HevSocks5 *)p)
|
||||
#define HEV_SOCKS5_CLASS(p) ((HevSocks5Class *)p)
|
||||
#define HEV_SOCKS5_TYPE (hev_socks5_class ())
|
||||
|
||||
typedef struct _HevSocks5 HevSocks5;
|
||||
typedef struct _HevSocks5Class HevSocks5Class;
|
||||
typedef enum _HevSocks5Type HevSocks5Type;
|
||||
typedef enum _HevSocks5AddrFamily HevSocks5AddrFamily;
|
||||
|
||||
enum _HevSocks5Type
|
||||
{
|
||||
HEV_SOCKS5_TYPE_NONE,
|
||||
HEV_SOCKS5_TYPE_TCP,
|
||||
HEV_SOCKS5_TYPE_UDP_IN_TCP,
|
||||
HEV_SOCKS5_TYPE_UDP_IN_UDP,
|
||||
};
|
||||
|
||||
enum _HevSocks5AddrFamily
|
||||
{
|
||||
HEV_SOCKS5_ADDR_FAMILY_IPV4 = AF_INET,
|
||||
HEV_SOCKS5_ADDR_FAMILY_IPV6 = AF_INET6,
|
||||
HEV_SOCKS5_ADDR_FAMILY_UNSPEC = AF_UNSPEC,
|
||||
};
|
||||
|
||||
struct _HevSocks5
|
||||
{
|
||||
HevObject base;
|
||||
|
||||
int fd;
|
||||
int timeout;
|
||||
int udp_associated;
|
||||
HevSocks5Type type;
|
||||
HevSocks5AddrFamily addr_family;
|
||||
};
|
||||
|
||||
struct _HevSocks5Class
|
||||
{
|
||||
HevObjectClass base;
|
||||
|
||||
int (*binder) (HevSocks5 *self, int sock, const struct sockaddr *dest);
|
||||
};
|
||||
|
||||
HevObjectClass *hev_socks5_class (void);
|
||||
|
||||
int hev_socks5_construct (HevSocks5 *self, HevSocks5Type type);
|
||||
|
||||
int hev_socks5_get_timeout (HevSocks5 *self);
|
||||
void hev_socks5_set_timeout (HevSocks5 *self, int timeout);
|
||||
|
||||
HevSocks5AddrFamily hev_socks5_get_addr_family (HevSocks5 *self);
|
||||
void hev_socks5_set_addr_family (HevSocks5 *self, HevSocks5AddrFamily family);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __HEV_SOCKS5_H__ */
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-config-const.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 - 2024 hev
|
||||
Description : Config Constants
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_CONFIG_CONST_H__
|
||||
#define __HEV_CONFIG_CONST_H__
|
||||
|
||||
#define MAJOR_VERSION (2)
|
||||
#define MINOR_VERSION (13)
|
||||
#define MICRO_VERSION (0)
|
||||
|
||||
static const int UDP_BUF_SIZE = 1500;
|
||||
static const int UDP_POOL_SIZE = 512;
|
||||
static const int TASK_STACK_SIZE = 20480;
|
||||
|
||||
#endif /* __HEV_CONFIG_CONST_H__ */
|
||||
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-config.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 - 2024 hev
|
||||
Description : Config
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <lwip/tcp.h>
|
||||
#include <yaml.h>
|
||||
|
||||
#include "hev-logger.h"
|
||||
#include "hev-config.h"
|
||||
#include "hev-config-const.h"
|
||||
|
||||
static char tun_name[64];
|
||||
static unsigned int tun_mtu = 8500;
|
||||
static int multi_queue;
|
||||
|
||||
static char tun_ipv4_address[16];
|
||||
static char tun_ipv6_address[64];
|
||||
|
||||
static char tun_post_up_script[1024];
|
||||
static char tun_pre_down_script[1024];
|
||||
|
||||
static HevConfigServer srv;
|
||||
|
||||
static int mapdns_address;
|
||||
static int mapdns_port;
|
||||
static int mapdns_network;
|
||||
static int mapdns_netmask;
|
||||
static int mapdns_cache_size;
|
||||
|
||||
static char log_file[1024];
|
||||
static char pid_file[1024];
|
||||
static int task_stack_size = 86016;
|
||||
static int tcp_buffer_size = 65536;
|
||||
static int connect_timeout = 5000;
|
||||
static int read_write_timeout = 60000;
|
||||
static int limit_nofile = 65535;
|
||||
static int log_level = HEV_LOGGER_WARN;
|
||||
|
||||
static int
|
||||
hev_config_parse_tunnel_ipv4 (yaml_document_t *doc, yaml_node_t *base)
|
||||
{
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
if (!base || YAML_MAPPING_NODE != base->type)
|
||||
return -1;
|
||||
|
||||
for (pair = base->data.mapping.pairs.start;
|
||||
pair < base->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key, *value;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
key = (const char *)node->data.scalar.value;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
value = (const char *)node->data.scalar.value;
|
||||
|
||||
if (0 == strcmp (key, "address"))
|
||||
strncpy (tun_ipv4_address, value, 16 - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_tunnel_ipv6 (yaml_document_t *doc, yaml_node_t *base)
|
||||
{
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
if (!base || YAML_MAPPING_NODE != base->type)
|
||||
return -1;
|
||||
|
||||
for (pair = base->data.mapping.pairs.start;
|
||||
pair < base->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key, *value;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
key = (const char *)node->data.scalar.value;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
value = (const char *)node->data.scalar.value;
|
||||
|
||||
if (0 == strcmp (key, "address"))
|
||||
strncpy (tun_ipv6_address, value, 64 - 1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_tunnel (yaml_document_t *doc, yaml_node_t *base)
|
||||
{
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
if (!base || YAML_MAPPING_NODE != base->type)
|
||||
return -1;
|
||||
|
||||
for (pair = base->data.mapping.pairs.start;
|
||||
pair < base->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
key = (const char *)node->data.scalar.value;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
if (!node)
|
||||
break;
|
||||
|
||||
if (YAML_SCALAR_NODE == node->type) {
|
||||
const char *value = (const char *)node->data.scalar.value;
|
||||
|
||||
if (0 == strcmp (key, "name"))
|
||||
strncpy (tun_name, value, 64 - 1);
|
||||
else if (0 == strcmp (key, "mtu"))
|
||||
tun_mtu = strtoul (value, NULL, 10);
|
||||
else if (0 == strcmp (key, "multi-queue"))
|
||||
multi_queue = strcasecmp (value, "false");
|
||||
else if (0 == strcmp (key, "ipv4"))
|
||||
strncpy (tun_ipv4_address, value, 16 - 1);
|
||||
else if (0 == strcmp (key, "ipv6"))
|
||||
strncpy (tun_ipv6_address, value, 64 - 1);
|
||||
else if (0 == strcmp (key, "post-up-script"))
|
||||
strncpy (tun_post_up_script, value, 64 - 1);
|
||||
else if (0 == strcmp (key, "pre-down-script"))
|
||||
strncpy (tun_pre_down_script, value, 64 - 1);
|
||||
} else {
|
||||
if (0 == strcmp (key, "ipv4"))
|
||||
hev_config_parse_tunnel_ipv4 (doc, node);
|
||||
else if (0 == strcmp (key, "ipv6"))
|
||||
hev_config_parse_tunnel_ipv6 (doc, node);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_socks5 (yaml_document_t *doc, yaml_node_t *base)
|
||||
{
|
||||
yaml_node_pair_t *pair;
|
||||
static char _user[256];
|
||||
static char _pass[256];
|
||||
const char *addr = NULL;
|
||||
const char *port = NULL;
|
||||
const char *udpm = NULL;
|
||||
const char *user = NULL;
|
||||
const char *pass = NULL;
|
||||
const char *mark = NULL;
|
||||
const char *pipe = NULL;
|
||||
|
||||
if (!base || YAML_MAPPING_NODE != base->type)
|
||||
return -1;
|
||||
|
||||
for (pair = base->data.mapping.pairs.start;
|
||||
pair < base->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key, *value;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
key = (const char *)node->data.scalar.value;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
value = (const char *)node->data.scalar.value;
|
||||
|
||||
if (0 == strcmp (key, "port"))
|
||||
port = value;
|
||||
else if (0 == strcmp (key, "address"))
|
||||
addr = value;
|
||||
else if (0 == strcmp (key, "udp"))
|
||||
udpm = value;
|
||||
else if (0 == strcmp (key, "pipeline"))
|
||||
pipe = value;
|
||||
else if (0 == strcmp (key, "username"))
|
||||
user = value;
|
||||
else if (0 == strcmp (key, "password"))
|
||||
pass = value;
|
||||
else if (0 == strcmp (key, "mark"))
|
||||
mark = value;
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
fprintf (stderr, "Can't found socks5.port!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!addr) {
|
||||
fprintf (stderr, "Can't found socks5.address!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((user && !pass) || (!user && pass)) {
|
||||
fprintf (stderr, "Must be set both socks5 username and password!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy (srv.addr, addr, 256 - 1);
|
||||
srv.port = strtoul (port, NULL, 10);
|
||||
|
||||
if (pipe && (strcasecmp (pipe, "true") == 0))
|
||||
srv.pipeline = 1;
|
||||
|
||||
if (udpm && (strcasecmp (udpm, "udp") == 0))
|
||||
srv.udp_in_udp = 1;
|
||||
|
||||
if (user && pass) {
|
||||
strncpy (_user, user, 256 - 1);
|
||||
strncpy (_pass, pass, 256 - 1);
|
||||
srv.user = _user;
|
||||
srv.pass = _pass;
|
||||
}
|
||||
|
||||
if (mark)
|
||||
srv.mark = strtoul (mark, NULL, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_mapdns (yaml_document_t *doc, yaml_node_t *base)
|
||||
{
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
if (!base || YAML_MAPPING_NODE != base->type)
|
||||
return -1;
|
||||
|
||||
for (pair = base->data.mapping.pairs.start;
|
||||
pair < base->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key, *value;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
key = (const char *)node->data.scalar.value;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
value = (const char *)node->data.scalar.value;
|
||||
|
||||
if (0 == strcmp (key, "address"))
|
||||
inet_pton (AF_INET, value, &mapdns_address);
|
||||
else if (0 == strcmp (key, "port"))
|
||||
mapdns_port = strtoul (value, NULL, 10);
|
||||
else if (0 == strcmp (key, "network"))
|
||||
inet_pton (AF_INET, value, &mapdns_network);
|
||||
else if (0 == strcmp (key, "netmask"))
|
||||
inet_pton (AF_INET, value, &mapdns_netmask);
|
||||
else if (0 == strcmp (key, "cache-size"))
|
||||
mapdns_cache_size = strtoul (value, NULL, 10);
|
||||
}
|
||||
|
||||
mapdns_network = ntohl (mapdns_network);
|
||||
mapdns_netmask = ntohl (mapdns_netmask);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_log_level (const char *value)
|
||||
{
|
||||
if (0 == strcmp (value, "debug"))
|
||||
return HEV_LOGGER_DEBUG;
|
||||
else if (0 == strcmp (value, "info"))
|
||||
return HEV_LOGGER_INFO;
|
||||
else if (0 == strcmp (value, "error"))
|
||||
return HEV_LOGGER_ERROR;
|
||||
|
||||
return HEV_LOGGER_WARN;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_misc (yaml_document_t *doc, yaml_node_t *base)
|
||||
{
|
||||
yaml_node_pair_t *pair;
|
||||
|
||||
if (!base || YAML_MAPPING_NODE != base->type)
|
||||
return -1;
|
||||
|
||||
for (pair = base->data.mapping.pairs.start;
|
||||
pair < base->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key, *value;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
key = (const char *)node->data.scalar.value;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
value = (const char *)node->data.scalar.value;
|
||||
|
||||
if (0 == strcmp (key, "task-stack-size"))
|
||||
task_stack_size = strtoul (value, NULL, 10);
|
||||
else if (0 == strcmp (key, "tcp-buffer-size"))
|
||||
tcp_buffer_size = strtoul (value, NULL, 10);
|
||||
else if (0 == strcmp (key, "connect-timeout"))
|
||||
connect_timeout = strtoul (value, NULL, 10);
|
||||
else if (0 == strcmp (key, "read-write-timeout"))
|
||||
read_write_timeout = strtoul (value, NULL, 10);
|
||||
else if (0 == strcmp (key, "pid-file"))
|
||||
strncpy (pid_file, value, 1024 - 1);
|
||||
else if (0 == strcmp (key, "log-file"))
|
||||
strncpy (log_file, value, 1024 - 1);
|
||||
else if (0 == strcmp (key, "log-level"))
|
||||
log_level = hev_config_parse_log_level (value);
|
||||
else if (0 == strcmp (key, "limit-nofile"))
|
||||
limit_nofile = strtol (value, NULL, 10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
hev_config_parse_doc (yaml_document_t *doc)
|
||||
{
|
||||
yaml_node_t *root;
|
||||
yaml_node_pair_t *pair;
|
||||
int min_task_stack_size;
|
||||
|
||||
root = yaml_document_get_root_node (doc);
|
||||
if (!root || YAML_MAPPING_NODE != root->type)
|
||||
return -1;
|
||||
|
||||
for (pair = root->data.mapping.pairs.start;
|
||||
pair < root->data.mapping.pairs.top; pair++) {
|
||||
yaml_node_t *node;
|
||||
const char *key;
|
||||
int res = 0;
|
||||
|
||||
if (!pair->key || !pair->value)
|
||||
break;
|
||||
|
||||
node = yaml_document_get_node (doc, pair->key);
|
||||
if (!node || YAML_SCALAR_NODE != node->type)
|
||||
break;
|
||||
|
||||
key = (const char *)node->data.scalar.value;
|
||||
node = yaml_document_get_node (doc, pair->value);
|
||||
|
||||
if (0 == strcmp (key, "tunnel"))
|
||||
res = hev_config_parse_tunnel (doc, node);
|
||||
else if (0 == strcmp (key, "socks5"))
|
||||
res = hev_config_parse_socks5 (doc, node);
|
||||
else if (0 == strcmp (key, "mapdns"))
|
||||
res = hev_config_parse_mapdns (doc, node);
|
||||
else if (0 == strcmp (key, "misc"))
|
||||
res = hev_config_parse_misc (doc, node);
|
||||
|
||||
if (res < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tcp_buffer_size > TCP_SND_BUF)
|
||||
tcp_buffer_size = TCP_SND_BUF;
|
||||
|
||||
min_task_stack_size = TASK_STACK_SIZE + tcp_buffer_size;
|
||||
if (task_stack_size < min_task_stack_size)
|
||||
task_stack_size = min_task_stack_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_init_from_file (const char *config_path)
|
||||
{
|
||||
yaml_parser_t parser;
|
||||
yaml_document_t doc;
|
||||
FILE *fp;
|
||||
int res = -1;
|
||||
|
||||
if (!yaml_parser_initialize (&parser))
|
||||
goto exit;
|
||||
|
||||
fp = fopen (config_path, "r");
|
||||
if (!fp) {
|
||||
fprintf (stderr, "Open %s failed!\n", config_path);
|
||||
goto exit_free_parser;
|
||||
}
|
||||
|
||||
yaml_parser_set_input_file (&parser, fp);
|
||||
if (!yaml_parser_load (&parser, &doc)) {
|
||||
fprintf (stderr, "Parse %s failed!\n", config_path);
|
||||
goto exit_close_fp;
|
||||
}
|
||||
|
||||
res = hev_config_parse_doc (&doc);
|
||||
yaml_document_delete (&doc);
|
||||
|
||||
exit_close_fp:
|
||||
fclose (fp);
|
||||
exit_free_parser:
|
||||
yaml_parser_delete (&parser);
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_init_from_str (const unsigned char *config_str,
|
||||
unsigned int config_len)
|
||||
{
|
||||
yaml_parser_t parser;
|
||||
yaml_document_t doc;
|
||||
int res = -1;
|
||||
|
||||
if (!yaml_parser_initialize (&parser))
|
||||
goto exit;
|
||||
|
||||
yaml_parser_set_input_string (&parser, config_str, config_len);
|
||||
if (!yaml_parser_load (&parser, &doc)) {
|
||||
fprintf (stderr, "Failed to parse config.");
|
||||
goto exit_free_parser;
|
||||
}
|
||||
|
||||
res = hev_config_parse_doc (&doc);
|
||||
yaml_document_delete (&doc);
|
||||
|
||||
exit_free_parser:
|
||||
yaml_parser_delete (&parser);
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
hev_config_fini (void)
|
||||
{
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_tunnel_name (void)
|
||||
{
|
||||
if (!tun_name[0])
|
||||
return NULL;
|
||||
|
||||
return tun_name;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
hev_config_get_tunnel_mtu (void)
|
||||
{
|
||||
return tun_mtu;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_tunnel_multi_queue (void)
|
||||
{
|
||||
return multi_queue;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_tunnel_ipv4_address (void)
|
||||
{
|
||||
if (!tun_ipv4_address[0])
|
||||
return NULL;
|
||||
|
||||
return tun_ipv4_address;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_tunnel_ipv6_address (void)
|
||||
{
|
||||
if (!tun_ipv6_address[0])
|
||||
return NULL;
|
||||
|
||||
return tun_ipv6_address;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_tunnel_post_up_script (void)
|
||||
{
|
||||
if (!tun_post_up_script[0])
|
||||
return NULL;
|
||||
|
||||
return tun_post_up_script;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_tunnel_pre_down_script (void)
|
||||
{
|
||||
if (!tun_pre_down_script[0])
|
||||
return NULL;
|
||||
|
||||
return tun_pre_down_script;
|
||||
}
|
||||
|
||||
HevConfigServer *
|
||||
hev_config_get_socks5_server (void)
|
||||
{
|
||||
return &srv;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_mapdns_address (void)
|
||||
{
|
||||
return mapdns_address;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_mapdns_port (void)
|
||||
{
|
||||
return mapdns_port;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_mapdns_network (void)
|
||||
{
|
||||
return mapdns_network;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_mapdns_netmask (void)
|
||||
{
|
||||
return mapdns_netmask;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_mapdns_cache_size (void)
|
||||
{
|
||||
return mapdns_cache_size;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_misc_task_stack_size (void)
|
||||
{
|
||||
return task_stack_size;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_misc_tcp_buffer_size (void)
|
||||
{
|
||||
return tcp_buffer_size;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_misc_connect_timeout (void)
|
||||
{
|
||||
return connect_timeout;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_misc_read_write_timeout (void)
|
||||
{
|
||||
return read_write_timeout;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_misc_limit_nofile (void)
|
||||
{
|
||||
return limit_nofile;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_misc_pid_file (void)
|
||||
{
|
||||
if (!pid_file[0])
|
||||
return NULL;
|
||||
|
||||
return pid_file;
|
||||
}
|
||||
|
||||
const char *
|
||||
hev_config_get_misc_log_file (void)
|
||||
{
|
||||
if (!log_file[0])
|
||||
return "stderr";
|
||||
|
||||
return log_file;
|
||||
}
|
||||
|
||||
int
|
||||
hev_config_get_misc_log_level (void)
|
||||
{
|
||||
return log_level;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-config.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 - 2023 hev
|
||||
Description : Config
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_CONFIG_H__
|
||||
#define __HEV_CONFIG_H__
|
||||
|
||||
typedef struct _HevConfigServer HevConfigServer;
|
||||
|
||||
struct _HevConfigServer
|
||||
{
|
||||
const char *user;
|
||||
const char *pass;
|
||||
unsigned int mark;
|
||||
short udp_in_udp;
|
||||
unsigned short port;
|
||||
unsigned char pipeline;
|
||||
char addr[256];
|
||||
};
|
||||
|
||||
int hev_config_init_from_file (const char *config_path);
|
||||
int hev_config_init_from_str (const unsigned char *config_str,
|
||||
unsigned int config_len);
|
||||
void hev_config_fini (void);
|
||||
|
||||
const char *hev_config_get_tunnel_name (void);
|
||||
unsigned int hev_config_get_tunnel_mtu (void);
|
||||
int hev_config_get_tunnel_multi_queue (void);
|
||||
|
||||
const char *hev_config_get_tunnel_ipv4_address (void);
|
||||
const char *hev_config_get_tunnel_ipv6_address (void);
|
||||
|
||||
const char *hev_config_get_tunnel_post_up_script (void);
|
||||
const char *hev_config_get_tunnel_pre_down_script (void);
|
||||
|
||||
HevConfigServer *hev_config_get_socks5_server (void);
|
||||
|
||||
int hev_config_get_mapdns_address (void);
|
||||
int hev_config_get_mapdns_port (void);
|
||||
int hev_config_get_mapdns_network (void);
|
||||
int hev_config_get_mapdns_netmask (void);
|
||||
int hev_config_get_mapdns_cache_size (void);
|
||||
|
||||
int hev_config_get_misc_task_stack_size (void);
|
||||
int hev_config_get_misc_tcp_buffer_size (void);
|
||||
int hev_config_get_misc_connect_timeout (void);
|
||||
int hev_config_get_misc_read_write_timeout (void);
|
||||
int hev_config_get_misc_limit_nofile (void);
|
||||
const char *hev_config_get_misc_pid_file (void);
|
||||
const char *hev_config_get_misc_log_file (void);
|
||||
int hev_config_get_misc_log_level (void);
|
||||
|
||||
#endif /* __HEV_CONFIG_H__ */
|
||||
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-jni.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 - 2023 hev
|
||||
Description : Jave Native Interface
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifdef ANDROID
|
||||
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "hev-main.h"
|
||||
|
||||
#include "hev-jni.h"
|
||||
|
||||
/* clang-format off */
|
||||
#ifndef PKGNAME
|
||||
#define PKGNAME hev/htproxy
|
||||
#endif
|
||||
#ifndef CLSNAME
|
||||
#define CLSNAME TProxyService
|
||||
#endif
|
||||
/* clang-format on */
|
||||
|
||||
#define STR(s) STR_ARG (s)
|
||||
#define STR_ARG(c) #c
|
||||
#define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
|
||||
|
||||
typedef struct _ThreadData ThreadData;
|
||||
|
||||
struct _ThreadData
|
||||
{
|
||||
char *path;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static int is_working;
|
||||
static JavaVM *java_vm;
|
||||
static pthread_t work_thread;
|
||||
static pthread_mutex_t mutex;
|
||||
static pthread_key_t current_jni_env;
|
||||
|
||||
static void native_start_service (JNIEnv *env, jobject thiz, jstring conig_path,
|
||||
jint fd);
|
||||
static void native_stop_service (JNIEnv *env, jobject thiz);
|
||||
static jlongArray native_get_stats (JNIEnv *env, jobject thiz);
|
||||
|
||||
static JNINativeMethod native_methods[] = {
|
||||
{ "TProxyStartService", "(Ljava/lang/String;I)V",
|
||||
(void *)native_start_service },
|
||||
{ "TProxyStopService", "()V", (void *)native_stop_service },
|
||||
{ "TProxyGetStats", "()[J", (void *)native_get_stats },
|
||||
};
|
||||
|
||||
static void
|
||||
detach_current_thread (void *env)
|
||||
{
|
||||
(*java_vm)->DetachCurrentThread (java_vm);
|
||||
}
|
||||
|
||||
jint
|
||||
JNI_OnLoad (JavaVM *vm, void *reserved)
|
||||
{
|
||||
JNIEnv *env = NULL;
|
||||
jclass klass;
|
||||
|
||||
java_vm = vm;
|
||||
if (JNI_OK != (*vm)->GetEnv (vm, (void **)&env, JNI_VERSION_1_4)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
klass = (*env)->FindClass (env, STR (PKGNAME) "/" STR (CLSNAME));
|
||||
(*env)->RegisterNatives (env, klass, native_methods,
|
||||
N_ELEMENTS (native_methods));
|
||||
(*env)->DeleteLocalRef (env, klass);
|
||||
|
||||
pthread_key_create (¤t_jni_env, detach_current_thread);
|
||||
pthread_mutex_init (&mutex, NULL);
|
||||
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
static void *
|
||||
thread_handler (void *data)
|
||||
{
|
||||
ThreadData *tdata = data;
|
||||
|
||||
hev_socks5_tunnel_main (tdata->path, tdata->fd);
|
||||
|
||||
free (tdata->path);
|
||||
free (tdata);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
native_start_service (JNIEnv *env, jobject thiz, jstring config_path, jint fd)
|
||||
{
|
||||
const jbyte *bytes;
|
||||
ThreadData *tdata;
|
||||
int res;
|
||||
|
||||
pthread_mutex_lock (&mutex);
|
||||
|
||||
if (is_working)
|
||||
goto exit;
|
||||
|
||||
tdata = malloc (sizeof (ThreadData));
|
||||
tdata->fd = fd;
|
||||
|
||||
bytes = (const jbyte *)(*env)->GetStringUTFChars (env, config_path, NULL);
|
||||
tdata->path = strdup ((const char *)bytes);
|
||||
(*env)->ReleaseStringUTFChars (env, config_path, (const char *)bytes);
|
||||
|
||||
res = pthread_create (&work_thread, NULL, thread_handler, tdata);
|
||||
if (res < 0) {
|
||||
free (tdata->path);
|
||||
free (tdata);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
is_working = 1;
|
||||
exit:
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
static void
|
||||
native_stop_service (JNIEnv *env, jobject thiz)
|
||||
{
|
||||
pthread_mutex_lock (&mutex);
|
||||
|
||||
if (!is_working)
|
||||
goto exit;
|
||||
|
||||
hev_socks5_tunnel_quit ();
|
||||
pthread_join (work_thread, NULL);
|
||||
|
||||
is_working = 0;
|
||||
exit:
|
||||
pthread_mutex_unlock (&mutex);
|
||||
}
|
||||
|
||||
static jlongArray
|
||||
native_get_stats (JNIEnv *env, jobject thiz)
|
||||
{
|
||||
size_t tx_packets, rx_packets, tx_bytes, rx_bytes;
|
||||
jlongArray res;
|
||||
jlong array[4];
|
||||
|
||||
hev_socks5_tunnel_stats (&tx_packets, &tx_bytes, &rx_packets, &rx_bytes);
|
||||
array[0] = tx_packets;
|
||||
array[1] = tx_bytes;
|
||||
array[2] = rx_packets;
|
||||
array[3] = rx_bytes;
|
||||
|
||||
res = (*env)->NewLongArray (env, 4);
|
||||
(*env)->SetLongArrayRegion (env, res, 0, 4, array);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* ANDROID */
|
||||
@@ -0,0 +1,13 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-jni.h
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 - 2023 hev
|
||||
Description : Java Native Interface
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#ifndef __HEV_JNI_H__
|
||||
#define __HEV_JNI_H__
|
||||
|
||||
#endif /* __HEV_JNI_H__ */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : hev-main.c
|
||||
Author : hev <r@hev.cc>
|
||||
Copyright : Copyright (c) 2019 - 2023 hev
|
||||
Description : Main
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <lwip/init.h>
|
||||
|
||||
#include <hev-task.h>
|
||||
#include <hev-task-system.h>
|
||||
|
||||
#include "hev-utils.h"
|
||||
#include "hev-config.h"
|
||||
#include "hev-config-const.h"
|
||||
#include "hev-logger.h"
|
||||
#include "hev-socks5-logger.h"
|
||||
#include "hev-socks5-tunnel.h"
|
||||
|
||||
#include "hev-main.h"
|
||||
|
||||
static int
|
||||
hev_socks5_tunnel_main_inner (int tun_fd)
|
||||
{
|
||||
const char *pid_file;
|
||||
const char *log_file;
|
||||
int log_level;
|
||||
int nofile;
|
||||
int res;
|
||||
|
||||
log_file = hev_config_get_misc_log_file ();
|
||||
log_level = hev_config_get_misc_log_level ();
|
||||
|
||||
res = hev_logger_init (log_level, log_file);
|
||||
if (res < 0)
|
||||
return -2;
|
||||
|
||||
res = hev_socks5_logger_init (log_level, log_file);
|
||||
if (res < 0)
|
||||
return -3;
|
||||
|
||||
nofile = hev_config_get_misc_limit_nofile ();
|
||||
res = set_limit_nofile (nofile);
|
||||
if (res < 0)
|
||||
LOG_I ("set limit nofile");
|
||||
|
||||
pid_file = hev_config_get_misc_pid_file ();
|
||||
if (pid_file)
|
||||
run_as_daemon (pid_file);
|
||||
|
||||
res = hev_task_system_init ();
|
||||
if (res < 0)
|
||||
return -4;
|
||||
|
||||
lwip_init ();
|
||||
|
||||
res = hev_socks5_tunnel_init (tun_fd);
|
||||
if (res < 0)
|
||||
return -5;
|
||||
|
||||
hev_socks5_tunnel_run ();
|
||||
|
||||
hev_socks5_tunnel_fini ();
|
||||
hev_socks5_logger_fini ();
|
||||
hev_logger_fini ();
|
||||
hev_config_fini ();
|
||||
hev_task_system_fini ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_tunnel_main_from_file (const char *config_path, int tun_fd)
|
||||
{
|
||||
int res = hev_config_init_from_file (config_path);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
return hev_socks5_tunnel_main_inner (tun_fd);
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_tunnel_main_from_str (const unsigned char *config_str,
|
||||
unsigned int config_len, int tun_fd)
|
||||
{
|
||||
int res = hev_config_init_from_str (config_str, config_len);
|
||||
if (res < 0)
|
||||
return -1;
|
||||
|
||||
return hev_socks5_tunnel_main_inner (tun_fd);
|
||||
}
|
||||
|
||||
int
|
||||
hev_socks5_tunnel_main (const char *config_path, int tun_fd)
|
||||
{
|
||||
return hev_socks5_tunnel_main_from_file (config_path, tun_fd);
|
||||
}
|
||||
|
||||
void
|
||||
hev_socks5_tunnel_quit (void)
|
||||
{
|
||||
hev_socks5_tunnel_stop ();
|
||||
}
|
||||
|
||||
#ifndef ENABLE_LIBRARY
|
||||
static void
|
||||
show_help (const char *self_path)
|
||||
{
|
||||
printf ("%s CONFIG_PATH\n", self_path);
|
||||
printf ("Version: %u.%u.%u %s\n", MAJOR_VERSION, MINOR_VERSION,
|
||||
MICRO_VERSION, COMMIT_ID);
|
||||
}
|
||||
|
||||
static void
|
||||
sigint_handler (int signum)
|
||||
{
|
||||
hev_socks5_tunnel_stop ();
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
int res;
|
||||
|
||||
if (argc < 2 || strcmp (argv[1], "--version") == 0) {
|
||||
show_help (argv[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
signal (SIGINT, sigint_handler);
|
||||
|
||||
res = hev_socks5_tunnel_main (argv[1], -1);
|
||||
if (res < 0)
|
||||
return -2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* ENABLE_LIBRARY */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user