You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

150 lines
3.7 KiB

package tunnel
import (
"crypto/sha1"
"time"
"github.com/pkg/errors"
"github.com/xtaci/kcp-go/v5"
"github.com/xtaci/smux"
"golang.org/x/crypto/pbkdf2"
)
type ConfigureConnFunc func(conn *kcp.UDPSession) error
type ConfigureListenerFunc func(listener *kcp.Listener) error
type ServerConfig struct {
Address string
BlockCrypt kcp.BlockCrypt
DataShards int
ParityShards int
Hooks *ServerHooks
ConfigureConn ConfigureConnFunc
ConfigureListener ConfigureListenerFunc
AuthenticationTimeout time.Duration
ProxyRequestTimeout time.Duration
SmuxConfig *smux.Config
}
// nolint: go-mnd
func DefaultServerConfig() *ServerConfig {
unencryptedBlock, err := kcp.NewNoneBlockCrypt(nil)
if err != nil { // should never happen
panic(errors.WithStack(err))
}
smuxConfig := smux.DefaultConfig()
smuxConfig.Version = 2
smuxConfig.KeepAliveInterval = 10 * time.Second
smuxConfig.MaxReceiveBuffer = 4194304
smuxConfig.MaxStreamBuffer = 2097152
return &ServerConfig{
Address: ":36543",
BlockCrypt: unencryptedBlock,
DataShards: 3,
ParityShards: 10,
Hooks: &ServerHooks{
onClientConnect: DefaultOnClientConnect,
onClientDisconnect: DefaultOnClientDisconnect,
onClientAuth: DefaultOnClientAuth,
},
ConfigureConn: DefaultServerConfigureConn,
ConfigureListener: DefaultServerConfigureListener,
AuthenticationTimeout: 30 * time.Second,
ProxyRequestTimeout: 5 * time.Second,
SmuxConfig: smuxConfig,
}
}
type ServerConfigFunc func(c *ServerConfig)
func WithServerAddress(address string) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.Address = address
}
}
func WithServerBlockCrypt(alg string, pass, salt string, iterations, keyLen int) ServerConfigFunc {
return func(conf *ServerConfig) {
key := pbkdf2.Key([]byte(pass), []byte(salt), iterations, keyLen, sha1.New)
block, err := createBlockCrypt(alg, key)
if err != nil {
panic(errors.Wrap(err, "could not create block crypt"))
}
conf.BlockCrypt = block
}
}
func WithServerOnClientAuth(fn OnClientAuthFunc) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.Hooks.onClientAuth = fn
}
}
func WithServerOnClientConnect(fn OnClientConnectFunc) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.Hooks.onClientConnect = fn
}
}
func WithServerOnClientDisconnect(fn OnClientDisconnectFunc) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.Hooks.onClientDisconnect = fn
}
}
func WithServerConfigureConn(fn ConfigureConnFunc) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.ConfigureConn = fn
}
}
func WithServerConfigureListener(fn ConfigureListenerFunc) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.ConfigureListener = fn
}
}
func WithServerSmuxConfig(c *smux.Config) ServerConfigFunc {
return func(conf *ServerConfig) {
conf.SmuxConfig = c
}
}
// nolint: go-mnd
func DefaultServerConfigureConn(conn *kcp.UDPSession) error {
// Based on kcptun default configuration, mode 'fast3'
conn.SetStreamMode(true)
conn.SetWriteDelay(false)
conn.SetNoDelay(1, 10, 2, 1)
conn.SetWindowSize(128, 512)
conn.SetMtu(1400)
conn.SetACKNoDelay(true)
if err := conn.SetDSCP(46); err != nil {
return errors.WithStack(err)
}
return nil
}
// nolint: go-mnd
func DefaultServerConfigureListener(listener *kcp.Listener) error {
// Based on kcptun default configuration, mode 'fast3'
if err := listener.SetReadBuffer(16777217); err != nil {
return errors.WithStack(err)
}
if err := listener.SetWriteBuffer(16777217); err != nil {
return errors.WithStack(err)
}
if err := listener.SetDSCP(46); err != nil {
return errors.WithStack(err)
}
return nil
}