github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/outbound/default.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "net" 6 "net/netip" 7 "os" 8 "time" 9 10 "github.com/inazumav/sing-box/adapter" 11 C "github.com/inazumav/sing-box/constant" 12 "github.com/inazumav/sing-box/log" 13 "github.com/inazumav/sing-box/option" 14 "github.com/sagernet/sing/common" 15 "github.com/sagernet/sing/common/buf" 16 "github.com/sagernet/sing/common/bufio" 17 "github.com/sagernet/sing/common/canceler" 18 E "github.com/sagernet/sing/common/exceptions" 19 N "github.com/sagernet/sing/common/network" 20 ) 21 22 type myOutboundAdapter struct { 23 protocol string 24 network []string 25 router adapter.Router 26 logger log.ContextLogger 27 tag string 28 dependencies []string 29 } 30 31 func (a *myOutboundAdapter) Type() string { 32 return a.protocol 33 } 34 35 func (a *myOutboundAdapter) Tag() string { 36 return a.tag 37 } 38 39 func (a *myOutboundAdapter) Network() []string { 40 return a.network 41 } 42 43 func (a *myOutboundAdapter) Dependencies() []string { 44 return a.dependencies 45 } 46 47 func (a *myOutboundAdapter) NewError(ctx context.Context, err error) { 48 NewError(a.logger, ctx, err) 49 } 50 51 func withDialerDependency(options option.DialerOptions) []string { 52 if options.Detour != "" { 53 return []string{options.Detour} 54 } 55 return nil 56 } 57 58 func NewConnection(ctx context.Context, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error { 59 ctx = adapter.WithContext(ctx, &metadata) 60 var outConn net.Conn 61 var err error 62 if len(metadata.DestinationAddresses) > 0 { 63 outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses) 64 } else { 65 outConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination) 66 } 67 if err != nil { 68 return N.HandshakeFailure(conn, err) 69 } 70 return CopyEarlyConn(ctx, conn, outConn) 71 } 72 73 func NewDirectConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn net.Conn, metadata adapter.InboundContext) error { 74 ctx = adapter.WithContext(ctx, &metadata) 75 var outConn net.Conn 76 var err error 77 if len(metadata.DestinationAddresses) > 0 { 78 outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, metadata.DestinationAddresses) 79 } else if metadata.Destination.IsFqdn() { 80 var destinationAddresses []netip.Addr 81 destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn) 82 if err != nil { 83 return N.HandshakeFailure(conn, err) 84 } 85 outConn, err = N.DialSerial(ctx, this, N.NetworkTCP, metadata.Destination, destinationAddresses) 86 } else { 87 outConn, err = this.DialContext(ctx, N.NetworkTCP, metadata.Destination) 88 } 89 if err != nil { 90 return N.HandshakeFailure(conn, err) 91 } 92 return CopyEarlyConn(ctx, conn, outConn) 93 } 94 95 func NewPacketConnection(ctx context.Context, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error { 96 ctx = adapter.WithContext(ctx, &metadata) 97 var outConn net.PacketConn 98 var destinationAddress netip.Addr 99 var err error 100 if len(metadata.DestinationAddresses) > 0 { 101 outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses) 102 } else { 103 outConn, err = this.ListenPacket(ctx, metadata.Destination) 104 } 105 if err != nil { 106 return N.HandshakeFailure(conn, err) 107 } 108 if destinationAddress.IsValid() { 109 if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { 110 natConn.UpdateDestination(destinationAddress) 111 } 112 } 113 switch metadata.Protocol { 114 case C.ProtocolSTUN: 115 ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout) 116 case C.ProtocolQUIC: 117 ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout) 118 case C.ProtocolDNS: 119 ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout) 120 } 121 return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn)) 122 } 123 124 func NewDirectPacketConnection(ctx context.Context, router adapter.Router, this N.Dialer, conn N.PacketConn, metadata adapter.InboundContext) error { 125 ctx = adapter.WithContext(ctx, &metadata) 126 var outConn net.PacketConn 127 var destinationAddress netip.Addr 128 var err error 129 if len(metadata.DestinationAddresses) > 0 { 130 outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, metadata.DestinationAddresses) 131 } else if metadata.Destination.IsFqdn() { 132 var destinationAddresses []netip.Addr 133 destinationAddresses, err = router.LookupDefault(ctx, metadata.Destination.Fqdn) 134 if err != nil { 135 return N.HandshakeFailure(conn, err) 136 } 137 outConn, destinationAddress, err = N.ListenSerial(ctx, this, metadata.Destination, destinationAddresses) 138 } else { 139 outConn, err = this.ListenPacket(ctx, metadata.Destination) 140 } 141 if err != nil { 142 return N.HandshakeFailure(conn, err) 143 } 144 if destinationAddress.IsValid() { 145 if natConn, loaded := common.Cast[bufio.NATPacketConn](conn); loaded { 146 natConn.UpdateDestination(destinationAddress) 147 } 148 } 149 switch metadata.Protocol { 150 case C.ProtocolSTUN: 151 ctx, conn = canceler.NewPacketConn(ctx, conn, C.STUNTimeout) 152 case C.ProtocolQUIC: 153 ctx, conn = canceler.NewPacketConn(ctx, conn, C.QUICTimeout) 154 case C.ProtocolDNS: 155 ctx, conn = canceler.NewPacketConn(ctx, conn, C.DNSTimeout) 156 } 157 return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn)) 158 } 159 160 func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error { 161 if cachedReader, isCached := conn.(N.CachedReader); isCached { 162 payload := cachedReader.ReadCached() 163 if payload != nil && !payload.IsEmpty() { 164 _, err := serverConn.Write(payload.Bytes()) 165 if err != nil { 166 return err 167 } 168 return bufio.CopyConn(ctx, conn, serverConn) 169 } 170 } 171 if earlyConn, isEarlyConn := common.Cast[N.EarlyConn](serverConn); isEarlyConn && earlyConn.NeedHandshake() { 172 payload := buf.NewPacket() 173 err := conn.SetReadDeadline(time.Now().Add(C.ReadPayloadTimeout)) 174 if err != os.ErrInvalid { 175 if err != nil { 176 return err 177 } 178 _, err = payload.ReadOnceFrom(conn) 179 if err != nil && !E.IsTimeout(err) { 180 return E.Cause(err, "read payload") 181 } 182 err = conn.SetReadDeadline(time.Time{}) 183 if err != nil { 184 payload.Release() 185 return err 186 } 187 } 188 _, err = serverConn.Write(payload.Bytes()) 189 if err != nil { 190 return N.HandshakeFailure(conn, err) 191 } 192 payload.Release() 193 } 194 return bufio.CopyConn(ctx, conn, serverConn) 195 } 196 197 func NewError(logger log.ContextLogger, ctx context.Context, err error) { 198 common.Close(err) 199 if E.IsClosedOrCanceled(err) { 200 logger.DebugContext(ctx, "connection closed: ", err) 201 return 202 } 203 logger.ErrorContext(ctx, err) 204 }