github.com/laof/lite-speed-test@v0.0.0-20230930011949-1f39b7037845/outbound/shadowsocks.go (about)

     1  package outbound
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"net"
     9  	"strconv"
    10  
    11  	"github.com/laof/lite-speed-test/stats"
    12  	"github.com/laof/lite-speed-test/transport/dialer"
    13  	"github.com/laof/lite-speed-test/transport/socks5"
    14  
    15  	"github.com/laof/go2/core"
    16  	"github.com/laof/lite-speed-test/common/structure"
    17  	C "github.com/laof/lite-speed-test/constant"
    18  	"github.com/laof/lite-speed-test/log"
    19  )
    20  
    21  type ShadowSocks struct {
    22  	*Base
    23  	cipher core.Cipher
    24  
    25  	// obfs
    26  	obfsMode   string
    27  	obfsOption *simpleObfsOption
    28  	// v2rayOption *v2rayObfs.Option
    29  }
    30  
    31  type ShadowSocksOption struct {
    32  	Name       string                 `proxy:"name,omitempty"`
    33  	Server     string                 `proxy:"server"`
    34  	Port       int                    `proxy:"port"`
    35  	Password   string                 `proxy:"password"`
    36  	Cipher     string                 `proxy:"cipher"`
    37  	UDP        bool                   `proxy:"udp,omitempty"`
    38  	Plugin     string                 `proxy:"plugin,omitempty"`
    39  	PluginOpts map[string]interface{} `proxy:"plugin-opts,omitempty"`
    40  	Remarks    string                 `proxy:"remarks,omitempty"`
    41  }
    42  
    43  type simpleObfsOption struct {
    44  	Mode string `obfs:"mode"`
    45  	Host string `obfs:"host,omitempty"`
    46  }
    47  
    48  type v2rayObfsOption struct {
    49  	Mode           string            `obfs:"mode"`
    50  	Host           string            `obfs:"host,omitempty"`
    51  	Path           string            `obfs:"path,omitempty"`
    52  	TLS            bool              `obfs:"tls,omitempty"`
    53  	Headers        map[string]string `obfs:"headers,omitempty"`
    54  	SkipCertVerify bool              `obfs:"skip-cert-verify,omitempty"`
    55  	Mux            bool              `obfs:"mux,omitempty"`
    56  }
    57  
    58  func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) {
    59  	// switch ss.obfsMode {
    60  	// case "tls":
    61  	// 	c = obfs.NewTLSObfs(c, ss.obfsOption.Host)
    62  	// case "http":
    63  	// 	_, port, _ := net.SplitHostPort(ss.addr)
    64  	// 	c = obfs.NewHTTPObfs(c, ss.obfsOption.Host, port)
    65  	// case "websocket":
    66  	// 	var err error
    67  	// 	c, err = v2rayObfs.NewV2rayObfs(c, ss.v2rayOption)
    68  	// 	if err != nil {
    69  	// 		return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
    70  	// 	}
    71  	// }
    72  	c = ss.cipher.StreamConn(c)
    73  	_, err := c.Write(serializesSocksAddr(metadata))
    74  	return c, err
    75  }
    76  
    77  func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (net.Conn, error) {
    78  	log.I("start dial from", ss.addr, "to", metadata.RemoteAddress())
    79  	c, err := dialer.DialContext(ctx, "tcp", ss.addr)
    80  	if err != nil {
    81  		return nil, fmt.Errorf("%s connect error: %w", ss.addr, err)
    82  	}
    83  	tcpKeepAlive(c)
    84  	log.I("start StreamConn from", ss.addr, "to", metadata.RemoteAddress())
    85  	sc := stats.NewStatsConn(c)
    86  	return ss.StreamConn(sc, metadata)
    87  }
    88  
    89  func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (net.PacketConn, error) {
    90  	pc, err := dialer.ListenPacket("udp", "")
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	addr, err := resolveUDPAddr("udp", ss.addr)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	spc := stats.NewStatsPacketConn(pc)
   101  	pc = ss.cipher.PacketConn(spc)
   102  	return &ssPacketConn{PacketConn: pc, rAddr: addr}, nil
   103  }
   104  
   105  func (ss *ShadowSocks) MarshalJSON() ([]byte, error) {
   106  	return json.Marshal(map[string]string{
   107  		"type": "shadowsocks",
   108  	})
   109  }
   110  
   111  func NewShadowSocks(option *ShadowSocksOption) (*ShadowSocks, error) {
   112  	addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port))
   113  	cipher := option.Cipher
   114  	password := option.Password
   115  	ciph, err := core.PickCipher(cipher, nil, password)
   116  	if err != nil {
   117  		return nil, fmt.Errorf("ss %s initialize error: %w", addr, err)
   118  	}
   119  
   120  	// var v2rayOption *v2rayObfs.Option
   121  	var obfsOption *simpleObfsOption
   122  	obfsMode := ""
   123  
   124  	decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true})
   125  	if option.Plugin == "obfs" {
   126  		opts := simpleObfsOption{Host: "bing.com"}
   127  		if err := decoder.Decode(option.PluginOpts, &opts); err != nil {
   128  			return nil, fmt.Errorf("ss %s initialize obfs error: %w", addr, err)
   129  		}
   130  
   131  		if opts.Mode != "tls" && opts.Mode != "http" {
   132  			return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode)
   133  		}
   134  		obfsMode = opts.Mode
   135  		obfsOption = &opts
   136  	} else if option.Plugin == "v2ray-plugin" {
   137  		opts := v2rayObfsOption{Host: "bing.com", Mux: true}
   138  		if err := decoder.Decode(option.PluginOpts, &opts); err != nil {
   139  			return nil, fmt.Errorf("ss %s initialize v2ray-plugin error: %w", addr, err)
   140  		}
   141  
   142  		if opts.Mode != "websocket" {
   143  			return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode)
   144  		}
   145  		obfsMode = opts.Mode
   146  		// v2rayOption = &v2rayObfs.Option{
   147  		// 	Host:    opts.Host,
   148  		// 	Path:    opts.Path,
   149  		// 	Headers: opts.Headers,
   150  		// 	Mux:     opts.Mux,
   151  		// }
   152  
   153  		// if opts.TLS {
   154  		// 	v2rayOption.TLS = true
   155  		// 	v2rayOption.SkipCertVerify = opts.SkipCertVerify
   156  		// 	v2rayOption.SessionCache = getClientSessionCache()
   157  		// }
   158  	}
   159  
   160  	return &ShadowSocks{
   161  		Base: &Base{
   162  			name: option.Name,
   163  			addr: addr,
   164  			udp:  option.UDP,
   165  		},
   166  		cipher: ciph,
   167  
   168  		obfsMode: obfsMode,
   169  		// v2rayOption: v2rayOption,
   170  		obfsOption: obfsOption,
   171  	}, nil
   172  }
   173  
   174  type ssPacketConn struct {
   175  	net.PacketConn
   176  	rAddr net.Addr
   177  }
   178  
   179  func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
   180  	packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
   181  	if err != nil {
   182  		return
   183  	}
   184  	return spc.PacketConn.WriteTo(packet[3:], spc.rAddr)
   185  }
   186  
   187  func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) {
   188  	n, _, e := spc.PacketConn.ReadFrom(b)
   189  	if e != nil {
   190  		return 0, nil, e
   191  	}
   192  
   193  	addr := socks5.SplitAddr(b[:n])
   194  	if addr == nil {
   195  		return 0, nil, errors.New("parse addr error")
   196  	}
   197  
   198  	udpAddr := addr.UDPAddr()
   199  	if udpAddr == nil {
   200  		return 0, nil, errors.New("parse addr error")
   201  	}
   202  
   203  	copy(b, b[len(addr):])
   204  	return n - len(addr), udpAddr, e
   205  }