mirror of
https://github.com/SunBK201/UA3F.git
synced 2025-12-16 16:57:08 +00:00
feat: support udp associate
This commit is contained in:
parent
34baa9ecde
commit
467fc515f7
@ -109,6 +109,6 @@ rules:
|
||||
- [x] 支持 LuCI
|
||||
- [x] 优化部署流程
|
||||
- [ ] 支持 SOCK5 Auth
|
||||
- [ ] 支持 UDP
|
||||
- [x] 支持 UDP
|
||||
- [ ] 支持 IPv6
|
||||
- [ ] 性能提升
|
||||
@ -1,11 +1,11 @@
|
||||
971e6a8bac9a149c4c51bf8ae3b2a4bb ./ua3f-0.2.3-386.tar.gz
|
||||
0c6b28a26fb7fd496c2596fad56d806f ./ua3f-0.2.3-amd64.tar.gz
|
||||
eb62d97cbedb95c5749d31840f300cfe ./ua3f-0.2.3-arm.tar.gz
|
||||
f0ed5bd4bf7d735988d184e12842b101 ./ua3f-0.2.3-arm64.tar.gz
|
||||
b997aec1bbc18f0d8bce860162580d31 ./ua3f-0.2.3-armv7.tar.gz
|
||||
f0ed5bd4bf7d735988d184e12842b101 ./ua3f-0.2.3-armv8.tar.gz
|
||||
16c0486a4753e7e6d4dd18ca99be948f ./ua3f-0.2.3-mips64.tar.gz
|
||||
a99e0855e1f42a1b9f316bb7e210cf4e ./ua3f-0.2.3-mipsle-hardfloat.tar.gz
|
||||
b3c68980761d58b1242a160aae91f1d8 ./ua3f-0.2.3-mipsle-softfloat.tar.gz
|
||||
bff8cecc43baa286bdb0ea153ec0144e ./ua3f-0.2.3-mipsle.tar.gz
|
||||
f130bee316c952f039e582fff0831088 ./ua3f-0.2.3-riscv64.tar.gz
|
||||
2e956b0acef25c77b05862242e00e839 ./ua3f-0.3.0-386.tar.gz
|
||||
0365ecb622ad8767b61338de24a94eb0 ./ua3f-0.3.0-amd64.tar.gz
|
||||
b17d821a1e59baba0a169e94e14aa719 ./ua3f-0.3.0-arm.tar.gz
|
||||
651e4b7e66650b967e0a6a6af00e7201 ./ua3f-0.3.0-arm64.tar.gz
|
||||
76f927277bb20b89253e0fe70e8d53c4 ./ua3f-0.3.0-armv7.tar.gz
|
||||
651e4b7e66650b967e0a6a6af00e7201 ./ua3f-0.3.0-armv8.tar.gz
|
||||
ddc6d9ad7c3171dc5a972c3c83aa670e ./ua3f-0.3.0-mips64.tar.gz
|
||||
cdbc9b71b1f7daed024e98703e0aa9c1 ./ua3f-0.3.0-mipsle-hardfloat.tar.gz
|
||||
3c514bb0c3a72bc5a89045328746576f ./ua3f-0.3.0-mipsle-softfloat.tar.gz
|
||||
ec9e3671cdeedd9150724968689e3afc ./ua3f-0.3.0-mipsle.tar.gz
|
||||
37b6239381190e8dbc695e6f8b08cbf8 ./ua3f-0.3.0-riscv64.tar.gz
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
bin/ua3f-0.3.0-386.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-386.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-amd64.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-amd64.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-arm.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-arm.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-arm64.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-arm64.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-armv7.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-armv7.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-armv8.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-armv8.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-mips64.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-mips64.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-mipsle-hardfloat.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-mipsle-hardfloat.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-mipsle-softfloat.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-mipsle-softfloat.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-mipsle.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-mipsle.tar.gz
Normal file
Binary file not shown.
BIN
bin/ua3f-0.3.0-riscv64.tar.gz
Normal file
BIN
bin/ua3f-0.3.0-riscv64.tar.gz
Normal file
Binary file not shown.
2
build.sh
2
build.sh
@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
|
||||
project_name="ua3f"
|
||||
release_version="0.2.3"
|
||||
release_version="0.3.0"
|
||||
target=cmd/ua3f.go
|
||||
|
||||
release_dir=./bin
|
||||
|
||||
180
cmd/ua3f.go
180
cmd/ua3f.go
@ -17,7 +17,7 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var version = "0.2.3"
|
||||
var version = "0.3.0"
|
||||
var payloadByte []byte
|
||||
var cache *expirable.LRU[string, string]
|
||||
var HTTP_METHOD = []string{"GET", "POST", "HEAD", "PUT", "DELETE", "OPTIONS", "TRACE", "CONNECT"}
|
||||
@ -91,6 +91,12 @@ func process(client net.Conn) {
|
||||
}
|
||||
target, destAddrPort, err := Socks5Connect(client)
|
||||
if err != nil {
|
||||
// UDP
|
||||
if strings.Contains(err.Error(), "UDP Associate") {
|
||||
Socks5UDP(client)
|
||||
client.Close()
|
||||
return
|
||||
}
|
||||
logrus.Error("Connect failed: ", err)
|
||||
client.Close()
|
||||
return
|
||||
@ -128,48 +134,134 @@ func Socks5Auth(client net.Conn) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// func Socks5UDP() {
|
||||
// https://datatracker.ietf.org/doc/html/rfc1928
|
||||
// // _, _ = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0x7f, 0, 0, 0x1, 0x04, 0x38})
|
||||
// _, _ = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0x04, 0x38})
|
||||
// server, _ := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4zero, Port: 1080})
|
||||
// _, _ = server.Read(buf[:4])
|
||||
// frag, atyp := buf[2], buf[3]
|
||||
// addr := ""
|
||||
// switch atyp {
|
||||
// case 1:
|
||||
// n, err = server.Read(buf[:4])
|
||||
// if n != 4 {
|
||||
// return nil, "", errors.New("invalid IPv4:" + err.Error())
|
||||
// }
|
||||
// addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
|
||||
// case 3:
|
||||
// n, err = server.Read(buf[:1])
|
||||
// if n != 1 {
|
||||
// return nil, "", errors.New("invalid hostname:" + err.Error())
|
||||
// }
|
||||
// addrLen := int(buf[0])
|
||||
// n, err = server.Read(buf[:addrLen])
|
||||
// if n != addrLen {
|
||||
// return nil, "", errors.New("invalid hostname:" + err.Error())
|
||||
// }
|
||||
// addr = string(buf[:addrLen])
|
||||
// case 4:
|
||||
// return nil, "", errors.New("IPv6: no supported yet")
|
||||
// default:
|
||||
// return nil, "", errors.New("invalid atyp")
|
||||
// }
|
||||
// n, err = server.Read(buf[:2])
|
||||
// port := binary.BigEndian.Uint16(buf[:2])
|
||||
// destAddrPort := fmt.Sprintf("%s:%d", addr, port)
|
||||
// logrus.Debug(fmt.Sprintf("Connecting %s", destAddrPort))
|
||||
// dest, err := net.Dial("udp", destAddrPort)
|
||||
// if err != nil {
|
||||
// return nil, destAddrPort, errors.New("dial dst:" + err.Error())
|
||||
// }
|
||||
// logrus.Debug(fmt.Sprintf("Connected %s", destAddrPort))
|
||||
//
|
||||
// }
|
||||
func isAlive(conn net.Conn) bool {
|
||||
one := make([]byte, 1)
|
||||
conn.SetReadDeadline(time.Now().Add(time.Second * 5))
|
||||
_, err := conn.Read(one)
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
logrus.Debug(fmt.Sprintf("[%s] isAlive: EOF", conn.RemoteAddr().String()))
|
||||
return false
|
||||
} else if strings.Contains(err.Error(), "use of closed network connection") {
|
||||
logrus.Debug(fmt.Sprintf("[%s] isAlive: closed", conn.RemoteAddr().String()))
|
||||
return false
|
||||
} else if strings.Contains(err.Error(), "i/o timeout") {
|
||||
logrus.Debug(fmt.Sprintf("[%s] isAlive: timeout", conn.RemoteAddr().String()))
|
||||
return true
|
||||
} else {
|
||||
logrus.Debug(fmt.Sprintf("[%s] isAlive: %s", conn.RemoteAddr().String(), err.Error()))
|
||||
return false
|
||||
}
|
||||
}
|
||||
conn.SetReadDeadline(time.Time{})
|
||||
return true
|
||||
}
|
||||
|
||||
func Socks5UDP(client net.Conn) {
|
||||
udpserver, err := net.ListenUDP("udp4", &net.UDPAddr{IP: net.IPv4zero, Port: 0})
|
||||
if err != nil {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] ListenUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
return
|
||||
}
|
||||
_, port, _ := net.SplitHostPort(udpserver.LocalAddr().String())
|
||||
logrus.Debug(fmt.Sprintf("[%s][UDP] ListenUDP on %s", client.RemoteAddr().String(), port))
|
||||
portInt, _ := net.LookupPort("udp", port)
|
||||
portBytes := make([]byte, 2)
|
||||
binary.BigEndian.PutUint16(portBytes, uint16(portInt))
|
||||
_, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, portBytes[0], portBytes[1]})
|
||||
if err != nil {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] Write rsp failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 65535)
|
||||
udpPortMap := make(map[string][]byte)
|
||||
var clientAddr *net.UDPAddr
|
||||
var isDomain bool = false
|
||||
for {
|
||||
udpserver.SetReadDeadline(time.Now().Add(time.Second * 10))
|
||||
n, fromAddr, err := udpserver.ReadFromUDP(buf)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "i/o timeout") {
|
||||
logrus.Debug(fmt.Sprintf("[%s][UDP] ReadFromUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
if !isAlive(client) {
|
||||
logrus.Debug(fmt.Sprintf("[%s][UDP] client is not alive", client.RemoteAddr().String()))
|
||||
udpserver.Close()
|
||||
return
|
||||
}
|
||||
} else {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] ReadFromUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
if clientAddr == nil {
|
||||
clientAddr = fromAddr
|
||||
}
|
||||
|
||||
if clientAddr.IP.Equal(fromAddr.IP) && clientAddr.Port == fromAddr.Port {
|
||||
// from client
|
||||
atyp := buf[3]
|
||||
targetAddr := ""
|
||||
var targetPort uint16 = 0
|
||||
var payload []byte
|
||||
var header []byte
|
||||
var targetIP net.IP
|
||||
if atyp == 1 {
|
||||
isDomain = false
|
||||
targetAddr = fmt.Sprintf("%d.%d.%d.%d", buf[4], buf[5], buf[6], buf[7])
|
||||
targetIP = net.ParseIP(targetAddr)
|
||||
targetPort = binary.BigEndian.Uint16(buf[8:10])
|
||||
payload = buf[10:n]
|
||||
header = buf[0:10]
|
||||
} else if atyp == 3 {
|
||||
isDomain = true
|
||||
addrLen := int(buf[4])
|
||||
targetAddr = string(buf[5 : 5+addrLen])
|
||||
targetIPaddr, err := net.ResolveIPAddr("ip", targetAddr)
|
||||
if err != nil {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] ResolveIPAddr failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
continue
|
||||
}
|
||||
targetIP = targetIPaddr.IP
|
||||
targetPort = binary.BigEndian.Uint16(buf[5+addrLen : 5+addrLen+2])
|
||||
payload = buf[5+addrLen+2 : n]
|
||||
header = buf[0 : 5+addrLen+2]
|
||||
} else if atyp == 4 {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] IPv6: no supported yet", client.RemoteAddr().String()))
|
||||
continue
|
||||
} else {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] invalid atyp", client.RemoteAddr().String()))
|
||||
continue
|
||||
}
|
||||
// targetAddrPort := fmt.Sprintf("%s:%d", targetAddr, targetPort)
|
||||
remoteAddr := &net.UDPAddr{IP: targetIP, Port: int(targetPort)}
|
||||
udpPortMap[remoteAddr.String()] = make([]byte, len(header))
|
||||
copy(udpPortMap[remoteAddr.String()], header)
|
||||
udpserver.SetWriteDeadline(time.Now().Add(time.Second * 10))
|
||||
if _, err = udpserver.WriteToUDP(payload, remoteAddr); err != nil {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] WriteToUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
// from remote
|
||||
fmt.Print(fromAddr.String())
|
||||
header := udpPortMap[fromAddr.String()]
|
||||
if header == nil {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] udpPortMap invalid header", client.RemoteAddr().String()))
|
||||
continue
|
||||
}
|
||||
// header + body
|
||||
if isDomain {
|
||||
header = header[0:4]
|
||||
}
|
||||
body := append(header, buf[:n]...)
|
||||
if _, err = udpserver.WriteToUDP(body, clientAddr); err != nil {
|
||||
logrus.Error(fmt.Sprintf("[%s][UDP] WriteToUDP failed: %s", client.RemoteAddr().String(), err.Error()))
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Socks5Connect(client net.Conn) (net.Conn, string, error) {
|
||||
buf := make([]byte, 256)
|
||||
@ -182,7 +274,7 @@ func Socks5Connect(client net.Conn) (net.Conn, string, error) {
|
||||
return nil, "", errors.New("invalid ver")
|
||||
}
|
||||
if cmd == 3 {
|
||||
return nil, "", errors.New("not support UDP")
|
||||
return nil, "", errors.New("UDP Associate")
|
||||
}
|
||||
if cmd != 1 {
|
||||
return nil, "", errors.New("invalid cmd, only support connect")
|
||||
|
||||
@ -20,7 +20,7 @@ ckcmd() {
|
||||
cd /root
|
||||
getcpucore
|
||||
|
||||
version=0.2.3
|
||||
version=0.3.0
|
||||
ua3f_tar=ua3f-$version-$cpucore.tar.gz
|
||||
|
||||
if id -u shellclash >/dev/null 2>&1; then
|
||||
@ -91,11 +91,12 @@ fi
|
||||
mkdir -p /usr/lib/lua/luci/controller
|
||||
mv controller.lua /usr/lib/lua/luci/controller/ua3f.lua
|
||||
|
||||
rm /tmp/luci-modulecache/* >/dev/null 2>&1
|
||||
rm /tmp/luci-indexcache* >/dev/null 2>&1
|
||||
chmod +x /etc/config/ua3f >/dev/null 2>&1
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Install UA3F Success."
|
||||
fi
|
||||
|
||||
rm /tmp/luci-modulecache/* >/dev/null 2>&1
|
||||
rm /tmp/luci-indexcache* >/dev/null 2>&1
|
||||
service ua3f.service reload >/dev/null 2>&1
|
||||
|
||||
@ -3,7 +3,7 @@ local uci = require("luci.model.uci").cursor()
|
||||
ua3f = Map("ua3f",
|
||||
"UA3F",
|
||||
[[
|
||||
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.2.3</a>
|
||||
<a href="https://github.com/SunBK201/UA3F" target="_blank">Version: 0.3.0</a>
|
||||
<br>
|
||||
Across the Campus we can reach every corner in the world.
|
||||
]]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user