Add shadowsocks service

This commit is contained in:
世界 2022-04-29 12:06:10 +08:00
parent 5be6eb2d64
commit df1e1cfafd
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
21 changed files with 1028 additions and 265 deletions

View file

@ -3,6 +3,8 @@ package main
import (
"context"
"encoding/base64"
"encoding/json"
"io/ioutil"
"net"
"net/netip"
"os"
@ -12,22 +14,29 @@ import (
"github.com/sagernet/sing"
"github.com/sagernet/sing/common"
"github.com/sagernet/sing/common/buf"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/gsync"
M "github.com/sagernet/sing/common/metadata"
"github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/common/random"
"github.com/sagernet/sing/common/rw"
"github.com/sagernet/sing/protocol/shadowsocks"
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead"
"github.com/sagernet/sing/protocol/shadowsocks/shadowaead_2022"
"github.com/sagernet/sing/protocol/socks"
"github.com/sagernet/sing/transport/tcp"
"github.com/sagernet/sing/transport/udp"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
type flags struct {
Bind string `json:"local_address"`
LocalPort uint16 `json:"local_port"`
// Password string `json:"password"`
Server string `json:"server"`
ServerPort uint16 `json:"server_port"`
Bind string `json:"local_address"`
LocalPort uint16 `json:"local_port"`
Password string `json:"password"`
Key string `json:"key"`
Method string `json:"method"`
Verbose bool `json:"verbose"`
@ -35,8 +44,6 @@ type flags struct {
}
func main() {
logrus.SetLevel(logrus.TraceLevel)
f := new(flags)
command := &cobra.Command{
@ -48,12 +55,16 @@ func main() {
},
}
command.Flags().StringVarP(&f.Server, "server", "s", "", "Set the server’s hostname or IP.")
command.Flags().Uint16VarP(&f.ServerPort, "server-port", "p", 0, "Set the server’s port number.")
command.Flags().StringVarP(&f.Bind, "local-address", "b", "", "Set the local address.")
command.Flags().Uint16VarP(&f.LocalPort, "local-port", "l", 0, "Set the local port number.")
command.Flags().StringVarP(&f.Key, "key", "k", "", "Set the key directly. The key should be encoded with URL-safe Base64.")
command.Flags().StringVar(&f.Key, "key", "", "Set the key directly. The key should be encoded with URL-safe Base64.")
command.Flags().StringVarP(&f.Password, "password", "k", "", "Set the password. The server and the client should use the same password.")
var supportedCiphers []string
supportedCiphers = append(supportedCiphers, shadowsocks.MethodNone)
supportedCiphers = append(supportedCiphers, shadowaead.List...)
supportedCiphers = append(supportedCiphers, shadowaead_2022.List...)
command.Flags().StringVarP(&f.Method, "encrypt-method", "m", "", "Set the cipher.\n\nSupported ciphers:\n\n"+strings.Join(supportedCiphers, "\n"))
@ -75,6 +86,10 @@ func run(cmd *cobra.Command, f *flags) {
if err != nil {
logrus.Fatal(err)
}
err = s.udpIn.Start()
if err != nil {
logrus.Fatal(err)
}
logrus.Info("server started at ", s.tcpIn.TCPListener.Addr())
osSignals := make(chan os.Signal, 1)
@ -82,33 +97,101 @@ func run(cmd *cobra.Command, f *flags) {
<-osSignals
s.tcpIn.Close()
s.udpIn.Close()
}
type server struct {
tcpIn *tcp.Listener
udpIn *udp.Listener
service shadowsocks.Service
udpNat gsync.Map[string, *net.UDPConn]
}
func (s *server) Start() error {
err := s.tcpIn.Start()
if err != nil {
return err
}
err = s.udpIn.Start()
return err
}
func (s *server) Close() error {
s.tcpIn.Close()
s.udpIn.Close()
return nil
}
func newServer(f *flags) (*server, error) {
s := new(server)
if f.ConfigFile != "" {
configFile, err := ioutil.ReadFile(f.ConfigFile)
if err != nil {
return nil, E.Cause(err, "read config file")
}
flagsNew := new(flags)
err = json.Unmarshal(configFile, flagsNew)
if err != nil {
return nil, E.Cause(err, "decode config file")
}
if flagsNew.Server != "" && f.Server == "" {
f.Server = flagsNew.Server
}
if flagsNew.ServerPort != 0 && f.ServerPort == 0 {
f.ServerPort = flagsNew.ServerPort
}
if flagsNew.Bind != "" && f.Bind == "" {
f.Bind = flagsNew.Bind
}
if flagsNew.LocalPort != 0 && f.LocalPort == 0 {
f.LocalPort = flagsNew.LocalPort
}
if flagsNew.Password != "" && f.Password == "" {
f.Password = flagsNew.Password
}
if flagsNew.Key != "" && f.Key == "" {
f.Key = flagsNew.Key
}
if flagsNew.Method != "" && f.Method == "" {
f.Method = flagsNew.Method
}
if flagsNew.Verbose {
f.Verbose = true
}
}
if f.Verbose {
logrus.SetLevel(logrus.TraceLevel)
}
if f.Server == "" {
return nil, E.New("missing server address")
} else if f.ServerPort == 0 {
return nil, E.New("missing server port")
} else if f.Method == "" {
return nil, E.New("missing method")
}
var key []byte
if f.Key != "" {
kb, err := base64.StdEncoding.DecodeString(f.Key)
if err != nil {
return nil, E.Cause(err, "decode key")
}
key = kb
}
if f.Method == shadowsocks.MethodNone {
s.service = shadowsocks.NewNoneService(s)
} else if common.Contains(shadowaead_2022.List, f.Method) {
var pskList [][]byte
if f.Key != "" {
keyStrList := strings.Split(f.Key, ":")
pskList = make([][]byte, len(keyStrList))
for i, keyStr := range keyStrList {
key, err := base64.StdEncoding.DecodeString(keyStr)
if err != nil {
return nil, E.Cause(err, "decode key")
}
pskList[i] = key
}
} else if common.Contains(shadowaead.List, f.Method) {
service, err := shadowaead.NewService(f.Method, key, []byte(f.Password), random.Blake3KeyedHash(), false, s)
if err != nil {
return nil, err
}
rng := random.System
service, err := shadowaead_2022.NewService(f.Method, pskList[0], rng, s)
s.service = service
} else if common.Contains(shadowaead_2022.List, f.Method) {
service, err := shadowaead_2022.NewService(f.Method, key, random.Blake3KeyedHash(), s)
if err != nil {
return nil, err
}
@ -118,16 +201,17 @@ func newServer(f *flags) (*server, error) {
}
var bind netip.Addr
if f.Bind != "" {
addr, err := netip.ParseAddr(f.Bind)
if f.Server != "" {
addr, err := netip.ParseAddr(f.Server)
if err != nil {
return nil, E.Cause(err, "bad local address")
return nil, E.Cause(err, "bad server address")
}
bind = addr
} else {
bind = netip.IPv6Unspecified()
}
s.tcpIn = tcp.NewTCPListener(netip.AddrPortFrom(bind, f.LocalPort), s)
s.tcpIn = tcp.NewTCPListener(netip.AddrPortFrom(bind, f.ServerPort), s)
s.udpIn = udp.NewUDPListener(netip.AddrPortFrom(bind, f.ServerPort), s)
return s, nil
}
@ -143,6 +227,19 @@ func (s *server) NewConnection(ctx context.Context, conn net.Conn, metadata M.Me
return rw.CopyConn(ctx, conn, destConn)
}
func (s *server) NewPacketConnection(conn socks.PacketConn, metadata M.Metadata) error {
logrus.Info("inbound UDP ", metadata.Source, " ==> ", metadata.Destination)
udpConn, err := net.ListenUDP("udp", nil)
if err != nil {
return err
}
return socks.CopyNetPacketConn(context.Background(), udpConn, conn)
}
func (s *server) NewPacket(conn socks.PacketConn, buffer *buf.Buffer, metadata M.Metadata) error {
return s.service.NewPacket(conn, buffer, metadata)
}
func (s *server) HandleError(err error) {
if E.IsClosed(err) {
return