Skip to content

Commit

Permalink
Improve: udp NAT type
Browse files Browse the repository at this point in the history
  • Loading branch information
Dreamacro committed Jan 31, 2020
1 parent aa207ec commit 26ce3e8
Show file tree
Hide file tree
Showing 18 changed files with 71 additions and 108 deletions.
4 changes: 2 additions & 2 deletions adapters/inbound/packet.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ func (s *PacketAdapter) Metadata() *C.Metadata {
}

// NewPacket is PacketAdapter generator
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, netType C.NetWork) *PacketAdapter {
func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type) *PacketAdapter {
metadata := parseSocksAddr(target)
metadata.NetWork = netType
metadata.NetWork = C.UDP
metadata.Type = source
if ip, port, err := parseAddr(packet.LocalAddr().String()); err == nil {
metadata.SrcIP = ip
Expand Down
4 changes: 2 additions & 2 deletions adapters/outbound/base.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ func (b *Base) Type() C.AdapterType {
return b.tp
}

func (b *Base) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
return nil, nil, errors.New("no support")
func (b *Base) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
return nil, errors.New("no support")
}

func (b *Base) SupportUDP() bool {
Expand Down
11 changes: 3 additions & 8 deletions adapters/outbound/direct.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,12 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return newConn(c, d), nil
}

func (d *Direct) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
func (d *Direct) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := net.ListenPacket("udp", "")
if err != nil {
return nil, nil, err
}

addr, err := resolveUDPAddr("udp", metadata.RemoteAddress())
if err != nil {
return nil, nil, err
return nil, err
}
return newPacketConn(pc, d), addr, nil
return newPacketConn(pc, d), nil
}

func NewDirect() *Direct {
Expand Down
4 changes: 2 additions & 2 deletions adapters/outbound/reject.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return newConn(&NopConn{}, r), nil
}

func (r *Reject) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
return nil, nil, errors.New("match reject rule")
func (r *Reject) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
return nil, errors.New("match reject rule")
}

func NewReject() *Reject {
Expand Down
19 changes: 7 additions & 12 deletions adapters/outbound/shadowsocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,19 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata) (C
return newConn(c, ss), err
}

func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := net.ListenPacket("udp", "")
if err != nil {
return nil, nil, err
return nil, err
}

addr, err := resolveUDPAddr("udp", ss.server)
if err != nil {
return nil, nil, err
}

targetAddr := socks5.ParseAddr(metadata.RemoteAddress())
if targetAddr == nil {
return nil, nil, fmt.Errorf("parse address %s error: %s", metadata.String(), metadata.DstPort)
return nil, err
}

pc = ss.cipher.PacketConn(pc)
return newPacketConn(&ssUDPConn{PacketConn: pc, rAddr: targetAddr}, ss), addr, nil
return newPacketConn(&ssUDPConn{PacketConn: pc, rAddr: addr}, ss), nil
}

func (ss *ShadowSocks) MarshalJSON() ([]byte, error) {
Expand Down Expand Up @@ -189,15 +184,15 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) {

type ssUDPConn struct {
net.PacketConn
rAddr socks5.Addr
rAddr net.Addr
}

func (uc *ssUDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
packet, err := socks5.EncodeUDPPacket(uc.rAddr, b)
packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
if err != nil {
return
}
return uc.PacketConn.WriteTo(packet[3:], addr)
return uc.PacketConn.WriteTo(packet[3:], uc.rAddr)
}

func (uc *ssUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
Expand Down
20 changes: 5 additions & 15 deletions adapters/outbound/socks5.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn
return newConn(c, ss), nil
}

func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, _ net.Addr, err error) {
func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, err error) {
ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
defer cancel()
c, err := dialContext(ctx, "tcp", ss.addr)
Expand Down Expand Up @@ -96,16 +96,6 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, _ net.Addr, err
return
}

addr, err := net.ResolveUDPAddr("udp", bindAddr.String())
if err != nil {
return
}

targetAddr := socks5.ParseAddr(metadata.RemoteAddress())
if targetAddr == nil {
return nil, nil, fmt.Errorf("parse address %s error: %s", metadata.String(), metadata.DstPort)
}

pc, err := net.ListenPacket("udp", "")
if err != nil {
return
Expand All @@ -119,7 +109,7 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ C.PacketConn, _ net.Addr, err
pc.Close()
}()

