chore: add vmess, shadowsocks, tcptun and udptun listener

This commit is contained in:
wwqgtxx
2022-11-11 20:56:08 +08:00
parent 6dadc2357a
commit 3eacce9a66
10 changed files with 796 additions and 58 deletions

68
listener/tunnel/tcp.go Normal file
View File

@ -0,0 +1,68 @@
package tunnel
import (
"net"
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
)
type Listener struct {
closed bool
config string
listeners []net.Listener
}
func New(config string, in chan<- C.ConnContext) (*Listener, error) {
tl := &Listener{false, config, nil}
pl := PairList{}
err := pl.Set(config)
if err != nil {
return nil, err
}
for _, p := range pl {
addr := p[0]
target := p[1]
go func() {
tgt := socks5.ParseAddr(target)
if tgt == nil {
log.Errorln("invalid target address %q", target)
return
}
l, err := net.Listen("tcp", addr)
if err != nil {
return
}
tl.listeners = append(tl.listeners, l)
log.Infoln("TCP tunnel %s <-> %s", l.Addr().String(), target)
for {
c, err := l.Accept()
if err != nil {
if tl.closed {
break
}
continue
}
_ = c.(*net.TCPConn).SetKeepAlive(true)
in <- inbound.NewSocket(tgt, c, C.TCPTUN)
}
}()
}
return tl, nil
}
func (l *Listener) Close() {
l.closed = true
for _, lis := range l.listeners {
_ = lis.Close()
}
}
func (l *Listener) Config() string {
return l.config
}

79
listener/tunnel/udp.go Normal file
View File

@ -0,0 +1,79 @@
package tunnel
import (
"net"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5"
)
type UdpListener struct {
closed bool
config string
listeners []net.PacketConn
}
func NewUdp(config string, in chan<- *inbound.PacketAdapter) (*UdpListener, error) {
ul := &UdpListener{false, config, nil}
pl := PairList{}
err := pl.Set(config)
if err != nil {
return nil, err
}
for _, p := range pl {
addr := p[0]
target := p[1]
go func() {
tgt := socks5.ParseAddr(target)
if tgt == nil {
log.Errorln("invalid target address %q", target)
return
}
l, err := net.ListenPacket("udp", addr)
if err != nil {
return
}
ul.listeners = append(ul.listeners, l)
log.Infoln("Udp tunnel %s <-> %s", l.LocalAddr().String(), target)
for {
buf := pool.Get(pool.RelayBufferSize)
n, remoteAddr, err := l.ReadFrom(buf)
if err != nil {
pool.Put(buf)
if ul.closed {
break
}
continue
}
packet := &packet{
pc: l,
rAddr: remoteAddr,
payload: buf[:n],
bufRef: buf,
}
select {
case in <- inbound.NewPacket(tgt, packet, C.UDPTUN):
default:
}
}
}()
}
return ul, nil
}
func (l *UdpListener) Close() {
l.closed = true
for _, lis := range l.listeners {
_ = lis.Close()
}
}
func (l *UdpListener) Config() string {
return l.config
}

63
listener/tunnel/utils.go Normal file
View File

@ -0,0 +1,63 @@
package tunnel
import (
"errors"
"net"
"strings"
"github.com/Dreamacro/clash/common/pool"
)
type PairList [][2]string // key1=val1,key2=val2,...
func (l PairList) String() string {
s := make([]string, len(l))
for i, pair := range l {
s[i] = pair[0] + "=" + pair[1]
}
return strings.Join(s, ",")
}
func (l *PairList) Set(s string) error {
for _, item := range strings.Split(s, ",") {
pair := strings.Split(item, "=")
if len(pair) != 2 {
return nil
}
*l = append(*l, [2]string{pair[0], pair[1]})
}
return nil
}
type packet struct {
pc net.PacketConn
rAddr net.Addr
payload []byte
bufRef []byte
}
func (c *packet) Data() []byte {
return c.payload
}
// WriteBack wirtes UDP packet with source(ip, port) = `addr`
func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
if addr == nil {
err = errors.New("address is invalid")
return
}
packet := b
return c.pc.WriteTo(packet, c.rAddr)
}
// LocalAddr returns the source IP/Port of UDP Packet
func (c *packet) LocalAddr() net.Addr {
return c.rAddr
}
func (c *packet) Drop() {
pool.Put(c.bufRef)
}
func (c *packet) InAddr() net.Addr {
return c.pc.LocalAddr()
}