123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- package main
- import (
- "context"
- "net"
- "net/http"
- "net/netip"
- "testing"
- C "github.com/sagernet/sing-box/constant"
- "github.com/sagernet/sing-box/option"
- "github.com/sagernet/sing-shadowsocks/shadowaead_2022"
- "github.com/sagernet/sing/common"
- F "github.com/sagernet/sing/common/format"
- "github.com/sagernet/sing/common/json/badoption"
- "github.com/stretchr/testify/require"
- )
- func TestShadowTLS(t *testing.T) {
- t.Run("v1", func(t *testing.T) {
- testShadowTLS(t, 1, "", false)
- })
- t.Run("v2", func(t *testing.T) {
- testShadowTLS(t, 2, "hello", false)
- })
- t.Run("v3", func(t *testing.T) {
- testShadowTLS(t, 3, "hello", false)
- })
- t.Run("v2-utls", func(t *testing.T) {
- testShadowTLS(t, 2, "hello", true)
- })
- t.Run("v3-utls", func(t *testing.T) {
- testShadowTLS(t, 3, "hello", true)
- })
- }
- func testShadowTLS(t *testing.T, version int, password string, utlsEanbled bool) {
- method := shadowaead_2022.List[0]
- ssPassword := mkBase64(t, 16)
- startInstance(t, option.Options{
- Inbounds: []option.Inbound{
- {
- Type: C.TypeMixed,
- Options: &option.HTTPMixedInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: clientPort,
- },
- },
- },
- {
- Type: C.TypeShadowTLS,
- Tag: "in",
- Options: &option.ShadowTLSInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: serverPort,
- InboundOptions: option.InboundOptions{
- Detour: "detour",
- },
- },
- Handshake: option.ShadowTLSHandshakeOptions{
- ServerOptions: option.ServerOptions{
- Server: "google.com",
- ServerPort: 443,
- },
- },
- Version: version,
- Password: password,
- Users: []option.ShadowTLSUser{{Password: password}},
- },
- },
- {
- Type: C.TypeShadowsocks,
- Tag: "detour",
- Options: &option.ShadowsocksInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: otherPort,
- },
- Method: method,
- Password: ssPassword,
- },
- },
- },
- Outbounds: []option.Outbound{
- {
- Type: C.TypeShadowsocks,
- Options: &option.ShadowsocksOutboundOptions{
- Method: method,
- Password: ssPassword,
- DialerOptions: option.DialerOptions{
- Detour: "detour",
- },
- },
- },
- {
- Type: C.TypeShadowTLS,
- Tag: "detour",
- Options: &option.ShadowTLSOutboundOptions{
- ServerOptions: option.ServerOptions{
- Server: "127.0.0.1",
- ServerPort: serverPort,
- },
- OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
- TLS: &option.OutboundTLSOptions{
- Enabled: true,
- ServerName: "google.com",
- UTLS: &option.OutboundUTLSOptions{
- Enabled: utlsEanbled,
- },
- },
- },
- Version: version,
- Password: password,
- },
- },
- {
- Type: C.TypeDirect,
- Tag: "direct",
- },
- },
- Route: &option.RouteOptions{
- Rules: []option.Rule{
- {
- Type: C.RuleTypeDefault,
- DefaultOptions: option.DefaultRule{
- RawDefaultRule: option.RawDefaultRule{
- Inbound: []string{"detour"},
- },
- RuleAction: option.RuleAction{
- Action: C.RuleActionTypeRoute,
- RouteOptions: option.RouteActionOptions{
- Outbound: "direct",
- },
- },
- },
- },
- },
- },
- })
- testTCP(t, clientPort, testPort)
- }
- func TestShadowTLSFallback(t *testing.T) {
- startInstance(t, option.Options{
- Inbounds: []option.Inbound{
- {
- Type: C.TypeShadowTLS,
- Options: &option.ShadowTLSInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: serverPort,
- },
- Handshake: option.ShadowTLSHandshakeOptions{
- ServerOptions: option.ServerOptions{
- Server: "google.com",
- ServerPort: 443,
- },
- },
- Version: 3,
- Users: []option.ShadowTLSUser{
- {Password: "hello"},
- },
- },
- },
- },
- })
- client := &http.Client{
- Transport: &http.Transport{
- DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
- var d net.Dialer
- return d.DialContext(ctx, network, "127.0.0.1:"+F.ToString(serverPort))
- },
- },
- }
- response, err := client.Get("https://google.com")
- require.NoError(t, err)
- require.Equal(t, response.StatusCode, 200)
- response.Body.Close()
- client.CloseIdleConnections()
- }
- func TestShadowTLSInbound(t *testing.T) {
- method := shadowaead_2022.List[0]
- password := mkBase64(t, 16)
- startDockerContainer(t, DockerOptions{
- Image: ImageShadowTLS,
- Ports: []uint16{serverPort, otherPort},
- EntryPoint: "shadow-tls",
- Cmd: []string{"--v3", "--threads", "1", "client", "--listen", "0.0.0.0:" + F.ToString(otherPort), "--server", "127.0.0.1:" + F.ToString(serverPort), "--sni", "google.com", "--password", password},
- })
- startInstance(t, option.Options{
- Inbounds: []option.Inbound{
- {
- Type: C.TypeMixed,
- Tag: "in",
- Options: &option.HTTPMixedInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: clientPort,
- },
- },
- },
- {
- Type: C.TypeShadowTLS,
- Options: &option.ShadowTLSInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: serverPort,
- InboundOptions: option.InboundOptions{
- Detour: "detour",
- },
- },
- Handshake: option.ShadowTLSHandshakeOptions{
- ServerOptions: option.ServerOptions{
- Server: "google.com",
- ServerPort: 443,
- },
- },
- Version: 3,
- Users: []option.ShadowTLSUser{
- {Password: password},
- },
- },
- },
- {
- Type: C.TypeShadowsocks,
- Tag: "detour",
- Options: &option.ShadowsocksInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- },
- Method: method,
- Password: password,
- },
- },
- },
- Outbounds: []option.Outbound{
- {
- Type: C.TypeDirect,
- },
- {
- Type: C.TypeShadowsocks,
- Tag: "out",
- Options: &option.ShadowsocksOutboundOptions{
- ServerOptions: option.ServerOptions{
- Server: "127.0.0.1",
- ServerPort: otherPort,
- },
- Method: method,
- Password: password,
- },
- },
- },
- Route: &option.RouteOptions{
- Rules: []option.Rule{
- {
- Type: C.RuleTypeDefault,
- DefaultOptions: option.DefaultRule{
- RawDefaultRule: option.RawDefaultRule{
- Inbound: []string{"in"},
- },
- RuleAction: option.RuleAction{
- Action: C.RuleActionTypeRoute,
- RouteOptions: option.RouteActionOptions{
- Outbound: "out",
- },
- },
- },
- },
- },
- },
- })
- testTCP(t, clientPort, testPort)
- }
- func TestShadowTLSOutbound(t *testing.T) {
- method := shadowaead_2022.List[0]
- password := mkBase64(t, 16)
- startDockerContainer(t, DockerOptions{
- Image: ImageShadowTLS,
- Ports: []uint16{serverPort, otherPort},
- EntryPoint: "shadow-tls",
- Cmd: []string{"--v3", "--threads", "1", "server", "--listen", "0.0.0.0:" + F.ToString(serverPort), "--server", "127.0.0.1:" + F.ToString(otherPort), "--tls", "google.com:443", "--password", "hello"},
- Env: []string{"RUST_LOG=trace"},
- })
- startInstance(t, option.Options{
- Inbounds: []option.Inbound{
- {
- Type: C.TypeMixed,
- Options: &option.HTTPMixedInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: clientPort,
- },
- },
- },
- {
- Type: C.TypeShadowsocks,
- Tag: "detour",
- Options: &option.ShadowsocksInboundOptions{
- ListenOptions: option.ListenOptions{
- Listen: common.Ptr(badoption.Addr(netip.IPv4Unspecified())),
- ListenPort: otherPort,
- },
- Method: method,
- Password: password,
- },
- },
- },
- Outbounds: []option.Outbound{
- {
- Type: C.TypeShadowsocks,
- Options: &option.ShadowsocksOutboundOptions{
- Method: method,
- Password: password,
- DialerOptions: option.DialerOptions{
- Detour: "detour",
- },
- },
- },
- {
- Type: C.TypeShadowTLS,
- Tag: "detour",
- Options: &option.ShadowTLSOutboundOptions{
- ServerOptions: option.ServerOptions{
- Server: "127.0.0.1",
- ServerPort: serverPort,
- },
- OutboundTLSOptionsContainer: option.OutboundTLSOptionsContainer{
- TLS: &option.OutboundTLSOptions{
- Enabled: true,
- ServerName: "google.com",
- },
- },
- Version: 3,
- Password: "hello",
- },
- },
- {
- Type: C.TypeDirect,
- Tag: "direct",
- },
- },
- Route: &option.RouteOptions{
- Rules: []option.Rule{
- {
- Type: C.RuleTypeDefault,
- DefaultOptions: option.DefaultRule{
- RawDefaultRule: option.RawDefaultRule{
- Inbound: []string{"detour"},
- },
- RuleAction: option.RuleAction{
- Action: C.RuleActionTypeRoute,
- RouteOptions: option.RouteActionOptions{
- Outbound: "direct",
- },
- },
- },
- },
- },
- },
- })
- testTCP(t, clientPort, testPort)
- }
|