Fix(socks5): fully udp associate support (#233)
This commit is contained in:
@ -92,13 +92,13 @@ func (ss *ShadowSocks) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr,
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
remoteAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(metadata.String(), metadata.DstPort))
|
||||
targetAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(metadata.String(), metadata.DstPort))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
pc = ss.cipher.PacketConn(pc)
|
||||
return &ssUDPConn{PacketConn: pc, rAddr: remoteAddr}, addr, nil
|
||||
return &ssUDPConn{PacketConn: pc, rAddr: targetAddr}, addr, nil
|
||||
}
|
||||
|
||||
func (ss *ShadowSocks) MarshalJSON() ([]byte, error) {
|
||||
|
@ -3,6 +3,8 @@ package adapters
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"strconv"
|
||||
|
||||
@ -51,24 +53,31 @@ func (ss *Socks5) Dial(metadata *C.Metadata) (net.Conn, error) {
|
||||
Password: ss.pass,
|
||||
}
|
||||
}
|
||||
if err := socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdConnect, user); err != nil {
|
||||
if _, err := socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdConnect, user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (ss *Socks5) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error) {
|
||||
func (ss *Socks5) DialUDP(metadata *C.Metadata) (_ net.PacketConn, _ net.Addr, err error) {
|
||||
c, err := dialTimeout("tcp", ss.addr, tcpTimeout)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s connect error", ss.addr)
|
||||
return
|
||||
}
|
||||
|
||||
if err == nil && ss.tls {
|
||||
if ss.tls {
|
||||
cc := tls.Client(c, ss.tlsConfig)
|
||||
err = cc.Handshake()
|
||||
c = cc
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("%s connect error", ss.addr)
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
c.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
tcpKeepAlive(c)
|
||||
var user *socks5.User
|
||||
if ss.user != "" {
|
||||
@ -78,10 +87,36 @@ func (ss *Socks5) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error
|
||||
}
|
||||
}
|
||||
|
||||
if err := socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdUDPAssociate, user); err != nil {
|
||||
return nil, nil, err
|
||||
bindAddr, err := socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdUDPAssociate, user)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%v client hanshake error", err)
|
||||
return
|
||||
}
|
||||
return &fakeUDPConn{Conn: c}, c.LocalAddr(), nil
|
||||
|
||||
addr, err := net.ResolveUDPAddr("udp", bindAddr.String())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
targetAddr, err := net.ResolveUDPAddr("udp", net.JoinHostPort(metadata.String(), metadata.DstPort))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
pc, err := net.ListenPacket("udp", "")
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
io.Copy(ioutil.Discard, c)
|
||||
c.Close()
|
||||
// A UDP association terminates when the TCP connection that the UDP
|
||||
// ASSOCIATE request arrived on terminates. RFC1928
|
||||
pc.Close()
|
||||
}()
|
||||
|
||||
return &socksUDPConn{PacketConn: pc, rAddr: targetAddr}, addr, nil
|
||||
}
|
||||
|
||||
func NewSocks5(option Socks5Option) *Socks5 {
|
||||
@ -108,3 +143,26 @@ func NewSocks5(option Socks5Option) *Socks5 {
|
||||
tlsConfig: tlsConfig,
|
||||
}
|
||||
}
|
||||
|
||||
type socksUDPConn struct {
|
||||
net.PacketConn
|
||||
rAddr net.Addr
|
||||
}
|
||||
|
||||
func (uc *socksUDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
|
||||
packet, err := socks5.EncodeUDPPacket(uc.rAddr.String(), b)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
return uc.PacketConn.WriteTo(packet, addr)
|
||||
}
|
||||
|
||||
func (uc *socksUDPConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||
n, a, e := uc.PacketConn.ReadFrom(b)
|
||||
addr, payload, err := socks5.DecodeUDPPacket(b)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
copy(b, payload)
|
||||
return n - len(addr) - 3, a, e
|
||||
}
|
||||
|
@ -48,7 +48,10 @@ func (v *Vmess) DialUDP(metadata *C.Metadata) (net.PacketConn, net.Addr, error)
|
||||
}
|
||||
tcpKeepAlive(c)
|
||||
c, err = v.client.New(c, parseVmessAddr(metadata))
|
||||
return &fakeUDPConn{Conn: c}, c.LocalAddr(), err
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("new vmess client error: %v", err)
|
||||
}
|
||||
return &fakeUDPConn{Conn: c}, c.RemoteAddr(), nil
|
||||
}
|
||||
|
||||
func NewVmess(option VmessOption) (*Vmess, error) {
|
||||
@ -74,7 +77,7 @@ func NewVmess(option VmessOption) (*Vmess, error) {
|
||||
Base: &Base{
|
||||
name: option.Name,
|
||||
tp: C.Vmess,
|
||||
udp: option.UDP,
|
||||
udp: true,
|
||||
},
|
||||
server: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)),
|
||||
client: client,
|
||||
|
Reference in New Issue
Block a user