Skip to content

Commit

Permalink
feat: configurable TCPKeepAlive interval
Browse files Browse the repository at this point in the history
  • Loading branch information
Larvan2 committed Sep 2, 2023
1 parent d79c130 commit 73fa79b
Show file tree
Hide file tree
Showing 23 changed files with 62 additions and 48 deletions.
4 changes: 3 additions & 1 deletion adapter/outbound/direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package outbound
import (
"context"
"errors"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
Expand All @@ -24,7 +26,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...
if err != nil {
return nil, err
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
return NewConn(c, d), nil
}

Expand Down
4 changes: 3 additions & 1 deletion adapter/outbound/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"encoding/base64"
"errors"
"fmt"

"io"
"net"
"net/http"
"strconv"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/proxydialer"
tlsC "github.com/Dreamacro/clash/component/tls"
Expand Down Expand Up @@ -74,7 +76,7 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", h.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down
2 changes: 1 addition & 1 deletion adapter/outbound/shadowsocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down
2 changes: 1 addition & 1 deletion adapter/outbound/shadowsocksr.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down
7 changes: 4 additions & 3 deletions adapter/outbound/snell.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"net"
"strconv"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/structure"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/proxydialer"
Expand Down Expand Up @@ -93,7 +94,7 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", s.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down Expand Up @@ -121,7 +122,7 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
if err != nil {
return nil, err
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption})

err = snell.WriteUDPHeader(c, s.version)
Expand Down Expand Up @@ -207,7 +208,7 @@ func NewSnell(option SnellOption) (*Snell, error) {
return nil, err
}

tcpKeepAlive(c)
N.TCPKeepAlive(c)
return streamConn(c, streamOption{psk, option.Version, addr, obfsOption}), nil
})
}
Expand Down
5 changes: 3 additions & 2 deletions adapter/outbound/socks5.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"net"
"strconv"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/proxydialer"
tlsC "github.com/Dreamacro/clash/component/tls"
Expand Down Expand Up @@ -80,7 +81,7 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down Expand Up @@ -126,7 +127,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata,
safeConnClose(c, err)
}(c)

tcpKeepAlive(c)
N.TCPKeepAlive(c)
var user *socks5.User
if ss.user != "" {
user = &socks5.User{
Expand Down
7 changes: 4 additions & 3 deletions adapter/outbound/trojan.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"strconv"

N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/component/dialer"
"github.com/Dreamacro/clash/component/proxydialer"
tlsC "github.com/Dreamacro/clash/component/tls"
Expand Down Expand Up @@ -131,7 +132,7 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)

defer func(c net.Conn) {
safeConnClose(c, err)
Expand Down Expand Up @@ -184,7 +185,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me
defer func(c net.Conn) {
safeConnClose(c, err)
}(c)
tcpKeepAlive(c)
N.TCPKeepAlive(c)
c, err = t.plainStream(ctx, c)
if err != nil {
return nil, fmt.Errorf("%s connect error: %w", t.addr, err)
Expand Down Expand Up @@ -268,7 +269,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) {
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
return c, nil
}

Expand Down
8 changes: 0 additions & 8 deletions adapter/outbound/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"net"
"net/netip"
"sync"
"time"

"github.com/Dreamacro/clash/component/resolver"
C "github.com/Dreamacro/clash/constant"
Expand All @@ -19,13 +18,6 @@ var (
once sync.Once
)

func tcpKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
_ = tcp.SetKeepAlive(true)
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
}
}

func getClientSessionCache() tls.ClientSessionCache {
once.Do(func() {
globalClientSessionCache = tls.NewLRUClientSessionCache(128)
Expand Down
6 changes: 3 additions & 3 deletions adapter/outbound/vless.go
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
defer func(c net.Conn) {
safeConnClose(c, err)
}(c)
Expand Down Expand Up @@ -328,7 +328,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
defer func(c net.Conn) {
safeConnClose(c, err)
}(c)
Expand Down Expand Up @@ -578,7 +578,7 @@ func NewVless(option VlessOption) (*Vless, error) {
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
return c, nil
}

Expand Down
6 changes: 3 additions & 3 deletions adapter/outbound/vmess.go
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
defer func(c net.Conn) {
safeConnClose(c, err)
}(c)
Expand Down Expand Up @@ -369,7 +369,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
defer func(c net.Conn) {
safeConnClose(c, err)
}(c)
Expand Down Expand Up @@ -469,7 +469,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
if err != nil {
return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error())
}
tcpKeepAlive(c)
N.TCPKeepAlive(c)
return c, nil
}

Expand Down
12 changes: 0 additions & 12 deletions adapter/outboundgroup/util.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,5 @@
package outboundgroup

import (
"net"
"time"
)

func tcpKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
_ = tcp.SetKeepAlive(true)
_ = tcp.SetKeepAlivePeriod(30 * time.Second)
}
}

