Style: code style

This commit is contained in:
Dreamacro 2021-06-13 17:23:10 +08:00
parent bcfc15e398
commit 6091fcdfec
27 changed files with 171 additions and 186 deletions

View file

@ -18,9 +18,9 @@ import (
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/dns" "github.com/Dreamacro/clash/dns"
P "github.com/Dreamacro/clash/listener"
authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
P "github.com/Dreamacro/clash/proxy"
authStore "github.com/Dreamacro/clash/proxy/auth"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
) )
@ -187,23 +187,26 @@ func updateGeneral(general *config.General, force bool) {
bindAddress := general.BindAddress bindAddress := general.BindAddress
P.SetBindAddress(bindAddress) P.SetBindAddress(bindAddress)
if err := P.ReCreateHTTP(general.Port); err != nil { tcpIn := tunnel.TCPIn()
udpIn := tunnel.UDPIn()
if err := P.ReCreateHTTP(general.Port, tcpIn); err != nil {
log.Errorln("Start HTTP server error: %s", err.Error()) log.Errorln("Start HTTP server error: %s", err.Error())
} }
if err := P.ReCreateSocks(general.SocksPort); err != nil { if err := P.ReCreateSocks(general.SocksPort, tcpIn, udpIn); err != nil {
log.Errorln("Start SOCKS5 server error: %s", err.Error()) log.Errorln("Start SOCKS5 server error: %s", err.Error())
} }
if err := P.ReCreateRedir(general.RedirPort); err != nil { if err := P.ReCreateRedir(general.RedirPort, tcpIn, udpIn); err != nil {
log.Errorln("Start Redir server error: %s", err.Error()) log.Errorln("Start Redir server error: %s", err.Error())
} }
if err := P.ReCreateTProxy(general.TProxyPort); err != nil { if err := P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn); err != nil {
log.Errorln("Start TProxy server error: %s", err.Error()) log.Errorln("Start TProxy server error: %s", err.Error())
} }
if err := P.ReCreateMixed(general.MixedPort); err != nil { if err := P.ReCreateMixed(general.MixedPort, tcpIn, udpIn); err != nil {
log.Errorln("Start Mixed(http and socks5) server error: %s", err.Error()) log.Errorln("Start Mixed(http and socks5) server error: %s", err.Error())
} }
} }

View file

@ -7,8 +7,8 @@ import (
"github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/resolver"
"github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/config"
"github.com/Dreamacro/clash/hub/executor" "github.com/Dreamacro/clash/hub/executor"
P "github.com/Dreamacro/clash/listener"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
P "github.com/Dreamacro/clash/proxy"
"github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel"
"github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5"
@ -66,11 +66,15 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) {
} }
ports := P.GetPorts() ports := P.GetPorts()
P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port))
P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort)) tcpIn := tunnel.TCPIn()
P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort)) udpIn := tunnel.UDPIn()
P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort))
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort)) P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn)
P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn)
P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn)
P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn)
P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn)
if general.Mode != nil { if general.Mode != nil {
tunnel.SetMode(*general.Mode) tunnel.SetMode(*general.Mode)

View file

@ -11,28 +11,25 @@ import (
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/component/auth" "github.com/Dreamacro/clash/component/auth"
C "github.com/Dreamacro/clash/constant"
authStore "github.com/Dreamacro/clash/listener/auth"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
authStore "github.com/Dreamacro/clash/proxy/auth"
"github.com/Dreamacro/clash/tunnel"
) )
type HTTPListener struct { type Listener struct {
net.Listener net.Listener
address string address string
closed bool closed bool
cache *cache.Cache cache *cache.Cache
} }
func NewHTTPProxy(addr string) (*HTTPListener, error) { func New(addr string, in chan<- C.ConnContext) (*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
} }
hl := &HTTPListener{l, addr, false, cache.New(30 * time.Second)} hl := &Listener{l, addr, false, cache.New(30 * time.Second)}
go func() { go func() {
log.Infoln("HTTP proxy listening at: %s", addr)
for { for {
c, err := hl.Accept() c, err := hl.Accept()
if err != nil { if err != nil {
@ -41,19 +38,19 @@ func NewHTTPProxy(addr string) (*HTTPListener, error) {
} }
continue continue
} }
go HandleConn(c, hl.cache) go HandleConn(c, in, hl.cache)
} }
}() }()
return hl, nil return hl, nil
} }
func (l *HTTPListener) Close() { func (l *Listener) Close() {
l.closed = true l.closed = true
l.Listener.Close() l.Listener.Close()
} }
func (l *HTTPListener) Address() string { func (l *Listener) Address() string {
return l.address return l.address
} }
@ -70,7 +67,7 @@ func canActivate(loginStr string, authenticator auth.Authenticator, cache *cache
return return
} }
func HandleConn(conn net.Conn, cache *cache.Cache) { func HandleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
br := bufio.NewReader(conn) br := bufio.NewReader(conn)
keepAlive: keepAlive:
@ -106,9 +103,9 @@ keepAlive:
conn.Close() conn.Close()
return return
} }
tunnel.Add(inbound.NewHTTPS(request, conn)) in <- inbound.NewHTTPS(request, conn)
return return
} }
tunnel.Add(inbound.NewHTTP(request, conn)) in <- inbound.NewHTTP(request, conn)
} }

