github.com/database64128/shadowsocks-go@v1.10.2-0.20240315062903-143a773533f1/service/server.go (about)

     1  package service
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net/netip"
     7  	"time"
     8  
     9  	v1 "github.com/database64128/shadowsocks-go/api/v1"
    10  	"github.com/database64128/shadowsocks-go/conn"
    11  	"github.com/database64128/shadowsocks-go/cred"
    12  	"github.com/database64128/shadowsocks-go/direct"
    13  	"github.com/database64128/shadowsocks-go/http"
    14  	"github.com/database64128/shadowsocks-go/jsonhelper"
    15  	"github.com/database64128/shadowsocks-go/router"
    16  	"github.com/database64128/shadowsocks-go/ss2022"
    17  	"github.com/database64128/shadowsocks-go/stats"
    18  	"github.com/database64128/shadowsocks-go/zerocopy"
    19  	"go.uber.org/zap"
    20  )
    21  
    22  // ListenerConfig is the shared part of TCP listener and UDP server socket configurations.
    23  type ListenerConfig struct {
    24  	// Network is the network type.
    25  	// Valid values include "tcp", "tcp4", "tcp6", "udp", "udp4", "udp6".
    26  	Network string `json:"network"`
    27  
    28  	// Address is the address to listen on.
    29  	Address string `json:"address"`
    30  
    31  	// Fwmark sets the listener's fwmark on Linux, or user cookie on FreeBSD.
    32  	//
    33  	// Available on Linux and FreeBSD.
    34  	Fwmark int `json:"fwmark"`
    35  
    36  	// TrafficClass sets the traffic class of the listener.
    37  	//
    38  	// Available on most platforms except Windows.
    39  	TrafficClass int `json:"trafficClass"`
    40  
    41  	// ReusePort enables SO_REUSEPORT on the listener.
    42  	//
    43  	// Available on Linux and the BSDs.
    44  	ReusePort bool `json:"reusePort"`
    45  }
    46  
    47  // TCPListenerConfig is the configuration for a TCP listener.
    48  type TCPListenerConfig struct {
    49  	// ListenerConfig is the shared part of TCP listener and UDP server socket configurations.
    50  	ListenerConfig
    51  
    52  	// FastOpen enables TCP Fast Open on the listener.
    53  	//
    54  	// Available on Linux, macOS, FreeBSD, and Windows.
    55  	FastOpen bool `json:"fastOpen"`
    56  
    57  	// FastOpenFallback enables runtime detection of TCP Fast Open support on the listener.
    58  	//
    59  	// When enabled, the listener will start without TFO if TFO is not available on the system.
    60  	// When disabled, the listener will abort if TFO cannot be enabled on the socket.
    61  	//
    62  	// Available on all platforms.
    63  	FastOpenFallback bool `json:"fastOpenFallback"`
    64  
    65  	// Multipath enables multipath TCP on the listener.
    66  	//
    67  	// Unlike Go std, we make MPTCP strictly opt-in.
    68  	// That is, if this field is false, MPTCP will be explicitly disabled.
    69  	// This ensures that if Go std suddenly decides to enable MPTCP by default,
    70  	// existing configurations won't encounter issues due to missing features in the kernel MPTCP stack,
    71  	// such as TCP keepalive (as of Linux 6.5), and failed connect attempts won't always be retried once.
    72  	//
    73  	// Available on platforms supported by Go std's MPTCP implementation.
    74  	Multipath bool `json:"multipath"`
    75  
    76  	// DisableInitialPayloadWait disables the brief wait for initial payload.
    77  	// Setting it to true is useful when the listener only relays server-speaks-first protocols.
    78  	DisableInitialPayloadWait bool `json:"disableInitialPayloadWait"`
    79  
    80  	// InitialPayloadWaitTimeout is the read timeout when waiting for the initial payload.
    81  	//
    82  	// The default value is 250ms.
    83  	InitialPayloadWaitTimeout jsonhelper.Duration `json:"initialPayloadWaitTimeout"`
    84  
    85  	// InitialPayloadWaitBufferSize is the read buffer size when waiting for the initial payload.
    86  	//
    87  	// The default value is 1440.
    88  	InitialPayloadWaitBufferSize int `json:"initialPayloadWaitBufferSize"`
    89  
    90  	// FastOpenBacklog specifies the maximum number of pending TFO connections on Linux.
    91  	// If the value is 0, Go std's listen(2) backlog is used.
    92  	//
    93  	// On other platforms, a non-negative value is ignored, as they do not have the option to set the TFO backlog.
    94  	//
    95  	// On all platforms, a negative value disables TFO.
    96  	FastOpenBacklog int `json:"fastOpenBacklog"`
    97  }
    98  
    99  // Configure returns a TCP listener configuration.
   100  func (lnc *TCPListenerConfig) Configure(listenConfigCache conn.ListenConfigCache, transparent, serverNativeInitialPayload bool) (tcpRelayListener, error) {
   101  	switch lnc.Network {
   102  	case "tcp", "tcp4", "tcp6":
   103  	default:
   104  		return tcpRelayListener{}, fmt.Errorf("invalid network: %s", lnc.Network)
   105  	}
   106  
   107  	initialPayloadWaitTimeout := time.Duration(lnc.InitialPayloadWaitTimeout)
   108  
   109  	switch {
   110  	case initialPayloadWaitTimeout == 0:
   111  		initialPayloadWaitTimeout = defaultInitialPayloadWaitTimeout
   112  	case initialPayloadWaitTimeout < 0:
   113  		return tcpRelayListener{}, fmt.Errorf("negative initial payload wait timeout: %s", initialPayloadWaitTimeout)
   114  	}
   115  
   116  	switch {
   117  	case lnc.InitialPayloadWaitBufferSize == 0:
   118  		lnc.InitialPayloadWaitBufferSize = defaultInitialPayloadWaitBufferSize
   119  	case lnc.InitialPayloadWaitBufferSize < 0:
   120  		return tcpRelayListener{}, fmt.Errorf("negative initial payload wait buffer size: %d", lnc.InitialPayloadWaitBufferSize)
   121  	}
   122  
   123  	return tcpRelayListener{
   124  		listenConfig: listenConfigCache.Get(conn.ListenerSocketOptions{
   125  			Fwmark:              lnc.Fwmark,
   126  			TrafficClass:        lnc.TrafficClass,
   127  			TCPFastOpenBacklog:  lnc.FastOpenBacklog,
   128  			ReusePort:           lnc.ReusePort,
   129  			Transparent:         transparent,
   130  			TCPFastOpen:         lnc.FastOpen,
   131  			TCPFastOpenFallback: lnc.FastOpenFallback,
   132  			MultipathTCP:        lnc.Multipath,
   133  		}),
   134  		waitForInitialPayload:        !serverNativeInitialPayload && !lnc.DisableInitialPayloadWait,
   135  		initialPayloadWaitTimeout:    initialPayloadWaitTimeout,
   136  		initialPayloadWaitBufferSize: lnc.InitialPayloadWaitBufferSize,
   137  		network:                      lnc.Network,
   138  		address:                      lnc.Address,
   139  	}, nil
   140  }
   141  
   142  // UDPListenerConfig is the configuration for a UDP server socket.
   143  type UDPListenerConfig struct {
   144  	// ListenerConfig is the shared part of TCP listener and UDP server socket configurations.
   145  	ListenerConfig
   146  
   147  	// UDPPerfConfig exposes performance tuning options.
   148  	UDPPerfConfig
   149  
   150  	// NATTimeout is the duration after which an inactive NAT mapping expires.
   151  	//
   152  	// The default value is 5 minutes.
   153  	NATTimeout jsonhelper.Duration `json:"natTimeout"`
   154  }
   155  
   156  // Configure returns a UDP server socket configuration.
   157  func (lnc *UDPListenerConfig) Configure(listenConfigCache conn.ListenConfigCache, minNATTimeout time.Duration, transparent bool) (udpRelayServerConn, error) {
   158  	switch lnc.Network {
   159  	case "udp", "udp4", "udp6":
   160  	default:
   161  		return udpRelayServerConn{}, fmt.Errorf("invalid network: %s", lnc.Network)
   162  	}
   163  
   164  	if err := lnc.UDPPerfConfig.CheckAndApplyDefaults(); err != nil {
   165  		return udpRelayServerConn{}, err
   166  	}
   167  
   168  	natTimeout := time.Duration(lnc.NATTimeout)
   169  
   170  	switch {
   171  	case natTimeout == 0:
   172  		natTimeout = defaultNatTimeout
   173  	case natTimeout < minNATTimeout:
   174  		return udpRelayServerConn{}, fmt.Errorf("NAT timeout %s is less than server's minimum NAT timeout %s", natTimeout, minNATTimeout)
   175  	}
   176  
   177  	return udpRelayServerConn{
   178  		listenConfig: listenConfigCache.Get(conn.ListenerSocketOptions{
   179  			Fwmark:            lnc.Fwmark,
   180  			TrafficClass:      lnc.TrafficClass,
   181  			ReusePort:         lnc.ReusePort,
   182  			Transparent:       transparent,
   183  			PathMTUDiscovery:  true,
   184  			ReceivePacketInfo: true,
   185  		}),
   186  		network:             lnc.Network,
   187  		address:             lnc.Address,
   188  		batchMode:           lnc.UDPPerfConfig.BatchMode,
   189  		relayBatchSize:      lnc.UDPPerfConfig.RelayBatchSize,
   190  		serverRecvBatchSize: lnc.UDPPerfConfig.ServerRecvBatchSize,
   191  		sendChannelCapacity: lnc.UDPPerfConfig.SendChannelCapacity,
   192  		natTimeout:          natTimeout,
   193  	}, nil
   194  }
   195  
   196  // ServerConfig stores a server configuration.
   197  // It may be marshaled as or unmarshaled from JSON.
   198  type ServerConfig struct {
   199  	// Name is the name of the server.
   200  	Name string `json:"name"`
   201  
   202  	// Protocol is the protocol the server uses.
   203  	// Valid values include "direct", "tproxy" (Linux only), "socks5", "http", "none", "plain", "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm".
   204  	Protocol string `json:"protocol"`
   205  
   206  	// TCPListeners is the list of TCP listeners.
   207  	TCPListeners []TCPListenerConfig `json:"tcpListeners"`
   208  
   209  	// UDPListeners is the list of UDP listeners.
   210  	UDPListeners []UDPListenerConfig `json:"udpListeners"`
   211  
   212  	// MTU is the MTU of the server's designated network path.
   213  	// The value is used for calculating UDP receive buffer size.
   214  	MTU int `json:"mtu"`
   215  
   216  	// Single listener configuration.
   217  
   218  	Listen               string `json:"listen"`
   219  	ListenerFwmark       int    `json:"listenerFwmark"`
   220  	ListenerTrafficClass int    `json:"listenerTrafficClass"`
   221  
   222  	// TCP
   223  
   224  	EnableTCP                 bool `json:"enableTCP"`
   225  	ListenerTFO               bool `json:"listenerTFO"`
   226  	DisableInitialPayloadWait bool `json:"disableInitialPayloadWait"`
   227  
   228  	// UDP
   229  
   230  	EnableUDP     bool `json:"enableUDP"`
   231  	NatTimeoutSec int  `json:"natTimeoutSec"`
   232  
   233  	// UDP performance tuning
   234  
   235  	UDPBatchMode           string `json:"udpBatchMode"`
   236  	UDPRelayBatchSize      int    `json:"udpRelayBatchSize"`
   237  	UDPServerRecvBatchSize int    `json:"udpServerRecvBatchSize"`
   238  	UDPSendChannelCapacity int    `json:"udpSendChannelCapacity"`
   239  
   240  	// Simple tunnel
   241  
   242  	TunnelRemoteAddress conn.Addr `json:"tunnelRemoteAddress"`
   243  	TunnelUDPTargetOnly bool      `json:"tunnelUDPTargetOnly"`
   244  
   245  	tcpEnabled bool
   246  	udpEnabled bool
   247  
   248  	// AllowSegmentedFixedLengthHeader disables the requirement that
   249  	// the fixed-length header must be read in a single read call.
   250  	//
   251  	// This option is useful when the underlying stream transport
   252  	// does not exhibit typical TCP behavior.
   253  	//
   254  	// Only applicable to Shadowsocks 2022 TCP.
   255  	AllowSegmentedFixedLengthHeader bool `json:"allowSegmentedFixedLengthHeader"`
   256  
   257  	// Shadowsocks
   258  
   259  	PSK           []byte `json:"psk"`
   260  	UPSKStorePath string `json:"uPSKStorePath"`
   261  	PaddingPolicy string `json:"paddingPolicy"`
   262  	RejectPolicy  string `json:"rejectPolicy"`
   263  
   264  	// SlidingWindowFilterSize is the size of the sliding window filter.
   265  	//
   266  	// The default value is 256.
   267  	//
   268  	// Only applicable to Shadowsocks 2022 UDP.
   269  	SlidingWindowFilterSize int `json:"slidingWindowFilterSize"`
   270  
   271  	userCipherConfig     ss2022.UserCipherConfig
   272  	identityCipherConfig ss2022.ServerIdentityCipherConfig
   273  	tcpCredStore         *ss2022.CredStore
   274  	udpCredStore         *ss2022.CredStore
   275  
   276  	// Taint
   277  
   278  	UnsafeFallbackAddress      conn.Addr `json:"unsafeFallbackAddress"`
   279  	UnsafeRequestStreamPrefix  []byte    `json:"unsafeRequestStreamPrefix"`
   280  	UnsafeResponseStreamPrefix []byte    `json:"unsafeResponseStreamPrefix"`
   281  
   282  	listenConfigCache conn.ListenConfigCache
   283  	collector         stats.Collector
   284  	router            *router.Router
   285  	logger            *zap.Logger
   286  	index             int
   287  }
   288  
   289  // Initialize initializes the server configuration.
   290  func (sc *ServerConfig) Initialize(listenConfigCache conn.ListenConfigCache, collector stats.Collector, router *router.Router, logger *zap.Logger, index int) error {
   291  	sc.tcpEnabled = sc.EnableTCP || len(sc.TCPListeners) > 0
   292  	sc.udpEnabled = sc.EnableUDP || len(sc.UDPListeners) > 0
   293  
   294  	switch sc.Protocol {
   295  	case "direct":
   296  		if !sc.TunnelRemoteAddress.IsValid() {
   297  			return errors.New("tunnelRemoteAddress is required for simple tunnel")
   298  		}
   299  
   300  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   301  		err := ss2022.CheckPSKLength(sc.Protocol, sc.PSK, nil)
   302  		if err != nil {
   303  			return err
   304  		}
   305  
   306  		if sc.UPSKStorePath == "" {
   307  			sc.userCipherConfig, err = ss2022.NewUserCipherConfig(sc.PSK, sc.udpEnabled)
   308  			if err != nil {
   309  				return err
   310  			}
   311  		} else {
   312  			sc.identityCipherConfig, err = ss2022.NewServerIdentityCipherConfig(sc.PSK, sc.udpEnabled)
   313  			if err != nil {
   314  				return err
   315  			}
   316  		}
   317  	}
   318  
   319  	if sc.EnableTCP {
   320  		sc.TCPListeners = append(sc.TCPListeners, TCPListenerConfig{
   321  			ListenerConfig: ListenerConfig{
   322  				Network:      "tcp",
   323  				Address:      sc.Listen,
   324  				Fwmark:       sc.ListenerFwmark,
   325  				TrafficClass: sc.ListenerTrafficClass,
   326  			},
   327  			FastOpen:                  sc.ListenerTFO,
   328  			DisableInitialPayloadWait: sc.DisableInitialPayloadWait,
   329  		})
   330  	}
   331  
   332  	if sc.EnableUDP {
   333  		sc.UDPListeners = append(sc.UDPListeners, UDPListenerConfig{
   334  			ListenerConfig: ListenerConfig{
   335  				Network:      "udp",
   336  				Address:      sc.Listen,
   337  				Fwmark:       sc.ListenerFwmark,
   338  				TrafficClass: sc.ListenerTrafficClass,
   339  			},
   340  			UDPPerfConfig: UDPPerfConfig{
   341  				BatchMode:           sc.UDPBatchMode,
   342  				RelayBatchSize:      sc.UDPRelayBatchSize,
   343  				ServerRecvBatchSize: sc.UDPServerRecvBatchSize,
   344  				SendChannelCapacity: sc.UDPSendChannelCapacity,
   345  			},
   346  			NATTimeout: jsonhelper.Duration(time.Duration(sc.NatTimeoutSec) * time.Second),
   347  		})
   348  	}
   349  
   350  	sc.listenConfigCache = listenConfigCache
   351  	sc.collector = collector
   352  	sc.router = router
   353  	sc.logger = logger
   354  	sc.index = index
   355  	return nil
   356  }
   357  
   358  // TCPRelay creates a TCP relay service from the ServerConfig.
   359  func (sc *ServerConfig) TCPRelay() (*TCPRelay, error) {
   360  	if len(sc.TCPListeners) == 0 {
   361  		return nil, errNetworkDisabled
   362  	}
   363  
   364  	var (
   365  		server              zerocopy.TCPServer
   366  		connCloser          zerocopy.TCPConnCloser
   367  		err                 error
   368  		listenerTransparent bool
   369  	)
   370  
   371  	switch sc.Protocol {
   372  	case "direct":
   373  		server = direct.NewTCPServer(sc.TunnelRemoteAddress)
   374  
   375  	case "tproxy":
   376  		server, err = direct.NewTCPTransparentServer()
   377  		if err != nil {
   378  			return nil, err
   379  		}
   380  		listenerTransparent = true
   381  
   382  	case "none", "plain":
   383  		server = direct.NewShadowsocksNoneTCPServer()
   384  
   385  	case "socks5":
   386  		server = direct.NewSocks5TCPServer(sc.tcpEnabled, sc.udpEnabled)
   387  
   388  	case "http":
   389  		server = http.NewProxyServer(sc.logger)
   390  
   391  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   392  		if len(sc.UnsafeRequestStreamPrefix) != 0 || len(sc.UnsafeResponseStreamPrefix) != 0 {
   393  			sc.logger.Warn("Unsafe stream prefix taints the server", zap.String("server", sc.Name))
   394  		}
   395  
   396  		s := ss2022.NewTCPServer(sc.AllowSegmentedFixedLengthHeader, sc.userCipherConfig, sc.identityCipherConfig, sc.UnsafeRequestStreamPrefix, sc.UnsafeResponseStreamPrefix)
   397  		sc.tcpCredStore = &s.CredStore
   398  		server = s
   399  
   400  	default:
   401  		return nil, fmt.Errorf("invalid protocol: %s", sc.Protocol)
   402  	}
   403  
   404  	serverInfo := server.Info()
   405  
   406  	connCloser, err = zerocopy.ParseRejectPolicy(sc.RejectPolicy, serverInfo.DefaultTCPConnCloser)
   407  	if err != nil {
   408  		return nil, err
   409  	}
   410  
   411  	if sc.UnsafeFallbackAddress.IsValid() {
   412  		sc.logger.Warn("Unsafe fallback taints the server",
   413  			zap.String("server", sc.Name),
   414  			zap.Stringer("fallbackAddress", sc.UnsafeFallbackAddress),
   415  		)
   416  	}
   417  
   418  	listeners := make([]tcpRelayListener, len(sc.TCPListeners))
   419  
   420  	for i := range listeners {
   421  		listeners[i], err = sc.TCPListeners[i].Configure(sc.listenConfigCache, listenerTransparent, serverInfo.NativeInitialPayload)
   422  		if err != nil {
   423  			return nil, err
   424  		}
   425  	}
   426  
   427  	return NewTCPRelay(sc.index, sc.Name, listeners, server, connCloser, sc.UnsafeFallbackAddress, sc.collector, sc.router, sc.logger), nil
   428  }
   429  
   430  // UDPRelay creates a UDP relay service from the ServerConfig.
   431  func (sc *ServerConfig) UDPRelay(maxClientPackerHeadroom zerocopy.Headroom) (Relay, error) {
   432  	if len(sc.UDPListeners) == 0 {
   433  		return nil, errNetworkDisabled
   434  	}
   435  
   436  	if sc.MTU < minimumMTU {
   437  		return nil, ErrMTUTooSmall
   438  	}
   439  
   440  	var (
   441  		natServer                   zerocopy.UDPNATServer
   442  		sessionServer               zerocopy.UDPSessionServer
   443  		serverUnpackerHeadroom      zerocopy.Headroom
   444  		transparentConnListenConfig conn.ListenConfig
   445  		minNATTimeout               time.Duration
   446  		err                         error
   447  		listenerTransparent         bool
   448  	)
   449  
   450  	switch sc.Protocol {
   451  	case "direct":
   452  		natServer = direct.NewDirectUDPNATServer(sc.TunnelRemoteAddress, sc.TunnelUDPTargetOnly)
   453  
   454  	case "tproxy":
   455  		transparentConnListenConfig = sc.listenConfigCache.Get(conn.ListenerSocketOptions{
   456  			Fwmark:           sc.ListenerFwmark,
   457  			TrafficClass:     sc.ListenerTrafficClass,
   458  			Transparent:      true,
   459  			ReusePort:        true,
   460  			PathMTUDiscovery: true,
   461  		})
   462  		listenerTransparent = true
   463  
   464  	case "none", "plain":
   465  		natServer = direct.ShadowsocksNoneUDPNATServer{}
   466  
   467  	case "socks5":
   468  		natServer = direct.Socks5UDPNATServer{}
   469  
   470  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   471  		shouldPad, err := ss2022.ParsePaddingPolicy(sc.PaddingPolicy)
   472  		if err != nil {
   473  			return nil, err
   474  		}
   475  
   476  		switch {
   477  		case sc.SlidingWindowFilterSize == 0:
   478  			sc.SlidingWindowFilterSize = ss2022.DefaultSlidingWindowFilterSize
   479  		case sc.SlidingWindowFilterSize < 0:
   480  			return nil, fmt.Errorf("negative sliding window filter size: %d", sc.SlidingWindowFilterSize)
   481  		}
   482  
   483  		s := ss2022.NewUDPServer(uint64(sc.SlidingWindowFilterSize), sc.userCipherConfig, sc.identityCipherConfig, shouldPad)
   484  		sc.udpCredStore = &s.CredStore
   485  		sessionServer = s
   486  
   487  	default:
   488  		return nil, fmt.Errorf("invalid protocol: %s", sc.Protocol)
   489  	}
   490  
   491  	switch sc.Protocol {
   492  	case "direct", "none", "plain", "socks5":
   493  		serverUnpackerHeadroom = natServer.Info().UnpackerHeadroom
   494  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   495  		info := sessionServer.Info()
   496  		serverUnpackerHeadroom = info.UnpackerHeadroom
   497  		minNATTimeout = info.MinNATTimeout
   498  	}
   499  
   500  	packetBufHeadroom := zerocopy.UDPRelayHeadroom(maxClientPackerHeadroom, serverUnpackerHeadroom)
   501  	packetBufRecvSize := zerocopy.MaxPacketSizeForAddr(sc.MTU, netip.IPv4Unspecified())
   502  	packetBufSize := packetBufHeadroom.Front + packetBufRecvSize + packetBufHeadroom.Rear
   503  
   504  	listeners := make([]udpRelayServerConn, len(sc.UDPListeners))
   505  
   506  	for i := range listeners {
   507  		listeners[i], err = sc.UDPListeners[i].Configure(sc.listenConfigCache, minNATTimeout, listenerTransparent)
   508  		if err != nil {
   509  			return nil, err
   510  		}
   511  	}
   512  
   513  	switch sc.Protocol {
   514  	case "direct", "none", "plain", "socks5":
   515  		return NewUDPNATRelay(sc.Name, sc.index, sc.MTU, packetBufHeadroom.Front, packetBufRecvSize, packetBufSize, listeners, natServer, sc.collector, sc.router, sc.logger), nil
   516  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   517  		return NewUDPSessionRelay(sc.Name, sc.index, sc.MTU, packetBufHeadroom.Front, packetBufRecvSize, packetBufSize, listeners, sessionServer, sc.collector, sc.router, sc.logger), nil
   518  	case "tproxy":
   519  		return NewUDPTransparentRelay(sc.Name, sc.index, sc.MTU, packetBufHeadroom.Front, packetBufRecvSize, packetBufSize, listeners, transparentConnListenConfig, sc.collector, sc.router, sc.logger)
   520  	default:
   521  		return nil, fmt.Errorf("invalid protocol: %s", sc.Protocol)
   522  	}
   523  }
   524  
   525  // PostInit performs post-initialization tasks.
   526  func (sc *ServerConfig) PostInit(credman *cred.Manager, apiSM *v1.ServerManager) error {
   527  	var cms *cred.ManagedServer
   528  
   529  	switch sc.Protocol {
   530  	case "2022-blake3-aes-128-gcm", "2022-blake3-aes-256-gcm":
   531  		if sc.UPSKStorePath != "" {
   532  			var err error
   533  			cms, err = credman.RegisterServer(sc.Name, sc.UPSKStorePath, len(sc.PSK), sc.tcpCredStore, sc.udpCredStore)
   534  			if err != nil {
   535  				return err
   536  			}
   537  		}
   538  	}
   539  
   540  	if apiSM != nil {
   541  		apiSM.AddServer(sc.Name, cms, sc.collector)
   542  	}
   543  
   544  	return nil
   545  }