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