Skip to content

Commit

Permalink
Initial Upload
Browse files Browse the repository at this point in the history
  • Loading branch information
cnbatch committed Nov 26, 2022
1 parent 03435e5 commit 6b29fb3
Show file tree
Hide file tree
Showing 23 changed files with 2,793 additions and 0 deletions.
58 changes: 58 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Prerequisites
*.d

# Compiled Object files
*.slo
*.lo
*.o
*.obj

# Precompiled Headers
*.gch
*.pch

# Compiled Dynamic libraries
*.so
*.dylib
*.dll

# Fortran module files
*.mod
*.smod

# Compiled Static libraries
*.lai
*.la
*.a
*.lib

# Executables
*.exe
*.out
*.app

CMakeLists.txt.user
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
_deps
CMakeSettings.json
build/
out/
obj/
x64/
Debug/
Release/
arm/
arm64/
.vs/
.idea/
.vscode/
cmake-build-debug/
cmake-build-release/
36 changes: 36 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
cmake_minimum_required(VERSION 3.15.0 FATAL_ERROR)

project(punchnat CXX)

set(CMAKE_C_STANDARD 17)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

set_property(GLOBAL PROPERTY USE_FOLDERS ON)

if(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
include_directories("/usr/local/include")
include_directories("/usr/local/include/botan-2")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
include_directories("/usr/pkg/include")
include_directories("/usr/pkg/include/botan-2")
endif()
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
include_directories("/usr/include/botan-2")
endif()

find_package(Threads REQUIRED)

if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN)
add_compile_options("$<$<C_COMPILER_ID:MSVC>:/utf-8>")
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif()