return newPacketConn(&socksUDPConn{PacketConn: pc, rAddr: targetAddr, tcpConn: c}, ss), addr, nil
return newPacketConn(&socksUDPConn{PacketConn: pc, rAddr: bindAddr.UDPAddr(), tcpConn: c}, ss), nil
}

func NewSocks5(option Socks5Option) *Socks5 {
Expand Down Expand Up @@ -149,16 +139,16 @@ func NewSocks5(option Socks5Option) *Socks5 {

type socksUDPConn struct {
net.PacketConn
rAddr socks5.Addr
rAddr net.Addr
tcpConn net.Conn
}

func (uc *socksUDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
packet, err := socks5.EncodeUDPPacket(uc.rAddr, b)
packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
if err != nil {
return
}
return uc.PacketConn.WriteTo(packet, addr)
return uc.PacketConn.WriteTo(packet, uc.rAddr)
}

func (uc *socksUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
Expand Down
8 changes: 4 additions & 4 deletions adapters/outbound/vmess.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,19 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata) (C.Conn,
return newConn(c, v), err
}

func (v *Vmess) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
func (v *Vmess) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
ctx, cancel := context.WithTimeout(context.Background(), tcpTimeout)
defer cancel()
c, err := dialContext(ctx, "tcp", v.server)
if err != nil {
return nil, nil, fmt.Errorf("%s connect error", v.server)
return nil, fmt.Errorf("%s connect error", v.server)
}
tcpKeepAlive(c)
c, err = v.client.New(c, parseVmessAddr(metadata))
if err != nil {
return nil, nil, fmt.Errorf("new vmess client error: %v", err)
return nil, fmt.Errorf("new vmess client error: %v", err)
}
return newPacketConn(&vmessUDPConn{Conn: c}, v), c.RemoteAddr(), nil
return newPacketConn(&vmessUDPConn{Conn: c}, v), nil
}

func NewVmess(option VmessOption) (*Vmess, error) {
Expand Down
7 changes: 3 additions & 4 deletions adapters/outboundgroup/fallback.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package outboundgroup
import (
"context"
"encoding/json"
"net"

"github.com/Dreamacro/clash/adapters/outbound"
"github.com/Dreamacro/clash/adapters/provider"
Expand Down Expand Up @@ -31,13 +30,13 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
return c, err
}

func (f *Fallback) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
func (f *Fallback) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
proxy := f.findAliveProxy()
pc, addr, err := proxy.DialUDP(metadata)
pc, err := proxy.DialUDP(metadata)
if err == nil {
pc.AppendToChains(f)
}
return pc, addr, err
return pc, err
}

func (f *Fallback) SupportUDP() bool {
Expand Down
2 changes: 1 addition & 1 deletion adapters/outboundgroup/loadbalance.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata) (c
return
}

func (lb *LoadBalance) DialUDP(metadata *C.Metadata) (pc C.PacketConn, addr net.Addr, err error) {
func (lb *LoadBalance) DialUDP(metadata *C.Metadata) (pc C.PacketConn, err error) {
defer func() {
if err == nil {
pc.AppendToChains(lb)
Expand Down
7 changes: 3 additions & 4 deletions adapters/outboundgroup/selector.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"errors"
"net"

"github.com/Dreamacro/clash/adapters/outbound"
"github.com/Dreamacro/clash/adapters/provider"
Expand All @@ -27,12 +26,12 @@ func (s *Selector) DialContext(ctx context.Context, metadata *C.Metadata) (C.Con
return c, err
}

func (s *Selector) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
pc, addr, err := s.selected.DialUDP(metadata)
func (s *Selector) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := s.selected.DialUDP(metadata)
if err == nil {
pc.AppendToChains(s)
}
return pc, addr, err
return pc, err
}

func (s *Selector) SupportUDP() bool {
Expand Down
7 changes: 3 additions & 4 deletions adapters/outboundgroup/urltest.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package outboundgroup
import (
"context"
"encoding/json"
"net"
"time"

"github.com/Dreamacro/clash/adapters/outbound"
Expand Down Expand Up @@ -31,12 +30,12 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata) (c C.Co
return c, err
}

func (u *URLTest) DialUDP(metadata *C.Metadata) (C.PacketConn, net.Addr, error) {
pc, addr, err := u.fast().DialUDP(metadata)
func (u *URLTest) DialUDP(metadata *C.Metadata) (C.PacketConn, error) {
pc, err := u.fast().DialUDP(metadata)
if err == nil {
pc.AppendToChains(u)
}
return pc, addr, err
return pc, err
}

func (u *URLTest) proxies() []C.Proxy {
Expand Down
20 changes: 5 additions & 15 deletions component/nat/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,26 +9,16 @@ type Table struct {
mapping sync.Map
}

type element struct {
RemoteAddr net.Addr
RemoteConn net.PacketConn
func (t *Table) Set(key string, pc net.PacketConn) {
t.mapping.Store(key, pc)
}

func (t *Table) Set(key string, pc net.PacketConn, addr net.Addr) {
// set conn read timeout
t.mapping.Store(key, &element{
RemoteConn: pc,
RemoteAddr: addr,
})
}

func (t *Table) Get(key string) (net.PacketConn, net.Addr) {
func (t *Table) Get(key string) net.PacketConn {
item, exist := t.mapping.Load(key)
if !exist {
return nil, nil
return nil
}
elm := item.(*element)
return elm.RemoteConn, elm.RemoteAddr
return item.(net.PacketConn)
}

func (t *Table) GetOrCreateLock(key string) (*sync.WaitGroup, bool) {
Expand Down
2 changes: 1 addition & 1 deletion constant/adapters.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ type ProxyAdapter interface {
Name() string
Type() AdapterType
DialContext(ctx context.Context, metadata *Metadata) (Conn, error)
DialUDP(metadata *Metadata) (PacketConn, net.Addr, error)
DialUDP(metadata *Metadata) (PacketConn, error)
SupportUDP() bool
MarshalJSON() ([]byte, error)
}
Expand Down
12 changes: 12 additions & 0 deletions constant/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package constant
import (
"encoding/json"
"net"
"strconv"
)

// Socks addr type
Expand Down Expand Up @@ -70,6 +71,17 @@ func (m *Metadata) RemoteAddress() string {
return net.JoinHostPort(m.String(), m.DstPort)
}

func (m *Metadata) UDPAddr() *net.UDPAddr {
if m.NetWork != UDP || m.DstIP == nil {
return nil
}
port, _ := strconv.Atoi(m.DstPort)
return &net.UDPAddr{
IP: m.DstIP,
Port: port,
}
}

func (m *Metadata) String() string {
if m.Host != "" {
return m.Host
Expand Down
5 changes: 2 additions & 3 deletions proxy/socks/udp.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,9 @@ func handleSocksUDP(pc net.PacketConn, buf []byte, addr net.Addr) {
}
packet := &fakeConn{
PacketConn: pc,
remoteAddr: addr,
targetAddr: target,
rAddr: addr,
payload: payload,
bufRef: buf,
}
tun.AddPacket(adapters.NewPacket(target, packet, C.SOCKS, C.UDP))
tun.AddPacket(adapters.NewPacket(target, packet, C.SOCKS))
}
21 changes: 7 additions & 14 deletions proxy/socks/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,9 @@ import (

type fakeConn struct {
net.PacketConn
remoteAddr net.Addr
targetAddr socks5.Addr
payload []byte
bufRef []byte
rAddr net.Addr
payload []byte
bufRef []byte
}

func (c *fakeConn) Data() []byte {
Expand All @@ -21,25 +20,19 @@ func (c *fakeConn) Data() []byte {

// WriteBack wirtes UDP packet with source(ip, port) = `addr`
func (c *fakeConn) WriteBack(b []byte, addr net.Addr) (n int, err error) {
from := c.targetAddr
if addr != nil {
// if addr is provided, use the parsed addr
from = socks5.ParseAddrToSocksAddr(addr)
}
packet, err := socks5.EncodeUDPPacket(from, b)
packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b)
if err != nil {
return
}
return c.PacketConn.WriteTo(packet, c.remoteAddr)
return c.PacketConn.WriteTo(packet, c.rAddr)
}

// LocalAddr returns the source IP/Port of UDP Packet
func (c *fakeConn) LocalAddr() net.Addr {
return c.remoteAddr
return c.PacketConn.LocalAddr()
}

func (c *fakeConn) Close() error {
err := c.PacketConn.Close()
pool.BufPool.Put(c.bufRef[:cap(c.bufRef)])
return err
return nil
}
Loading

0 comments on commit 26ce3e8

Please sign in to comment.