github.com/metacubex/mihomo@v1.18.5/adapter/outbound/shadowsocksr.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "strconv" 9 10 N "github.com/metacubex/mihomo/common/net" 11 "github.com/metacubex/mihomo/component/dialer" 12 "github.com/metacubex/mihomo/component/proxydialer" 13 C "github.com/metacubex/mihomo/constant" 14 "github.com/metacubex/mihomo/transport/shadowsocks/core" 15 "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" 16 "github.com/metacubex/mihomo/transport/shadowsocks/shadowstream" 17 "github.com/metacubex/mihomo/transport/socks5" 18 "github.com/metacubex/mihomo/transport/ssr/obfs" 19 "github.com/metacubex/mihomo/transport/ssr/protocol" 20 ) 21 22 type ShadowSocksR struct { 23 *Base 24 option *ShadowSocksROption 25 cipher core.Cipher 26 obfs obfs.Obfs 27 protocol protocol.Protocol 28 } 29 30 type ShadowSocksROption struct { 31 BasicOption 32 Name string `proxy:"name"` 33 Server string `proxy:"server"` 34 Port int `proxy:"port"` 35 Password string `proxy:"password"` 36 Cipher string `proxy:"cipher"` 37 Obfs string `proxy:"obfs"` 38 ObfsParam string `proxy:"obfs-param,omitempty"` 39 Protocol string `proxy:"protocol"` 40 ProtocolParam string `proxy:"protocol-param,omitempty"` 41 UDP bool `proxy:"udp,omitempty"` 42 } 43 44 // StreamConnContext implements C.ProxyAdapter 45 func (ssr *ShadowSocksR) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { 46 c = ssr.obfs.StreamConn(c) 47 c = ssr.cipher.StreamConn(c) 48 var ( 49 iv []byte 50 err error 51 ) 52 switch conn := c.(type) { 53 case *shadowstream.Conn: 54 iv, err = conn.ObtainWriteIV() 55 if err != nil { 56 return nil, err 57 } 58 case *shadowaead.Conn: 59 return nil, fmt.Errorf("invalid connection type") 60 } 61 c = ssr.protocol.StreamConn(c, iv) 62 _, err = c.Write(serializesSocksAddr(metadata)) 63 return c, err 64 } 65 66 // DialContext implements C.ProxyAdapter 67 func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { 68 return ssr.DialContextWithDialer(ctx, dialer.NewDialer(ssr.Base.DialOptions(opts...)...), metadata) 69 } 70 71 // DialContextWithDialer implements C.ProxyAdapter 72 func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { 73 if len(ssr.option.DialerProxy) > 0 { 74 dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer) 75 if err != nil { 76 return nil, err 77 } 78 } 79 c, err := dialer.DialContext(ctx, "tcp", ssr.addr) 80 if err != nil { 81 return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err) 82 } 83 N.TCPKeepAlive(c) 84 85 defer func(c net.Conn) { 86 safeConnClose(c, err) 87 }(c) 88 89 c, err = ssr.StreamConnContext(ctx, c, metadata) 90 return NewConn(c, ssr), err 91 } 92 93 // ListenPacketContext implements C.ProxyAdapter 94 func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { 95 return ssr.ListenPacketWithDialer(ctx, dialer.NewDialer(ssr.Base.DialOptions(opts...)...), metadata) 96 } 97 98 // ListenPacketWithDialer implements C.ProxyAdapter 99 func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { 100 if len(ssr.option.DialerProxy) > 0 { 101 dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer) 102 if err != nil { 103 return nil, err 104 } 105 } 106 addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) 107 if err != nil { 108 return nil, err 109 } 110 111 pc, err := dialer.ListenPacket(ctx, "udp", "", addr.AddrPort()) 112 if err != nil { 113 return nil, err 114 } 115 116 epc := ssr.cipher.PacketConn(N.NewEnhancePacketConn(pc)) 117 epc = ssr.protocol.PacketConn(epc) 118 return newPacketConn(&ssrPacketConn{EnhancePacketConn: epc, rAddr: addr}, ssr), nil 119 } 120 121 // SupportWithDialer implements C.ProxyAdapter 122 func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork { 123 return C.ALLNet 124 } 125 126 func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { 127 // SSR protocol compatibility 128 // https://github.com/metacubex/mihomo/pull/2056 129 if option.Cipher == "none" { 130 option.Cipher = "dummy" 131 } 132 133 addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) 134 cipher := option.Cipher 135 password := option.Password 136 coreCiph, err := core.PickCipher(cipher, nil, password) 137 if err != nil { 138 return nil, fmt.Errorf("ssr %s initialize error: %w", addr, err) 139 } 140 var ( 141 ivSize int 142 key []byte 143 ) 144 145 if option.Cipher == "dummy" { 146 ivSize = 0 147 key = core.Kdf(option.Password, 16) 148 } else { 149 ciph, ok := coreCiph.(*core.StreamCipher) 150 if !ok { 151 return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher) 152 } 153 ivSize = ciph.IVSize() 154 key = ciph.Key 155 } 156 157 obfs, obfsOverhead, err := obfs.PickObfs(option.Obfs, &obfs.Base{ 158 Host: option.Server, 159 Port: option.Port, 160 Key: key, 161 IVSize: ivSize, 162 Param: option.ObfsParam, 163 }) 164 if err != nil { 165 return nil, fmt.Errorf("ssr %s initialize obfs error: %w", addr, err) 166 } 167 168 protocol, err := protocol.PickProtocol(option.Protocol, &protocol.Base{ 169 Key: key, 170 Overhead: obfsOverhead, 171 Param: option.ProtocolParam, 172 }) 173 if err != nil { 174 return nil, fmt.Errorf("ssr %s initialize protocol error: %w", addr, err) 175 } 176 177 return &ShadowSocksR{ 178 Base: &Base{ 179 name: option.Name, 180 addr: addr, 181 tp: C.ShadowsocksR, 182 udp: option.UDP, 183 tfo: option.TFO, 184 mpTcp: option.MPTCP, 185 iface: option.Interface, 186 rmark: option.RoutingMark, 187 prefer: C.NewDNSPrefer(option.IPVersion), 188 }, 189 option: &option, 190 cipher: coreCiph, 191 obfs: obfs, 192 protocol: protocol, 193 }, nil 194 } 195 196 type ssrPacketConn struct { 197 N.EnhancePacketConn 198 rAddr net.Addr 199 } 200 201 func (spc *ssrPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { 202 packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) 203 if err != nil { 204 return 205 } 206 return spc.EnhancePacketConn.WriteTo(packet[3:], spc.rAddr) 207 } 208 209 func (spc *ssrPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 210 n, _, e := spc.EnhancePacketConn.ReadFrom(b) 211 if e != nil { 212 return 0, nil, e 213 } 214 215 addr := socks5.SplitAddr(b[:n]) 216 if addr == nil { 217 return 0, nil, errors.New("parse addr error") 218 } 219 220 udpAddr := addr.UDPAddr() 221 if udpAddr == nil { 222 return 0, nil, errors.New("parse addr error") 223 } 224 225 copy(b, b[len(addr):]) 226 return n - len(addr), udpAddr, e 227 } 228 229 func (spc *ssrPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { 230 data, put, _, err = spc.EnhancePacketConn.WaitReadFrom() 231 if err != nil { 232 return nil, nil, nil, err 233 } 234 235 _addr := socks5.SplitAddr(data) 236 if _addr == nil { 237 if put != nil { 238 put() 239 } 240 return nil, nil, nil, errors.New("parse addr error") 241 } 242 243 addr = _addr.UDPAddr() 244 if addr == nil { 245 if put != nil { 246 put() 247 } 248 return nil, nil, nil, errors.New("parse addr error") 249 } 250 251 data = data[len(_addr):] 252 return 253 }