github.com/metacubex/sing-shadowsocks@v0.2.6/shadowaead_2022/relay.go (about)

     1  package shadowaead_2022
     2  
     3  import (
     4  	"context"
     5  	"crypto/aes"
     6  	"crypto/cipher"
     7  	"encoding/base64"
     8  	"encoding/binary"
     9  	"net"
    10  	"os"
    11  
    12  	"github.com/metacubex/sing-shadowsocks"
    13  	"github.com/metacubex/sing-shadowsocks/shadowaead"
    14  	"github.com/sagernet/sing/common/auth"
    15  	"github.com/sagernet/sing/common/buf"
    16  	"github.com/sagernet/sing/common/bufio"
    17  	E "github.com/sagernet/sing/common/exceptions"
    18  	M "github.com/sagernet/sing/common/metadata"
    19  	N "github.com/sagernet/sing/common/network"
    20  	"github.com/sagernet/sing/common/udpnat"
    21  
    22  	"lukechampine.com/blake3"
    23  )
    24  
    25  var _ shadowsocks.Service = (*RelayService[int])(nil)
    26  
    27  type RelayService[U comparable] struct {
    28  	name          string
    29  	keySaltLength int
    30  	handler       shadowsocks.Handler
    31  
    32  	constructor      func(key []byte) (cipher.AEAD, error)
    33  	blockConstructor func(key []byte) (cipher.Block, error)
    34  	udpBlockCipher   cipher.Block
    35  
    36  	iPSK         []byte
    37  	uPSKHash     map[[aes.BlockSize]byte]U
    38  	uDestination map[U]M.Socksaddr
    39  	uCipher      map[U]cipher.Block
    40  	udpNat       *udpnat.Service[uint64]
    41  }
    42  
    43  func (s *RelayService[U]) Name() string {
    44  	return s.name
    45  }
    46  
    47  func (s *RelayService[U]) Password() string {
    48  	return base64.StdEncoding.EncodeToString(s.iPSK)
    49  }
    50  
    51  func (s *RelayService[U]) UpdateUsers(userList []U, keyList [][]byte, destinationList []M.Socksaddr) error {
    52  	uPSKHash := make(map[[aes.BlockSize]byte]U)
    53  	uDestination := make(map[U]M.Socksaddr)
    54  	uCipher := make(map[U]cipher.Block)
    55  	for i, user := range userList {
    56  		key := keyList[i]
    57  		destination := destinationList[i]
    58  		if len(key) < s.keySaltLength {
    59  			return shadowsocks.ErrBadKey
    60  		} else if len(key) > s.keySaltLength {
    61  			key = Key(key, s.keySaltLength)
    62  		}
    63  
    64  		var hash [aes.BlockSize]byte
    65  		hash512 := blake3.Sum512(key)
    66  		copy(hash[:], hash512[:])
    67  
    68  		uPSKHash[hash] = user
    69  		uDestination[user] = destination
    70  		var err error
    71  		uCipher[user], err = s.blockConstructor(key)
    72  		if err != nil {
    73  			return err
    74  		}
    75  	}
    76  
    77  	s.uPSKHash = uPSKHash
    78  	s.uDestination = uDestination
    79  	s.uCipher = uCipher
    80  	return nil
    81  }
    82  
    83  func (s *RelayService[U]) UpdateUsersWithPasswords(userList []U, passwordList []string, destinationList []M.Socksaddr) error {
    84  	keyList := make([][]byte, 0, len(passwordList))
    85  	for _, password := range passwordList {
    86  		if password == "" {
    87  			return shadowsocks.ErrMissingPassword
    88  		}
    89  		uPSK, err := base64.StdEncoding.DecodeString(password)
    90  		if err != nil {
    91  			return E.Cause(err, "decode psk")
    92  		}
    93  		keyList = append(keyList, uPSK)
    94  	}
    95  	return s.UpdateUsers(userList, keyList, destinationList)
    96  }
    97  
    98  func NewRelayServiceWithPassword[U comparable](method string, password string, udpTimeout int64, handler shadowsocks.Handler) (*RelayService[U], error) {
    99  	if password == "" {
   100  		return nil, ErrMissingPSK
   101  	}
   102  	iPSK, err := base64.StdEncoding.DecodeString(password)
   103  	if err != nil {
   104  		return nil, E.Cause(err, "decode psk")
   105  	}
   106  	return NewRelayService[U](method, iPSK, udpTimeout, handler)
   107  }
   108  
   109  func NewRelayService[U comparable](method string, psk []byte, udpTimeout int64, handler shadowsocks.Handler) (*RelayService[U], error) {
   110  	s := &RelayService[U]{
   111  		name:    method,
   112  		handler: handler,
   113  
   114  		uPSKHash:     make(map[[aes.BlockSize]byte]U),
   115  		uDestination: make(map[U]M.Socksaddr),
   116  		uCipher:      make(map[U]cipher.Block),
   117  
   118  		udpNat: udpnat.New[uint64](udpTimeout, handler),
   119  	}
   120  
   121  	switch method {
   122  	case "2022-blake3-aes-128-gcm":
   123  		s.keySaltLength = 16
   124  		s.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM)
   125  		s.blockConstructor = aes.NewCipher
   126  	case "2022-blake3-aes-256-gcm":
   127  		s.keySaltLength = 32
   128  		s.constructor = aeadCipher(aes.NewCipher, cipher.NewGCM)
   129  		s.blockConstructor = aes.NewCipher
   130  	default:
   131  		return nil, os.ErrInvalid
   132  	}
   133  	if len(psk) != s.keySaltLength {
   134  		if len(psk) < s.keySaltLength {
   135  			return nil, shadowsocks.ErrBadKey
   136  		} else {
   137  			psk = Key(psk, s.keySaltLength)
   138  		}
   139  	}
   140  	s.iPSK = psk
   141  	var err error
   142  	s.udpBlockCipher, err = s.blockConstructor(psk)
   143  	return s, err
   144  }
   145  
   146  func (s *RelayService[U]) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
   147  	err := s.newConnection(ctx, conn, metadata)
   148  	if err != nil {
   149  		err = &shadowsocks.ServerConnError{Conn: conn, Source: metadata.Source, Cause: err}
   150  	}
   151  	return err
   152  }
   153  
   154  func (s *RelayService[U]) newConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error {
   155  	requestHeader := buf.New()
   156  	defer requestHeader.Release()
   157  	n, err := requestHeader.ReadOnceFrom(conn)
   158  	if err != nil {
   159  		return err
   160  	} else if int(n) < s.keySaltLength+aes.BlockSize {
   161  		return shadowaead.ErrBadHeader
   162  	}
   163  	requestSalt := requestHeader.To(s.keySaltLength)
   164  	var _eiHeader [aes.BlockSize]byte
   165  	eiHeader := _eiHeader[:]
   166  	copy(eiHeader, requestHeader.Range(s.keySaltLength, s.keySaltLength+aes.BlockSize))
   167  
   168  	keyMaterial := make([]byte, s.keySaltLength*2)
   169  	copy(keyMaterial, s.iPSK)
   170  	copy(keyMaterial[s.keySaltLength:], requestSalt)
   171  	identitySubkey := buf.NewSize(s.keySaltLength)
   172  	identitySubkey.Extend(identitySubkey.FreeLen())
   173  	blake3.DeriveKey(identitySubkey.Bytes(), "shadowsocks 2022 identity subkey", keyMaterial)
   174  	b, err := s.blockConstructor(identitySubkey.Bytes())
   175  	identitySubkey.Release()
   176  	if err != nil {
   177  		return err
   178  	}
   179  	b.Decrypt(eiHeader, eiHeader)
   180  
   181  	var user U
   182  	if u, loaded := s.uPSKHash[_eiHeader]; loaded {
   183  		user = u
   184  	} else {
   185  		return E.New("invalid request")
   186  	}
   187  
   188  	copy(requestHeader.Range(aes.BlockSize, aes.BlockSize+s.keySaltLength), requestHeader.To(s.keySaltLength))
   189  	requestHeader.Advance(aes.BlockSize)
   190  
   191  	metadata.Protocol = "shadowsocks-relay"
   192  	metadata.Destination = s.uDestination[user]
   193  	conn = bufio.NewCachedConn(conn, requestHeader)
   194  	return s.handler.NewConnection(auth.ContextWithUser(ctx, user), conn, metadata)
   195  }
   196  
   197  func (s *RelayService[U]) WriteIsThreadUnsafe() {
   198  }
   199  
   200  func (s *RelayService[U]) NewPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata M.Metadata) error {
   201  	err := s.newPacket(ctx, conn, buffer, metadata)
   202  	if err != nil {
   203  		err = &shadowsocks.ServerPacketError{Source: metadata.Source, Cause: err}
   204  	}
   205  	return err
   206  }
   207  
   208  func (s *RelayService[U]) newPacket(ctx context.Context, conn N.PacketConn, buffer *buf.Buffer, metadata M.Metadata) error {
   209  	packetHeader := buffer.To(aes.BlockSize)
   210  	s.udpBlockCipher.Decrypt(packetHeader, packetHeader)
   211  
   212  	sessionId := binary.BigEndian.Uint64(packetHeader)
   213  
   214  	var _eiHeader [aes.BlockSize]byte
   215  	eiHeader := _eiHeader[:]
   216  	s.udpBlockCipher.Decrypt(eiHeader, buffer.Range(aes.BlockSize, 2*aes.BlockSize))
   217  	xorWords(eiHeader, eiHeader, packetHeader)
   218  
   219  	var user U
   220  	if u, loaded := s.uPSKHash[_eiHeader]; loaded {
   221  		user = u
   222  	} else {
   223  		return E.New("invalid request")
   224  	}
   225  
   226  	s.uCipher[user].Encrypt(packetHeader, packetHeader)
   227  	copy(buffer.Range(aes.BlockSize, 2*aes.BlockSize), packetHeader)
   228  	buffer.Advance(aes.BlockSize)
   229  
   230  	metadata.Protocol = "shadowsocks-relay"
   231  	metadata.Destination = s.uDestination[user]
   232  	s.udpNat.NewContextPacket(ctx, sessionId, buffer, metadata, func(natConn N.PacketConn) (context.Context, N.PacketWriter) {
   233  		return auth.ContextWithUser(ctx, user), &udpnat.DirectBackWriter{Source: conn, Nat: natConn}
   234  	})
   235  	return nil
   236  }
   237  
   238  func (s *RelayService[U]) NewError(ctx context.Context, err error) {
   239  	s.handler.NewError(ctx, err)
   240  }