Compare commits

..

3 Commits

Author SHA1 Message Date
1d6d419f86 fix(修复异常): 修复无法区分无数据和出错
/ build (push) Successful in 5m36s
2026-01-22 16:22:44 +08:00
2be0a4a40b feat(协议支持): 更好的支持IPv6 2026-01-22 16:17:25 +08:00
1c2dea15f9 fix(修复功能): 修复IPv6支持 2026-01-22 16:05:28 +08:00
4 changed files with 50 additions and 21 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ func main() {
var err error var err error
if s5 != "" { if s5 != "" {
fmt.Printf("通过代理探测: %s\n", s5) fmt.Printf("通过代理探测: %s\n", s5)
conn, err = DialSocks5UDP(s5) conn, err = DialSocks5UDP(s5, network)
if err != nil { if err != nil {
fmt.Printf("连接代理失败: %v\n", err) fmt.Printf("连接代理失败: %v\n", err)
return return
+15 -2
View File
@@ -103,7 +103,9 @@ func performTest(conn net.PacketConn, serverAddr string, network string, timeout
return nil, nil, err return nil, nil, err
} }
txID := [12]byte{} txID := [12]byte{}
rand.Read(txID[:]) if _, err := rand.Read(txID[:]); err != nil {
return nil, nil, err
}
req := encodeSTUNRequest(txID, changeIP, changePort) req := encodeSTUNRequest(txID, changeIP, changePort)
if _, err := conn.WriteTo(req, dst); err != nil { if _, err := conn.WriteTo(req, dst); err != nil {
return nil, nil, err return nil, nil, err
@@ -147,6 +149,14 @@ func DetectNAT(conn net.PacketConn, primarySTUN, secondarySTUN, network string,
return res return res
} }
res.MappedIP = mappedAddr1.String() res.MappedIP = mappedAddr1.String()
if localAddr, ok := conn.LocalAddr().(*net.UDPAddr); ok {
if localAddr.IP.Equal(mappedAddr1.IP) && localAddr.Port == mappedAddr1.Port {
res.Type = NATOpen
res.Mapping = MappingEndpointIndependent
res.Filtering = FilteringEndpointIndependent
return res
}
}
var targetSTUN2 string var targetSTUN2 string
if secondarySTUN != "" { if secondarySTUN != "" {
targetSTUN2 = secondarySTUN targetSTUN2 = secondarySTUN
@@ -158,7 +168,10 @@ func DetectNAT(conn net.PacketConn, primarySTUN, secondarySTUN, network string,
host, port, _ := net.SplitHostPort(primarySTUN) host, port, _ := net.SplitHostPort(primarySTUN)
ips, err := net.LookupIP(host) ips, err := net.LookupIP(host)
if err == nil && len(ips) > 1 { if err == nil && len(ips) > 1 {
primaryIP, _ := net.ResolveIPAddr("ip", host) primaryIP, err := net.ResolveIPAddr("ip", host)
if err != nil {
return res
}
wantIPv4 := network == "udp4" wantIPv4 := network == "udp4"
wantIPv6 := network == "udp6" wantIPv6 := network == "udp6"
if network == "udp" { if network == "udp" {
+20 -7
View File
@@ -58,7 +58,7 @@ func (c *socks5PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
return 0, nil, err return 0, nil, err
} }
if n < 10 { if n < 10 {
return 0, nil, nil return 0, nil, errors.New("packet too short")
} }
atyp := buf[3] atyp := buf[3]
var rAddr *net.UDPAddr var rAddr *net.UDPAddr
@@ -93,6 +93,8 @@ func (c *socks5PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error)
port := binary.BigEndian.Uint16(buf[20:22]) port := binary.BigEndian.Uint16(buf[20:22])
rAddr = &net.UDPAddr{IP: ip, Port: int(port)} rAddr = &net.UDPAddr{IP: ip, Port: int(port)}
dataOffset = 22 dataOffset = 22
default:
return 0, nil, fmt.Errorf("unknown address type: 0x%x", atyp)
} }
copy(p, buf[dataOffset:n]) copy(p, buf[dataOffset:n])
return n - dataOffset, rAddr, nil return n - dataOffset, rAddr, nil
@@ -142,8 +144,12 @@ func (c *socks5PacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) {
// Close 关闭连接 // Close 关闭连接
// 返回: err 关闭错误 // 返回: err 关闭错误
func (c *socks5PacketConn) Close() error { func (c *socks5PacketConn) Close() error {
c.tcpConn.Close() err1 := c.tcpConn.Close()
return c.udpConn.Close() err2 := c.udpConn.Close()
if err1 != nil {
return err1
}
return err2
} }
// LocalAddr 获取本地地址 // LocalAddr 获取本地地址
@@ -174,9 +180,9 @@ func (c *socks5PacketConn) SetWriteDeadline(t time.Time) error {
} }
// DialSocks5UDP 建立SOCKS5 UDP关联 // DialSocks5UDP 建立SOCKS5 UDP关联
// 入参: proxyAddr 代理服务器地址 // 入参: proxyAddr 代理服务器地址, network 网络协议(udp/udp4/udp6)
// 返回: conn 数据包连接, err 连接错误 // 返回: conn 数据包连接, err 连接错误
func DialSocks5UDP(proxyAddr string) (net.PacketConn, error) { func DialSocks5UDP(proxyAddr, network string) (net.PacketConn, error) {
var host string var host string
if strings.Contains(proxyAddr, "://") { if strings.Contains(proxyAddr, "://") {
u, err := url.Parse(proxyAddr) u, err := url.Parse(proxyAddr)
@@ -187,7 +193,14 @@ func DialSocks5UDP(proxyAddr string) (net.PacketConn, error) {
} else { } else {
host = proxyAddr host = proxyAddr
} }
conn, err := net.DialTimeout("tcp", host, 5*time.Second) tcpNetwork := "tcp"
switch network {
case "udp4":
tcpNetwork = "tcp4"
case "udp6":
tcpNetwork = "tcp6"
}
conn, err := net.DialTimeout(tcpNetwork, host, 5*time.Second)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@@ -266,7 +279,7 @@ func DialSocks5UDP(proxyAddr string) (net.PacketConn, error) {
} }
} }
relayAddr := &net.UDPAddr{IP: relayIP, Port: relayPort} relayAddr := &net.UDPAddr{IP: relayIP, Port: relayPort}
lConn, err := net.ListenUDP("udp", nil) lConn, err := net.ListenUDP(network, nil)
if err != nil { if err != nil {
conn.Close() conn.Close()
return nil, err return nil, err
+10 -7
View File
@@ -136,9 +136,9 @@ func decodeSTUNResponse(data []byte, txID [12]byte) (*stunMessage, error) {
} }
// parseAddress 解析STUN属性中的地址信息 // parseAddress 解析STUN属性中的地址信息
// 入参: attrType 属性类型, data 属性值数据 // 入参: attrType 属性类型, data 属性值数据, txID 事务ID用于XOR解码
// 返回: addr 解析出的UDP地址, err 解析错误信息 // 返回: addr 解析出的UDP地址, err 解析错误信息
func parseAddress(attrType uint16, data []byte) (*net.UDPAddr, error) { func parseAddress(attrType uint16, data []byte, txID [12]byte) (*net.UDPAddr, error) {
if len(data) < 4 { if len(data) < 4 {
return nil, errors.New("attribute too short") return nil, errors.New("attribute too short")
} }
@@ -157,12 +157,15 @@ func parseAddress(attrType uint16, data []byte) (*net.UDPAddr, error) {
copy(ip, data[4:4+ipLen]) copy(ip, data[4:4+ipLen])
if attrType == attrXorMappedAddress { if attrType == attrXorMappedAddress {
port ^= uint16(stunMagicCookie >> 16) port ^= uint16(stunMagicCookie >> 16)
if ipLen == 4 {
mc := make([]byte, 4) mc := make([]byte, 4)
binary.BigEndian.PutUint32(mc, stunMagicCookie) binary.BigEndian.PutUint32(mc, stunMagicCookie)
for i := 0; i < 4; i++ { for i := 0; i < 4; i++ {
ip[i] ^= mc[i] ip[i] ^= mc[i]
} }
if ipLen == 16 {
for i := 4; i < 16; i++ {
ip[i] ^= txID[i-4]
}
} }
} }
return &net.UDPAddr{IP: ip, Port: int(port)}, nil return &net.UDPAddr{IP: ip, Port: int(port)}, nil
@@ -173,14 +176,14 @@ func parseAddress(attrType uint16, data []byte) (*net.UDPAddr, error) {
func (m *stunMessage) GetMappedAddress() *net.UDPAddr { func (m *stunMessage) GetMappedAddress() *net.UDPAddr {
for _, attr := range m.Attributes { for _, attr := range m.Attributes {
if attr.Type == attrXorMappedAddress { if attr.Type == attrXorMappedAddress {
if addr, err := parseAddress(attr.Type, attr.Value); err == nil { if addr, err := parseAddress(attr.Type, attr.Value, m.Header.ID); err == nil {
return addr return addr
} }
} }
} }
for _, attr := range m.Attributes { for _, attr := range m.Attributes {
if attr.Type == attrMappedAddress { if attr.Type == attrMappedAddress {
if addr, err := parseAddress(attr.Type, attr.Value); err == nil { if addr, err := parseAddress(attr.Type, attr.Value, m.Header.ID); err == nil {
return addr return addr
} }
} }
@@ -193,14 +196,14 @@ func (m *stunMessage) GetMappedAddress() *net.UDPAddr {
func (m *stunMessage) GetChangedAddress() *net.UDPAddr { func (m *stunMessage) GetChangedAddress() *net.UDPAddr {
for _, attr := range m.Attributes { for _, attr := range m.Attributes {
if attr.Type == attrChangedAddress { if attr.Type == attrChangedAddress {
if addr, err := parseAddress(attr.Type, attr.Value); err == nil { if addr, err := parseAddress(attr.Type, attr.Value, m.Header.ID); err == nil {
return addr return addr
} }
} }
} }
for _, attr := range m.Attributes { for _, attr := range m.Attributes {
if attr.Type == attrOtherAddress { if attr.Type == attrOtherAddress {
if addr, err := parseAddress(attr.Type, attr.Value); err == nil { if addr, err := parseAddress(attr.Type, attr.Value, m.Header.ID); err == nil {
return addr return addr
} }
} }