View file

@ -6,26 +6,29 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/listener/http"
"github.com/Dreamacro/clash/listener/mixed"
"github.com/Dreamacro/clash/listener/redir"
"github.com/Dreamacro/clash/listener/socks"
"github.com/Dreamacro/clash/listener/tproxy"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/proxy/http"
"github.com/Dreamacro/clash/proxy/mixed"
"github.com/Dreamacro/clash/proxy/redir"
"github.com/Dreamacro/clash/proxy/socks"
) )
var ( var (
allowLan = false allowLan = false
bindAddress = "*" bindAddress = "*"
socksListener *socks.SockListener socksListener *socks.Listener
socksUDPListener *socks.SockUDPListener socksUDPListener *socks.UDPListener
httpListener *http.HTTPListener httpListener *http.Listener
redirListener *redir.RedirListener redirListener *redir.Listener
redirUDPListener *redir.RedirUDPListener redirUDPListener *tproxy.UDPListener
tproxyListener *redir.TProxyListener tproxyListener *tproxy.Listener
tproxyUDPListener *redir.RedirUDPListener tproxyUDPListener *tproxy.UDPListener
mixedListener *mixed.MixedListener mixedListener *mixed.Listener
mixedUDPLister *socks.SockUDPListener mixedUDPLister *socks.UDPListener
// lock for recreate function // lock for recreate function
socksMux sync.Mutex socksMux sync.Mutex
@ -59,7 +62,7 @@ func SetBindAddress(host string) {
bindAddress = host bindAddress = host
} }
func ReCreateHTTP(port int) error { func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) error {
httpMux.Lock() httpMux.Lock()
defer httpMux.Unlock() defer httpMux.Unlock()
@ -78,15 +81,16 @@ func ReCreateHTTP(port int) error {
} }
var err error var err error
httpListener, err = http.NewHTTPProxy(addr) httpListener, err = http.New(addr, tcpIn)
if err != nil { if err != nil {
return err return err
} }
log.Infoln("HTTP proxy listening at: %s", httpListener.Address())
return nil return nil
} }
func ReCreateSocks(port int) error { func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
socksMux.Lock() socksMux.Lock()
defer socksMux.Unlock() defer socksMux.Unlock()
@ -121,12 +125,12 @@ func ReCreateSocks(port int) error {
return nil return nil
} }
tcpListener, err := socks.NewSocksProxy(addr) tcpListener, err := socks.New(addr, tcpIn)
if err != nil { if err != nil {
return err return err
} }
udpListener, err := socks.NewSocksUDPProxy(addr) udpListener, err := socks.NewUDP(addr, udpIn)
if err != nil { if err != nil {
tcpListener.Close() tcpListener.Close()
return err return err
@ -135,10 +139,11 @@ func ReCreateSocks(port int) error {
socksListener = tcpListener socksListener = tcpListener
socksUDPListener = udpListener socksUDPListener = udpListener
log.Infoln("SOCKS5 proxy listening at: %s", socksListener.Address())
return nil return nil
} }
func ReCreateRedir(port int) error { func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
redirMux.Lock() redirMux.Lock()
defer redirMux.Unlock() defer redirMux.Unlock()
@ -165,20 +170,21 @@ func ReCreateRedir(port int) error {
} }
var err error var err error
redirListener, err = redir.NewRedirProxy(addr) redirListener, err = redir.New(addr, tcpIn)
if err != nil { if err != nil {
return err return err
} }
redirUDPListener, err = redir.NewRedirUDPProxy(addr) redirUDPListener, err = tproxy.NewUDP(addr, udpIn)
if err != nil { if err != nil {
log.Warnln("Failed to start Redir UDP Listener: %s", err) log.Warnln("Failed to start Redir UDP Listener: %s", err)
} }
log.Infoln("Redirect proxy listening at: %s", redirListener.Address())
return nil return nil
} }
func ReCreateTProxy(port int) error { func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
tproxyMux.Lock() tproxyMux.Lock()
defer tproxyMux.Unlock() defer tproxyMux.Unlock()
@ -205,20 +211,21 @@ func ReCreateTProxy(port int) error {
} }
var err error var err error
tproxyListener, err = redir.NewTProxy(addr) tproxyListener, err = tproxy.New(addr, tcpIn)
if err != nil { if err != nil {
return err return err
} }
tproxyUDPListener, err = redir.NewRedirUDPProxy(addr) tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn)
if err != nil { if err != nil {
log.Warnln("Failed to start TProxy UDP Listener: %s", err) log.Warnln("Failed to start TProxy UDP Listener: %s", err)
} }
log.Infoln("TProxy server listening at: %s", tproxyListener.Address())
return nil return nil
} }
func ReCreateMixed(port int) error { func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) error {
mixedMux.Lock() mixedMux.Lock()
defer mixedMux.Unlock() defer mixedMux.Unlock()
@ -253,17 +260,18 @@ func ReCreateMixed(port int) error {
} }
var err error var err error
mixedListener, err = mixed.NewMixedProxy(addr) mixedListener, err = mixed.New(addr, tcpIn)
if err != nil { if err != nil {
return err return err
} }
mixedUDPLister, err = socks.NewSocksUDPProxy(addr) mixedUDPLister, err = socks.NewUDP(addr, udpIn)
if err != nil { if err != nil {
mixedListener.Close() mixedListener.Close()
return err return err
} }
log.Infoln("Mixed(http+socks5) proxy listening at: %s", mixedListener.Address())
return nil return nil
} }

