chore: shadowsocks listener support old cipher

This commit is contained in:
wwqgtxx
2022-11-11 22:44:44 +08:00
parent 3eacce9a66
commit 68b28ed530
7 changed files with 261 additions and 11 deletions

105
listener/shadowsocks/tcp.go Normal file
View File

@ -0,0 +1,105 @@
package shadowsocks
import (
"net"
"strings"
"github.com/Dreamacro/clash/adapter/inbound"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/shadowsocks/core"
"github.com/Dreamacro/clash/transport/socks5"
)
type Listener struct {
closed bool
config string
listeners []net.Listener
udpListeners []*UDPListener
pickCipher core.Cipher
}
var _listener *Listener
func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (*Listener, error) {
addr, cipher, password, err := parseSSURL(config)
if err != nil {
return nil, err
}
pickCipher, err := core.PickCipher(cipher, nil, password)
if err != nil {
return nil, err
}
sl := &Listener{false, config, nil, nil, pickCipher}
_listener = sl
for _, addr := range strings.Split(addr, ",") {
addr := addr
//UDP
ul, err := NewUDP(addr, pickCipher, udpIn)
if err != nil {
return nil, err
}
sl.udpListeners = append(sl.udpListeners, ul)
//TCP
l, err := net.Listen("tcp", addr)
if err != nil {
return nil, err
}
sl.listeners = append(sl.listeners, l)
go func() {
log.Infoln("ShadowSocks proxy listening at: %s", l.Addr().String())
for {
c, err := l.Accept()
if err != nil {
if sl.closed {
break
}
continue
}
_ = c.(*net.TCPConn).SetKeepAlive(true)
go sl.HandleConn(c, tcpIn)
}
}()
}
return sl, nil
}
func (l *Listener) Close() {
l.closed = true
for _, lis := range l.listeners {
_ = lis.Close()
}
for _, lis := range l.udpListeners {
_ = lis.Close()
}
}
func (l *Listener) Config() string {
return l.config
}
func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext) {
conn = l.pickCipher.StreamConn(conn)
target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen))
if err != nil {
_ = conn.Close()
return
}
in <- inbound.NewSocket(target, conn, C.SHADOWSOCKS)
}
func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext) bool {
if _listener != nil && _listener.pickCipher != nil {
go _listener.HandleConn(conn, in)
return true
}
return false
}

View File

@ -0,0 +1,76 @@
package shadowsocks
import (
"net"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/common/sockopt"
C "github.com/Dreamacro/clash/constant"
"github.com/Dreamacro/clash/log"
"github.com/Dreamacro/clash/transport/shadowsocks/core"
"github.com/Dreamacro/clash/transport/socks5"
)
type UDPListener struct {
packetConn net.PacketConn
closed bool
}
func NewUDP(addr string, pickCipher core.Cipher, in chan<- *inbound.PacketAdapter) (*UDPListener, error) {
l, err := net.ListenPacket("udp", addr)
if err != nil {
return nil, err
}
err = sockopt.UDPReuseaddr(l.(*net.UDPConn))
if err != nil {
log.Warnln("Failed to Reuse UDP Address: %s", err)
}
sl := &UDPListener{l, false}
conn := pickCipher.PacketConn(l)
go func() {
for {
buf := pool.Get(pool.RelayBufferSize)
n, remoteAddr, err := conn.ReadFrom(buf)
if err != nil {
pool.Put(buf)
if sl.closed {
break
}
continue
}
handleSocksUDP(conn, in, buf[:n], remoteAddr)
}
}()
return sl, nil
}
func (l *UDPListener) Close() error {
l.closed = true
return l.packetConn.Close()
}
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
tgtAddr := socks5.SplitAddr(buf)
if tgtAddr == nil {
// Unresolved UDP packet, return buffer to the pool
pool.Put(buf)
return
}
target := socks5.ParseAddr(tgtAddr.String())
payload := buf[len(tgtAddr):]
packet := &packet{
pc: pc,
rAddr: addr,
payload: payload,
bufRef: buf,
}
select {
case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS):
default:
}
}

View File

@ -0,0 +1,59 @@
package shadowsocks
import (
"bytes"
"errors"
"net"
"net/url"
"github.com/Dreamacro/clash/common/pool"
"github.com/Dreamacro/clash/transport/socks5"
)
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 := bytes.Join([][]byte{socks5.ParseAddrToSocksAddr(addr), b}, []byte{})
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()
}
func parseSSURL(s string) (addr, cipher, password string, err error) {
u, err := url.Parse(s)
if err != nil {
return
}
addr = u.Host
if u.User != nil {
cipher = u.User.Username()
password, _ = u.User.Password()
}
return
}