mirror of https://github.com/XTLS/Xray-core
世界
2 years ago
20 changed files with 523 additions and 238 deletions
@ -0,0 +1,46 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
M "github.com/sagernet/sing/common/metadata" |
||||
N "github.com/sagernet/sing/common/network" |
||||
"github.com/xtls/xray-core/common/net" |
||||
) |
||||
|
||||
func ToNetwork(network string) net.Network { |
||||
switch N.NetworkName(network) { |
||||
case N.NetworkTCP: |
||||
return net.Network_TCP |
||||
case N.NetworkUDP: |
||||
return net.Network_UDP |
||||
default: |
||||
return net.Network_Unknown |
||||
} |
||||
} |
||||
|
||||
func ToDestination(socksaddr M.Socksaddr, network net.Network) net.Destination { |
||||
if socksaddr.IsFqdn() { |
||||
return net.Destination{ |
||||
Network: network, |
||||
Address: net.DomainAddress(socksaddr.Fqdn), |
||||
Port: net.Port(socksaddr.Port), |
||||
} |
||||
} else { |
||||
return net.Destination{ |
||||
Network: network, |
||||
Address: net.IPAddress(socksaddr.Addr.AsSlice()), |
||||
Port: net.Port(socksaddr.Port), |
||||
} |
||||
} |
||||
} |
||||
|
||||
func ToSocksaddr(destination net.Destination) M.Socksaddr { |
||||
var addr M.Socksaddr |
||||
switch destination.Address.Family() { |
||||
case net.AddressFamilyDomain: |
||||
addr.Fqdn = destination.Address.Domain() |
||||
default: |
||||
addr.Addr = M.AddrFromIP(destination.Address.IP()) |
||||
} |
||||
addr.Port = uint16(destination.Port) |
||||
return addr |
||||
} |
@ -0,0 +1,59 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
"context" |
||||
"os" |
||||
|
||||
M "github.com/sagernet/sing/common/metadata" |
||||
N "github.com/sagernet/sing/common/network" |
||||
"github.com/xtls/xray-core/common/net" |
||||
"github.com/xtls/xray-core/common/net/cnc" |
||||
"github.com/xtls/xray-core/common/session" |
||||
"github.com/xtls/xray-core/proxy" |
||||
"github.com/xtls/xray-core/transport" |
||||
"github.com/xtls/xray-core/transport/internet" |
||||
"github.com/xtls/xray-core/transport/pipe" |
||||
) |
||||
|
||||
var _ N.Dialer = (*XrayDialer)(nil) |
||||
|
||||
type XrayDialer struct { |
||||
internet.Dialer |
||||
} |
||||
|
||||
func NewDialer(dialer internet.Dialer) *XrayDialer { |
||||
return &XrayDialer{dialer} |
||||
} |
||||
|
||||
func (d *XrayDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { |
||||
return d.Dialer.Dial(ctx, ToDestination(destination, ToNetwork(network))) |
||||
} |
||||
|
||||
func (d *XrayDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { |
||||
return nil, os.ErrInvalid |
||||
} |
||||
|
||||
type XrayOutboundDialer struct { |
||||
outbound proxy.Outbound |
||||
dialer internet.Dialer |
||||
} |
||||
|
||||
func NewOutboundDialer(outbound proxy.Outbound, dialer internet.Dialer) *XrayOutboundDialer { |
||||
return &XrayOutboundDialer{outbound, dialer} |
||||
} |
||||
|
||||
func (d *XrayOutboundDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { |
||||
ctx = session.ContextWithOutbound(context.Background(), &session.Outbound{ |
||||
Target: ToDestination(destination, ToNetwork(network)), |
||||
}) |
||||
opts := []pipe.Option{pipe.WithSizeLimit(64 * 1024)} |
||||
uplinkReader, uplinkWriter := pipe.New(opts...) |
||||
downlinkReader, downlinkWriter := pipe.New(opts...) |
||||
conn := cnc.NewConnection(cnc.ConnectionInputMulti(downlinkWriter), cnc.ConnectionOutputMulti(uplinkReader)) |
||||
go d.outbound.Process(ctx, &transport.Link{Reader: downlinkReader, Writer: uplinkWriter}, d.dialer) |
||||
return conn, nil |
||||
} |
||||
|
||||
func (d *XrayOutboundDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { |
||||
return nil, os.ErrInvalid |
||||
} |
@ -0,0 +1,10 @@
|
||||
package singbridge |
||||
|
||||
import E "github.com/sagernet/sing/common/exceptions" |
||||
|
||||
func ReturnError(err error) error { |
||||
if E.IsClosedOrCanceled(err) { |
||||
return nil |
||||
} |
||||
return err |
||||
} |
@ -0,0 +1,51 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
"context" |
||||
"io" |
||||
|
||||
M "github.com/sagernet/sing/common/metadata" |
||||
N "github.com/sagernet/sing/common/network" |
||||
"github.com/xtls/xray-core/common/buf" |
||||
"github.com/xtls/xray-core/common/errors" |
||||
"github.com/xtls/xray-core/common/net" |
||||
"github.com/xtls/xray-core/common/session" |
||||
"github.com/xtls/xray-core/features/routing" |
||||
"github.com/xtls/xray-core/transport" |
||||
) |
||||
|
||||
var ( |
||||
_ N.TCPConnectionHandler = (*Dispatcher)(nil) |
||||
_ N.UDPConnectionHandler = (*Dispatcher)(nil) |
||||
) |
||||
|
||||
type Dispatcher struct { |
||||
upstream routing.Dispatcher |
||||
newErrorFunc func(values ...any) *errors.Error |
||||
} |
||||
|
||||
func NewDispatcher(dispatcher routing.Dispatcher, newErrorFunc func(values ...any) *errors.Error) *Dispatcher { |
||||
return &Dispatcher{ |
||||
upstream: dispatcher, |
||||
newErrorFunc: newErrorFunc, |
||||
} |
||||
} |
||||
|
||||
func (d *Dispatcher) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { |
||||
xConn := NewConn(conn) |
||||
return d.upstream.DispatchLink(ctx, ToDestination(metadata.Destination, net.Network_TCP), &transport.Link{ |
||||
Reader: xConn, |
||||
Writer: xConn, |
||||
}) |
||||
} |
||||
|
||||
func (d *Dispatcher) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata M.Metadata) error { |
||||
return d.upstream.DispatchLink(ctx, ToDestination(metadata.Destination, net.Network_UDP), &transport.Link{ |
||||
Reader: buf.NewPacketReader(conn.(io.Reader)), |
||||
Writer: buf.NewWriter(conn.(io.Writer)), |
||||
}) |
||||
} |
||||
|
||||
func (d *Dispatcher) NewError(ctx context.Context, err error) { |
||||
d.newErrorFunc(err).WriteToLog(session.ExportIDToError(ctx)) |
||||
} |
@ -0,0 +1,71 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
"github.com/sagernet/sing/common/logger" |
||||
"github.com/xtls/xray-core/common/errors" |
||||
"github.com/xtls/xray-core/common/session" |
||||
) |
||||
|
||||
var _ logger.ContextLogger = (*XrayLogger)(nil) |
||||
|
||||
type XrayLogger struct { |
||||
newError func(values ...any) *errors.Error |
||||
} |
||||
|
||||
func NewLogger(newErrorFunc func(values ...any) *errors.Error) *XrayLogger { |
||||
return &XrayLogger{ |
||||
newErrorFunc, |
||||
} |
||||
} |
||||
|
||||
func (l *XrayLogger) Trace(args ...any) { |
||||
} |
||||
|
||||
func (l *XrayLogger) Debug(args ...any) { |
||||
l.newError(args...).AtDebug().WriteToLog() |
||||
} |
||||
|
||||
func (l *XrayLogger) Info(args ...any) { |
||||
l.newError(args...).AtInfo().WriteToLog() |
||||
} |
||||
|
||||
func (l *XrayLogger) Warn(args ...any) { |
||||
l.newError(args...).AtWarning().WriteToLog() |
||||
} |
||||
|
||||
func (l *XrayLogger) Error(args ...any) { |
||||
l.newError(args...).AtError().WriteToLog() |
||||
} |
||||
|
||||
func (l *XrayLogger) Fatal(args ...any) { |
||||
} |
||||
|
||||
func (l *XrayLogger) Panic(args ...any) { |
||||
} |
||||
|
||||
func (l *XrayLogger) TraceContext(ctx context.Context, args ...any) { |
||||
} |
||||
|
||||
func (l *XrayLogger) DebugContext(ctx context.Context, args ...any) { |
||||
l.newError(args...).AtDebug().WriteToLog(session.ExportIDToError(ctx)) |
||||
} |
||||
|
||||
func (l *XrayLogger) InfoContext(ctx context.Context, args ...any) { |
||||
l.newError(args...).AtInfo().WriteToLog(session.ExportIDToError(ctx)) |
||||
} |
||||
|
||||
func (l *XrayLogger) WarnContext(ctx context.Context, args ...any) { |
||||
l.newError(args...).AtWarning().WriteToLog(session.ExportIDToError(ctx)) |
||||
} |
||||
|
||||
func (l *XrayLogger) ErrorContext(ctx context.Context, args ...any) { |
||||
l.newError(args...).AtError().WriteToLog(session.ExportIDToError(ctx)) |
||||
} |
||||
|
||||
func (l *XrayLogger) FatalContext(ctx context.Context, args ...any) { |
||||
} |
||||
|
||||
func (l *XrayLogger) PanicContext(ctx context.Context, args ...any) { |
||||
} |
@ -0,0 +1,82 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
"context" |
||||
|
||||
B "github.com/sagernet/sing/common/buf" |
||||
"github.com/sagernet/sing/common/bufio" |
||||
M "github.com/sagernet/sing/common/metadata" |
||||
"github.com/xtls/xray-core/common/buf" |
||||
"github.com/xtls/xray-core/common/net" |
||||
"github.com/xtls/xray-core/transport" |
||||
) |
||||
|
||||
func CopyPacketConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, destination net.Destination, serverConn net.PacketConn) error { |
||||
conn := &PacketConnWrapper{ |
||||
Reader: link.Reader, |
||||
Writer: link.Writer, |
||||
Dest: destination, |
||||
Conn: inboundConn, |
||||
} |
||||
return ReturnError(bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn))) |
||||
} |
||||
|
||||
type PacketConnWrapper struct { |
||||
buf.Reader |
||||
buf.Writer |
||||
net.Conn |
||||
Dest net.Destination |
||||
cached buf.MultiBuffer |
||||
} |
||||
|
||||
func (w *PacketConnWrapper) ReadPacket(buffer *B.Buffer) (M.Socksaddr, error) { |
||||
if w.cached != nil { |
||||
mb, bb := buf.SplitFirst(w.cached) |
||||
if bb == nil { |
||||
w.cached = nil |
||||
} else { |
||||
buffer.Write(bb.Bytes()) |
||||
w.cached = mb |
||||
var destination net.Destination |
||||
if bb.UDP != nil { |
||||
destination = *bb.UDP |
||||
} else { |
||||
destination = w.Dest |
||||
} |
||||
bb.Release() |
||||
return ToSocksaddr(destination), nil |
||||
} |
||||
} |
||||
mb, err := w.ReadMultiBuffer() |
||||
if err != nil { |
||||
return M.Socksaddr{}, err |
||||
} |
||||
nb, bb := buf.SplitFirst(mb) |
||||
if bb == nil { |
||||
return M.Socksaddr{}, nil |
||||
} else { |
||||
buffer.Write(bb.Bytes()) |
||||
w.cached = nb |
||||
var destination net.Destination |
||||
if bb.UDP != nil { |
||||
destination = *bb.UDP |
||||
} else { |
||||
destination = w.Dest |
||||
} |
||||
bb.Release() |
||||
return ToSocksaddr(destination), nil |
||||
} |
||||
} |
||||
|
||||
func (w *PacketConnWrapper) WritePacket(buffer *B.Buffer, destination M.Socksaddr) error { |
||||
vBuf := buf.New() |
||||
vBuf.Write(buffer.Bytes()) |
||||
endpoint := ToDestination(destination, net.Network_UDP) |
||||
vBuf.UDP = &endpoint |
||||
return w.Writer.WriteMultiBuffer(buf.MultiBuffer{vBuf}) |
||||
} |
||||
|
||||
func (w *PacketConnWrapper) Close() error { |
||||
buf.ReleaseMulti(w.cached) |
||||
return nil |
||||
} |
@ -0,0 +1,61 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
"context" |
||||
"io" |
||||
"net" |
||||
|
||||
"github.com/sagernet/sing/common/bufio" |
||||
"github.com/xtls/xray-core/common/buf" |
||||
"github.com/xtls/xray-core/transport" |
||||
) |
||||
|
||||
func CopyConn(ctx context.Context, inboundConn net.Conn, link *transport.Link, serverConn net.Conn) error { |
||||
conn := &PipeConnWrapper{ |
||||
W: link.Writer, |
||||
Conn: inboundConn, |
||||
} |
||||
if ir, ok := link.Reader.(io.Reader); ok { |
||||
conn.R = ir |
||||
} else { |
||||
conn.R = &buf.BufferedReader{Reader: link.Reader} |
||||
} |
||||
return ReturnError(bufio.CopyConn(ctx, conn, serverConn)) |
||||
} |
||||
|
||||
type PipeConnWrapper struct { |
||||
R io.Reader |
||||
W buf.Writer |
||||
net.Conn |
||||
} |
||||
|
||||
func (w *PipeConnWrapper) Close() error { |
||||
return nil |
||||
} |
||||
|
||||
func (w *PipeConnWrapper) Read(b []byte) (n int, err error) { |
||||
return w.R.Read(b) |
||||
} |
||||
|
||||
func (w *PipeConnWrapper) Write(p []byte) (n int, err error) { |
||||
n = len(p) |
||||
var mb buf.MultiBuffer |
||||
pLen := len(p) |
||||
for pLen > 0 { |
||||
buffer := buf.New() |
||||
if pLen > buf.Size { |
||||
_, err = buffer.Write(p[:buf.Size]) |
||||
p = p[buf.Size:] |
||||
} else { |
||||
buffer.Write(p) |
||||
} |
||||
pLen -= int(buffer.Len()) |
||||
mb = append(mb, buffer) |
||||
} |
||||
err = w.W.WriteMultiBuffer(mb) |
||||
if err != nil { |
||||
n = 0 |
||||
buf.ReleaseMulti(mb) |
||||
} |
||||
return |
||||
} |
@ -0,0 +1,66 @@
|
||||
package singbridge |
||||
|
||||
import ( |
||||
"time" |
||||
|
||||
"github.com/sagernet/sing/common" |
||||
"github.com/sagernet/sing/common/bufio" |
||||
N "github.com/sagernet/sing/common/network" |
||||
"github.com/xtls/xray-core/common/buf" |
||||
"github.com/xtls/xray-core/common/net" |
||||
) |
||||
|
||||
var ( |
||||
_ buf.Reader = (*Conn)(nil) |
||||
_ buf.TimeoutReader = (*Conn)(nil) |
||||
_ buf.Writer = (*Conn)(nil) |
||||
) |
||||
|
||||
type Conn struct { |
||||
net.Conn |
||||
writer N.VectorisedWriter |
||||
} |
||||
|
||||
func NewConn(conn net.Conn) *Conn { |
||||
writer, _ := bufio.CreateVectorisedWriter(conn) |
||||
return &Conn{ |
||||
Conn: conn, |
||||
writer: writer, |
||||
} |
||||
} |
||||
|
||||
func (c *Conn) ReadMultiBuffer() (buf.MultiBuffer, error) { |
||||
buffer, err := buf.ReadBuffer(c.Conn) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return buf.MultiBuffer{buffer}, nil |
||||
} |
||||
|
||||
func (c *Conn) ReadMultiBufferTimeout(duration time.Duration) (buf.MultiBuffer, error) { |
||||
err := c.SetReadDeadline(time.Now().Add(duration)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
defer c.SetReadDeadline(time.Time{}) |
||||
return c.ReadMultiBuffer() |
||||
} |
||||
|
||||
func (c *Conn) WriteMultiBuffer(bufferList buf.MultiBuffer) error { |
||||
defer buf.ReleaseMulti(bufferList) |
||||
if c.writer != nil { |
||||
bytesList := make([][]byte, len(bufferList)) |
||||
for i, buffer := range bufferList { |
||||
bytesList[i] = buffer.Bytes() |
||||
} |
||||
return common.Error(bufio.WriteVectorised(c.writer, bytesList)) |
||||
} |
||||
// Since this conn is only used by tun, we don't force buffer writes to merge.
|
||||
for _, buffer := range bufferList { |
||||
_, err := c.Conn.Write(buffer.Bytes()) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
Loading…
Reference in new issue