Anyone who has used home broadband from the three major telecom operators in China and needs to connect to other home networks will almost always experience UDP speed restrictions. In order to avoid the QoS targeting UDP by the three major telecom operators, I have developed a tool, named UDP Hop。The principle of this tool is to regularly re-establish a connection automatically, by change the port number and address.
However, UDP Hop can only forwards UDP traffic. In order to forward TCP traffic using UDP, KCP Tube is developed. The reliable retransmission of KCP ensures that the forwarded TCP packets will not be lost.
Another reason why I developed KCP Tube is that other KCP forwarding tools can only forward TCP traffic, but I need to forward UDP traffic as well. This is mainly for the convenience of playing games.
Of course, in fact, both udphop and kcptube were conceived at the same time. So for convenience, KCP Tube was first developed with a framework, and then trimmed into udphop based on KCP Tube. Then the patch code of udphop was merged back into KCP Tube in reverse.
In order to facilitate the use of Full Cone NAT users, when KCP Tube runs in server basic mode, it can use STUN to punch holes, and supports both IPv4 and IPv6.
Just like the purpose of KCP itself, the main goal of KCP Tube is to reduce latency, rather than focusing on transmitting large amounts of data. Can it transmit large amounts of data? Yes, but the effect may not be better than existing TCP forwarding tools.
Currently 3 modes are supported:
- Client Mode
- Servers Mode
- Relay Mode
Reminder: The time of the client must be synchronized with the server and the time difference cannot exceed 255 seconds.
Please refer Wiki Page, or Document Page
You can generate a configuration file by using KCPTube Generator
kcptube config.conf
Example of client mode:
mode=client
kcp=regular3
inbound_bandwidth=500M
outbound_bandwidth=50M
listen_port=59000
destination_port=3000
destination_address=123.45.67.89
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Example of server mode:
mode=server
kcp=regular3
inbound_bandwidth=1G
outbound_bandwidth=1G
listen_port=3000
destination_port=59000
destination_address=::1
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
stun_server=stun.qq.com
log_path=./
Note: When connecting for the first time, the server will inform the client of its port range. Therefore, the listen_port
of the client mode does not necessarily have to be equal to the destination_port
of the server mode. The port numbers on both sides can be inconsistent, but the port number range written by the client cannot exceed the port number range of the server to avoid the situation where the client selects the wrong port and cannot connect.
If you want to specify the NIC to listen to, then specify the IP address of the NIC and add a line
listen_on=192.168.1.1
If you want to listen to multiple ports and multiple NICs, just run kcptube with multiple configuration files
kcptube config1.conf config2.conf
If you want to test connectivity before establish connection, just add --try
option
kcptube --try config1.conf
or
kcptube config1.conf --try
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
kcp=regular3
inbound_bandwidth=500M
outbound_bandwidth=50M
listen_port=6000
destination_port=3000-4000
destination_address=123.45.67.89
dport_refresh=600
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Example of server mode:
mode=server
kcp=regular3
inbound_bandwidth=1G
outbound_bandwidth=1G
listen_port=3000-4000
destination_port=6000
destination_address=::1
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Example of client mode:
mode=client
kcp=manual
kcp_mtu=1400
kcp_sndwnd=512
kcp_rcvwnd=2048
kcp_nodelay=1
kcp_interval=10
kcp_resend=2
kcp_nc=true
udp_timeout=300
listen_port=6000
destination_port=3000-4000
destination_address=123.45.67.89
dport_refresh=600
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Example of server mode:
mode=server
kcp=manual
kcp_mtu=1400
kcp_sndwnd=512
kcp_rcvwnd=2048
kcp_nodelay=1
kcp_interval=10
kcp_resend=2
kcp_nc=true
udp_timeout=300
listen_port=3000-4000
destination_port=6000
destination_address=::1
encryption_password=qwerty1234
encryption_algorithm=AES-GCM
Name | Value | Require | Note |
---|---|---|---|
mode | client server relay |
Yes | Client Mode Server Mode Relay Node 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 | Port ranges can be specified when running as a server mode |
destination_port | 1 - 65535 | Yes | Port ranges can be specified when running as a client mode |
destination_address | IP address, domain name | Yes | Brackets are not required when filling in an IPv6 address. ultiple addresses should be comma-separated. |
dport_refresh | 20 - 65535 | No | The unit is ‘second’. Not writting this option means using the default value of 60 seconds. 1 to 20 is treated as 20 seconds; greater than 32767 is treated as 32767 seconds. Set to 0 means disable this option. |
encryption_algorithm | AES-GCM AES-OCB chacha20 xchacha20 none |
No | AES-256-GCM-AEAD AES-256-OCB-AEAD ChaCha20-Poly1305 XChaCha20-Poly1305 No Encryption |
encryption_password | Any character | Depends… | …on the setting of encryption_algorithm, if the value is set and it is not none, it is required |
udp_timeout | 0 - 65535 | No | The unit is ‘second’. The default value is 180 seconds, set to 0 to use the default value This option represents the timeout setting between UDP application ↔ kcptube |
keep_alive | 0 - 65535 | No | The unit is ‘second’. The default value is 0, which means that Keep Alive is disabled. This option refers to Keep Alive between two KCP endpoints. Can be enabled on any side. If no response is received after 30 seconds, the channel will be closed. |
mux_tunnels | 0 - 65535 | No | The default value is 0, which means that multiplexing is disabled. This option means how many multiplexing tunnels between two KCP endpoints. Client Mode only. |
stun_server | STUN Server's address | No | Cannot be used if listen_port option is port range mode |
log_path | The directory where the Logs are stored | No | Cannot point to the file itself |
fec | uint8:uint8 | No | The format is fec=D:R , for example fec=20:4 . Note: The maximum total value of D + R is 255 and cannot exceed this number. A value of 0 on either side of the colon indicates that the option is not used. Must be the same value on both side. Please refer to The Usage of FEC |
mtu | Positive Integer | No | MTU Value of current network, is to automatically calculate the value of kcp_mtu |
kcp_mtu | Positive Integer | No | This option refers to the length of the data content within a UDP packet. The value set for this option refers to the value set by calling ikcp_setmtu(). Default value is 1440. |
kcp | manual fast1 - 6 regular1 - 5 |
Yes | Setup Manually Fast Modes Regular Speeds (the number at the end: the smaller the value, the faster the speed) |
kcp_sndwnd | Positive Integer | No | See the table below for default values, which can be overridden individually |
kcp_rcvwnd | Positive Integer | No | See the table below for default values, which can be overridden individually |
kcp_nodelay | Positive Integer | Depends… | …on the setting of ‘kcp=’, if if the value is set as ‘kcp==manual’, this option is required. See the table below for default values. |
kcp_interval | Positive Integer | Depends… | …on the setting of ‘kcp=’, if if the value is set as ‘kcp==manual’, this option is required. See the table below for default values. |
kcp_resend | Positive Integer | Depends… | …on the setting of ‘kcp=’, if if the value is set as ‘kcp==manual’, this option is required. See the table below for default values. |
kcp_nc | yes true 1 no false 0 |
Depends… | …on the setting of ‘kcp=’, if if the value is set as ‘kcp==manual’, this option is required. See the table below for default values. |
outbound_bandwidth | Positive Integer | No | Outbound bandwidth, used to dynamically update the value of kcp_sndwnd during communication |
inbound_bandwidth | Positive Integer | No | Inbound bandwidth, used to dynamically update the value of kcp_rcvwnd during communication |
ipv4_only | yes true 1 no false 0 |
No | If the system disables IPv6, this option must be enabled and set to yes or true or 1 |
ipv6_only | yes true 1 no false 0 |
No | Ignore IPv4 address |
blast | yes true 1 no false 0 |
No | Packets are forwarded as quickly as possible regardless of KCP flow control settings. May lead to overload. |
[listener] | N/A | Yes (Relay Mode only) |
Section Name of Relay Mode, KCP 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, KCP settings for specifying the forwarding mode This tag represents data exchanged with the server |
[custom_input] | N/A | No | Section Name of Custom-IP-Mapping Mode, please refer to The Usage of Custom IP Mappings |
[custom_input_tcp] | N/A | No | Section Name of Custom-IP-Mapping Mode, please refer to The Usage of Custom IP Mappings |
[custom_input_udp] | N/A | No | Section Name of Custom-IP-Mapping Mode, please refer to The Usage of Custom IP Mappings |
Note: encryption_algorithm
and encryption_password
must be consistent at both ends of the communication.
Name | Value | Require | Note |
---|---|---|---|
fib_ingress | 0 - 65535 | No | FIB for ingress connections |
fib_egress | 0 - 65535 | No | FIB for egress connections |
Available suffixes: K / M / G
The suffix is case-sensitive, uppercase is calculated as binary (1024), lowercase is calculated as decimal (1000).
-
Entering 1000 represents a bandwidth of 1000 bps
-
Entering 100k represents a bandwidth of 100 kbps (100000 bps)
-
Entering 100K represents a bandwidth of 100 Kbps (102400 bps)
-
Entering 100M represents a bandwidth of 100 Mbps (102400 Kbps)
-
Entering 1G represents a bandwidth of 1 Gbps (1024 Mbps)
Please note that it is bps (Bits Per Second), not Bps (Bytes Per Second).
This bandwidth values should not larger than your actual bandwidth, otherwise this will cause the sending window to be congested and cause blocking.
Important Notice:
KCPTube will calculate and set the KCP sending window size based on the delay value of the handshake packet and the values of outbound_bandwidth and inbound_bandwidth about 5 seconds after the KCP link is established. Within a period of time after the setup is completed, there is a high chance that the traffic will fluctuate significantly, or even the traffic may suddenly drop to 0, and it will take several seconds to recover.
Fast Mode | kcp_sndwnd | kcp_rcvwnd | kcp_nodelay | kcp_interval | kcp_resend | kcp_nc |
---|---|---|---|---|---|---|
fast1 | 2048 | 2048 | 1 | 1 | 2 | 1 |
fast2 | 2048 | 2048 | 2 | 1 | 2 | 1 |
fast3 | 2048 | 2048 | 1 | 1 | 3 | 1 |
fast4 | 2048 | 2048 | 2 | 1 | 3 | 1 |
fast5 | 2048 | 2048 | 1 | 1 | 4 | 1 |
fast6 | 2048 | 2048 | 2 | 1 | 4 | 1 |
Regular Mode | kcp_sndwnd | kcp_rcvwnd | kcp_nodelay | kcp_interval | kcp_resend | kcp_nc |
---|---|---|---|---|---|---|
regular1 | 1024 | 1024 | 1 | 1 | 5 | 1 |
regular2 | 1024 | 1024 | 2 | 1 | 5 | 1 |
regular3 | 1024 | 1024 | 0 | 1 | 2 | 1 |
regular4 | 1024 | 1024 | 0 | 15 | 2 | 1 |
regular5 | 1024 | 1024 | 0 | 30 | 2 | 1 |
Note: If the packet loss rate is high enough (higner than 10%), kcp_nodelay=1 may better than kcp_nodelay=2. If the packet loss rate is not too high, kcp_nodelay=2 can make the network latency smoother.
For low packet loss environments, each mode is suitable for use. The difference lies only in the amount of wasted traffic and the slightly different upper limit of the highest speed.
Among them, regular3 wastes less traffic.
It is recommended to enable the blast=1
setting at the same time.
For high packet loss environments, consider using FEC settings at the same time. For more details, please refer to The Usage of FEC.
For more details, please refer to Parameter Details.
After obtaining the IP address and port after NAT hole punching for the first time, and after the IP address and port of NAT hole punching change, an ip_address.txt file will be created in the Log directory (overwrite if it exists), and the IP address and port will be written in.
The obtained NAT hole punching address will be displayed on the console at the same time.
log_path=
must point to a directory, not to a file itself.
If you don't need to write to the Log file, then delete the log_path
line.
The STUN servers obtained from NatTypeTeste:
- stun.syncthing.net
- stun.qq.com
- stun.miwifi.com
- stun.bige0.com
- stun.stunprotocol.org
The STUN servers obtained from 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
For ease of use, precompiled binary executable files for multiple platforms have been provided
- Windows
- FreeBSD
- Linux
All precompiled binary files are statically compiled. The Linux version is mostly statically compiled, except for libc. Therefore, two versions have been prepared, one for glibc (2.31) and the other for musl.
For Linux environments, a Docker Image is also provided (currently only for x64). Download kcptube_docker_image.zip and unzip it, then use docker load -i kcptube_docker.tar
to import it.
After importing, use it as:
docker run -v /path/to/config_file.conf:/config_file.conf kcptube config_file.conf
Such as:
docker run -v /home/someone/config1.conf:/config1.conf kcptube config1.conf
FreeBSD users can copy the downloaded binaries to /usr/local/bin/
, then run the command
chmod +x /usr/local/bin/kcptube
The service
directory of this project has prepared corresponding service files.
- Find the kcptube file and copy it to
/usr/local/etc/rc.d/
. - Run the command
chmod +x /usr/local/etc/rc.d/kcptube
. - Copy the configuration file to
/usr/local/etc/kcptube/
.- Remember to name the configuration file
config.conf
.- Full path name:
/usr/local/etc/kcptube/config.conf
- Full path name:
- Remember to name the configuration file
- Add a line
kcptube_enable="YES"
to/etc/rc.conf
.
Finally, run service kcptube start to start the service.
The compiler must support C++17
Dependent libraries:
Please use vcpkg to install the dependent packages asio
and botan
in advance, the command is as follows:
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 version, please adjust the options yourself)
Then open sln\kcptube.sln
with Visual Studio and compile it yourself
Similarly, please install the dependencies asio
and botan3
first, and cmake is also required, which can be installed with the pkg that comes with the Freebsd system:
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, please install asio
, botan3
and cmake
with the package manager that comes with the distribution.
apk add asio botan3-libs cmake
Then build in the ‘build’ directory
mkdir build
cd build
cmake ..
make
If the asio
version of the distribution you are using is too low, you need to solve it yourself.
There are two ways
-
Way 1
After compiling according to the normal process, delete the newly generated kcptube binary file, and run the command
make VERBOSE=1
Then copy the last C++ link command from the output, and change
-lbotan-3
in the middle to the full path of libbotan-3.a, such as/usr/lib/x86_64-linux-gnu/libbotan-3.a
. -
Way 2
Open src/CMakeLists.txt,Change
target_link_libraries(${PROJECT_NAME} PRIVATE botan-3)
totarget_link_libraries(${PROJECT_NAME} PRIVATE botan-3 -static)
then it can be compiled normally. Note that if the system uses glibc, static compilation in this way will also include glibc, which will result in warnings about getaddrinfo.
I don't have an Apple computer, please solve all the steps by yourself.
Increasing the receive buffer can improve UDP transmission performance.
You can use the command sysctl kern.ipc.maxsockbuf
to view the buffer size. If you need to adjust it, run the following command (replace the number with the desired value):
sysctl -w kern.ipc.maxsockbuf=33554434
Alternatively, you can write the following in /etc/sysctl.conf
:
kern.ipc.maxsockbuf=33554434
You can use the command sysctl net.inet.udp.recvspace
to view the receive buffer size. If you need to adjust it, run the following command (replace the number with the desired value):
sysctl -w net.inet.udp.recvspace=33554434
Alternatively, you can write the following in /etc/sysctl.conf
:
net.inet.udp.recvspace=33554434
If necessary, you can also adjust the value of net.inet.udp.sendspace
, which is for the send buffer.
For the receive buffer, you can use the commands sysctl net.core.rmem_max
and sysctl net.core.rmem_default
to view the receive buffer size.
If you need to adjust it, run the following commands (replace the number with the desired value):
sysctl -w net.core.rmem_max=33554434
sysctl -w net.core.rmem_default=33554434
Alternatively, you can write the following in /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
, which are for the send buffer settings.
As kcptube uses IPv6 single-stack + enabled IPv4 mapped addresses (IPv4-mapped IPv6) to simultaneously use IPv4 and IPv6 networks internally, please ensure that the value of the v6only option is 0.
Under normal circumstances, no additional settings are required, as FreeBSD, Linux, and Windows all allow IPv4 addresses to be mapped to IPv6 by default.
If the system does not support IPv6 or IPv6 is disabled, please set ipv4_only=true in the configuration file, so that kcptube will fall back to using IPv4 single-stack mode.
After running command
sysctl -w net.inet6.ip6.v6only=0
Single stack + mapped address mode can listen to dual stack.
However, for unknown reasons, it may not be possible to actively connect to an IPv4-mapped address may not be possible.
OpenBSD completely blocks IPv4-mapped IPv6, if you use dual-stack on the OpenBSD platform, you need to save the configuration file as two files, one of which enables ipv4_only=1, and then load both configuration files when using kcptube.
In most cases, this kind of message only occurs on the server side, not on the client side.
If you do encounter it on the client side, please check whether the value of mux_tunnels is set too high. (please also refer to the paragraph on "Multiplexing (mux_tunnels=N)")
In general, most BSD systems will not encounter this issue, only GhostBSD updated in the second half of 2023 will encounter it.
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 or comment out this line.
Alternatively, use the command sysctl kern.maxfiles=300000
to temporarily change the limit value.
Since the Open Files limit for Linux systems is 1024, it's easy to encounter such problems.
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
Since TCP data transmission is required, data verification cannot be ignored, just like TCP itself.
Regardless of whether encryption is enabled or not, this program will reduce the MTU by 2 bytes and append 2-byte data at the end.
If the encryption option is used, then the 2-byte data appended at the end will be a temporarily generated IV.
If the encryption feature is not selected, the 2-byte data appended at the end will be the checksum, generated by XORing the high and low bytes of CRC32.
Please note that using checksum still cannot completely avoid content errors, just like TCP itself. If you really need accuracy, please enable the encryption option.
The function of multiplexing is not automatically enabled by default. Without using this feature, for each incoming connection accepted, a corresponding outgoing connection is created.
The reason is to avoid the QoS of operators. Once a port number is affected by QoS in multiplexing mode, other sessions sharing the same port number will also be blocked until the port number is changed.
The connections are independent of each other. Even if a port number is affected by QoS, only this session will be affected, not other sessions.
Unless the carried program generates many independent connections. In this case, KCP Tube will create many KCP channels and consume more CPU resources during communication.
If you really need to use the ‘multiplexing’ function, you can refer to the following classifications:
-
Scenarios suitable for using multiplexing:
- Proxy forwarding programs, such as Shadowsocks
-
Scenarios that do not require using multiplexing:
- VPN, such as
- OpenVPN
- Wireguard
- VPN, such as
When "Multiplexing" is enabled, KCPTube will pre-create N links, and all inbound new connections will transmit data from the existing links instead of creating new links separately. At this time, the KCP channel timeout is 30 seconds.
In most cases, setting mux_tunnels
to 3 - 10 is enough, and there is no need to set an excessively high value.
To reduce latency, kcptube has enabled the TCP_NODELAY option. For some high-traffic application scenarios, this may result in a reduction in the amount of TCP data transmitted.
KCP Tube uses a modified version of KCP:
- The original ‘sent data packet cache’ used a queue, and the modified version changed to use std::map, with three mapping tables: a total queue sorted by packet number, and two wait-for-resend queues, one sorted by time and the other sorted by the number of lost packets.
- The original
flush()
function first transfers the data to be sent to the sending queue, and then completes the three things of ‘sending new data packet’, ‘resending data packet’, and ‘sending ACK packet’ in the same loop. The modified version changes to first do ‘resend data packet’ and ‘send ACK packet’, and then do ‘transfer data to be sent to sending queue’, while sending it during the transfer. - The original
check()
function would traverse the sending queue every time to look for the timestamp of the already arrived resend. In the modified version: the first timestamp is read from the already sorted mapping table, eliminating the searching step.
And other ‘bugs’ in the original version, will also exist in kcptube. For example:
Therefore, kcptube has set a more obvious pause plan. For TCP data, when the receiving limit is reached (queue full), the reception of TCP data will be paused until there is space available to resume; for UDP data, it will be directly discarded when the receiving limit is reached.
This limit will not have much impact on application scenarios with small transfer volumes.
The thread pool used by kcptube comes from BS::thread_pool, and has been slightly modified for parallel encryption and decryption processing in multiple connections.
I wrote these codes very casually, wherever I thought of something, I wrote it down, resulting in a messy layout. To be precise, it is extremely chaotic.
As for the feelings of the readers... well, they will definitely not be pleased. It's not my problem, I'm out!