View file

@ -5,29 +5,27 @@ import (
"time" "time"
"github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/common/cache"
"github.com/Dreamacro/clash/log" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/proxy/http" "github.com/Dreamacro/clash/listener/http"
"github.com/Dreamacro/clash/proxy/socks" "github.com/Dreamacro/clash/listener/socks"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
) )
type MixedListener struct { type Listener struct {
net.Listener net.Listener
address string address string
closed bool closed bool
cache *cache.Cache cache *cache.Cache
} }
func NewMixedProxy(addr string) (*MixedListener, error) { func New(addr string, in chan<- C.ConnContext) (*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
} }
ml := &MixedListener{l, addr, false, cache.New(30 * time.Second)} ml := &Listener{l, addr, false, cache.New(30 * time.Second)}
go func() { go func() {
log.Infoln("Mixed(http+socks5) proxy listening at: %s", addr)
for { for {
c, err := ml.Accept() c, err := ml.Accept()
if err != nil { if err != nil {
@ -36,23 +34,23 @@ func NewMixedProxy(addr string) (*MixedListener, error) {
} }
continue continue
} }
go handleConn(c, ml.cache) go handleConn(c, in, ml.cache)
} }
}() }()
return ml, nil return ml, nil
} }
func (l *MixedListener) Close() { func (l *Listener) Close() {
l.closed = true l.closed = true
l.Listener.Close() l.Listener.Close()
} }
func (l *MixedListener) Address() string { func (l *Listener) Address() string {
return l.address return l.address
} }
func handleConn(conn net.Conn, cache *cache.Cache) { func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.Cache) {
bufConn := NewBufferedConn(conn) bufConn := NewBufferedConn(conn)
head, err := bufConn.Peek(1) head, err := bufConn.Peek(1)
if err != nil { if err != nil {
@ -60,9 +58,9 @@ func handleConn(conn net.Conn, cache *cache.Cache) {
} }
if head[0] == socks5.Version { if head[0] == socks5.Version {
socks.HandleSocks(bufConn) socks.HandleSocks(bufConn, in)
return return
} }
http.HandleConn(bufConn, cache) http.HandleConn(bufConn, in, cache)
} }

View file

