mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2024-12-22 23:57:26 +08:00
refactor: udp
This commit is contained in:
parent
cd466f05d3
commit
637a8b6ed5
@ -2,7 +2,7 @@ package inbound
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PacketAdapter is a UDP Packet adapter for socks/redir/tun
|
// PacketAdapter is a UDP Packet adapter for socks/redir/tun
|
||||||
@ -17,8 +17,8 @@ func (s *PacketAdapter) Metadata() *C.Metadata {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewPacket is PacketAdapter generator
|
// NewPacket is PacketAdapter generator
|
||||||
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter {
|
func NewPacket(target M.Socksaddr, packet C.UDPPacket, source C.Type) *PacketAdapter {
|
||||||
metadata := parseSocksAddr(target)
|
metadata := socksAddrToMetadata(target)
|
||||||
metadata.NetWork = C.UDP
|
metadata.NetWork = C.UDP
|
||||||
metadata.Type = source
|
metadata.Type = source
|
||||||
if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil {
|
if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil {
|
||||||
|
@ -10,8 +10,26 @@ import (
|
|||||||
"github.com/Dreamacro/clash/common/nnip"
|
"github.com/Dreamacro/clash/common/nnip"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func socksAddrToMetadata(addr M.Socksaddr) *C.Metadata {
|
||||||
|
metadata := &C.Metadata{}
|
||||||
|
switch addr.Family() {
|
||||||
|
case M.AddressFamilyIPv4:
|
||||||
|
metadata.AddrType = C.AtypIPv4
|
||||||
|
metadata.DstIP = addr.Addr
|
||||||
|
case M.AddressFamilyIPv6:
|
||||||
|
metadata.AddrType = C.AtypIPv6
|
||||||
|
metadata.DstIP = addr.Addr
|
||||||
|
case M.AddressFamilyFqdn:
|
||||||
|
metadata.AddrType = C.AtypDomainName
|
||||||
|
metadata.Host = addr.Fqdn
|
||||||
|
}
|
||||||
|
metadata.DstPort = strconv.Itoa(int(addr.Port))
|
||||||
|
return metadata
|
||||||
|
}
|
||||||
|
|
||||||
func parseSocksAddr(target socks5.Addr) *C.Metadata {
|
func parseSocksAddr(target socks5.Addr) *C.Metadata {
|
||||||
metadata := &C.Metadata{
|
metadata := &C.Metadata{
|
||||||
AddrType: int(target[0]),
|
AddrType: int(target[0]),
|
||||||
|
@ -10,6 +10,10 @@ import (
|
|||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
"github.com/sagernet/sing/common/bufio"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
@ -157,6 +161,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn {
|
|||||||
|
|
||||||
type packetConn struct {
|
type packetConn struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
|
nc N.PacketConn
|
||||||
chain C.Chain
|
chain C.Chain
|
||||||
actualRemoteDestination string
|
actualRemoteDestination string
|
||||||
}
|
}
|
||||||
@ -175,8 +180,22 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) {
|
|||||||
c.chain = append(c.chain, a.Name())
|
c.chain = append(c.chain, a.Name())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) ReadPacket(buffer *buf.Buffer) (addr M.Socksaddr, err error) {
|
||||||
|
return c.nc.ReadPacket(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *packetConn) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
|
||||||
|
return c.nc.WritePacket(buffer, addr)
|
||||||
|
}
|
||||||
|
|
||||||
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
|
func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn {
|
||||||
return &packetConn{pc, []string{a.Name()}, parseRemoteDestination(a.Addr())}
|
var nc N.PacketConn
|
||||||
|
if n, isNc := pc.(N.PacketConn); isNc {
|
||||||
|
nc = n
|
||||||
|
} else {
|
||||||
|
nc = &bufio.PacketConnWrapper{PacketConn: pc}
|
||||||
|
}
|
||||||
|
return &packetConn{pc, nc, []string{a.Name()}, parseRemoteDestination(a.Addr())}
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseRemoteDestination(addr string) string {
|
func parseRemoteDestination(addr string) string {
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
"github.com/Dreamacro/clash/common/structure"
|
"github.com/Dreamacro/clash/common/structure"
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
@ -16,15 +15,10 @@ import (
|
|||||||
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
|
v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin"
|
||||||
"github.com/sagernet/sing-shadowsocks"
|
"github.com/sagernet/sing-shadowsocks"
|
||||||
"github.com/sagernet/sing-shadowsocks/shadowimpl"
|
"github.com/sagernet/sing-shadowsocks/shadowimpl"
|
||||||
"github.com/sagernet/sing/common/buf"
|
|
||||||
"github.com/sagernet/sing/common/bufio"
|
"github.com/sagernet/sing/common/bufio"
|
||||||
M "github.com/sagernet/sing/common/metadata"
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
|
||||||
buf.DefaultAllocator = pool.DefaultAllocator
|
|
||||||
}
|
|
||||||
|
|
||||||
type ShadowSocks struct {
|
type ShadowSocks struct {
|
||||||
*Base
|
*Base
|
||||||
method shadowsocks.Method
|
method shadowsocks.Method
|
||||||
|
@ -6,9 +6,15 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
)
|
)
|
||||||
|
|
||||||
var DefaultAllocator = NewAllocator()
|
var defaultAllocator = NewAllocator()
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
buf.DefaultAllocator = defaultAllocator
|
||||||
|
}
|
||||||
|
|
||||||
// Allocator for incoming frames, optimized to prevent overwriting after zeroing
|
// Allocator for incoming frames, optimized to prevent overwriting after zeroing
|
||||||
type Allocator struct {
|
type Allocator struct {
|
||||||
|
@ -13,9 +13,9 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func Get(size int) []byte {
|
func Get(size int) []byte {
|
||||||
return DefaultAllocator.Get(size)
|
return defaultAllocator.Get(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Put(buf []byte) error {
|
func Put(buf []byte) error {
|
||||||
return DefaultAllocator.Put(buf)
|
return defaultAllocator.Put(buf)
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,8 @@ import (
|
|||||||
"github.com/Dreamacro/clash/component/trie"
|
"github.com/Dreamacro/clash/component/trie"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
providerTypes "github.com/Dreamacro/clash/constant/provider"
|
||||||
"github.com/Dreamacro/clash/constant/sniffer"
|
|
||||||
snifferTypes "github.com/Dreamacro/clash/constant/sniffer"
|
snifferTypes "github.com/Dreamacro/clash/constant/sniffer"
|
||||||
|
"github.com/Dreamacro/clash/constant/sniffer"
|
||||||
"github.com/Dreamacro/clash/dns"
|
"github.com/Dreamacro/clash/dns"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
@ -7,6 +7,8 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/component/dialer"
|
"github.com/Dreamacro/clash/component/dialer"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Adapter Type
|
// Adapter Type
|
||||||
@ -75,6 +77,7 @@ type Conn interface {
|
|||||||
type PacketConn interface {
|
type PacketConn interface {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
Connection
|
Connection
|
||||||
|
N.PacketConn
|
||||||
// Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed
|
// Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed
|
||||||
// WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error)
|
// WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error)
|
||||||
}
|
}
|
||||||
@ -184,7 +187,7 @@ func (at AdapterType) String() string {
|
|||||||
// UDPPacket contains the data of UDP packet, and offers control/info of UDP packet's source
|
// UDPPacket contains the data of UDP packet, and offers control/info of UDP packet's source
|
||||||
type UDPPacket interface {
|
type UDPPacket interface {
|
||||||
// Data get the payload of UDP Packet
|
// Data get the payload of UDP Packet
|
||||||
Data() []byte
|
Data() *buf.Buffer
|
||||||
|
|
||||||
// WriteBack writes the payload with source IP/Port equals addr
|
// WriteBack writes the payload with source IP/Port equals addr
|
||||||
// - variable source IP/Port is important to STUN
|
// - variable source IP/Port is important to STUN
|
||||||
@ -192,8 +195,7 @@ type UDPPacket interface {
|
|||||||
// this is important when using Fake-IP.
|
// this is important when using Fake-IP.
|
||||||
WriteBack(b []byte, addr net.Addr) (n int, err error)
|
WriteBack(b []byte, addr net.Addr) (n int, err error)
|
||||||
|
|
||||||
// Drop call after packet is used, could recycle buffer in this function.
|
N.PacketWriter
|
||||||
Drop()
|
|
||||||
|
|
||||||
// LocalAddr returns the source IP/Port of packet
|
// LocalAddr returns the source IP/Port of packet
|
||||||
LocalAddr() net.Addr
|
LocalAddr() net.Addr
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/netip"
|
"net/netip"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Socks addr type
|
// Socks addr type
|
||||||
@ -170,6 +172,18 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Metadata) Socksaddr() M.Socksaddr {
|
||||||
|
port, _ := strconv.ParseUint(m.DstPort, 10, 16)
|
||||||
|
if m.Host != "" {
|
||||||
|
return M.Socksaddr{
|
||||||
|
Fqdn: m.Host,
|
||||||
|
Port: uint16(port),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return M.SocksaddrFromAddrPort(m.DstIP, uint16(port))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *Metadata) String() string {
|
func (m *Metadata) String() string {
|
||||||
if m.Host != "" {
|
if m.Host != "" {
|
||||||
return m.Host
|
return m.Host
|
||||||
|
2
go.mod
2
go.mod
@ -13,7 +13,7 @@ require (
|
|||||||
github.com/lucas-clemente/quic-go v0.27.2
|
github.com/lucas-clemente/quic-go v0.27.2
|
||||||
github.com/miekg/dns v1.1.49
|
github.com/miekg/dns v1.1.49
|
||||||
github.com/oschwald/geoip2-golang v1.7.0
|
github.com/oschwald/geoip2-golang v1.7.0
|
||||||
github.com/sagernet/sing v0.0.0-20220609091055-86d0144940e7
|
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13
|
||||||
github.com/sirupsen/logrus v1.8.1
|
github.com/sirupsen/logrus v1.8.1
|
||||||
github.com/stretchr/testify v1.7.2
|
github.com/stretchr/testify v1.7.2
|
||||||
|
4
go.sum
4
go.sum
@ -305,8 +305,8 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
|
|||||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/sagernet/sing v0.0.0-20220609091055-86d0144940e7 h1:Q+uNKLNSKqpx+p96qcBTVFh8RUKiQFr4IrNVi5Q5yl0=
|
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159 h1:G3fww5jjADkHWi6yDOEzkZbQ6lnrytv0mKesBtEslxo=
|
||||||
github.com/sagernet/sing v0.0.0-20220609091055-86d0144940e7/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
|
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 h1:bQN0hjTHdB7SyaD9yjEYAl+bDl/kXW9zC0xNa+LMTrA=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 h1:bQN0hjTHdB7SyaD9yjEYAl+bDl/kXW9zC0xNa+LMTrA=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
@ -4,11 +4,11 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/inbound"
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
"github.com/Dreamacro/clash/common/sockopt"
|
"github.com/Dreamacro/clash/common/sockopt"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UDPListener struct {
|
type UDPListener struct {
|
||||||
@ -49,34 +49,35 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
|
|||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
buffer := buf.NewPacket()
|
||||||
n, remoteAddr, err := l.ReadFrom(buf)
|
n, remoteAddr, err := l.ReadFrom(buffer.FreeBytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pool.Put(buf)
|
buffer.Release()
|
||||||
if sl.closed {
|
if sl.closed {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
handleSocksUDP(l, in, buf[:n], remoteAddr)
|
buffer.Extend(n)
|
||||||
|
handleSocksUDP(l, in, buffer, remoteAddr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return sl, nil
|
return sl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) {
|
func handleSocksUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buffer *buf.Buffer, addr net.Addr) {
|
||||||
target, payload, err := socks5.DecodeUDPPacket(buf)
|
buffer.Advance(3)
|
||||||
|
target, err := M.SocksaddrSerializer.ReadAddrPort(buffer)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Unresolved UDP packet, return buffer to the pool
|
// Unresolved UDP packet, return buffer to the pool
|
||||||
pool.Put(buf)
|
buffer.Release()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
packet := &packet{
|
packet := &packet{
|
||||||
pc: pc,
|
pc: pc,
|
||||||
rAddr: addr,
|
rAddr: addr,
|
||||||
payload: payload,
|
payload: buffer,
|
||||||
bufRef: buf,
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case in <- inbound.NewPacket(target, packet, C.SOCKS5):
|
case in <- inbound.NewPacket(target, packet, C.SOCKS5):
|
||||||
|
@ -3,18 +3,19 @@ package socks
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type packet struct {
|
type packet struct {
|
||||||
pc net.PacketConn
|
pc net.PacketConn
|
||||||
rAddr net.Addr
|
rAddr net.Addr
|
||||||
payload []byte
|
payload *buf.Buffer
|
||||||
bufRef []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Data() []byte {
|
func (c *packet) Data() *buf.Buffer {
|
||||||
return c.payload
|
return c.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,11 +28,15 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
return c.pc.WriteTo(packet, c.rAddr)
|
return c.pc.WriteTo(packet, c.rAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *packet) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error {
|
||||||
|
defer buffer.Release()
|
||||||
|
header := buf.With(buffer.ExtendHeader(3 + M.SocksaddrSerializer.AddrPortLen(destination)))
|
||||||
|
common.Must(header.WriteZeroN(3))
|
||||||
|
common.Must(M.SocksaddrSerializer.WriteAddrPort(header, destination))
|
||||||
|
return common.Error(c.pc.WriteTo(buffer.Bytes(), c.rAddr))
|
||||||
|
}
|
||||||
|
|
||||||
// LocalAddr returns the source IP/Port of UDP Packet
|
// LocalAddr returns the source IP/Port of UDP Packet
|
||||||
func (c *packet) LocalAddr() net.Addr {
|
func (c *packet) LocalAddr() net.Addr {
|
||||||
return c.rAddr
|
return c.rAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Drop() {
|
|
||||||
pool.Put(c.bufRef)
|
|
||||||
}
|
|
||||||
|
@ -3,15 +3,16 @@ package tproxy
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type packet struct {
|
type packet struct {
|
||||||
lAddr *net.UDPAddr
|
lAddr *net.UDPAddr
|
||||||
buf []byte
|
buf *buf.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Data() []byte {
|
func (c *packet) Data() *buf.Buffer {
|
||||||
return c.buf
|
return c.buf
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,11 +28,18 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *packet) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
|
||||||
|
defer buffer.Release()
|
||||||
|
tc, err := dialUDP("udp", addr.UDPAddr(), c.lAddr)
|
||||||
|
defer tc.Close()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = tc.Write(buffer.Bytes())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// LocalAddr returns the source IP/Port of UDP Packet
|
// LocalAddr returns the source IP/Port of UDP Packet
|
||||||
func (c *packet) LocalAddr() net.Addr {
|
func (c *packet) LocalAddr() net.Addr {
|
||||||
return c.lAddr
|
return c.lAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Drop() {
|
|
||||||
pool.Put(c.buf)
|
|
||||||
}
|
|
||||||
|
@ -4,9 +4,9 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/adapter/inbound"
|
"github.com/Dreamacro/clash/adapter/inbound"
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type UDPListener struct {
|
type UDPListener struct {
|
||||||
@ -57,10 +57,10 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
|
|||||||
go func() {
|
go func() {
|
||||||
oob := make([]byte, 1024)
|
oob := make([]byte, 1024)
|
||||||
for {
|
for {
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
buffer := buf.NewPacket()
|
||||||
n, oobn, _, lAddr, err := c.ReadMsgUDP(buf, oob)
|
n, oobn, _, lAddr, err := c.ReadMsgUDP(buffer.FreeBytes(), oob)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
pool.Put(buf)
|
buffer.Release()
|
||||||
if rl.closed {
|
if rl.closed {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -71,21 +71,21 @@ func NewUDP(addr string, in chan<- *inbound.PacketAdapter) (*UDPListener, error)
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
handlePacketConn(l, in, buf[:n], lAddr, rAddr)
|
buffer.Extend(n)
|
||||||
|
handlePacketConn(l, in, buffer, lAddr, rAddr)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return rl, nil
|
return rl, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
|
func handlePacketConn(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf *buf.Buffer, lAddr *net.UDPAddr, rAddr *net.UDPAddr) {
|
||||||
target := socks5.ParseAddrToSocksAddr(rAddr)
|
|
||||||
pkt := &packet{
|
pkt := &packet{
|
||||||
lAddr: lAddr,
|
lAddr: lAddr,
|
||||||
buf: buf,
|
buf: buf,
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case in <- inbound.NewPacket(target, pkt, C.TPROXY):
|
case in <- inbound.NewPacket(M.SocksaddrFromNet(rAddr), pkt, C.TPROXY):
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,8 @@ import (
|
|||||||
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
D "github.com/Dreamacro/clash/listener/tun/ipstack/commons"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/Dreamacro/clash/transport/socks5"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ adapter.Handler = (*gvHandler)(nil)
|
var _ adapter.Handler = (*gvHandler)(nil)
|
||||||
@ -96,27 +98,24 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
target := socks5.ParseAddrToSocksAddr(rAddr)
|
target := M.SocksaddrFromNet(rAddr)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
buffer := buf.NewPacket()
|
||||||
|
|
||||||
n, addr, err := tunConn.ReadFrom(buf)
|
n, addr, err := tunConn.ReadFrom(buffer.FreeBytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = pool.Put(buf)
|
buffer.Release()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
buffer.Truncate(n)
|
||||||
payload := buf[:n]
|
|
||||||
|
|
||||||
if D.ShouldHijackDns(gh.dnsHijack, rAddrPort) {
|
if D.ShouldHijackDns(gh.dnsHijack, rAddrPort) {
|
||||||
go func() {
|
go func() {
|
||||||
defer func() {
|
defer buffer.Release()
|
||||||
_ = pool.Put(buf)
|
|
||||||
}()
|
|
||||||
|
|
||||||
msg, err1 := D.RelayDnsPacket(payload)
|
msg, err1 := D.RelayDnsPacket(buffer.Bytes())
|
||||||
if err1 != nil {
|
if err1 != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -130,7 +129,7 @@ func (gh *gvHandler) HandleUDP(tunConn adapter.UDPConn) {
|
|||||||
gvPacket := &packet{
|
gvPacket := &packet{
|
||||||
pc: tunConn,
|
pc: tunConn,
|
||||||
rAddr: addr,
|
rAddr: addr,
|
||||||
payload: payload,
|
payload: buffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
|
@ -5,10 +5,12 @@ package gvisor
|
|||||||
import (
|
import (
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/adapter"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/gvisor/option"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
"gvisor.dev/gvisor/pkg/tcpip/adapters/gonet"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
"gvisor.dev/gvisor/pkg/tcpip/stack"
|
||||||
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
"gvisor.dev/gvisor/pkg/tcpip/transport/udp"
|
||||||
@ -51,10 +53,10 @@ func (c *udpConn) ID() *stack.TransportEndpointID {
|
|||||||
type packet struct {
|
type packet struct {
|
||||||
pc adapter.UDPConn
|
pc adapter.UDPConn
|
||||||
rAddr net.Addr
|
rAddr net.Addr
|
||||||
payload []byte
|
payload *buf.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Data() []byte {
|
func (c *packet) Data() *buf.Buffer {
|
||||||
return c.payload
|
return c.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,11 +65,11 @@ func (c *packet) WriteBack(b []byte, _ net.Addr) (n int, err error) {
|
|||||||
return c.pc.WriteTo(b, c.rAddr)
|
return c.pc.WriteTo(b, c.rAddr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *packet) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
|
||||||
|
return common.Error(c.pc.WriteTo(buffer.Bytes(), c.rAddr))
|
||||||
|
}
|
||||||
|
|
||||||
// LocalAddr returns the source IP/Port of UDP Packet
|
// LocalAddr returns the source IP/Port of UDP Packet
|
||||||
func (c *packet) LocalAddr() net.Addr {
|
func (c *packet) LocalAddr() net.Addr {
|
||||||
return c.rAddr
|
return c.rAddr
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *packet) Drop() {
|
|
||||||
_ = pool.Put(c.payload)
|
|
||||||
}
|
|
||||||
|
@ -21,7 +21,8 @@ import (
|
|||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars"
|
||||||
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/nat"
|
"github.com/Dreamacro/clash/listener/tun/ipstack/system/mars/nat"
|
||||||
"github.com/Dreamacro/clash/log"
|
"github.com/Dreamacro/clash/log"
|
||||||
"github.com/Dreamacro/clash/transport/socks5"
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
)
|
)
|
||||||
|
|
||||||
type sysStack struct {
|
type sysStack struct {
|
||||||
@ -153,37 +154,37 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
|
|||||||
}(stack.UDP())
|
}(stack.UDP())
|
||||||
|
|
||||||
for !ipStack.closed {
|
for !ipStack.closed {
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
buffer := buf.NewPacket()
|
||||||
|
|
||||||
n, lRAddr, rRAddr, err := stack.UDP().ReadFrom(buf)
|
n, lRAddr, rRAddr, err := stack.UDP().ReadFrom(buffer.FreeBytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = pool.Put(buf)
|
buffer.Release()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
buffer.Truncate(n)
|
||||||
|
|
||||||
raw := buf[:n]
|
|
||||||
lAddr := lRAddr.(*net.UDPAddr)
|
lAddr := lRAddr.(*net.UDPAddr)
|
||||||
rAddr := rRAddr.(*net.UDPAddr)
|
rAddr := rRAddr.(*net.UDPAddr)
|
||||||
|
|
||||||
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
rAddrPort := netip.AddrPortFrom(nnip.IpToAddr(rAddr.IP), uint16(rAddr.Port))
|
||||||
|
|
||||||
if rAddrPort.Addr().IsLoopback() || rAddrPort.Addr() == gateway {
|
if rAddrPort.Addr().IsLoopback() || rAddrPort.Addr() == gateway {
|
||||||
_ = pool.Put(buf)
|
buffer.Release()
|
||||||
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
|
if D.ShouldHijackDns(dnsAddr, rAddrPort) {
|
||||||
go func() {
|
go func() {
|
||||||
msg, err := D.RelayDnsPacket(raw)
|
msg, err := D.RelayDnsPacket(buffer.Bytes())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_ = pool.Put(buf)
|
buffer.Release()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _ = stack.UDP().WriteTo(msg, rAddr, lAddr)
|
_, _ = stack.UDP().WriteTo(msg, rAddr, lAddr)
|
||||||
|
|
||||||
_ = pool.Put(buf)
|
buffer.Release()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
continue
|
continue
|
||||||
@ -191,17 +192,14 @@ func New(device device.Device, dnsHijack []netip.AddrPort, tunAddress netip.Pref
|
|||||||
|
|
||||||
pkt := &packet{
|
pkt := &packet{
|
||||||
local: lAddr,
|
local: lAddr,
|
||||||
data: raw,
|
data: buffer,
|
||||||
writeBack: func(b []byte, addr net.Addr) (int, error) {
|
writeBack: func(b []byte, addr net.Addr) (int, error) {
|
||||||
return stack.UDP().WriteTo(b, rAddr, lAddr)
|
return stack.UDP().WriteTo(b, rAddr, lAddr)
|
||||||
},
|
},
|
||||||
drop: func() {
|
|
||||||
_ = pool.Put(buf)
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case udpIn <- inbound.NewPacket(socks5.ParseAddrToSocksAddr(rAddr), pkt, C.TUN):
|
case udpIn <- inbound.NewPacket(M.SocksaddrFromNet(rAddr), pkt, C.TUN):
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
package system
|
package system
|
||||||
|
|
||||||
import "net"
|
import (
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
)
|
||||||
|
|
||||||
type packet struct {
|
type packet struct {
|
||||||
local *net.UDPAddr
|
local *net.UDPAddr
|
||||||
data []byte
|
data *buf.Buffer
|
||||||
writeBack func(b []byte, addr net.Addr) (int, error)
|
writeBack func(b []byte, addr net.Addr) (int, error)
|
||||||
drop func()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *packet) Data() []byte {
|
func (pkt *packet) Data() *buf.Buffer {
|
||||||
return pkt.data
|
return pkt.data
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -17,8 +22,9 @@ func (pkt *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) {
|
|||||||
return pkt.writeBack(b, addr)
|
return pkt.writeBack(b, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *packet) Drop() {
|
func (pkt *packet) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
|
||||||
pkt.drop()
|
defer buffer.Release()
|
||||||
|
return common.Error(pkt.writeBack(buffer.Bytes(), addr.UDPAddr()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pkt *packet) LocalAddr() net.Addr {
|
func (pkt *packet) LocalAddr() net.Addr {
|
||||||
|
@ -61,7 +61,7 @@ require (
|
|||||||
github.com/prometheus/client_model v0.2.0 // indirect
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
github.com/prometheus/common v0.32.1 // indirect
|
github.com/prometheus/common v0.32.1 // indirect
|
||||||
github.com/prometheus/procfs v0.7.3 // indirect
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
github.com/sagernet/sing v0.0.0-20220609091055-86d0144940e7 // indirect
|
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159 // indirect
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 // indirect
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 // indirect
|
||||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/tobyxdd/hysteria v1.0.4 // indirect
|
github.com/tobyxdd/hysteria v1.0.4 // indirect
|
||||||
|
@ -323,8 +323,8 @@ github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0
|
|||||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
github.com/sagernet/sing v0.0.0-20220609091055-86d0144940e7 h1:Q+uNKLNSKqpx+p96qcBTVFh8RUKiQFr4IrNVi5Q5yl0=
|
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159 h1:G3fww5jjADkHWi6yDOEzkZbQ6lnrytv0mKesBtEslxo=
|
||||||
github.com/sagernet/sing v0.0.0-20220609091055-86d0144940e7/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
|
github.com/sagernet/sing v0.0.0-20220609123159-a93588755159/go.mod h1:w2HnJzXKHpD6F5Z/9XlSD4qbcpHY2RSZuQnFzqgELMg=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 h1:bQN0hjTHdB7SyaD9yjEYAl+bDl/kXW9zC0xNa+LMTrA=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13 h1:bQN0hjTHdB7SyaD9yjEYAl+bDl/kXW9zC0xNa+LMTrA=
|
||||||
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
|
github.com/sagernet/sing-shadowsocks v0.0.0-20220609092835-699292971c13/go.mod h1:Fp/9+odJhtgDmiHbZClMLnxaVvmDRJxwA7u/+uXWDiQ=
|
||||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||||
|
@ -1,19 +1,20 @@
|
|||||||
package tunnel
|
package tunnel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"net"
|
"net"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
N "github.com/Dreamacro/clash/common/net"
|
cN "github.com/Dreamacro/clash/common/net"
|
||||||
"github.com/Dreamacro/clash/common/pool"
|
|
||||||
"github.com/Dreamacro/clash/component/resolver"
|
"github.com/Dreamacro/clash/component/resolver"
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
|
"github.com/sagernet/sing/common"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
|
N "github.com/sagernet/sing/common/network"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
|
func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error {
|
||||||
defer packet.Drop()
|
defer packet.Data().Release()
|
||||||
|
|
||||||
// local resolve UDP dns
|
// local resolve UDP dns
|
||||||
if !metadata.Resolved() {
|
if !metadata.Resolved() {
|
||||||
ip, err := resolver.ResolveIP(metadata.Host)
|
ip, err := resolver.ResolveIP(metadata.Host)
|
||||||
@ -23,12 +24,7 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
|
|||||||
metadata.DstIP = ip
|
metadata.DstIP = ip
|
||||||
}
|
}
|
||||||
|
|
||||||
addr := metadata.UDPAddr()
|
if err := pc.WritePacket(packet.Data(), metadata.Socksaddr()); err != nil {
|
||||||
if addr == nil {
|
|
||||||
return errors.New("udp addr invalid")
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := pc.WriteTo(packet.Data(), addr); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// reset timeout
|
// reset timeout
|
||||||
@ -37,30 +33,45 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, fAddr net.Addr) {
|
func handleUDPToLocal(packet C.UDPPacket, pc C.PacketConn, key string, fAddr net.Addr) {
|
||||||
buf := pool.Get(pool.UDPBufferSize)
|
|
||||||
defer pool.Put(buf)
|
|
||||||
defer natTable.Delete(key)
|
defer natTable.Delete(key)
|
||||||
defer pc.Close()
|
defer pc.Close()
|
||||||
|
var fSocksaddr M.Socksaddr
|
||||||
for {
|
if fAddr != nil {
|
||||||
pc.SetReadDeadline(time.Now().Add(udpTimeout))
|
fSocksaddr = M.SocksaddrFromNet(fAddr)
|
||||||
n, from, err := pc.ReadFrom(buf)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if fAddr != nil {
|
|
||||||
from = fAddr
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err = packet.WriteBack(buf[:n], from)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
_, _ = copyPacketTimeout(packet, pc, udpTimeout, fSocksaddr, fAddr != nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleSocket(ctx C.ConnContext, outbound net.Conn) {
|
func handleSocket(ctx C.ConnContext, outbound net.Conn) {
|
||||||
N.Relay(ctx.Conn(), outbound)
|
cN.Relay(ctx.Conn(), outbound)
|
||||||
|
}
|
||||||
|
|
||||||
|
func copyPacketTimeout(dst N.PacketWriter, src N.TimeoutPacketReader, timeout time.Duration, fAddr M.Socksaddr, fOverride bool) (n int64, err error) {
|
||||||
|
_buffer := buf.StackNewPacket()
|
||||||
|
defer common.KeepAlive(_buffer)
|
||||||
|
buffer := common.Dup(_buffer)
|
||||||
|
buffer.IncRef()
|
||||||
|
defer buffer.DecRef()
|
||||||
|
var destination M.Socksaddr
|
||||||
|
for {
|
||||||
|
buffer.Reset()
|
||||||
|
err = src.SetReadDeadline(time.Now().Add(timeout))
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
destination, err = src.ReadPacket(buffer)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if fOverride {
|
||||||
|
destination = fAddr
|
||||||
|
}
|
||||||
|
dataLen := buffer.Len()
|
||||||
|
err = dst.WritePacket(buffer, destination)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
n += int64(dataLen)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
|
|
||||||
C "github.com/Dreamacro/clash/constant"
|
C "github.com/Dreamacro/clash/constant"
|
||||||
"github.com/gofrs/uuid"
|
"github.com/gofrs/uuid"
|
||||||
|
"github.com/sagernet/sing/common/buf"
|
||||||
|
M "github.com/sagernet/sing/common/metadata"
|
||||||
"go.uber.org/atomic"
|
"go.uber.org/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -115,6 +117,25 @@ func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) {
|
|||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ut *udpTracker) ReadPacket(buffer *buf.Buffer) (addr M.Socksaddr, err error) {
|
||||||
|
addr, err = ut.PacketConn.ReadPacket(buffer)
|
||||||
|
download := int64(buffer.Len())
|
||||||
|
ut.manager.PushDownloaded(download)
|
||||||
|
ut.DownloadTotal.Add(download)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ut *udpTracker) WritePacket(buffer *buf.Buffer, addr M.Socksaddr) error {
|
||||||
|
dataLen := buffer.Len()
|
||||||
|
err := ut.PacketConn.WritePacket(buffer, addr)
|
||||||
|
if err == nil {
|
||||||
|
upload := int64(dataLen)
|
||||||
|
ut.manager.PushUploaded(upload)
|
||||||
|
ut.UploadTotal.Add(upload)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func (ut *udpTracker) Close() error {
|
func (ut *udpTracker) Close() error {
|
||||||
ut.manager.Leave(ut)
|
ut.manager.Leave(ut)
|
||||||
return ut.PacketConn.Close()
|
return ut.PacketConn.Close()
|
||||||
|
Loading…
Reference in New Issue
Block a user