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