diff --git a/README.md b/README.md index 592f995..52e0613 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,6 @@ rules: - [x] 支持 LuCI - [x] 优化部署流程 - [ ] 支持 SOCK5 Auth -- [ ] 支持 UDP +- [x] 支持 UDP - [ ] 支持 IPv6 - [ ] 性能提升 \ No newline at end of file diff --git a/bin/sha1sum.txt b/bin/sha1sum.txt index 47c5795..e9b16b4 100644 --- a/bin/sha1sum.txt +++ b/bin/sha1sum.txt @@ -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 diff --git a/bin/ua3f-0.2.3-386.tar.gz b/bin/ua3f-0.2.3-386.tar.gz deleted file mode 100644 index aac90dc..0000000 Binary files a/bin/ua3f-0.2.3-386.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-amd64.tar.gz b/bin/ua3f-0.2.3-amd64.tar.gz deleted file mode 100644 index 43f0c3c..0000000 Binary files a/bin/ua3f-0.2.3-amd64.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-arm.tar.gz b/bin/ua3f-0.2.3-arm.tar.gz deleted file mode 100644 index 7b3c1be..0000000 Binary files a/bin/ua3f-0.2.3-arm.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-arm64.tar.gz b/bin/ua3f-0.2.3-arm64.tar.gz deleted file mode 100644 index 13b62ed..0000000 Binary files a/bin/ua3f-0.2.3-arm64.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-armv7.tar.gz b/bin/ua3f-0.2.3-armv7.tar.gz deleted file mode 100644 index d8a356a..0000000 Binary files a/bin/ua3f-0.2.3-armv7.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-armv8.tar.gz b/bin/ua3f-0.2.3-armv8.tar.gz deleted file mode 100644 index 13b62ed..0000000 Binary files a/bin/ua3f-0.2.3-armv8.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-mips64.tar.gz b/bin/ua3f-0.2.3-mips64.tar.gz deleted file mode 100644 index d89ec90..0000000 Binary files a/bin/ua3f-0.2.3-mips64.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-mipsle-hardfloat.tar.gz b/bin/ua3f-0.2.3-mipsle-hardfloat.tar.gz deleted file mode 100644 index 5169bda..0000000 Binary files a/bin/ua3f-0.2.3-mipsle-hardfloat.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-mipsle-softfloat.tar.gz b/bin/ua3f-0.2.3-mipsle-softfloat.tar.gz deleted file mode 100644 index 4ac51fc..0000000 Binary files a/bin/ua3f-0.2.3-mipsle-softfloat.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-mipsle.tar.gz b/bin/ua3f-0.2.3-mipsle.tar.gz deleted file mode 100644 index cc472b1..0000000 Binary files a/bin/ua3f-0.2.3-mipsle.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.2.3-riscv64.tar.gz b/bin/ua3f-0.2.3-riscv64.tar.gz deleted file mode 100644 index 711a604..0000000 Binary files a/bin/ua3f-0.2.3-riscv64.tar.gz and /dev/null differ diff --git a/bin/ua3f-0.3.0-386.tar.gz b/bin/ua3f-0.3.0-386.tar.gz new file mode 100644 index 0000000..a24f016 Binary files /dev/null and b/bin/ua3f-0.3.0-386.tar.gz differ diff --git a/bin/ua3f-0.3.0-amd64.tar.gz b/bin/ua3f-0.3.0-amd64.tar.gz new file mode 100644 index 0000000..5a28b19 Binary files /dev/null and b/bin/ua3f-0.3.0-amd64.tar.gz differ diff --git a/bin/ua3f-0.3.0-arm.tar.gz b/bin/ua3f-0.3.0-arm.tar.gz new file mode 100644 index 0000000..bf5a1aa Binary files /dev/null and b/bin/ua3f-0.3.0-arm.tar.gz differ diff --git a/bin/ua3f-0.3.0-arm64.tar.gz b/bin/ua3f-0.3.0-arm64.tar.gz new file mode 100644 index 0000000..db16cb3 Binary files /dev/null and b/bin/ua3f-0.3.0-arm64.tar.gz differ diff --git a/bin/ua3f-0.3.0-armv7.tar.gz b/bin/ua3f-0.3.0-armv7.tar.gz new file mode 100644 index 0000000..bd4f949 Binary files /dev/null and b/bin/ua3f-0.3.0-armv7.tar.gz differ diff --git a/bin/ua3f-0.3.0-armv8.tar.gz b/bin/ua3f-0.3.0-armv8.tar.gz new file mode 100644 index 0000000..db16cb3 Binary files /dev/null and b/bin/ua3f-0.3.0-armv8.tar.gz differ diff --git a/bin/ua3f-0.3.0-mips64.tar.gz b/bin/ua3f-0.3.0-mips64.tar.gz new file mode 100644 index 0000000..94bb7fc Binary files /dev/null and b/bin/ua3f-0.3.0-mips64.tar.gz differ diff --git a/bin/ua3f-0.3.0-mipsle-hardfloat.tar.gz b/bin/ua3f-0.3.0-mipsle-hardfloat.tar.gz new file mode 100644 index 0000000..5d8a413 Binary files /dev/null and b/bin/ua3f-0.3.0-mipsle-hardfloat.tar.gz differ diff --git a/bin/ua3f-0.3.0-mipsle-softfloat.tar.gz b/bin/ua3f-0.3.0-mipsle-softfloat.tar.gz new file mode 100644 index 0000000..bf2cb09 Binary files /dev/null and b/bin/ua3f-0.3.0-mipsle-softfloat.tar.gz differ diff --git a/bin/ua3f-0.3.0-mipsle.tar.gz b/bin/ua3f-0.3.0-mipsle.tar.gz new file mode 100644 index 0000000..84882e6 Binary files /dev/null and b/bin/ua3f-0.3.0-mipsle.tar.gz differ diff --git a/bin/ua3f-0.3.0-riscv64.tar.gz b/bin/ua3f-0.3.0-riscv64.tar.gz new file mode 100644 index 0000000..18e7b4e Binary files /dev/null and b/bin/ua3f-0.3.0-riscv64.tar.gz differ diff --git a/build.sh b/build.sh index 2ff46b2..7d52983 100755 --- a/build.sh +++ b/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 diff --git a/cmd/ua3f.go b/cmd/ua3f.go index be02e37..38ab76f 100644 --- a/cmd/ua3f.go +++ b/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") diff --git a/install.sh b/install.sh index d02df1a..2bb9f87 100755 --- a/install.sh +++ b/install.sh @@ -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 diff --git a/luci/cbi.lua b/luci/cbi.lua index fc08757..b41e0a9 100644 --- a/luci/cbi.lua +++ b/luci/cbi.lua @@ -3,7 +3,7 @@ local uci = require("luci.model.uci").cursor() ua3f = Map("ua3f", "UA3F", [[ - Version: 0.2.3 + Version: 0.3.0
Across the Campus we can reach every corner in the world. ]]