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

     1  package conn
     2  
     3  import (
     4  	"context"
     5  	"net"
     6  	"syscall"
     7  
     8  	"github.com/database64128/tfo-go/v2"
     9  )
    10  
    11  type setFunc = func(fd int, network string) error
    12  
    13  type setFuncSlice []setFunc
    14  
    15  func (fns setFuncSlice) controlContextFunc() func(ctx context.Context, network, address string, c syscall.RawConn) error {
    16  	if len(fns) == 0 {
    17  		return nil
    18  	}
    19  	return func(ctx context.Context, network, address string, c syscall.RawConn) (err error) {
    20  		if cerr := c.Control(func(fd uintptr) {
    21  			for _, fn := range fns {
    22  				if err = fn(int(fd), network); err != nil {
    23  					return
    24  				}
    25  			}
    26  		}); cerr != nil {
    27  			return cerr
    28  		}
    29  		return
    30  	}
    31  }
    32  
    33  func (fns setFuncSlice) controlFunc() func(network, address string, c syscall.RawConn) error {
    34  	if len(fns) == 0 {
    35  		return nil
    36  	}
    37  	return func(network, address string, c syscall.RawConn) (err error) {
    38  		if cerr := c.Control(func(fd uintptr) {
    39  			for _, fn := range fns {
    40  				if err = fn(int(fd), network); err != nil {
    41  					return
    42  				}
    43  			}
    44  		}); cerr != nil {
    45  			return cerr
    46  		}
    47  		return
    48  	}
    49  }
    50  
    51  // ListenerSocketOptions contains listener-specific socket options.
    52  type ListenerSocketOptions struct {
    53  	// Fwmark sets the listener's fwmark on Linux, or user cookie on FreeBSD.
    54  	//
    55  	// Available on Linux and FreeBSD.
    56  	Fwmark int
    57  
    58  	// TrafficClass sets the traffic class of the listener.
    59  	//
    60  	// Available on most platforms except Windows.
    61  	TrafficClass int
    62  
    63  	// ReusePort enables SO_REUSEPORT on the listener.
    64  	//
    65  	// Available on Linux and the BSDs.
    66  	ReusePort bool
    67  
    68  	// Transparent enables transparent proxy on the listener.
    69  	//
    70  	// Only available on Linux.
    71  	Transparent bool
    72  
    73  	// PathMTUDiscovery enables Path MTU Discovery on the listener.
    74  	//
    75  	// Available on Linux, macOS, FreeBSD, and Windows.
    76  	PathMTUDiscovery bool
    77  
    78  	// TCPFastOpen enables TCP Fast Open on the listener.
    79  	//
    80  	// Available on Linux, macOS, FreeBSD, and Windows.
    81  	TCPFastOpen bool
    82  
    83  	// ReceivePacketInfo enables the reception of packet information control messages on the listener.
    84  	//
    85  	// Available on Linux, macOS, and Windows.
    86  	ReceivePacketInfo bool
    87  
    88  	// ReceiveOriginalDestAddr enables the reception of original destination address control messages on the listener.
    89  	//
    90  	// Only available on Linux.
    91  	ReceiveOriginalDestAddr bool
    92  }
    93  
    94  // ListenConfig returns a [tfo.ListenConfig] with a control function that sets the socket options.
    95  func (lso ListenerSocketOptions) ListenConfig() tfo.ListenConfig {
    96  	return tfo.ListenConfig{
    97  		ListenConfig: net.ListenConfig{
    98  			Control: lso.buildSetFns().controlFunc(),
    99  		},
   100  		DisableTFO: !lso.TCPFastOpen,
   101  	}
   102  }
   103  
   104  var (
   105  	// DefaultTCPListenerSocketOptions is the default [ListenerSocketOptions] for TCP servers.
   106  	DefaultTCPListenerSocketOptions = ListenerSocketOptions{
   107  		TCPFastOpen: true,
   108  	}
   109  
   110  	// DefaultTCPListenConfig is the default [tfo.ListenConfig] for TCP listeners.
   111  	DefaultTCPListenConfig = DefaultTCPListenerSocketOptions.ListenConfig()
   112  
   113  	// DefaultUDPServerSocketOptions is the default [ListenerSocketOptions] for UDP servers.
   114  	DefaultUDPServerSocketOptions = ListenerSocketOptions{
   115  		PathMTUDiscovery:  true,
   116  		ReceivePacketInfo: true,
   117  	}
   118  
   119  	// DefaultUDPServerListenConfig is the default [tfo.ListenConfig] for UDP servers.
   120  	DefaultUDPServerListenConfig = DefaultUDPServerSocketOptions.ListenConfig()
   121  
   122  	// DefaultUDPClientSocketOptions is the default [ListenerSocketOptions] for UDP clients.
   123  	DefaultUDPClientSocketOptions = ListenerSocketOptions{
   124  		PathMTUDiscovery: true,
   125  	}
   126  
   127  	// DefaultUDPClientListenConfig is the default [tfo.ListenConfig] for UDP clients.
   128  	DefaultUDPClientListenConfig = DefaultUDPClientSocketOptions.ListenConfig()
   129  )
   130  
   131  // DialerSocketOptions contains dialer-specific socket options.
   132  type DialerSocketOptions struct {
   133  	// Fwmark sets the dialer's fwmark on Linux, or user cookie on FreeBSD.
   134  	//
   135  	// Available on Linux and FreeBSD.
   136  	Fwmark int
   137  
   138  	// TrafficClass sets the traffic class of the dialer.
   139  	//
   140  	// Available on most platforms except Windows.
   141  	TrafficClass int
   142  
   143  	// TCPFastOpen enables TCP Fast Open on the dialer.
   144  	//
   145  	// Available on Linux, macOS, FreeBSD, and Windows.
   146  	TCPFastOpen bool
   147  }
   148  
   149  // Dialer returns a [tfo.Dialer] with a control function that sets the socket options.
   150  func (dso DialerSocketOptions) Dialer() tfo.Dialer {
   151  	return tfo.Dialer{
   152  		Dialer: net.Dialer{
   153  			ControlContext: dso.buildSetFns().controlContextFunc(),
   154  		},
   155  		DisableTFO: !dso.TCPFastOpen,
   156  	}
   157  }
   158  
   159  var (
   160  	// DefaultTCPDialerSocketOptions is the default [DialerSocketOptions] for TCP clients.
   161  	DefaultTCPDialerSocketOptions = DialerSocketOptions{
   162  		TCPFastOpen: true,
   163  	}
   164  
   165  	// DefaultTCPDialer is the default [tfo.Dialer] for TCP clients.
   166  	DefaultTCPDialer = DefaultTCPDialerSocketOptions.Dialer()
   167  )
   168  
   169  // ListenConfigCache is a map of [ListenerSocketOptions] to [tfo.ListenConfig].
   170  type ListenConfigCache map[ListenerSocketOptions]tfo.ListenConfig
   171  
   172  // NewListenConfigCache creates a new cache for [tfo.ListenConfig] with a few default entries.
   173  func NewListenConfigCache() ListenConfigCache {
   174  	cache := make(ListenConfigCache)
   175  	cache[DefaultTCPListenerSocketOptions] = DefaultTCPListenConfig
   176  	cache[DefaultUDPServerSocketOptions] = DefaultUDPServerListenConfig
   177  	cache[DefaultUDPClientSocketOptions] = DefaultUDPClientListenConfig
   178  	return cache
   179  }
   180  
   181  // Get returns a [tfo.ListenConfig] for the given [ListenerSocketOptions].
   182  func (cache ListenConfigCache) Get(lso ListenerSocketOptions) (lc tfo.ListenConfig) {
   183  	lc, ok := cache[lso]
   184  	if ok {
   185  		return
   186  	}
   187  	lc = lso.ListenConfig()
   188  	cache[lso] = lc
   189  	return
   190  }
   191  
   192  // DialerCache is a map of [DialerSocketOptions] to [tfo.Dialer].
   193  type DialerCache map[DialerSocketOptions]tfo.Dialer
   194  
   195  // NewDialerCache creates a new cache for [tfo.Dialer] with a few default entries.
   196  func NewDialerCache() DialerCache {
   197  	cache := make(DialerCache)
   198  	cache[DefaultTCPDialerSocketOptions] = DefaultTCPDialer
   199  	return cache
   200  }
   201  
   202  // Get returns a [tfo.Dialer] for the given [DialerSocketOptions].
   203  func (cache DialerCache) Get(dso DialerSocketOptions) (d tfo.Dialer) {
   204  	d, ok := cache[dso]
   205  	if ok {
   206  		return
   207  	}
   208  	d = dso.Dialer()
   209  	cache[dso] = d
   210  	return
   211  }
   212  
   213  // ListenUDP creates a [*net.UDPConn] from the given [tfo.ListenConfig].
   214  func ListenUDP(listenConfig tfo.ListenConfig, network, address string) (*net.UDPConn, error) {
   215  	packetConn, err := listenConfig.ListenPacket(context.Background(), network, address)
   216  	if err != nil {
   217  		return nil, err
   218  	}
   219  	return packetConn.(*net.UDPConn), nil
   220  }