diff --git a/common/net/packetaddr/connection_adaptor.go b/common/net/packetaddr/connection_adaptor.go new file mode 100644 index 000000000..68cb79337 --- /dev/null +++ b/common/net/packetaddr/connection_adaptor.go @@ -0,0 +1,100 @@ +package packetaddr + +import ( + gonet "net" + "sync" + "time" + + "github.com/v2fly/v2ray-core/v4/common" + "github.com/v2fly/v2ray-core/v4/common/buf" + "github.com/v2fly/v2ray-core/v4/common/errors" + "github.com/v2fly/v2ray-core/v4/common/net" + "github.com/v2fly/v2ray-core/v4/transport" +) + +var errNotPacketConn = errors.New("not a packet connection") +var errUnsupported = errors.New("unsupported action") + +func ToPacketAddrConn(link *transport.Link, dest net.Destination) (net.PacketConn, error) { + if !dest.Address.Family().IsDomain() { + return nil, errNotPacketConn + } + switch dest.Address.Domain() { + case seqPacketMagicAddress: + return &packetConnectionAdaptor{ + readerAccess: &sync.Mutex{}, + readerBuffer: nil, + link: link, + }, nil + default: + return nil, errNotPacketConn + } +} + +func CreatePacketAddrConn(link *transport.Link, isStream bool) (net.PacketConn, net.Destination, error) { + if isStream { + return nil, net.Destination{}, errUnsupported + } + return &packetConnectionAdaptor{ + readerAccess: &sync.Mutex{}, + readerBuffer: nil, + link: link, + }, net.Destination{ + Address: net.DomainAddress(seqPacketMagicAddress), + Port: 0, + Network: net.Network_UDP, + }, nil +} + +type packetConnectionAdaptor struct { + readerAccess *sync.Mutex + readerBuffer buf.MultiBuffer + link *transport.Link +} + +func (c *packetConnectionAdaptor) ReadFrom(p []byte) (n int, addr gonet.Addr, err error) { + c.readerAccess.Lock() + defer c.readerAccess.Unlock() + if c.readerBuffer.IsEmpty() { + c.readerBuffer, err = c.link.Reader.ReadMultiBuffer() + } + c.readerBuffer, n = buf.SplitFirstBytes(c.readerBuffer, p) + p, addr = ExtractAddressFromPacket(p) + return +} + +func (c *packetConnectionAdaptor) WriteTo(p []byte, addr gonet.Addr) (n int, err error) { + payloadLen := len(p) + p = AttachAddressToPacket(p, addr) + buffer := buf.New() + mb := buf.MultiBuffer{buffer} + err = c.link.Writer.WriteMultiBuffer(mb) + buf.ReleaseMulti(mb) + if err != nil { + return 0, err + } + return payloadLen, nil +} + +func (c *packetConnectionAdaptor) Close() error { + c.readerAccess.Lock() + defer c.readerAccess.Unlock() + c.readerBuffer = buf.ReleaseMulti(c.readerBuffer) + return common.Interrupt(c.link) +} + +func (c packetConnectionAdaptor) LocalAddr() gonet.Addr { + return &gonet.UnixAddr{Name: "unsupported"} +} + +func (c packetConnectionAdaptor) SetDeadline(t time.Time) error { + return nil +} + +func (c packetConnectionAdaptor) SetReadDeadline(t time.Time) error { + return nil +} + +func (c packetConnectionAdaptor) SetWriteDeadline(t time.Time) error { + return nil +} diff --git a/common/net/packetaddr/packetaddr.go b/common/net/packetaddr/packetaddr.go index 014596f69..99d26841c 100644 --- a/common/net/packetaddr/packetaddr.go +++ b/common/net/packetaddr/packetaddr.go @@ -5,7 +5,7 @@ import ( "github.com/v2fly/v2ray-core/v4/common/buf" "github.com/v2fly/v2ray-core/v4/common/net" "github.com/v2fly/v2ray-core/v4/common/protocol" - sysnet "net" + gonet "net" ) var addrParser = protocol.NewAddressParser( @@ -13,9 +13,9 @@ var addrParser = protocol.NewAddressParser( protocol.AddressFamilyByte(0x02, net.AddressFamilyIPv6), ) -func AttachAddressToPacket(data []byte, address sysnet.Addr) []byte { +func AttachAddressToPacket(data []byte, address gonet.Addr) []byte { packetBuf := buf.StackNew() - udpaddr := address.(*sysnet.UDPAddr) + udpaddr := address.(*gonet.UDPAddr) port, err := net.PortFromInt(uint32(udpaddr.Port)) if err != nil { panic(err) @@ -29,13 +29,13 @@ func AttachAddressToPacket(data []byte, address sysnet.Addr) []byte { return data } -func ExtractAddressFromPacket(data []byte) ([]byte, sysnet.Addr) { +func ExtractAddressFromPacket(data []byte) ([]byte, gonet.Addr) { packetBuf := buf.StackNew() address, port, err := addrParser.ReadAddressPort(&packetBuf, bytes.NewReader(data)) if err != nil { panic(err) } - var addr = &sysnet.UDPAddr{ + var addr = &gonet.UDPAddr{ IP: address.IP(), Port: int(port.Value()), Zone: "", diff --git a/common/net/packetaddr/special_address.go b/common/net/packetaddr/special_address.go new file mode 100644 index 000000000..8c5053b81 --- /dev/null +++ b/common/net/packetaddr/special_address.go @@ -0,0 +1,3 @@ +package packetaddr + +const seqPacketMagicAddress = "sp.packet-addr.v2fly.arpa"