@ -5,25 +5,22 @@ import (
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/tunnel"
) )
type RedirListener struct { type Listener struct {
net.Listener net.Listener
address string address string
closed bool closed bool
} }
func NewRedirProxy(addr string) (*RedirListener, error) { func New(addr string, in chan<- C.ConnContext) (*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
} }
rl := &RedirListener{l, addr, false} rl := &Listener{l, addr, false}
go func() { go func() {
log.Infoln("Redir proxy listening at: %s", addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
@ -32,28 +29,28 @@ func NewRedirProxy(addr string) (*RedirListener, error) {
} }
continue continue
} }
go handleRedir(c) go handleRedir(c, in)
} }
}() }()
return rl, nil return rl, nil
} }
func (l *RedirListener) Close() { func (l *Listener) Close() {
l.closed = true l.closed = true
l.Listener.Close() l.Listener.Close()
} }
func (l *RedirListener) Address() string { func (l *Listener) Address() string {
return l.address return l.address
} }
func handleRedir(conn net.Conn) { func handleRedir(conn net.Conn, in chan<- C.ConnContext) {
target, err := parserPacket(conn) target, err := parserPacket(conn)
if err != nil { if err != nil {
conn.Close() conn.Close()
return return
} }
conn.(*net.TCPConn).SetKeepAlive(true) conn.(*net.TCPConn).SetKeepAlive(true)
tunnel.Add(inbound.NewSocket(target, conn, C.REDIR)) in <- inbound.NewSocket(target, conn, C.REDIR)
} }

View file

@ -7,27 +7,24 @@ import (
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" authStore "github.com/Dreamacro/clash/listener/auth"
authStore "github.com/Dreamacro/clash/proxy/auth"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
) )
type SockListener struct { type Listener struct {
net.Listener net.Listener
address string address string
closed bool closed bool
} }
func NewSocksProxy(addr string) (*SockListener, error) { func New(addr string, in chan<- C.ConnContext) (*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
} }
sl := &SockListener{l, addr, false} sl := &Listener{l, addr, false}
go func() { go func() {
log.Infoln("SOCKS proxy listening at: %s", addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
@ -36,23 +33,23 @@ func NewSocksProxy(addr string) (*SockListener, error) {
} }
continue continue
} }
go HandleSocks(c) go HandleSocks(c, in)
} }
}() }()
return sl, nil return sl, nil
} }
func (l *SockListener) Close() { func (l *Listener) Close() {
l.closed = true l.closed = true
l.Listener.Close() l.Listener.Close()
} }
func (l *SockListener) Address() string { func (l *Listener) Address() string {
return l.address return l.address
} }
func HandleSocks(conn net.Conn) { func HandleSocks(conn net.Conn, in chan<- C.ConnContext) {
target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator()) target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator())
if err != nil { if err != nil {
conn.Close() conn.Close()
@ -66,5 +63,5 @@ func HandleSocks(conn net.Conn) {
io.Copy(ioutil.Discard, conn) io.Copy(ioutil.Discard, conn)
return return
} }
tunnel.Add(inbound.NewSocket(target, conn, C.SOCKS)) in <- inbound.NewSocket(target, conn, C.SOCKS)
} }

View file

@ -9,27 +9,25 @@ import (
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
) )
type SockUDPListener struct { type UDPListener struct {
net.PacketConn net.PacketConn
address string address string
closed bool closed bool
} }
func NewSocksUDPProxy(addr string) (*SockUDPListener, error) { func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, 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
} }
err = sockopt.UDPReuseaddr(l.(*net.UDPConn)) if err := sockopt.UDPReuseaddr(l.(*net.UDPConn)); err != nil {
if err != nil {
log.Warnln("Failed to Reuse UDP Address: %s", err) log.Warnln("Failed to Reuse UDP Address: %s", err)
} }
sl := &SockUDPListener{l, addr, false} sl := &UDPListener{l, addr, false}
go func() { go func() {
for { for {
buf := pool.Get(pool.RelayBufferSize) buf := pool.Get(pool.RelayBufferSize)
@ -41,23 +39,23 @@ func NewSocksUDPProxy(addr string) (*SockUDPListener, error) {
} }
continue continue
} }
handleSocksUDP(l, buf[:n], remoteAddr) handleSocksUDP(l, in, buf[:n], remoteAddr)
} }
}() }()
return sl, nil return sl, nil
} }
func (l *SockUDPListener) Close() error { func (l *UDPListener) Close() error {
l.closed = true l.closed = true
return l.PacketConn.Close() return l.PacketConn.Close()
} }
func (l *SockUDPListener) Address() string { func (l *UDPListener) Address() string {
return l.address return l.address
} }
func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) { func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
target, payload, err := socks5.DecodeUDPPacket(buf) target, payload, err := socks5.DecodeUDPPacket(buf)
if err != nil { if err != nil {
// Unresolved UDP packet, return buffer to the pool // Unresolved UDP packet, return buffer to the pool
@ -70,5 +68,8 @@ func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) {
payload: payload, payload: payload,
bufRef: buf, bufRef: buf,
} }
tunnel.AddPacket(inbound.NewPacket(target, packet, C.SOCKS)) select {
case in <- inbound.NewPacket(target, packet, C.TPROXY):
default:
}
} }

