github.com/yaling888/clash@v1.53.0/adapter/outbound/shadowsocks.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "strconv" 9 10 "github.com/yaling888/clash/common/structure" 11 "github.com/yaling888/clash/component/dialer" 12 C "github.com/yaling888/clash/constant" 13 "github.com/yaling888/clash/transport/shadowsocks/core" 14 obfs "github.com/yaling888/clash/transport/simple-obfs" 15 "github.com/yaling888/clash/transport/socks5" 16 v2rayObfs "github.com/yaling888/clash/transport/v2ray-plugin" 17 ) 18 19 var _ C.ProxyAdapter = (*ShadowSocks)(nil) 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 BasicOption 33 Name string `proxy:"name"` 34 Server string `proxy:"server"` 35 Port int `proxy:"port"` 36 Password string `proxy:"password"` 37 Cipher string `proxy:"cipher"` 38 UDP bool `proxy:"udp,omitempty"` 39 Plugin string `proxy:"plugin,omitempty"` 40 PluginOpts map[string]any `proxy:"plugin-opts,omitempty"` 41 RandomHost bool `proxy:"rand-host,omitempty"` 42 RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"` 43 } 44 45 type simpleObfsOption struct { 46 Mode string `obfs:"mode,omitempty"` 47 Host string `obfs:"host,omitempty"` 48 RandomHost bool `obfs:"rand-host,omitempty"` 49 } 50 51 type v2rayObfsOption struct { 52 Mode string `obfs:"mode"` 53 Host string `obfs:"host,omitempty"` 54 Path string `obfs:"path,omitempty"` 55 TLS bool `obfs:"tls,omitempty"` 56 Headers map[string]string `obfs:"headers,omitempty"` 57 SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` 58 Mux bool `obfs:"mux,omitempty"` 59 } 60 61 // StreamConn implements C.ProxyAdapter 62 func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { 63 switch ss.obfsMode { 64 case "tls": 65 c = obfs.NewTLSObfs(c, ss.obfsOption.Host) 66 case "http": 67 _, port, _ := net.SplitHostPort(ss.addr) 68 c = obfs.NewHTTPObfs(c, ss.obfsOption.Host, port, ss.obfsOption.RandomHost) 69 case "websocket": 70 var err error 71 c, err = v2rayObfs.NewV2rayObfs(c, ss.v2rayOption) 72 if err != nil { 73 return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) 74 } 75 } 76 c = ss.cipher.StreamConn(c) 77 _, err := c.Write(serializesSocksAddr(metadata)) 78 return c, err 79 } 80 81 // StreamPacketConn implements C.ProxyAdapter 82 func (ss *ShadowSocks) StreamPacketConn(c net.Conn, _ *C.Metadata) (net.Conn, error) { 83 if !IsPacketConn(c) { 84 return c, fmt.Errorf("%s connect error: can not convert net.Conn to net.PacketConn", ss.addr) 85 } 86 87 addr, err := resolveUDPAddr("udp", ss.addr) 88 if err != nil { 89 return c, err 90 } 91 92 pc := ss.cipher.PacketConn(c.(net.PacketConn)) 93 return WrapConn(&ssPacketConn{PacketConn: pc, rAddr: addr}), nil 94 } 95 96 // DialContext implements C.ProxyAdapter 97 func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 98 c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) 99 if err != nil { 100 return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) 101 } 102 tcpKeepAlive(c) 103 104 defer func(cc net.Conn, e error) { 105 safeConnClose(cc, e) 106 }(c, err) 107 108 c, err = ss.StreamConn(c, metadata) 109 return NewConn(c, ss), err 110 } 111 112 // ListenPacketContext implements C.ProxyAdapter 113 func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { 114 pc, err := dialer.ListenPacket(ctx, "udp", "", ss.Base.DialOptions(opts...)...) 115 if err != nil { 116 return nil, err 117 } 118 119 c, err := ss.StreamPacketConn(WrapConn(pc), metadata) 120 if err != nil { 121 _ = pc.Close() 122 return nil, err 123 } 124 125 return NewPacketConn(c.(net.PacketConn), ss), nil 126 } 127 128 func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { 129 addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) 130 cipher := option.Cipher 131 password := option.Password 132 ciph, err := core.PickCipher(cipher, nil, password) 133 if err != nil { 134 return nil, fmt.Errorf("ss %s initialize error: %w", addr, err) 135 } 136 137 var v2rayOption *v2rayObfs.Option 138 var obfsOption *simpleObfsOption 139 obfsMode := "" 140 141 decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true}) 142 if option.Plugin == "obfs" { 143 opts := simpleObfsOption{Host: "bing.com", RandomHost: option.RandomHost} 144 if err := decoder.Decode(option.PluginOpts, &opts); err != nil { 145 return nil, fmt.Errorf("ss %s initialize obfs error: %w", addr, err) 146 } 147 148 if opts.Mode != "tls" && opts.Mode != "http" { 149 return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode) 150 } 151 obfsMode = opts.Mode 152 obfsOption = &opts 153 } else if option.Plugin == "v2ray-plugin" { 154 opts := v2rayObfsOption{Host: "bing.com", Mux: true} 155 if err := decoder.Decode(option.PluginOpts, &opts); err != nil { 156 return nil, fmt.Errorf("ss %s initialize v2ray-plugin error: %w", addr, err) 157 } 158 159 if opts.Mode != "websocket" { 160 return nil, fmt.Errorf("ss %s obfs mode error: %s", addr, opts.Mode) 161 } 162 obfsMode = opts.Mode 163 v2rayOption = &v2rayObfs.Option{ 164 Host: opts.Host, 165 Path: opts.Path, 166 Headers: opts.Headers, 167 Mux: opts.Mux, 168 RandomHost: option.RandomHost, 169 } 170 171 if opts.TLS { 172 v2rayOption.TLS = true 173 v2rayOption.SkipCertVerify = opts.SkipCertVerify 174 } 175 } 176 177 return &ShadowSocks{ 178 Base: &Base{ 179 name: option.Name, 180 addr: addr, 181 tp: C.Shadowsocks, 182 udp: option.UDP, 183 iface: option.Interface, 184 rmark: option.RoutingMark, 185 dns: option.RemoteDnsResolve, 186 }, 187 cipher: ciph, 188 189 obfsMode: obfsMode, 190 v2rayOption: v2rayOption, 191 obfsOption: obfsOption, 192 }, nil 193 } 194 195 type ssPacketConn struct { 196 net.PacketConn 197 rAddr net.Addr 198 } 199 200 func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { 201 packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) 202 if err != nil { 203 return 204 } 205 return spc.PacketConn.WriteTo(packet[3:], spc.rAddr) 206 } 207 208 func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 209 n, _, e := spc.PacketConn.ReadFrom(b) 210 if e != nil { 211 return 0, nil, e 212 } 213 214 addr := socks5.SplitAddr(b[:n]) 215 if addr == nil { 216 return 0, nil, errors.New("parse addr error") 217 } 218 219 udpAddr := addr.UDPAddr() 220 if udpAddr == nil { 221 return 0, nil, errors.New("parse addr error") 222 } 223 224 copy(b, b[len(addr):]) 225 return n - len(addr), udpAddr, e 226 }