github.com/sagernet/sing-box@v1.2.7/outbound/shadowsocksr.go (about) 1 //go:build with_shadowsocksr 2 3 package outbound 4 5 import ( 6 "context" 7 "errors" 8 "fmt" 9 "net" 10 11 "github.com/sagernet/sing-box/adapter" 12 "github.com/sagernet/sing-box/common/dialer" 13 C "github.com/sagernet/sing-box/constant" 14 "github.com/sagernet/sing-box/log" 15 "github.com/sagernet/sing-box/option" 16 "github.com/sagernet/sing-box/transport/clashssr/obfs" 17 "github.com/sagernet/sing-box/transport/clashssr/protocol" 18 "github.com/sagernet/sing/common/bufio" 19 E "github.com/sagernet/sing/common/exceptions" 20 M "github.com/sagernet/sing/common/metadata" 21 N "github.com/sagernet/sing/common/network" 22 23 "github.com/Dreamacro/clash/transport/shadowsocks/core" 24 "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" 25 "github.com/Dreamacro/clash/transport/socks5" 26 ) 27 28 var _ adapter.Outbound = (*ShadowsocksR)(nil) 29 30 type ShadowsocksR struct { 31 myOutboundAdapter 32 dialer N.Dialer 33 serverAddr M.Socksaddr 34 cipher core.Cipher 35 obfs obfs.Obfs 36 protocol protocol.Protocol 37 } 38 39 func NewShadowsocksR(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksROutboundOptions) (*ShadowsocksR, error) { 40 outbound := &ShadowsocksR{ 41 myOutboundAdapter: myOutboundAdapter{ 42 protocol: C.TypeShadowsocksR, 43 network: options.Network.Build(), 44 router: router, 45 logger: logger, 46 tag: tag, 47 }, 48 dialer: dialer.New(router, options.DialerOptions), 49 serverAddr: options.ServerOptions.Build(), 50 } 51 var cipher string 52 var err error 53 switch options.Method { 54 case "none": 55 cipher = "dummy" 56 default: 57 cipher = options.Method 58 } 59 outbound.cipher, err = core.PickCipher(cipher, nil, options.Password) 60 if err != nil { 61 return nil, err 62 } 63 var ( 64 ivSize int 65 key []byte 66 ) 67 if cipher == "dummy" { 68 ivSize = 0 69 key = core.Kdf(options.Password, 16) 70 } else { 71 streamCipher, ok := outbound.cipher.(*core.StreamCipher) 72 if !ok { 73 return nil, fmt.Errorf("%s is not none or a supported stream cipher in ssr", cipher) 74 } 75 ivSize = streamCipher.IVSize() 76 key = streamCipher.Key 77 } 78 obfs, obfsOverhead, err := obfs.PickObfs(options.Obfs, &obfs.Base{ 79 Host: options.Server, 80 Port: int(options.ServerPort), 81 Key: key, 82 IVSize: ivSize, 83 Param: options.ObfsParam, 84 }) 85 if err != nil { 86 return nil, E.Cause(err, "initialize obfs") 87 } 88 protocol, err := protocol.PickProtocol(options.Protocol, &protocol.Base{ 89 Key: key, 90 Overhead: obfsOverhead, 91 Param: options.ProtocolParam, 92 }) 93 if err != nil { 94 return nil, E.Cause(err, "initialize protocol") 95 } 96 outbound.obfs = obfs 97 outbound.protocol = protocol 98 return outbound, nil 99 } 100 101 func (h *ShadowsocksR) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { 102 ctx, metadata := adapter.AppendContext(ctx) 103 metadata.Outbound = h.tag 104 metadata.Destination = destination 105 switch network { 106 case N.NetworkTCP: 107 h.logger.InfoContext(ctx, "outbound connection to ", destination) 108 conn, err := h.dialer.DialContext(ctx, network, h.serverAddr) 109 if err != nil { 110 return nil, err 111 } 112 conn = h.cipher.StreamConn(h.obfs.StreamConn(conn)) 113 writeIv, err := conn.(*shadowstream.Conn).ObtainWriteIV() 114 if err != nil { 115 conn.Close() 116 return nil, err 117 } 118 conn = h.protocol.StreamConn(conn, writeIv) 119 err = M.SocksaddrSerializer.WriteAddrPort(conn, destination) 120 if err != nil { 121 conn.Close() 122 return nil, E.Cause(err, "write request") 123 } 124 return conn, nil 125 case N.NetworkUDP: 126 conn, err := h.ListenPacket(ctx, destination) 127 if err != nil { 128 return nil, err 129 } 130 return bufio.NewBindPacketConn(conn, destination), nil 131 default: 132 return nil, E.Extend(N.ErrUnknownNetwork, network) 133 } 134 } 135 136 func (h *ShadowsocksR) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { 137 ctx, metadata := adapter.AppendContext(ctx) 138 metadata.Outbound = h.tag 139 metadata.Destination = destination 140 h.logger.InfoContext(ctx, "outbound packet connection to ", destination) 141 outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr) 142 if err != nil { 143 return nil, err 144 } 145 packetConn := h.cipher.PacketConn(bufio.NewUnbindPacketConn(outConn)) 146 packetConn = h.protocol.PacketConn(packetConn) 147 packetConn = &ssPacketConn{packetConn, outConn.RemoteAddr()} 148 return packetConn, nil 149 } 150 151 func (h *ShadowsocksR) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 152 return NewConnection(ctx, h, conn, metadata) 153 } 154 155 func (h *ShadowsocksR) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { 156 return NewPacketConnection(ctx, h, conn, metadata) 157 } 158 159 type ssPacketConn struct { 160 net.PacketConn 161 rAddr net.Addr 162 } 163 164 func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { 165 packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) 166 if err != nil { 167 return 168 } 169 return spc.PacketConn.WriteTo(packet[3:], spc.rAddr) 170 } 171 172 func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { 173 n, _, e := spc.PacketConn.ReadFrom(b) 174 if e != nil { 175 return 0, nil, e 176 } 177 178 addr := socks5.SplitAddr(b[:n]) 179 if addr == nil { 180 return 0, nil, errors.New("parse addr error") 181 } 182 183 udpAddr := addr.UDPAddr() 184 if udpAddr == nil { 185 return 0, nil, errors.New("parse addr error") 186 } 187 188 copy(b, b[len(addr):]) 189 return n - len(addr), udpAddr, e 190 }