View file

@ -1,4 +1,4 @@
package redir package tproxy
import ( import (
"net" "net"

View file

@ -1,6 +1,6 @@
// +build linux // +build linux
package redir package tproxy
import ( import (
"net" "net"

View file

@ -1,6 +1,6 @@
// +build !linux // +build !linux
package redir package tproxy
import ( import (
"errors" "errors"

View file

@ -1,22 +1,20 @@
package redir package tproxy
import ( import (
"net" "net"
"github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
) )
type TProxyListener struct { type Listener struct {
net.Listener net.Listener
address string address string
closed bool closed bool
} }
func NewTProxy(addr string) (*TProxyListener, error) { func New(addr string, in chan<- C.ConnContext) (*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
@ -33,13 +31,12 @@ func NewTProxy(addr string) (*TProxyListener, error) {
return nil, err return nil, err
} }
rl := &TProxyListener{ rl := &Listener{
Listener: l, Listener: l,
address: addr, address: addr,
} }
go func() { go func() {
log.Infoln("TProxy server listening at: %s", addr)
for { for {
c, err := l.Accept() c, err := l.Accept()
if err != nil { if err != nil {
@ -48,24 +45,24 @@ func NewTProxy(addr string) (*TProxyListener, error) {
} }
continue continue
} }
go rl.handleTProxy(c) go rl.handleTProxy(c, in)
} }
}() }()
return rl, nil return rl, nil
} }
func (l *TProxyListener) Close() { func (l *Listener) Close() {
l.closed = true l.closed = true
l.Listener.Close() l.Listener.Close()
} }
func (l *TProxyListener) Address() string { func (l *Listener) Address() string {
return l.address return l.address
} }
func (l *TProxyListener) handleTProxy(conn net.Conn) { func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext) {
target := socks5.ParseAddrToSocksAddr(conn.LocalAddr()) target := socks5.ParseAddrToSocksAddr(conn.LocalAddr())
conn.(*net.TCPConn).SetKeepAlive(true) conn.(*net.TCPConn).SetKeepAlive(true)
tunnel.Add(inbound.NewSocket(target, conn, C.TPROXY)) in <- inbound.NewSocket(target, conn, C.TPROXY)
} }

View file

@ -1,4 +1,4 @@
package redir package tproxy
import ( import (
"net" "net"
@ -7,22 +7,21 @@ import (
"github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/pool"
C "github.com/Dreamacro/clash/constant" C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/socks5"
"github.com/Dreamacro/clash/tunnel"
) )
type RedirUDPListener struct { type UDPListener struct {
net.PacketConn net.PacketConn
address string address string
closed bool closed bool
} }
func NewRedirUDPProxy(addr string) (*RedirUDPListener, error) { func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, 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
} }
rl := &RedirUDPListener{l, addr, false} rl := &UDPListener{l, addr, false}
c := l.(*net.UDPConn) c := l.(*net.UDPConn)
@ -53,27 +52,30 @@ func NewRedirUDPProxy(addr string) (*RedirUDPListener, error) {
if err != nil { if err != nil {
continue continue
} }
handleRedirUDP(l, buf[:n], lAddr, rAddr) handlePacketConn(l, in, buf[:n], lAddr, rAddr)
} }
}() }()
return rl, nil return rl, nil
} }
func (l *RedirUDPListener) Close() error { func (l *UDPListener) Close() error {
l.closed = true l.closed = true
return l.PacketConn.Close() return l.PacketConn.Close()
} }
func (l *RedirUDPListener) Address() string { func (l *UDPListener) Address() string {
return l.address return l.address
} }
func handleRedirUDP(pc net.PacketConn, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) { func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
target := socks5.ParseAddrToSocksAddr(rAddr) target := socks5.ParseAddrToSocksAddr(rAddr)
pkt := &packet{ pkt := &packet{
lAddr: lAddr, lAddr: lAddr,
buf: buf, buf: buf,
} }
tunnel.AddPacket(inbound.NewPacket(target, pkt, C.TPROXY)) select {
case in <- inbound.NewPacket(target, pkt, C.TPROXY):
default:
}
} }

