github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/proxy/shadowsocks/protocol_test.go (about)

     1  package shadowsocks_test
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/google/go-cmp/cmp"
     7  	"github.com/xtls/xray-core/common"
     8  	"github.com/xtls/xray-core/common/buf"
     9  	"github.com/xtls/xray-core/common/net"
    10  	"github.com/xtls/xray-core/common/protocol"
    11  	. "github.com/xtls/xray-core/proxy/shadowsocks"
    12  )
    13  
    14  func toAccount(a *Account) protocol.Account {
    15  	account, err := a.AsAccount()
    16  	common.Must(err)
    17  	return account
    18  }
    19  
    20  func equalRequestHeader(x, y *protocol.RequestHeader) bool {
    21  	return cmp.Equal(x, y, cmp.Comparer(func(x, y protocol.RequestHeader) bool {
    22  		return x == y
    23  	}))
    24  }
    25  
    26  func TestUDPEncodingDecoding(t *testing.T) {
    27  	testRequests := []protocol.RequestHeader{
    28  		{
    29  			Version: Version,
    30  			Command: protocol.RequestCommandUDP,
    31  			Address: net.LocalHostIP,
    32  			Port:    1234,
    33  			User: &protocol.MemoryUser{
    34  				Email: "love@example.com",
    35  				Account: toAccount(&Account{
    36  					Password:   "password",
    37  					CipherType: CipherType_AES_128_GCM,
    38  				}),
    39  			},
    40  		},
    41  		{
    42  			Version: Version,
    43  			Command: protocol.RequestCommandUDP,
    44  			Address: net.LocalHostIP,
    45  			Port:    1234,
    46  			User: &protocol.MemoryUser{
    47  				Email: "love@example.com",
    48  				Account: toAccount(&Account{
    49  					Password:   "123",
    50  					CipherType: CipherType_NONE,
    51  				}),
    52  			},
    53  		},
    54  	}
    55  
    56  	for _, request := range testRequests {
    57  		data := buf.New()
    58  		common.Must2(data.WriteString("test string"))
    59  		encodedData, err := EncodeUDPPacket(&request, data.Bytes())
    60  		common.Must(err)
    61  
    62  		validator := new(Validator)
    63  		validator.Add(request.User)
    64  		decodedRequest, decodedData, err := DecodeUDPPacket(validator, encodedData)
    65  		common.Must(err)
    66  
    67  		if r := cmp.Diff(decodedData.Bytes(), data.Bytes()); r != "" {
    68  			t.Error("data: ", r)
    69  		}
    70  
    71  		if equalRequestHeader(decodedRequest, &request) == false {
    72  			t.Error("different request")
    73  		}
    74  	}
    75  }
    76  
    77  func TestUDPDecodingWithPayloadTooShort(t *testing.T) {
    78  	testAccounts := []protocol.Account{
    79  		toAccount(&Account{
    80  			Password:   "password",
    81  			CipherType: CipherType_AES_128_GCM,
    82  		}),
    83  		toAccount(&Account{
    84  			Password:   "password",
    85  			CipherType: CipherType_NONE,
    86  		}),
    87  	}
    88  
    89  	for _, account := range testAccounts {
    90  		data := buf.New()
    91  		data.WriteString("short payload")
    92  		validator := new(Validator)
    93  		validator.Add(&protocol.MemoryUser{
    94  			Account: account,
    95  		})
    96  		_, _, err := DecodeUDPPacket(validator, data)
    97  		if err == nil {
    98  			t.Fatal("expected error")
    99  		}
   100  	}
   101  }
   102  
   103  func TestTCPRequest(t *testing.T) {
   104  	cases := []struct {
   105  		request *protocol.RequestHeader
   106  		payload []byte
   107  	}{
   108  		{
   109  			request: &protocol.RequestHeader{
   110  				Version: Version,
   111  				Command: protocol.RequestCommandTCP,
   112  				Address: net.LocalHostIP,
   113  				Port:    1234,
   114  				User: &protocol.MemoryUser{
   115  					Email: "love@example.com",
   116  					Account: toAccount(&Account{
   117  						Password:   "tcp-password",
   118  						CipherType: CipherType_AES_128_GCM,
   119  					}),
   120  				},
   121  			},
   122  			payload: []byte("test string"),
   123  		},
   124  		{
   125  			request: &protocol.RequestHeader{
   126  				Version: Version,
   127  				Command: protocol.RequestCommandTCP,
   128  				Address: net.LocalHostIPv6,
   129  				Port:    1234,
   130  				User: &protocol.MemoryUser{
   131  					Email: "love@example.com",
   132  					Account: toAccount(&Account{
   133  						Password:   "password",
   134  						CipherType: CipherType_AES_256_GCM,
   135  					}),
   136  				},
   137  			},
   138  			payload: []byte("test string"),
   139  		},
   140  		{
   141  			request: &protocol.RequestHeader{
   142  				Version: Version,
   143  				Command: protocol.RequestCommandTCP,
   144  				Address: net.DomainAddress("example.com"),
   145  				Port:    1234,
   146  				User: &protocol.MemoryUser{
   147  					Email: "love@example.com",
   148  					Account: toAccount(&Account{
   149  						Password:   "password",
   150  						CipherType: CipherType_CHACHA20_POLY1305,
   151  					}),
   152  				},
   153  			},
   154  			payload: []byte("test string"),
   155  		},
   156  	}
   157  
   158  	runTest := func(request *protocol.RequestHeader, payload []byte) {
   159  		data := buf.New()
   160  		common.Must2(data.Write(payload))
   161  
   162  		cache := buf.New()
   163  		defer cache.Release()
   164  
   165  		writer, err := WriteTCPRequest(request, cache)
   166  		common.Must(err)
   167  
   168  		common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{data}))
   169  
   170  		validator := new(Validator)
   171  		validator.Add(request.User)
   172  		decodedRequest, reader, err := ReadTCPSession(validator, cache)
   173  		common.Must(err)
   174  		if equalRequestHeader(decodedRequest, request) == false {
   175  			t.Error("different request")
   176  		}
   177  
   178  		decodedData, err := reader.ReadMultiBuffer()
   179  		common.Must(err)
   180  		if r := cmp.Diff(decodedData[0].Bytes(), payload); r != "" {
   181  			t.Error("data: ", r)
   182  		}
   183  	}
   184  
   185  	for _, test := range cases {
   186  		runTest(test.request, test.payload)
   187  	}
   188  }
   189  
   190  func TestUDPReaderWriter(t *testing.T) {
   191  	user := &protocol.MemoryUser{
   192  		Account: toAccount(&Account{
   193  			Password:   "test-password",
   194  			CipherType: CipherType_CHACHA20_POLY1305,
   195  		}),
   196  	}
   197  	cache := buf.New()
   198  	defer cache.Release()
   199  
   200  	writer := &UDPWriter{
   201  		Writer: cache,
   202  		Request: &protocol.RequestHeader{
   203  			Version: Version,
   204  			Address: net.DomainAddress("example.com"),
   205  			Port:    123,
   206  			User:    user,
   207  		},
   208  	}
   209  
   210  	reader := &UDPReader{
   211  		Reader: cache,
   212  		User:   user,
   213  	}
   214  
   215  	{
   216  		b := buf.New()
   217  		common.Must2(b.WriteString("test payload"))
   218  		common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))
   219  
   220  		payload, err := reader.ReadMultiBuffer()
   221  		common.Must(err)
   222  		if payload[0].String() != "test payload" {
   223  			t.Error("unexpected output: ", payload[0].String())
   224  		}
   225  	}
   226  
   227  	{
   228  		b := buf.New()
   229  		common.Must2(b.WriteString("test payload 2"))
   230  		common.Must(writer.WriteMultiBuffer(buf.MultiBuffer{b}))
   231  
   232  		payload, err := reader.ReadMultiBuffer()
   233  		common.Must(err)
   234  		if payload[0].String() != "test payload 2" {
   235  			t.Error("unexpected output: ", payload[0].String())
   236  		}
   237  	}
   238  }