clash/listener/sing_shadowsocks/server.go
2022-11-11 22:48:44 +08:00

161 lines
3.6 KiB
Go

package sing_shadowsocks
import (
"context"
"fmt"
"net"
"strings"
"github.com/Dreamacro/clash/adapter/inbound"
"github.com/Dreamacro/clash/common/sockopt"
C "github.com/Dreamacro/clash/constant"
embedSS "github.com/Dreamacro/clash/listener/shadowsocks"
"github.com/Dreamacro/clash/listener/sing"
"github.com/Dreamacro/clash/log"
shadowsocks "github.com/sagernet/sing-shadowsocks"
"github.com/sagernet/sing-shadowsocks/shadowaead"
"github.com/sagernet/sing-shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
"github.com/sagernet/sing/common/bufio"
"github.com/sagernet/sing/common/metadata"
)
type Listener struct {
closed bool
config string
listeners []net.Listener
udpListeners []net.PacketConn
service shadowsocks.Service
}
var _listener *Listener
func New(config string, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) (C.AdvanceListener, error) {
addr, cipher, password, err := embedSS.ParseSSURL(config)
if err != nil {
return nil, err
}
udpTimeout := int64(sing.UDPTimeout.Seconds())
h := &sing.ListenerHandler{
TcpIn: tcpIn,
UdpIn: udpIn,
Type: C.SHADOWSOCKS,
}
sl := &Listener{false, config, nil, nil, nil}
switch {
case cipher == shadowsocks.MethodNone:
sl.service = shadowsocks.NewNoneService(udpTimeout, h)
case common.Contains(shadowaead.List, cipher):
sl.service, err = shadowaead.NewService(cipher, nil, password, udpTimeout, h)
case common.Contains(shadowaead_2022.List, cipher):
sl.service, err = shadowaead_2022.NewServiceWithPassword(cipher, password, udpTimeout, h)
default:
err = fmt.Errorf("shadowsocks: unsupported method: %s", cipher)
return embedSS.New(config, tcpIn, udpIn)
}
if err != nil {
return nil, err
}
_listener = sl
for _, addr := range strings.Split(addr, ",") {
addr := addr
//UDP
ul, err := net.ListenPacket("udp", addr)
if err != nil {
return nil, err
}
err = sockopt.UDPReuseaddr(ul.(*net.UDPConn))
if err != nil {
log.Warnln("Failed to Reuse UDP Address: %s", err)
}
sl.udpListeners = append(sl.udpListeners, ul)
go func() {
conn := bufio.NewPacketConn(ul)
for {
buff := buf.NewPacket()
remoteAddr, err := conn.ReadPacket(buff)
if err != nil {
buff.Release()
if sl.closed {
break
}
continue
}
_ = sl.service.NewPacket(context.TODO(), conn, buff, metadata.Metadata{
Protocol: "shadowsocks",
Source: remoteAddr,
})
}
}()
//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) {
err := l.service.NewConnection(context.TODO(), conn, metadata.Metadata{
Protocol: "shadowsocks",
Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()),
})
if err != nil {
_ = conn.Close()
return
}
}
func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext) bool {
if _listener != nil && _listener.service != nil {
go _listener.HandleConn(conn, in)
return true
}
return embedSS.HandleShadowSocks(conn, in)
}