Some ISPs limit the UDP traffic of home broadband, such as the three major ISPs in China.
To overcome this limitation, a common solution is to "turn" UDP traffic into TCP traffic using tools such as udp2raw. Unfortunately, the server version of udp2raw only supports Linux. Phantun is another tool similar to udp2raw.
So, can we continue to use UDP to avoid speed limits? This approach would offer more flexibility. Perhaps we can, as someone has suggested that after UDP is limited, the speed will recover as long as we reconnect.
If that's the case, we can build a new tool based on this idea - let's call it UDP Hop. Every once in a while, the UDP Hop client will automatically re-establish a connection and transfer the transmission link to the new connection to continue sending data.
For the convenience of Full Cone NAT users of home broadband, when UDP Hop runs in server basic mode, it can use STUN punch-through and support both IPv4 and IPv6.
Unlike TCP disguised tools, UDP Hop keeps using UDP throughout the process and assigns a Session ID for each UDP connection ("source IP: source port" tuple) internally to distinguish multiple UDP connections. The timeout period is 180 seconds, which means that a single Session will be automatically cleared if there is no traffic for more than 3 minutes.
When using it in practice, adjust the frequency of port hopping according to device performance to avoid causing significant NAT pressure on your gateway device, thereby affecting network performance. If conditions permit, it is recommended to run it on a soft router. If the soft router itself is also the gateway, this can eliminate NAT burden.
If you want to forward TCP traffic at the same time, you can try KCP Tube.
Reminder: The time of the client must be synchronized with the server and the time difference cannot exceed 255 seconds.
udphop config.conf
Example of client mode:
mode=client
listen_port=59000
destination_port=3000
destination_address=123.45.67.89
dport_refresh=3600
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Example of server mode:
mode=server
listen_port=3000
destination_port=59000
destination_address=::1
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
stun_server=stun.qq.com
log_path=./
Note: The listen_port
in client mode does not necessarily have to be equal to the destination_port
in server mode; the ports on both sides can be different.
If you want to specify the network card to listen on, simply specify the IP address of that network card by adding a line:
listen_on=192.168.1.1
If you want to listen on multiple ports and multiple network cards, separate them into multiple configuration files:
udphop config1.conf config2.conf
Use the --check-config
option to check the configuration file for errors.
kcptube --check-config config1.conf
or
kcptube config1.conf --check-config
Example of client mode:
mode=client
listen_port=6000
destination_port=3000-4000
destination_address=123.45.67.89
dport_refresh=3600
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Example of server mode:
mode=server
listen_port=3000-4000
destination_port=6000
destination_address=::1
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Name | Possible Values | Required | Remarks |
---|---|---|---|
mode | client server |
Yes | Choose between client and server mode |
listen_on | domain name or IP address | No | domain name / IP address only. Multiple addresses should be comma-separated. |
listen_port | 1 - 65535 | Yes | Specify the port range when running as a server |
destination_port | 1 - 65535 | Yes | Specify the port range when running as a client |
destination_address | IP address, domain name | Yes | When inputting an IPv6 address, no need for square brackets. Multiple addresses should be comma-separated. |
dport_refresh | 20 - 65535 | No | Unit: seconds. Default value is 60 seconds. If less than 20 seconds, it will be considered as 20 seconds; if greater than 65535, it will be considered as 65536 seconds |
encryption_algorithm | AES-GCM AES-OCB chacha20 xchacha20 |
No | Select from AES-256-GCM-AEAD, AES-256-OCB-AEAD, ChaCha20-Poly1305, XChaCha20-Poly1305 |
encryption_password | Any characters | Depending on situation | Required when setting encryption_algorithm |
timeout | 0 - 65535 | No | Unit: seconds. Default value is 1800. Set to 0 to use the default value. Represents the timeout setting between the UDP application and udphop |
keep_alive | 0 - 65535 | No | Default value is 0, which means Keep Alive is disabled |
stun_server | STUN server address | No | Cannot be used when listen_port is in port range mode |
log_path | Directory for storing logs | No | Should point to a directory, not a file itself. If not needed, remove this line |
ipv4_only | yes true 1 no false 0 |
No | If IPv6 is disabled on the system, enable this option and set to yes, true, or 1 |
ipv6_only | yes true 1 no false 0 |
No | Ignore IPv4 address |
fec | uint8:uint8 | No | Format is fec=D:R , for example fec=20:3 . The total of D + R cannot exceed 255. If one side is set to 0, it means this option is not used. Both ends must have the same settings |
[listener] | N/A | Yes (Relay Mode only) |
Section Name of Relay Mode, UDPHop settings for specifying the listening mode This tag represents data exchanged with the client |
[forwarder] | N/A | Yes (Relay Mode only) |
Section Name of Relay Mode, UDPHop settings for specifying the forwarding mode This tag represents data exchanged with the server |
FEC format is fec=D:R
, where D represents the original data quantity, and R represents the redundancy data quantity. The total of D + R cannot exceed 255.
For example, you can input fec=20:4
, which means for every 20 data packets sent, 4 redundant packets are generated and sent.
Reminder: It is not recommended for OpenVPN using AEAD encryption mode to use this feature, because OpenVPN's tolerance for out-of-order packets is very poor under this circumstance, and UDPHop is not responsible for reordering packets, even for FEC-recovered data.
Please refer to The Usage of Relay Mode.
After obtaining the punched IP address and port for the first time, and when there is a change in the punched IP address and port, an ip_address.txt
file will be created in the Log directory (overwriting if it already exists), with the IP address and port written into it.
The obtained punched address will also be displayed in the console.
log_path=
must point to a directory, not a file itself.
If log writing is not needed, then remove the log_path
line.
STUN Servers found in NatTypeTeste:
- stun.syncthing.net
- stun.qq.com
- stun.miwifi.com
- stun.bige0.com
- stun.stunprotocol.org
STUN Servers found in 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
Other STUN Servers: public-stun-list.txt
To facilitate usage, pre-compiled binary executable files are provided for multiple platforms:
- Windows
- FreeBSD
- Linux
All pre-compiled binary files are statically compiled. The Linux version is mostly statically compiled, except for libc. Therefore, two versions are prepared, one for glibc (2.31) and the other for musl.
For Linux environments, Docker images are also available (currently limited to x64). Download udphop_docker_image.zip and unzip it, then import it using docker load -i udphop_docker.tar
.
After importing, the usage is as follows:
docker run -v /path/to/config_file.conf:/config_file.conf udphop config_file.conf
For example:
docker run -v /home/someone/config1.conf:/config1.conf udphop config1.conf
FreeBSD users can copy the downloaded binary file to /usr/local/bin/
and then run the command:
chmod +x /usr/local/bin/udphop
The corresponding service files in the service
directory of this project have been prepared.
- Find the udphop file and copy it to
/usr/local/etc/rc.d/
. - Run the command
chmod +x /usr/local/etc/rc.d/udphop
. - Copy the configuration file to
/usr/local/etc/udphop/
.- Remember to name the configuration file
config.conf
.- The full pathname is:
/usr/local/etc/udphop/config.conf
.
- The full pathname is:
- Remember to name the configuration file
- Add a line to
/etc/rc.conf
:udphop_enable="YES"
Finally, run service udphop start
to start the service.
The compiler must support C++17.
Dependencies:
Please use vcpkg to install the dependency package asio
in advance, with one command:
vcpkg install asio:x64-windows asio:x64-windows-static
vcpkg install botan:x64-windows botan:x64-windows-static
(If you need ARM or 32-bit x86 versions, please adjust the options yourself.)
Then open sln\udphop.sln
with Visual Studio and compile it yourself.
Similarly, install dependencies asio and botan3 first, and cmake is also required. You can use the system's built-in pkg to install them:
pkg install asio botan3 cmake
Then build in the build directory:
mkdir build
cd build
cmake ..
make
The steps are similar to FreeBSD. For NetBSD, use pkgin to install dependencies and cmake:
pkgin install asio
pkgin install cmake
Please use pkg_add
on OpenBSD to install the two dependencies mentioned above. On DragonflyBSD, please use pkg
, the usage is the same as FreeBSD.
Since botan-3 is not yet included in these BSD systems, it needs to be compiled manually.
Please refer to the aforementioned FreeBSD for the remaining build steps.
Note that due to the lower versions of the compilers included in these BSD systems, please install a higher version of GCC in advance.
The steps are similar to FreeBSD. Install asio and botan3 as well as cmake using the package manager provided by the distribution.
apk add asio botan3-libs cmake
Then build in the build directory:
mkdir build
cd build
cmake ..
make
There are two approaches:
-
Approach 1
Compile as usual and delete the generated
udphop
binary file. Then run the command:make VERBOSE=1
Extract the last C++ linking command from the output, replace the
-lbotan-3
in the middle with the full path tolibbotan-3.a
, for example/usr/lib/x86_64-linux-gnu/libbotan-3.a
. -
Approach 2
Open
src/CMakeLists.txt
, changetarget_link_libraries(${PROJECT_NAME} PRIVATE botan-3)
totarget_link_libraries(${PROJECT_NAME} PRIVATE botan-3 -static)
.Then compile as usual. Note that if the system uses glibc, this will statically compile glibc as well, resulting in warnings about
getaddrinfo
.
I don't have a Mac computer, please figure out the steps by yourself.
Increasing the receive buffer can improve UDP transmission performance.
Use the command sysctl kern.ipc.maxsockbuf
to check the buffer size. To adjust it, run the command (change the number to the desired value):
sysctl -w kern.ipc.maxsockbuf=33554434
Alternatively, write it to /etc/sysctl.conf
:
kern.ipc.maxsockbuf=33554434
Use the command sysctl net.inet.udp.recvspace
to check the receive buffer size. To adjust it, run the command (change the number to the desired value):
sysctl -w net.inet.udp.recvspace=33554434
Alternatively, write it to /etc/sysctl.conf
:
net.inet.udp.recvspace=33554434
If necessary, you can also adjust the value of net.inet.udp.sendspace
. This is the setting for the send buffer.
For the receive buffer, use the commands sysctl net.core.rmem_max
and sysctl net.core.rmem_default
to check the size.
To adjust it, run the command (change the number to the desired value):
sysctl -w net.core.rmem_max=33554434
sysctl -w net.core.rmem_default=33554434
Alternatively, write it to /etc/sysctl.conf
:
net.core.rmem_max=33554434
net.core.rmem_default=33554434
If necessary, you can also adjust the values of net.core.wmem_max
and net.core.wmem_default
. These are the settings for the send buffer.
Since udphop internally uses IPv6 single-stack + enabling IPv4-mapped IPv6 addresses to simultaneously use IPv4 and IPv6 networks, make sure that the v6only
option is set to 0.
In normal situations, no additional settings are required. FreeBSD, Linux, and Windows all allow IPv4 addresses to be mapped to IPv6 by default.
If the system does not support IPv6 or it is disabled, set ipv4_only=true
in the configuration file. This will cause udphop to fall back to using IPv4 single-stack mode.
UDPHop does not split data packets, it only adds a "shell" on the original data packet. Therefore, for programs like OpenVPN, the MTU value needs to be modified.
The size of the "shell" added by UDPHop is:
UDPHop data header occupies 12 bytes.
- Encryption option
- If encryption is enabled, an additional 48 bytes are added
- If encryption is not enabled, only 2 bytes are added for checksum
If FEC is enabled, an additional 5 bytes will be occupied.
Use the command
sysctl -w net.inet6.ip6.v6only=0
After setting, single-stack + mapping address mode can listen to dual-stack.
However, for unknown reasons, it is not possible to actively connect to IPv4 mapped addresses.
Because OpenBSD completely blocks IPv4 mapped addresses, if dual-stack is used on the OpenBSD platform, the configuration file needs to be saved as two, one of which enables ipv4_only=1, and then both configuration files are loaded when using udphop.
Most of the time, this prompt is only encountered on the server side and not on the client side.
If it does occur on the client side, please check if the value of mux_tunnels
is too high (please also refer to the "Multiplexing (mux_tunnels=N)" section).
In general, most BSD systems will not encounter this, only GhostBSD updated in the second half of 2023 will encounter this phenomenon.
This is because GhostBSD has added this line in /etc/sysctl.conf
:
kern.maxfiles=100000
This line reduces the upper limit, far below the corresponding value of the original FreeBSD.
The solution is simple, just delete this line. Commenting it out also works.
You can also use the command sysctl kern.maxfiles=300000
to temporarily modify the upper limit value.
Due to the Open Files limit in Linux system being 1024, it is easy to encounter this problem.
Temporary solution:
- Run the command
ulimit -n
to check the output value - If the value is indeed only 1024, run the command
ulimit -n 300000
Permanent solution:
Edit /etc/security/limits.conf and add at the end:
* hard nofile 300000
* soft nofile 300000
root hard nofile 300000
root soft nofile 300000
The thread pool used by UDPHop comes from BS::thread_pool, with some modifications made for parallel encryption and decryption processing in multiple connections.
The FEC used by UDPHop uses Reed-Solomon coding, and the FEC code library comes from fecpp with some modifications.
The code is written very casually, wherever I think of writing, so the layout is messy.
As for the reader's feelings... well... that will definitely be unpleasant.