type SelectAble interface {
Set(string) error
ForceSet(name string)
Expand Down
10 changes: 10 additions & 0 deletions common/net/tcpip.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,11 @@ import (
"fmt"
"net"
"strings"
"time"
)

var KeepAliveInterval time.Duration

func SplitNetworkType(s string) (string, string, error) {
var (
shecme string
Expand Down Expand Up @@ -44,3 +47,10 @@ func SplitHostPort(s string) (host, port string, hasPort bool, err error) {
host, port, err = net.SplitHostPort(temp)
return
}

func TCPKeepAlive(c net.Conn) {
if tcp, ok := c.(*net.TCPConn); ok {
_ = tcp.SetKeepAlive(true)
_ = tcp.SetKeepAlivePeriod(KeepAliveInterval * time.Second)
}
}
9 changes: 9 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/Dreamacro/clash/adapter/outbound"
"github.com/Dreamacro/clash/adapter/outboundgroup"
"github.com/Dreamacro/clash/adapter/provider"
N "github.com/Dreamacro/clash/common/net"
"github.com/Dreamacro/clash/common/utils"
"github.com/Dreamacro/clash/component/auth"
"github.com/Dreamacro/clash/component/dialer"
Expand Down Expand Up @@ -59,6 +60,7 @@ type General struct {
Sniffing bool `json:"sniffing"`
EBpf EBpf `json:"-"`
GlobalClientFingerprint string `json:"global-client-fingerprint"`
KeepAliveInterval int `json:"keep-alive-interval"`
}

// Inbound config
Expand Down Expand Up @@ -280,6 +282,7 @@ type RawConfig struct {
TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"`
FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"`
GlobalClientFingerprint string `yaml:"global-client-fingerprint"`
KeepAliveInterval int `yaml:"keep-alive-interval"`

Sniffer RawSniffer `yaml:"sniffer"`
ProxyProvider map[string]map[string]any `yaml:"proxy-providers"`
Expand Down Expand Up @@ -559,6 +562,11 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
C.GeoSiteUrl = cfg.GeoXUrl.GeoSite
C.MmdbUrl = cfg.GeoXUrl.Mmdb
C.GeodataMode = cfg.GeodataMode
if cfg.KeepAliveInterval == 0 {
cfg.KeepAliveInterval = 30
}
N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second
log.Infoln("Keep Alive Interval set %+v", N.KeepAliveInterval)
// checkout externalUI exist
if externalUI != "" {
externalUI = C.Path.Resolve(externalUI)
Expand Down Expand Up @@ -600,6 +608,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) {
FindProcessMode: cfg.FindProcessMode,
EBpf: cfg.EBpf,
GlobalClientFingerprint: cfg.GlobalClientFingerprint,
KeepAliveInterval: cfg.KeepAliveInterval,
}, nil
}

Expand Down
2 changes: 2 additions & 0 deletions docs/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ external-ui: /path/to/ui/folder # 配置 WEB UI 目录,使用 http://{{externa
# Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan.
global-client-fingerprint: chrome

keep-alive-interval: 30

# routing-mark:6666 # 配置 fwmark 仅用于 Linux
experimental:

Expand Down
3 changes: 2 additions & 1 deletion listener/autoredir/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"net/netip"

"github.com/Dreamacro/clash/adapter/inbound"
N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
Expand Down Expand Up @@ -55,7 +56,7 @@ func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) {
return
}

_ = conn.(*net.TCPConn).SetKeepAlive(true)
N.TCPKeepAlive(conn)

in <- inbound.NewSocket(target, conn, C.REDIR, l.additions...)
}
Expand Down
4 changes: 2 additions & 2 deletions listener/mixed/mixed.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package mixed

import (
"github.com/Dreamacro/clash/adapter/inbound"
"net"

"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/cache"
N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
Expand Down Expand Up @@ -70,7 +70,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*
}

func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], additions ...inbound.Addition) {
conn.(*net.TCPConn).SetKeepAlive(true)
N.TCPKeepAlive(conn)

bufConn := N.NewBufferedConn(conn)
head, err := bufConn.Peek(1)
Expand Down
3 changes: 2 additions & 1 deletion listener/redir/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"net"

"github.com/Dreamacro/clash/adapter/inbound"
N "github.com/Dreamacro/clash/common/net"
C "github.com/Dreamacro/clash/constant"
)

Expand Down Expand Up @@ -66,6 +67,6 @@ func handleRedir(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Ad
conn.Close()
return
}
conn.(*net.TCPConn).SetKeepAlive(true)
N.TCPKeepAlive(conn)
in <- inbound.NewSocket(target, conn, C.REDIR, additions...)
}
2 changes: 1 addition & 1 deletion listener/shadowsocks/tcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C
}
continue
}
_ = c.(*net.TCPConn).SetKeepAlive(true)
N.TCPKeepAlive(c)
go sl.HandleConn(c, tcpIn)
}
}()
Expand Down

0 comments on commit 73fa79b

Please sign in to comment.