github.com/database64128/shadowsocks-go@v1.7.0/service/server.go (about)

     1  package service
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  
     7  	v1 "github.com/database64128/shadowsocks-go/api/v1"
     8  	"github.com/database64128/shadowsocks-go/conn"
     9  	"github.com/database64128/shadowsocks-go/cred"
    10  	"github.com/database64128/shadowsocks-go/direct"
    11  	"github.com/database64128/shadowsocks-go/http"
    12  	"github.com/database64128/shadowsocks-go/router"
    13  	"github.com/database64128/shadowsocks-go/ss2022"
    14  	"github.com/database64128/shadowsocks-go/stats"
    15  	"github.com/database64128/shadowsocks-go/zerocopy"
    16  	"github.com/database64128/tfo-go/v2"
    17  	"go.uber.org/zap"
    18  )
    19  
    20  // ServerConfig stores a server configuration.
    21  // It may be marshaled as or unmarshaled from JSON.
    22  type ServerConfig struct {
    23  	Name                 string `json:"name"`
    24  	Listen               string `json:"listen"`
    25  	Protocol             string `json:"protocol"`
    26  	ListenerFwmark       int    `json:"listenerFwmark"`
    27  	ListenerTrafficClass int    `json:"listenerTrafficClass"`
    28  
    29  	// TCP
    30  	EnableTCP                 bool `json:"enableTCP"`
    31  	ListenerTFO               bool `json:"listenerTFO"`
    32  	DisableInitialPayloadWait bool `json:"disableInitialPayloadWait"`
    33  
    34  	// UDP
    35  	EnableUDP     bool `json:"enableUDP"`
    36  	MTU           int  `json:"mtu"`
    37  	NatTimeoutSec int  `json:"natTimeoutSec"`
    38  
    39  	// UDP performance tuning
    40  	UDPBatchMode           string `json:"udpBatchMode"`
    41  	UDPRelayBatchSize      int    `json:"udpRelayBatchSize"`
    42  	UDPServerRecvBatchSize int    `json:"udpServerRecvBatchSize"`
    43  	UDPSendChannelCapacity int    `json:"udpSendChannelCapacity"`
    44  
    45  	// Simple tunnel
    46  	TunnelRemoteAddress conn.Addr `json:"tunnelRemoteAddress"`
    47  	TunnelUDPTargetOnly bool      `json:"tunnelUDPTargetOnly"`
    48  
    49  	// Shadowsocks
    50  	PSK                  []byte `json:"psk"`
    51  	UPSKStorePath        string `json:"uPSKStorePath"`
    52  	PaddingPolicy        string `json:"paddingPolicy"`
    53  	RejectPolicy         string `json:"rejectPolicy"`
    54  	userCipherConfig     ss2022.UserCipherConfig
    55  	identityCipherConfig ss2022.ServerIdentityCipherConfig
    56  	tcpCredStore         *ss2022.CredStore
    57  	udpCredStore         *ss2022.CredStore
    58  
    59  	// Taint
    60  	UnsafeFallbackAddress      *conn.Addr `json:"unsafeFallbackAddress"`
    61  	UnsafeRequestStreamPrefix  []byte     `json:"unsafeRequestStreamPrefix"`
    62  	UnsafeResponseStreamPrefix []byte     `json:"unsafeResponseStreamPrefix"`
    63  
    64  	listenConfigCache conn.ListenConfigCache
    65  	collector         stats.Collector
    66  	router            *router.Router
    67  	logger            *zap.Logger
    68  	index             int
    69  }
    70  
    71  // Initialize initializes the server configuration.
    72  func (sc *ServerConfig) Initialize(listenConfigCache conn.ListenConfigCache, collector stats.Collector, router *router.Router, logger *zap.Logger, index int) error {
    73  	switch sc.Protocol {
    74  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
    75  		err := ss2022.CheckPSKLength(sc.Protocol, sc.PSK, nil)
    76  		if err != nil {
    77  			return err
    78  		}
    79  
    80  		if sc.UPSKStorePath == "" {
    81  			sc.userCipherConfig, err = ss2022.NewUserCipherConfig(sc.PSK, sc.EnableUDP)
    82  			if err != nil {
    83  				return err
    84  			}
    85  		} else {
    86  			sc.identityCipherConfig, err = ss2022.NewServerIdentityCipherConfig(sc.PSK, sc.EnableUDP)
    87  			if err != nil {
    88  				return err
    89  			}
    90  		}
    91  	}
    92  
    93  	sc.listenConfigCache = listenConfigCache
    94  	sc.collector = collector
    95  	sc.router = router
    96  	sc.logger = logger
    97  	sc.index = index
    98  	return nil
    99  }
   100  
   101  // TCPRelay creates a TCP relay service from the ServerConfig.
   102  func (sc *ServerConfig) TCPRelay() (*TCPRelay, error) {
   103  	if !sc.EnableTCP && sc.Protocol != "socks5" {
   104  		return nil, errNetworkDisabled
   105  	}
   106  
   107  	var (
   108  		server              zerocopy.TCPServer
   109  		connCloser          zerocopy.TCPConnCloser
   110  		err                 error
   111  		listenerTransparent bool
   112  	)
   113  
   114  	switch sc.Protocol {
   115  	case "direct":
   116  		server = direct.NewTCPServer(sc.TunnelRemoteAddress)
   117  
   118  	case "tproxy":
   119  		server, err = direct.NewTCPTransparentServer()
   120  		if err != nil {
   121  			return nil, err
   122  		}
   123  		listenerTransparent = true
   124  
   125  	case "none", "plain":
   126  		server = direct.NewShadowsocksNoneTCPServer()
   127  
   128  	case "socks5":
   129  		server = direct.NewSocks5TCPServer(sc.EnableTCP, sc.EnableUDP)
   130  
   131  	case "http":
   132  		server = http.NewProxyServer(sc.logger)
   133  
   134  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   135  		if len(sc.UnsafeRequestStreamPrefix) != 0 || len(sc.UnsafeResponseStreamPrefix) != 0 {
   136  			sc.logger.Warn("Unsafe stream prefix taints the server", zap.String("server", sc.Name))
   137  		}
   138  
   139  		s := ss2022.NewTCPServer(sc.userCipherConfig, sc.identityCipherConfig, sc.UnsafeRequestStreamPrefix, sc.UnsafeResponseStreamPrefix)
   140  		sc.tcpCredStore = &s.CredStore
   141  		server = s
   142  
   143  	default:
   144  		return nil, fmt.Errorf("invalid protocol: %s", sc.Protocol)
   145  	}
   146  
   147  	serverInfo := server.Info()
   148  
   149  	connCloser, err = zerocopy.ParseRejectPolicy(sc.RejectPolicy, serverInfo.DefaultTCPConnCloser)
   150  	if err != nil {
   151  		return nil, err
   152  	}
   153  
   154  	if sc.UnsafeFallbackAddress != nil {
   155  		sc.logger.Warn("Unsafe fallback taints the server",
   156  			zap.String("server", sc.Name),
   157  			zap.Stringer("fallbackAddress", sc.UnsafeFallbackAddress),
   158  		)
   159  	}
   160  
   161  	waitForInitialPayload := !serverInfo.NativeInitialPayload && !sc.DisableInitialPayloadWait
   162  
   163  	listenConfig := sc.listenConfigCache.Get(conn.ListenerSocketOptions{
   164  		Fwmark:       sc.ListenerFwmark,
   165  		TrafficClass: sc.ListenerTrafficClass,
   166  		Transparent:  listenerTransparent,
   167  		TCPFastOpen:  sc.ListenerTFO,
   168  	})
   169  
   170  	return NewTCPRelay(sc.index, sc.Name, sc.Listen, waitForInitialPayload, listenConfig, server, connCloser, sc.UnsafeFallbackAddress, sc.collector, sc.router, sc.logger), nil
   171  }
   172  
   173  // UDPRelay creates a UDP relay service from the ServerConfig.
   174  func (sc *ServerConfig) UDPRelay(maxClientPackerHeadroom zerocopy.Headroom) (Relay, error) {
   175  	if !sc.EnableUDP {
   176  		return nil, errNetworkDisabled
   177  	}
   178  
   179  	if sc.MTU < minimumMTU {
   180  		return nil, ErrMTUTooSmall
   181  	}
   182  
   183  	switch sc.UDPBatchMode {
   184  	case "", "no", "sendmmsg":
   185  	default:
   186  		return nil, fmt.Errorf("unknown UDP batch mode: %s", sc.UDPBatchMode)
   187  	}
   188  
   189  	switch {
   190  	case sc.UDPRelayBatchSize > 0 && sc.UDPRelayBatchSize <= 1024:
   191  	case sc.UDPRelayBatchSize == 0:
   192  		sc.UDPRelayBatchSize = defaultRelayBatchSize
   193  	default:
   194  		return nil, fmt.Errorf("UDP relay batch size out of range [0, 1024]: %d", sc.UDPRelayBatchSize)
   195  	}
   196  
   197  	switch {
   198  	case sc.UDPServerRecvBatchSize > 0 && sc.UDPServerRecvBatchSize <= 1024:
   199  	case sc.UDPServerRecvBatchSize == 0:
   200  		sc.UDPServerRecvBatchSize = defaultServerRecvBatchSize
   201  	default:
   202  		return nil, fmt.Errorf("UDP server recv batch size out of range [0, 1024]: %d", sc.UDPServerRecvBatchSize)
   203  	}
   204  
   205  	switch {
   206  	case sc.UDPSendChannelCapacity >= 64:
   207  	case sc.UDPSendChannelCapacity == 0:
   208  		sc.UDPSendChannelCapacity = defaultSendChannelCapacity
   209  	default:
   210  		return nil, fmt.Errorf("UDP send channel capacity must be at least 64: %d", sc.UDPSendChannelCapacity)
   211  	}
   212  
   213  	var (
   214  		natTimeout                  time.Duration
   215  		natServer                   zerocopy.UDPNATServer
   216  		server                      zerocopy.UDPSessionServer
   217  		serverConnListenConfig      tfo.ListenConfig
   218  		transparentConnListenConfig tfo.ListenConfig
   219  	)
   220  
   221  	switch {
   222  	case sc.NatTimeoutSec == 0:
   223  		natTimeout = defaultNatTimeout
   224  	case sc.NatTimeoutSec < minNatTimeoutSec:
   225  		return nil, fmt.Errorf("natTimeoutSec too short: %d, must be at least %d", sc.NatTimeoutSec, minNatTimeoutSec)
   226  	default:
   227  		natTimeout = time.Duration(sc.NatTimeoutSec) * time.Second
   228  	}
   229  
   230  	switch sc.Protocol {
   231  	case "direct":
   232  		natServer = direct.NewDirectUDPNATServer(sc.TunnelRemoteAddress, sc.TunnelUDPTargetOnly)
   233  
   234  	case "tproxy":
   235  
   236  	case "none", "plain":
   237  		natServer = direct.ShadowsocksNoneUDPNATServer{}
   238  
   239  	case "socks5":
   240  		natServer = direct.Socks5UDPNATServer{}
   241  
   242  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   243  		shouldPad, err := ss2022.ParsePaddingPolicy(sc.PaddingPolicy)
   244  		if err != nil {
   245  			return nil, err
   246  		}
   247  
   248  		s := ss2022.NewUDPServer(sc.userCipherConfig, sc.identityCipherConfig, shouldPad)
   249  		sc.udpCredStore = &s.CredStore
   250  		server = s
   251  
   252  	default:
   253  		return nil, fmt.Errorf("invalid protocol: %s", sc.Protocol)
   254  	}
   255  
   256  	switch sc.Protocol {
   257  	case "tproxy":
   258  		serverConnListenConfig = sc.listenConfigCache.Get(conn.ListenerSocketOptions{
   259  			Fwmark:                  sc.ListenerFwmark,
   260  			TrafficClass:            sc.ListenerTrafficClass,
   261  			Transparent:             true,
   262  			PathMTUDiscovery:        true,
   263  			ReceiveOriginalDestAddr: true,
   264  		})
   265  		transparentConnListenConfig = sc.listenConfigCache.Get(conn.ListenerSocketOptions{
   266  			Fwmark:           sc.ListenerFwmark,
   267  			TrafficClass:     sc.ListenerTrafficClass,
   268  			Transparent:      true,
   269  			ReusePort:        true,
   270  			PathMTUDiscovery: true,
   271  		})
   272  	default:
   273  		serverConnListenConfig = sc.listenConfigCache.Get(conn.ListenerSocketOptions{
   274  			Fwmark:            sc.ListenerFwmark,
   275  			TrafficClass:      sc.ListenerTrafficClass,
   276  			PathMTUDiscovery:  true,
   277  			ReceivePacketInfo: true,
   278  		})
   279  	}
   280  
   281  	switch sc.Protocol {
   282  	case "direct", "none", "plain", "socks5":
   283  		return NewUDPNATRelay(sc.UDPBatchMode, sc.Name, sc.Listen, sc.UDPRelayBatchSize, sc.UDPServerRecvBatchSize, sc.UDPSendChannelCapacity, sc.index, sc.MTU, maxClientPackerHeadroom, natTimeout, natServer, serverConnListenConfig, sc.collector, sc.router, sc.logger), nil
   284  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   285  		return NewUDPSessionRelay(sc.UDPBatchMode, sc.Name, sc.Listen, sc.UDPRelayBatchSize, sc.UDPServerRecvBatchSize, sc.UDPSendChannelCapacity, sc.index, sc.MTU, maxClientPackerHeadroom, natTimeout, server, serverConnListenConfig, sc.collector, sc.router, sc.logger), nil
   286  	case "tproxy":
   287  		return NewUDPTransparentRelay(sc.Name, sc.Listen, sc.UDPRelayBatchSize, sc.UDPServerRecvBatchSize, sc.UDPSendChannelCapacity, sc.index, sc.MTU, maxClientPackerHeadroom, natTimeout, serverConnListenConfig, transparentConnListenConfig, sc.collector, sc.router, sc.logger)
   288  	default:
   289  		return nil, fmt.Errorf("invalid protocol: %s", sc.Protocol)
   290  	}
   291  }
   292  
   293  // PostInit performs post-initialization tasks.
   294  func (sc *ServerConfig) PostInit(credman *cred.Manager, apiSM *v1.ServerManager) error {
   295  	var cms *cred.ManagedServer
   296  
   297  	switch sc.Protocol {
   298  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   299  		if sc.UPSKStorePath != "" {
   300  			var err error
   301  			cms, err = credman.RegisterServer(sc.Name, sc.UPSKStorePath, len(sc.PSK), sc.tcpCredStore, sc.udpCredStore)
   302  			if err != nil {
   303  				return err
   304  			}
   305  		}
   306  	}
   307  
   308  	if apiSM != nil {
   309  		apiSM.AddServer(sc.Name, cms, sc.collector)
   310  	}
   311  
   312  	return nil
   313  }