Click Here for English Version
Anyone who has used home broadband from the three major operators and needs home broadband interconnection will almost always experience UDP being speed limited. In order to avoid the QoS of the three major operators for UDP, I made another tool called UDP Hop. The principle is to regularly establish new connections (change port numbers and connect to new addresses).
However, UDP Hop only supports forwarding UDP traffic. In order to be able to use UDP to forward TCP traffic, there is KCP Tube. KCP's reliable retransmission is used to ensure that forwarded TCP packets will not be lost.
Another reason for making KCP Tube is that other KCP forwarding tools can only forward TCP traffic, but I need to use KCP to forward UDP traffic. Mainly for the convenience of playing games.
Of course, udphop and kcptube were actually conceived at the same time. So for the sake of convenience, we first set up the KCP Tube and set up the framework, and then cut it into UDP Hop based on the KCP Tube. Then reverse-merge the UDP Hop patch code back to KCP Tube.
In order to facilitate home broadband Full Cone NAT users, KCP Tube can use STUN to drill holes when running in basic server mode, 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 favoring the transmission of extremely large traffic. So can it transmit extremely large traffic? Yes, but the effect may not be as good as the existing TCP-KCP forwarding tool.
Currently 3 modes are supported:
Note that the client's time and the server's time must be synchronized, and the time difference cannot be greater than 255 seconds.
Please go to the wiki page, or go to the documentation page.
If you need a profile generator, go here: KCPTube Generator
kcptube config.conf
Client mode example:
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
Server mode example:
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, so listen_port
in client mode does not have to be equal to destination_port
in server mode. The ports on both sides can be inconsistent, but the port number range written by the client cannot Beyond the scope of the server to prevent the client from selecting the wrong port and failing to connect.
If you want to specify the listening network card, then specify the IP address of the network card and add one line.
listen_on=192.168.1.1
If you want to listen to multiple ports and multiple network cards, separate multiple configuration files.
kcptube config1.conf config2.conf
If you want to test whether the connection is smooth before connecting, you can add the --try
option
kcptube --try config1.conf
or
kcptube config1.conf --try
Use the --check-config
option to verify that the configuration file is correct:
kcptube --check-config config1.conf
or
kcptube config1.conf --check-config
Client mode example:
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
Server mode example:
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
Client mode example:
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
Server mode example:
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 | Settable value | Required | Remark |
---|---|---|---|
mode | client server relay | yes | Client server relay node |
listen_on | Domain name or IP address | no | Only domain name or IP address can be filled in. Please separate multiple addresses with commas |
listen_port | 1-65535 | yes | When running as a server, you can specify a port range |
destination_port | 1-65535 | yes | Port ranges can be specified when running as a client. Please separate multiple addresses with commas |
destination_address | IP address, domain name | yes | No square brackets are required when filling in the IPv6 address |
dport_refresh | 0 - 32767 | no | The unit is "second". If left blank, the default value of 60 seconds will be used. 1 to 20 is calculated as 20 seconds, and greater than 32767 is calculated as 32767 seconds. Set to 0 to disable. |
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 situation | Required when encryption_algorithm is set and is not none |
udp_timeout | 0 - 65535 | no | The unit is "second". The default value is 180 seconds. If set to 0, the default value is used. 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 is equivalent to disabling Keep Alive. This option refers to Keep Alive between two KCP ends Can be enabled unilaterally to detect if the channel stops responding. If there is no response after 30 seconds, the channel will be closed. |
mux_tunnels | 0 - 65535 | no | The default value is 0, which is equivalent to not using multiplexing channels. This option refers to the number of multiplexing channels between the two KCP ends. This option is only enabled on the client side. |
stun_server | STUN server address | no | Cannot be used when listen_port is in port range mode |
log_path | Directory to store Log | no | Cannot point to the file itself |
fec | uint8:uint8 | no | The format is fec=D:R , for example, fec=20:3 can be filled in.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. The settings must be the same on both ends. For details, please refer to the FEC usage guide. |
mtu | positive integer | no | Current network MTU value, used to automatically calculate kcp_mtu |
kcp_mtu | positive integer | no | Default value is 1440. The value set by calling ikcp_setmtu() is the length of the data content in the UDP packet. |
kcp | manual fast1-6 regular1-5 | yes | Manually set fast normal speed (Number at the end: the smaller the value, the faster the speed) |
kcp_sndwnd | positive integer | no | The default values are shown in the table below and can be overridden individually. |
kcp_rcvwnd | positive integer | no | The default values are shown in the table below and can be overridden individually. |
kcp_nodelay | positive integer | Depends on the situation | Required when kcp=manual, the default value is shown in the table below |
kcp_interval | positive integer | Depends on the situation | Required when kcp=manual, the default value is shown in the table below |
kcp_resend | positive integer | Depends on the situation | Required when kcp=manual, the default value is shown in the table below |
kcp_nc | yes true 1 no false 0 | Depends on the situation | Required when kcp=manual, the default value is shown in the table below |
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 the communication process |
ipv4_only | yes true 1 no false 0 | no | If IPv6 is disabled on the system, this option must be enabled and set to yes or true or 1 |
ipv6_only | yes true 1 no false 0 | no | Ignore IPv4 addresses |
blast | yes true 1 no false 0 | no | Try to ignore KCP flow control settings and forward packets as quickly as possible. May cause excessive load |
[listener] | N/A | yes (relay mode only) | The label of the relay mode, used to specify the KCP in the listening mode. Setting this label indicates the interaction data with the client. |
[forwarder] | N/A | yes (relay mode only) | The label of the relay mode, used to specify the KCP of the transfer mode. Setting this label indicates the interaction data with the server. |
[custom_input] | N/A | no | Label of custom mapping mode, please refer to the usage method of custom mapping |
[custom_input_tcp] | N/A | no | Label of custom mapping mode, please refer to the usage method of custom mapping |
[custom_input_udp] | N/A | no | Label of custom mapping mode, please refer to the usage method of custom mapping |
Among them, encryption_algorithm
and encryption_password
must be consistent at both ends of the communication.
name | Settable value | Required | Remark |
---|---|---|---|
fib_ingress | 0 - 65535 | no | FIB used by inbound connections |
fib_egress | 0 - 65535 | no | FIB used for outbound connections |
Available suffixes: K/M/G
The suffix is case-sensitive, uppercase is calculated as binary (1024), and lowercase is calculated as decimal (1000).
Fill in 1000, indicating that the bandwidth is 1000 bps
Fill in 100k, indicating that the bandwidth is 100 kbps (100000 bps)
Fill in 100K, indicating that the bandwidth is 100 Kbps (102400 bps)
Fill in 100M, indicating that the bandwidth is 100 Mbps (102400 Kbps)
Fill in 1G, indicating that the bandwidth is 1 Gbps (1024 Mbps)
Note that it is bps (Bits Per Second), not Bps (Bytes Per Second).
It should be reminded that the bandwidth value filled in should not exceed the actual bandwidth to avoid congestion in the sending window.
IMPORTANT NOTE :
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.
Quick 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 |
normal speed 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 |
Among them, the higher the packet loss rate (higher than 10%), the more advantage kcp_nodelay=1 has over kcp_nodelay=2. When the packet loss rate is not particularly high, kcp_nodelay=2 can make the delay jitter smoother.
For low packet loss environments, each mode is suitable for use. The only difference lies in whether more or less wasted traffic is used, and the upper limit of the maximum speed is different. Among them, regular3 does not waste so much traffic.
It is recommended to enable blast=1
setting at the same time.
For high packet loss environments, consider overlaying the FEC setting. For details, please refer to the FEC usage guide.
For more details, see the parameter list.
After the hole-punched IP address and port are obtained for the first time, and after the hole-punched IP address and port change, the ip_address.txt file will be created in the Log directory (overwritten if it exists), and the IP address and port will be written into it.
The obtained hole drilling address will be displayed in the console at the same time.
log_path=
must point to a directory, not the file itself.
If you do not need to write to the Log file, delete the log_path
line.
Common STUN servers found from NatTypeTeste:
STUN server found from Natter:
Other STUN servers: public-stun-list.txt
For ease of use, binary executable files for multiple platforms have been provided:
Precompiled binaries are all statically compiled. The Linux version is basically statically compiled, except for libc, so two versions are prepared, one for glibc (2.31) and the other for musl.
For the Linux environment, Docker images are also provided (currently x64 only). Download kcptube_docker_image.zip and decompress it, and then use docker load -i kcptube_docker.tar
to import it.
After importing, the usage method is:
docker run -v /path/to/config_file.conf:/config_file.conf kcptube config_file.conf
For example:
docker run -v /home/someone/config1.conf:/config1.conf kcptube config1.conf
FreeBSD users can copy the downloaded binary file to /usr/local/bin/
and then run the command
chmod +x /usr/local/bin/kcptube
The corresponding service files have been prepared in the service
directory of this project.
/usr/local/etc/rc.d/
chmod +x /usr/local/etc/rc.d/kcptube
/usr/local/etc/kcptube/
config.conf
/usr/local/etc/kcptube/config.conf
kcptube_enable="YES"
to /etc/rc.conf
Finally, run service kcptube start
to start the service
The compiler must support C++20
Dependent libraries:
Please use vcpkg to install the dependency 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 use Visual Studio to open slnkcptube.sln
and compile it yourself
Similarly, please install the dependencies asio and botan3 first. In addition, cmake is required. You can install it with the system's own pkg:
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, please use pkgin to install dependencies and cmake:
pkgin install asio
pkgin install cmake
OpenBSD Please use pkg_add
to install the above two dependencies. DragonflyBSD please use pkg
, the usage is the same as FreeBSD.
Since botan-3 has not been included in these BSD systems, you must compile botan-3 yourself.
For the remaining build steps, please refer to FreeBSD above.
Note that since these BSDs come with lower compiler versions, please install a higher version of GCC in advance.
The steps are similar to FreeBSD. Please use the package manager that comes with the distribution to install asio, botan3 and cmake.
apk add asio botan3-libs cmake
Then build in the build directory
mkdir build
cd build
cmake ..
make
There are two ways
Practice 1
Compile according to the normal process, delete the kcptube binary file just generated, and run the command
make VERBOSE=1
Then extract the last C++ link command from the output content, 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
.
Practice 2
Open src/CMakeLists.txt and change target_link_libraries(${PROJECT_NAME} PRIVATE botan-3)
to target_link_libraries(${PROJECT_NAME} PRIVATE botan-3 -static)
Then it compiles normally. Note that if the system uses glibc, it will be statically compiled together with glibc, and a warning about getaddrinfo will pop up.
I don't have an Apple computer, so please solve all the steps yourself.
Increasing the receive cache can improve UDP transmission performance
You can use the command sysctl kern.ipc.maxsockbuf
to view the cache size. If adjustments are needed, run the command (change the number to the desired value):
sysctl -w kern.ipc.maxsockbuf=33554434
Or write in /etc/sysctl.conf
kern.ipc.maxsockbuf=33554434
You can use the command sysctl net.inet.udp.recvspace
to check the receive buffer size. If adjustments are needed, run the command (change the number to the desired value):
sysctl -w net.inet.udp.recvspace=33554434
Or write in /etc/sysctl.conf
net.inet.udp.recvspace=33554434
If necessary, you can adjust the value of net.inet.udp.sendspace
at the same time. This is the send cache setting.
For the receive cache, you can use the commands sysctl net.core.rmem_max
and sysctl net.core.rmem_default
to view the receive cache size.
If adjustments are needed, run the command (change the number to the desired value):
sysctl -w net.core.rmem_max=33554434
sysctl -w net.core.rmem_default=33554434
Or write in /etc/sysctl.conf
net.core.rmem_max=33554434
net.core.rmem_default=33554434
If necessary, you can adjust the values of net.core.wmem_max
and net.core.wmem_default
at the same time. This is the send cache setting.
Since kcptube internally uses IPv6 single stack + turns on IPv4 mapped address (IPv4-mapped IPv6) to use both IPv4 and IPv6 networks, please ensure that the value of the v6only option is 0.
Under normal circumstances, 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 IPv6 is disabled, please set ipv4_only=true in the configuration file, so that kcptube will fall back to using IPv4 single-stack mode.
Use command
sysctl -w net.inet6.ip6.v6only=0
After setting, single stack + mapped address mode can listen to dual stack.
However, due to unknown reasons, the IPv4 mapped address may not be actively connected.
Because OpenBSD completely blocks IPv4 mapping addresses, if you use dual stack on the OpenBSD platform, you need to save two configuration files, one of which enables ipv4_only=1, and then load both configuration files at the same time when using kcptube.
In most cases, this prompt will only be encountered on the server side, not the client side.
If it is indeed encountered on the client, please check whether the value of mux_tunnels
is too high (please refer to the "Multiplexing (mux_tunnels=N)" paragraph by the way).
Under normal circumstances, the vast majority of BSD systems will not encounter this kind of thing. Only GhostBSD that will be updated in the second half of 2023 will encounter this phenomenon.
This is because GhostBSD added this line to /etc/sysctl.conf
:
kern.maxfiles=100000
This line reduces the upper limit to much lower than the corresponding value in vanilla FreeBSD.
The solution is simple, just delete this line. You can also comment it out.
You can also use the command sysctl kern.maxfiles=300000
to temporarily modify the upper limit value.
Since the number of Open Files in Linux systems is limited to 1024, it is easy to encounter this problem.
Temporary solution:
ulimit -n
to view the output valueulimit -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 needs to be transmitted, data validation cannot be ignored, just like TCP itself.
Regardless of whether it is encrypted or not, kcptube will reduce the MTU by 2 bytes and append 2 bytes of data.
If the encryption option has been used, the appended 2 bytes of data are the temporarily generated IV.
If you choose not to use the encryption function, the appended 2-byte data is the check code, which is the XOR of the high and low bits of CRC32.
It should be reminded that using check codes still cannot 100% prevent content errors, and the same is true for TCP itself. If you really need to be precise, enable the encryption option.
Although KCP Tube has a "multiplexing" function, it is not actively opened by default. Without this feature, for every inbound connection accepted, a corresponding outbound connection is created.
The reason is to avoid the operator's QoS. In the multiplexing state, once a certain port number is QoS, other sessions sharing the same port number will be blocked at the same time until the port number is changed.
The connections are independent of each other. Even if a certain port number is QoS, only this session will be affected and other sessions will not be affected.
Unless the hosted program generates a large number of independent connections. In this case, KCP Tube will create a large number of KCP channels, which will consume more CPU resources during the communication process.
If you really want to use the "multiplexing" function, you can refer to the following categories:
Scenarios suitable for using "multiplexing":
Scenarios where "multiplexing" is not necessary:
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 timeout time of the KCP channel is 30 seconds.
Generally speaking, setting `mux_tunnels to 3 ~ 10 is enough, and there is no need to set too high a value.
To reduce latency, kcptube enables the TCP_NODELAY option. For some large traffic application scenarios, the amount of TCP data transmission may be reduced.
Based on the original KCP, the following modifications have been made:
flush()
first transfers the data to be sent to the sending queue, and then redoes the three things of "sending new data packets", "resending data packets", and "sending ACK packets" in the same cycle. The modified version first performs "data packet retransmission" and "ACK packet transmission", and then "transfers the data to be sent to the sending queue", and sends it during the transfer period.check()
will traverse the sending queue again every time to find the retransmission timestamp of the reached point. The modified version becomes: read the first timestamp from the sorted mapping table, eliminating the search step.In addition, the original version has "bugs", and kcptube will also have them. For example:
So kcptube set up a more obvious suspension plan. For TCP data, when the reception limit is reached (the queue is full), the reception of TCP data will be suspended until there is space and then resumed; for UDP data, the packet will be lost directly when the reception limit is reached.
This limitation will basically have no impact on application scenarios where the transmission volume is not large.
The thread pool used by kcptube comes from BS::thread_pool, with some modifications for parallel encryption and decryption processing during multiple connections.
The code is written very casually, and I write it wherever I think, so the layout is confusing. To be precise, it's very confusing.
Some of the lines of code are as long as bamboo poles, mainly because I was too lazy to change lines in order to follow the train of thought when writing. After all, I don't use vim/emacs. When I use an IDE, the text size set in the code area of the IDE is different from the text size in other areas, and even the fonts are different, which helps me alleviate the confusion problem.
As for the readers' feelings... they will definitely be unhappy. It's none of my business, leave it alone.