View file

@ -1,8 +1,10 @@
// +build linux // +build linux
package redir package tproxy
import ( import (
"encoding/binary"
"errors"
"fmt" "fmt"
"net" "net"
"os" "os"
@ -10,6 +12,11 @@ import (
"syscall" "syscall"
) )
const (
IPV6_TRANSPARENT = 0x4b
IPV6_RECVORIGDSTADDR = 0x4a
)
// dialUDP acts like net.DialUDP for transparent proxy. // dialUDP acts like net.DialUDP for transparent proxy.
// It binds to a non-local address(`lAddr`). // It binds to a non-local address(`lAddr`).
func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) { func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
@ -94,3 +101,24 @@ func udpAddrFamily(net string, lAddr, rAddr *net.UDPAddr) int {
} }
return syscall.AF_INET6 return syscall.AF_INET6
} }
func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
msgs, err := syscall.ParseSocketControlMessage(oob[:oobn])
if err != nil {
return nil, err
}
for _, msg := range msgs {
if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {
ip := net.IP(msg.Data[4:8])
port := binary.BigEndian.Uint16(msg.Data[2:4])
return &net.UDPAddr{IP: ip, Port: int(port)}, nil
} else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR {
ip := net.IP(msg.Data[8:24])
port := binary.BigEndian.Uint16(msg.Data[2:4])
return &net.UDPAddr{IP: ip, Port: int(port)}, nil
}
}
return nil, errors.New("cannot find origDst")
}

View file

@ -1,12 +1,16 @@
// +build !linux // +build !linux
package redir package tproxy
import ( import (
"errors" "errors"
"net" "net"
) )
func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
return nil, errors.New("UDP redir not supported on current platform")
}
func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) { func dialUDP(network string, lAddr *net.UDPAddr, rAddr *net.UDPAddr) (*net.UDPConn, error) {
return nil, errors.New("UDP redir not supported on current platform") return nil, errors.New("UDP redir not supported on current platform")
} }

View file

@ -1,36 +0,0 @@
// +build linux
package redir
import (
"encoding/binary"
"errors"
"net"
"syscall"
)
const (
IPV6_TRANSPARENT = 0x4b
IPV6_RECVORIGDSTADDR = 0x4a
)
func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
msgs, err := syscall.ParseSocketControlMessage(oob[:oobn])
if err != nil {
return nil, err
}
for _, msg := range msgs {
if msg.Header.Level == syscall.SOL_IP && msg.Header.Type == syscall.IP_RECVORIGDSTADDR {
ip := net.IP(msg.Data[4:8])
port := binary.BigEndian.Uint16(msg.Data[2:4])
return &net.UDPAddr{IP: ip, Port: int(port)}, nil
} else if msg.Header.Level == syscall.SOL_IPV6 && msg.Header.Type == IPV6_RECVORIGDSTADDR {
ip := net.IP(msg.Data[8:24])
port := binary.BigEndian.Uint16(msg.Data[2:4])
return &net.UDPAddr{IP: ip, Port: int(port)}, nil
}
}
return nil, errors.New("cannot find origDst")
}

View file

@ -1,12 +0,0 @@
// +build !linux
package redir
import (
"errors"
"net"
)
func getOrigDst(oob []byte, oobn int) (*net.UDPAddr, error) {
return nil, errors.New("UDP redir not supported on current platform")
}

View file

@ -37,17 +37,14 @@ func init() {
go process() go process()
} }
// Add request to queue // TCPIn return fan-in queue
func Add(ctx C.ConnContext) { func TCPIn() chan<- C.ConnContext {
tcpQueue <- ctx return tcpQueue
} }
// AddPacket add udp Packet to queue // UDPIn return fan-in udp queue
func AddPacket(packet *inbound.PacketAdapter) { func UDPIn() chan<- *inbound.PacketAdapter {
select { return udpQueue
case udpQueue <- packet:
default:
}
} }
// Rules return all rules // Rules return all rules