add_executable(${PROJECT_NAME} src/main.cpp)
add_subdirectory(src)
set_property(TARGET punchnat PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")

203 changes: 203 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
# PunchNAT
利用 STUN 打洞,同时支持 TCP 与 UDP,同时支持 IPv4 与 IPv6。

注意:TCP 打洞需要 STUN 服务器的支持。

## 用法
`punchnat config.conf`

`config.conf` 示例:
```
listen_port=50000
destination_address=192.168.1.10
destination_port=3389
stun_server=stun.qq.com
log_path=./
```

如果要指定侦听的网卡,那就指定该网卡的 IP 地址
```
listen_on=192.168.1.1
listen_port=50000
destination_address=192.168.1.10
destination_port=3389
stun_server=stun.qq.com
log_path=./
```

如果想要指定多个端口、多个网卡,那就分开多个配置文件

```
punchnat config1.conf config2.conf
```

### Log 文件
目前只提供输出 IP 地址到指定 Log 目录的功能。

在首次获取打洞后的 IP 地址与端口后,以及打洞的 IP 地址与端口发生变化后,会向 Log 目录创建 ip_address.txt 文件(若存在就追加),将 IP 地址与端口写进去。

获取到的打洞地址会同时显示在控制台当中。

`log_path=` 必须指向目录,不能指向文件本身。

如果不需要写入 Log 文件,那就删除 `log_path` 这一行。

### STUN Servers
不支持 TCP 的普通 STUN 服务器(来自于[NatTypeTeste](https://github.com/HMBSbige/NatTypeTester)
- stun.syncthing.net
- stun.qq.com
- stun.miwifi.com
- stun.bige0.com
- stun.stunprotocol.org

同时支持 TCP 与 UDP 打洞的 STUN 服务器(来自于[Natter](https://github.com/MikeWang000000/Natter)
- fwa.lifesizecloud.com
- stun.isp.net.au
- stun.freeswitch.org
- stun.voip.blackberry.com
- stun.nextcloud.com
- stun.stunprotocol.org
- stun.sipnet.com
- stun.radiojar.com
- stun.sonetel.com
- stun.voipgate.com

其它 STUN 服务器:[public-stun-list.txt](https://gist.github.com/mondain/b0ec1cf5f60ae726202e)

---

## 预编译二进制
为了方便使用,目前已经提供了多个平台的二进制可执行文件:
- Windows
- FreeBSD
- Linux

FreeBSD 用户可将下载好的二进制文件复制到 `/usr/local/bin/`,然后运行命令
```
chmod +x /usr/local/bin/punchnat
```

---

## 建立服务
### FreeBSD

**提示:务必事先做完上一个步骤,将二进制文件复制到 `/usr/local/bin/`**

本项目的 `service` 目录已经准备好相应服务文件。

1. 找到 punchnatd 文件,复制到 `/usr/local/etc/rc.d/`
2. 运行命令 `chmod +x /usr/local/etc/rc.d/punchnatd`
3. 把配置文件复制到 `/usr/local/etc/punchnatd/`
- 记得把配置文件命名为 `config.conf`
- 完整的路径名:`/usr/local/etc/punchnatd/config.conf`
4.`/etc/rc.conf` 加一行 `punchnatd_enable="YES"`

最后,运行 `service punchnatd start` 即可启动服务

---

## 编译
编译器须支持 C++17

依赖库:[asio](https://github.com/chriskohlhoff/asio) ≥ 1.18.2

### Windows
请事先使用 vcpkg 安装依赖包 `asio`,一句命令即可:

```
vcpkg install asio:x64-windows asio:x64-windows-static
```
(如果需要 ARM 或者 32 位 x86 版本,请自行调整选项)

然后用 Visual Studio 打开 `sln\punchnat.sln` 自行编译

### FreeBSD
同样,请先安装依赖项 asio,另外还需要 cmake,用系统自带 pkg 即可安装:

```
pkg install asio cmake
```
接着在 build 目录当中构建
```
mkdir build
cd build
cmake ..
make
```

### NetBSD
步骤与 FreeBSD 类似,使用 [pkgin](https://www.netbsd.org/docs/pkgsrc/using.html) 安装依赖项与 cmake:
```
pkgin install asio
pkgin install cmake
```
构建步骤请参考上述的 FreeBSD。

注意,由于 NetBSD 自带的 GCC 版本较低,未必能成功编译出可用的二进制文件,有可能需要用 pkgin 额外安装高版本 GCC。

### Linux
步骤与 FreeBSD 类似,请用发行版自带的包管理器安装 asio 与 cmake。

#### Fedora
````
dnf install asio cmake
````
接着在 build 目录当中构建
```
mkdir build
cd build
cmake ..
make
```

如果所使用发行版的 asio 版本过低,需要自行解决。

如果不想用 io_ruing,请打开项目内的 src/CMakeLists.txt 删除相关选项,编译时会自动使用 epoll。

### macOS
我没苹果电脑,所有步骤请自行解决。

---

## IPv4 映射 IPv6
由于该项目内部使用的是 IPv6 单栈 + 开启 IPv4 映射地址(IPv4-mapped IPv6)来使用 IPv4 网络,因此请确保 v6only 选项的值为 0。

**正常情况下不需要任何额外设置,FreeBSD 与 Linux 以及 Windows 都默认允许 IPv4 地址映射到 IPv6。**

如果不放心,那么可以这样做
### FreeBSD
按照FreeBSD手册 [33.9.5. IPv6 and IPv4 Address Mapping](https://docs.freebsd.org/en/books/handbook/advanced-networking/#_ipv6_and_ipv4_address_mapping) 介绍,在 `/etc/rc.conf` 加一行即可
```
ipv6_ipv4mapping="YES"
```
如果还是不放心,那就运行命令
```
sysctl net.inet6.ip6.v6only=0
```

### Linux
可运行命令
```
sysctl -w net.ipv6.bindv6only=0
```
正常情况下不需要这样做,它的默认值就是 0。

## 其它注意事项
### NetBSD
使用命令
```
sysctl -w net.inet6.ip6.v6only=0
```
设置后,单栈+映射地址模式可以侦听双栈。

但由于未知的原因,它无法主动连接 IPv4 映射地址,因此 `destination_address` 只能使用 IPv6 地址。

### OpenBSD
因为 OpenBSD 彻底屏蔽了 IPv4 映射地址,所以在 OpenBSD 平台只能使用 IPv6 单栈模式。

## 关于代码
### 为什么要用两个 asio::io_context
这里用了两个 asio::io_context,其中一个是用于处理 UDP 数据的异步循环,另一个用于处理内部逻辑以及 TCP 数据的收发。

之所以要这样做,完全是为了迁就 BSD 系统。如果只用一个 io_context 去做所有的事,由于两次接收之间的延迟过高,在 BSD 平台会导致 UDP 丢包率过高。
5 changes: 5 additions & 0 deletions service/config_sample.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
listen_port=33890
destination_port=3389
destination_address=192.168.0.10
#stun_server=stun.qq.com
#log_path=./
43 changes: 43 additions & 0 deletions service/punchnatd
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#!/bin/sh
#
# $FreeBSD$
#

# PROVIDE: punchnat
# REQUIRE: LOGIN DAEMON
# KEYWORD: shutdown

# Add these lines to /etc/rc.conf.local or /etc/rc.conf to enable `punchnatd':
#
# punchnatd_enable (bool): Set to "NO" by default.
# Set it to "YES" to enable punchnatd
# punchnatd_config (path): Set to "/usr/local/etc/punchnatd/config.conf" by default
# Set it to the punchnatd server config

. /etc/rc.subr

name="punchnatd"
rcvar="${name}_enable"

eval ": \${${name}_enable:=\"NO\"}"
eval ": \${${name}_config:=\"/usr/local/etc/${name}/config.conf\"}"

pidfile="/var/run/${name}.pid"
procname="/usr/local/bin/punchnat"
configfile="$(eval echo \${${name}_config})"

start_precmd="punchnatd_startprecmd"
start_cmd=punchnatd_start

punchnatd_startprecmd()
{
touch "${pidfile}"
}

punchnatd_start()
{
/usr/sbin/daemon -c -p ${pidfile} ${procname} ${configfile} > /dev/null 2>&1
}

load_rc_config "$name"
run_rc_command "$1"
39 changes: 39 additions & 0 deletions sln/punchnat.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.32428.217
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "punchnat", "punchnat\punchnat.vcxproj", "{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM = Debug|ARM
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM = Release|ARM
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Debug|ARM.ActiveCfg = Debug|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Debug|ARM64.ActiveCfg = Debug|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Debug|x64.ActiveCfg = Debug|x64
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Debug|x64.Build.0 = Debug|x64
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Debug|x86.ActiveCfg = Debug|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Debug|x86.Build.0 = Debug|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Release|ARM.ActiveCfg = Release|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Release|ARM64.ActiveCfg = Release|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Release|x64.ActiveCfg = Release|x64
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Release|x64.Build.0 = Release|x64
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Release|x86.ActiveCfg = Release|Win32
{9205A90F-CDDA-49BE-A53B-33F31B7AE94F}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FDBF6160-79CE-47E9-ABAF-4C1053872B31}
EndGlobalSection
EndGlobal
Loading

0 comments on commit 6b29fb3

Please sign in to comment.