chore: listeners support tunnel

This commit is contained in:
wwqgtxx 2022-12-05 17:03:12 +08:00
parent 8c58d8a8ad
commit 5c410b8df4
5 changed files with 118 additions and 8 deletions

View file

@ -671,11 +671,13 @@ listeners:
#listen: 0.0.0.0 # 默认监听 0.0.0.0 #listen: 0.0.0.0 # 默认监听 0.0.0.0
# rule: sub-rule-name1 # 默认使用 rules如果未找到 sub-rule 则直接使用 rules # rule: sub-rule-name1 # 默认使用 rules如果未找到 sub-rule 则直接使用 rules
# udp: false # 默认 true # udp: false # 默认 true
- name: http-in-1 - name: http-in-1
type: http type: http
port: 10809 port: 10809
listen: 0.0.0.0 listen: 0.0.0.0
# rule: sub-rule # rule: sub-rule
- name: mixed-in-1 - name: mixed-in-1
type: mixed # HTTP(S) 和 SOCKS 代理混合 type: mixed # HTTP(S) 和 SOCKS 代理混合
port: 10810 port: 10810
@ -729,3 +731,12 @@ listeners:
# alpn: # alpn:
# - h3 # - h3
# max-udp-relay-packet-size: 1500 # max-udp-relay-packet-size: 1500
- name: tunnel-in-1
type: tunnel
port: 10816
listen: 0.0.0.0
# rule: sub-rule
network: [ tcp, udp ]
target: target.com

View file

@ -0,0 +1,92 @@
package inbound
import (
"fmt"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/listener/tunnel"
"github.com/Dreamacro/clash/log"
)
type TunnelOption struct {
BaseOption
Network []string `inbound:"network"`
Target string `inbound:"target"`
Proxy string `inbound:"proxy,omitempty"`
}
func (o TunnelOption) Equal(config C.InboundConfig) bool {
return optionToString(o) == optionToString(config)
}
type Tunnel struct {
*Base
config *TunnelOption
ttl *tunnel.Listener
tul *tunnel.PacketConn
}
func NewTunnel(options *TunnelOption) (*Tunnel, error) {
base, err := NewBase(&options.BaseOption)
if err != nil {
return nil, err
}
return &Tunnel{
Base: base,
config: options,
}, nil
}
// Config implements constant.InboundListener
func (t *Tunnel) Config() C.InboundConfig {
return t.config
}
// Close implements constant.InboundListener
func (t *Tunnel) Close() error {
var err error
if t.ttl != nil {
if tcpErr := t.ttl.Close(); tcpErr != nil {
err = tcpErr
}
}
if t.tul != nil {
if udpErr := t.tul.Close(); udpErr != nil {
if err == nil {
err = udpErr
} else {
return fmt.Errorf("close tcp err: %t, close udp err: %t", err.Error(), udpErr.Error())
}
}
}
return err
}
// Address implements constant.InboundListener
func (t *Tunnel) Address() string {
return t.ttl.Address()
}
// Listen implements constant.InboundListener
func (t *Tunnel) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) error {
var err error
for _, network := range t.config.Network {
switch network {
case "tcp":
if t.ttl, err = tunnel.New(t.RawAddress(), t.config.Target, t.config.Proxy, tcpIn, t.Additions()...); err != nil {
return err
}
case "udp":
if t.tul, err = tunnel.NewUDP(t.RawAddress(), t.config.Target, t.config.Proxy, udpIn, t.Additions()...); err != nil {
return err
}
default:
return fmt.Errorf("unknow network type: %s", network)
}
log.Infoln("Tunnel[%s](%s/%s)proxy listening at: %s", t.Name(), network, t.config.Target, t.Address())
}
return nil
}
var _ C.InboundListener = (*Tunnel)(nil)

View file

@ -55,6 +55,13 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) {
return nil, err return nil, err
} }
listener, err = IN.NewMixed(mixedOption) listener, err = IN.NewMixed(mixedOption)
case "tunnel":
tunnelOption := &IN.TunnelOption{}
err = decoder.Decode(mapping, tunnelOption)
if err != nil {
return nil, err
}
listener, err = IN.NewTunnel(tunnelOption)
case "shadowsocks": case "shadowsocks":
shadowsocksOption := &IN.ShadowSocksOption{} shadowsocksOption := &IN.ShadowSocksOption{}
err = decoder.Decode(mapping, shadowsocksOption) err = decoder.Decode(mapping, shadowsocksOption)

View file

@ -33,14 +33,14 @@ func (l *Listener) Close() error {
return l.listener.Close() return l.listener.Close()
} }
func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext) { func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) {
conn.(*net.TCPConn).SetKeepAlive(true) conn.(*net.TCPConn).SetKeepAlive(true)
ctx := inbound.NewSocket(l.target, conn, C.TUNNEL) ctx := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...)
ctx.Metadata().SpecialProxy = l.proxy ctx.Metadata().SpecialProxy = l.proxy
in <- ctx in <- ctx
} }
func New(addr, target, proxy string, in chan<- C.ConnContext) (*Listener, error) { func New(addr, target, proxy string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) {
l, err := net.Listen("tcp", addr) l, err := net.Listen("tcp", addr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -67,7 +67,7 @@ func New(addr, target, proxy string, in chan<- C.ConnContext) (*Listener, error)
} }
continue continue
} }
go rl.handleTCP(c, in) go rl.handleTCP(c, in, additions...)
} }
}() }()

View file

@ -34,7 +34,7 @@ func (l *PacketConn) Close() error {
return l.conn.Close() return l.conn.Close()
} }
func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter) (*PacketConn, error) { func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*PacketConn, error) {
l, err := net.ListenPacket("udp", addr) l, err := net.ListenPacket("udp", addr)
if err != nil { if err != nil {
return nil, err return nil, err
@ -62,21 +62,21 @@ func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter) (*PacketConn,
} }
continue continue
} }
sl.handleUDP(l, in, buf[:n], remoteAddr) sl.handleUDP(l, in, buf[:n], remoteAddr, additions...)
} }
}() }()
return sl, nil return sl, nil
} }
func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr) { func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr, additions ...inbound.Addition) {
packet := &packet{ packet := &packet{
pc: pc, pc: pc,
rAddr: addr, rAddr: addr,
payload: buf, payload: buf,
} }
ctx := inbound.NewPacket(l.target, packet, C.TUNNEL) ctx := inbound.NewPacket(l.target, packet, C.TUNNEL, additions...)
ctx.Metadata().SpecialProxy = l.proxy ctx.Metadata().SpecialProxy = l.proxy
select { select {
case in <- ctx: case in <- ctx: