Improve(socks5): unify addr parsing

This commit is contained in:
xjasonlyu
2022-02-06 19:48:12 +08:00
parent cc56100f15
commit 1b38ce2d25
4 changed files with 49 additions and 85 deletions

View File

@@ -1,12 +1,8 @@
package metadata package metadata
import ( import (
"bytes"
"encoding/binary"
"net" "net"
"strconv" "strconv"
"github.com/xjasonlyu/tun2socks/v2/transport/socks5"
) )
// Metadata contains metadata of transport protocol sessions. // Metadata contains metadata of transport protocol sessions.
@@ -55,23 +51,6 @@ func (m *Metadata) UDPAddr() *net.UDPAddr {
} }
} }
func (m *Metadata) SerializeSocksAddr() socks5.Addr {
var (
buf [][]byte
port [2]byte
)
binary.BigEndian.PutUint16(port[:], m.DstPort)
if m.DstIP.To4() != nil /* IPv4 */ {
aType := socks5.AtypIPv4
buf = [][]byte{{aType}, m.DstIP.To4(), port[:]}
} else /* IPv6 */ {
aType := socks5.AtypIPv6
buf = [][]byte{{aType}, m.DstIP.To16(), port[:]}
}
return bytes.Join(buf, nil)
}
// Addr implements the net.Addr interface. // Addr implements the net.Addr interface.
type Addr struct { type Addr struct {
metadata *Metadata metadata *Metadata

View File

@@ -61,7 +61,7 @@ func (ss *Shadowsocks) DialContext(ctx context.Context, metadata *M.Metadata) (c
} }
c = ss.cipher.StreamConn(c) c = ss.cipher.StreamConn(c)
_, err = c.Write(metadata.SerializeSocksAddr()) _, err = c.Write(serializeSocksAddr(metadata))
return return
} }
@@ -89,9 +89,9 @@ type ssPacketConn struct {
func (pc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { func (pc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
var packet []byte var packet []byte
if ma, ok := addr.(*M.Addr); ok { if ma, ok := addr.(*M.Addr); ok {
packet, err = socks5.EncodeUDPPacket(ma.Metadata().SerializeSocksAddr(), b) packet, err = socks5.EncodeUDPPacket(serializeSocksAddr(ma.Metadata()), b)
} else { } else {
packet, err = socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) packet, err = socks5.EncodeUDPPacket(socks5.ParseAddr(addr), b)
} }
if err != nil { if err != nil {

View File

@@ -59,7 +59,7 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *M.Metadata) (c net.
} }
} }
_, err = socks5.ClientHandshake(c, metadata.SerializeSocksAddr(), socks5.CmdConnect, user) _, err = socks5.ClientHandshake(c, serializeSocksAddr(metadata), socks5.CmdConnect, user)
return return
} }
@@ -142,9 +142,9 @@ type socksPacketConn struct {
func (pc *socksPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { func (pc *socksPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
var packet []byte var packet []byte
if ma, ok := addr.(*M.Addr); ok { if ma, ok := addr.(*M.Addr); ok {
packet, err = socks5.EncodeUDPPacket(ma.Metadata().SerializeSocksAddr(), b) packet, err = socks5.EncodeUDPPacket(serializeSocksAddr(ma.Metadata()), b)
} else { } else {
packet, err = socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) packet, err = socks5.EncodeUDPPacket(socks5.ParseAddr(addr), b)
} }
if err != nil { if err != nil {
@@ -178,3 +178,7 @@ func (pc *socksPacketConn) Close() error {
pc.tcpConn.Close() pc.tcpConn.Close()
return pc.PacketConn.Close() return pc.PacketConn.Close()
} }
func serializeSocksAddr(m *M.Metadata) socks5.Addr {
return socks5.SerializeAddr("", m.DstIP, m.DstPort)
}

View File

@@ -278,74 +278,55 @@ func SplitAddr(b []byte) Addr {
return b[:addrLen] return b[:addrLen]
} }
// ParseAddr parses the address in string s. Returns nil if failed. // SerializeAddr serializes destination address and port to Addr.
func ParseAddr(s string) Addr { // If a domain name is provided, AtypDomainName would be used first.
func SerializeAddr(domainName string, dstIP net.IP, dstPort uint16) Addr {
var (
buf [][]byte
port [2]byte
)
binary.BigEndian.PutUint16(port[:], dstPort)
if domainName != "" /* Domain Name */ {
length := len(domainName)
buf = [][]byte{{AtypDomainName, uint8(length)}, []byte(domainName), port[:]}
} else if dstIP.To4() != nil /* IPv4 */ {
buf = [][]byte{{AtypIPv4}, dstIP.To4(), port[:]}
} else /* IPv6 */ {
buf = [][]byte{{AtypIPv6}, dstIP.To16(), port[:]}
}
return bytes.Join(buf, nil)
}
// ParseAddr parses a socks addr from net.Addr.
// This is a fast path of ParseAddrString(addr.String())
func ParseAddr(addr net.Addr) Addr {
switch v := addr.(type) {
case *net.TCPAddr:
return SerializeAddr("", v.IP, uint16(v.Port))
case *net.UDPAddr:
return SerializeAddr("", v.IP, uint16(v.Port))
default:
return ParseAddrString(addr.String())
}
}
// ParseAddrString parses the address in string s to Addr. Returns nil if failed.
func ParseAddrString(s string) Addr {
host, port, err := net.SplitHostPort(s) host, port, err := net.SplitHostPort(s)
if err != nil { if err != nil {
return nil return nil
} }
var addr Addr dstPort, err := strconv.ParseUint(port, 10, 16)
if ip := net.ParseIP(host); ip != nil {
if ip4 := ip.To4(); ip4 != nil {
addr = make([]byte, 1+net.IPv4len+2)
addr[0] = AtypIPv4
copy(addr[1:], ip4)
} else {
addr = make([]byte, 1+net.IPv6len+2)
addr[0] = AtypIPv6
copy(addr[1:], ip)
}
} else {
if len(host) > 255 {
return nil
}
addr = make([]byte, 1+1+len(host)+2)
addr[0] = AtypDomainName
addr[1] = byte(len(host))
copy(addr[2:], host)
}
p, err := strconv.ParseUint(port, 10, 16)
if err != nil { if err != nil {
return nil return nil
} }
binary.BigEndian.PutUint16(addr[len(addr)-2:], uint16(p))
return addr if ip := net.ParseIP(host); ip != nil {
} return SerializeAddr("", ip, uint16(dstPort))
// ParseAddrToSocksAddr parse a socks addr from net.addr
// This is a fast path of ParseAddr(addr.String())
func ParseAddrToSocksAddr(addr net.Addr) Addr {
var ip net.IP
var port int
if udpAddr, ok := addr.(*net.UDPAddr); ok {
ip = udpAddr.IP
port = udpAddr.Port
} else if tcpAddr, ok := addr.(*net.TCPAddr); ok {
ip = tcpAddr.IP
port = tcpAddr.Port
} }
return SerializeAddr(host, nil, uint16(dstPort))
// fallback parse
if ip == nil {
return ParseAddr(addr.String())
}
var parsed Addr
if ip4 := ip.To4(); ip4 != nil {
parsed = make([]byte, 1+net.IPv4len+2)
parsed[0] = AtypIPv4
copy(parsed[1:], ip4)
binary.BigEndian.PutUint16(parsed[1+net.IPv4len:], uint16(port))
} else {
parsed = make([]byte, 1+net.IPv6len+2)
parsed[0] = AtypIPv6
copy(parsed[1:], ip)
binary.BigEndian.PutUint16(parsed[1+net.IPv6len:], uint16(port))
}
return parsed
} }
// DecodeUDPPacket split `packet` to addr payload, and this function is mutable with `packet` // DecodeUDPPacket split `packet` to addr payload, and this function is mutable with `packet`