fix: sanity check read EOF in first read phase

This commit is contained in:
SunBK201 2023-12-13 14:48:03 +08:00
parent 4729762bc6
commit b4064d1fb7
24 changed files with 56 additions and 44 deletions

View File

@ -1,10 +1,10 @@
5a75ec8000a8b3593a853c12863e2b46 ./ua3f-0.1.1-386.tar.gz 69348631c2d1bf17768dcbeac972b63f ./ua3f-0.1.2-386.tar.gz
85cce8bd5d2aef5d8481cfe6f1f9b099 ./ua3f-0.1.1-amd64.tar.gz 06b14787b948906ce42372ab656d2078 ./ua3f-0.1.2-amd64.tar.gz
4bfe414dd58e2eeb57e3381cbada7a2b ./ua3f-0.1.1-arm.tar.gz b53f3b49d42b4d93800e4665e525f26c ./ua3f-0.1.2-arm.tar.gz
da1d3a054e66d5680a38a3ffcb67862a ./ua3f-0.1.1-arm64.tar.gz 3497c75d7f53085b8d34d148059831f8 ./ua3f-0.1.2-arm64.tar.gz
da1d3a054e66d5680a38a3ffcb67862a ./ua3f-0.1.1-armv8.tar.gz 3497c75d7f53085b8d34d148059831f8 ./ua3f-0.1.2-armv8.tar.gz
02fe1c3c18115dcecf4bf38f62e5de83 ./ua3f-0.1.1-mips64.tar.gz 7a19c7e1539294b2fe18244bab9ad12e ./ua3f-0.1.2-mips64.tar.gz
69d64e2f443859418f74749e7d02e018 ./ua3f-0.1.1-mipsle-hardfloat.tar.gz 8034fb13e48c836793dfbc3f1d213c2f ./ua3f-0.1.2-mipsle-hardfloat.tar.gz
23781cf6da653e6bfd40c91ccb258885 ./ua3f-0.1.1-mipsle-softfloat.tar.gz b386e9b12c94413f53bdf7e8bcc232d7 ./ua3f-0.1.2-mipsle-softfloat.tar.gz
41b823964a881b5e2c429e785287e4e4 ./ua3f-0.1.1-mipsle.tar.gz 8034fb13e48c836793dfbc3f1d213c2f ./ua3f-0.1.2-mipsle.tar.gz
4319b5e0e69bf2637a33ca6aee3ed284 ./ua3f-0.1.1-riscv64.tar.gz 5f6870e9f7b8d4c0e4ffc56eff1c37d4 ./ua3f-0.1.2-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.

BIN
bin/ua3f-0.1.2-386.tar.gz Normal file

Binary file not shown.

BIN
bin/ua3f-0.1.2-amd64.tar.gz Normal file

Binary file not shown.

BIN
bin/ua3f-0.1.2-arm.tar.gz Normal file

Binary file not shown.

BIN
bin/ua3f-0.1.2-arm64.tar.gz Normal file

Binary file not shown.

BIN
bin/ua3f-0.1.2-armv8.tar.gz Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
project_name="ua3f" project_name="ua3f"
release_version="0.1.1" release_version="0.1.2"
target=cmd/ua3f.go target=cmd/ua3f.go
release_dir=./bin release_dir=./bin

View File

@ -16,7 +16,7 @@ import (
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
var version = "0.1.1" var version = "0.1.2"
var payloadByte []byte var payloadByte []byte
var cache *expirable.LRU[string, string] var cache *expirable.LRU[string, string]
@ -67,13 +67,13 @@ func process(client net.Conn) {
client.Close() client.Close()
return return
} }
target, err := Socks5Connect(client) target, destAddrPort, err := Socks5Connect(client)
if err != nil { if err != nil {
logrus.Error("Connect failed: ", err) logrus.Error("Connect failed: ", err)
client.Close() client.Close()
return return
} }
Socks5Forward(client, target) Socks5Forward(client, target, destAddrPort)
} }
func Socks5Auth(client net.Conn) (err error) { func Socks5Auth(client net.Conn) (err error) {
@ -97,61 +97,61 @@ func Socks5Auth(client net.Conn) (err error) {
return nil return nil
} }
func Socks5Connect(client net.Conn) (net.Conn, error) { func Socks5Connect(client net.Conn) (net.Conn, string, error) {
buf := make([]byte, 256) buf := make([]byte, 256)
n, err := io.ReadFull(client, buf[:4]) n, err := io.ReadFull(client, buf[:4])
if n != 4 { if n != 4 {
return nil, errors.New("read header:" + err.Error()) return nil, "", errors.New("read header:" + err.Error())
} }
ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3] ver, cmd, _, atyp := buf[0], buf[1], buf[2], buf[3]
if ver != 5 || cmd != 1 { if ver != 5 || cmd != 1 {
return nil, errors.New("invalid ver/cmd") return nil, "", errors.New("invalid ver/cmd")
} }
addr := "" addr := ""
switch atyp { switch atyp {
case 1: case 1:
n, err = io.ReadFull(client, buf[:4]) n, err = io.ReadFull(client, buf[:4])
if n != 4 { if n != 4 {
return nil, errors.New("invalid IPv4:" + err.Error()) return nil, "", errors.New("invalid IPv4:" + err.Error())
} }
addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]) addr = fmt.Sprintf("%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3])
case 3: case 3:
n, err = io.ReadFull(client, buf[:1]) n, err = io.ReadFull(client, buf[:1])
if n != 1 { if n != 1 {
return nil, errors.New("invalid hostname:" + err.Error()) return nil, "", errors.New("invalid hostname:" + err.Error())
} }
addrLen := int(buf[0]) addrLen := int(buf[0])
n, err = io.ReadFull(client, buf[:addrLen]) n, err = io.ReadFull(client, buf[:addrLen])
if n != addrLen { if n != addrLen {
return nil, errors.New("invalid hostname:" + err.Error()) return nil, "", errors.New("invalid hostname:" + err.Error())
} }
addr = string(buf[:addrLen]) addr = string(buf[:addrLen])
case 4: case 4:
return nil, errors.New("IPv6: no supported yet") return nil, "", errors.New("IPv6: no supported yet")
default: default:
return nil, errors.New("invalid atyp") return nil, "", errors.New("invalid atyp")
} }
n, err = io.ReadFull(client, buf[:2]) n, err = io.ReadFull(client, buf[:2])
if n != 2 { if n != 2 {
return nil, errors.New("read port:" + err.Error()) return nil, "", errors.New("read port:" + err.Error())
} }
port := binary.BigEndian.Uint16(buf[:2]) port := binary.BigEndian.Uint16(buf[:2])
destAddrPort := fmt.Sprintf("%s:%d", addr, port) destAddrPort := fmt.Sprintf("%s:%d", addr, port)
logrus.Debug(fmt.Sprintf("Connecting %s", destAddrPort)) logrus.Debug(fmt.Sprintf("Connecting %s", destAddrPort))
dest, err := net.Dial("tcp", destAddrPort) dest, err := net.Dial("tcp", destAddrPort)
if err != nil { if err != nil {
return nil, errors.New("dial dst:" + err.Error()) return nil, destAddrPort, errors.New("dial dst:" + err.Error())
} }
logrus.Debug(fmt.Sprintf("Connected %s", destAddrPort)) logrus.Debug(fmt.Sprintf("Connected %s", destAddrPort))
_, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0}) _, err = client.Write([]byte{0x05, 0x00, 0x00, 0x01, 0, 0, 0, 0, 0, 0})
if err != nil { if err != nil {
dest.Close() dest.Close()
return nil, errors.New("write rsp:" + err.Error()) return nil, destAddrPort, errors.New("write rsp:" + err.Error())
} }
return dest, nil return dest, destAddrPort, nil
} }
func Socks5Forward(client, target net.Conn) { func Socks5Forward(client, target net.Conn, destAddrPort string) {
forward := func(src, dest net.Conn) { forward := func(src, dest net.Conn) {
defer src.Close() defer src.Close()
defer dest.Close() defer dest.Close()
@ -161,22 +161,33 @@ func Socks5Forward(client, target net.Conn) {
gforward := func(dst, src net.Conn) { gforward := func(dst, src net.Conn) {
defer dst.Close() defer dst.Close()
defer src.Close() defer src.Close()
CopyPileline(dst, src) CopyPileline(dst, src, destAddrPort)
} }
go forward(client, target) go forward(client, target)
if cache.Contains(string(target.RemoteAddr().String())) { if cache.Contains(destAddrPort) {
logrus.Debug(fmt.Sprintf("Hit LRU Relay Cache: %s", destAddrPort))
go forward(target, client) go forward(target, client)
return return
} }
go gforward(target, client) go gforward(target, client)
} }
func CopyPileline(dst io.Writer, src io.Reader) { func CopyPileline(dst io.Writer, src io.Reader, destAddrPort string) {
buf := make([]byte, 1024*8) buf := make([]byte, 1024*8)
nr, err := src.Read(buf) nr, err := src.Read(buf)
if err != nil && err != io.EOF { if err != nil {
logrus.Error("read error: ", err) if err == io.EOF {
logrus.Debug(fmt.Sprintf("[%s][%s] read EOF in first phase", destAddrPort, src.(*net.TCPConn).RemoteAddr().String()))
} else if strings.Contains(err.Error(), "use of closed network connection") {
logrus.Debug(fmt.Sprintf("[%s][%s] read closed in first phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
} else {
logrus.Error(fmt.Sprintf("[%s][%s] read error in first phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
}
return
}
if nr == 0 {
logrus.Debug(fmt.Sprintf("[%s][%s] read 0 in first phase", destAddrPort, src.(*net.TCPConn).RemoteAddr().String()))
return return
} }
hint := string(buf[0:7]) hint := string(buf[0:7])
@ -191,7 +202,8 @@ func CopyPileline(dst io.Writer, src io.Reader) {
if !is_http { if !is_http {
dst.Write(buf[0:nr]) dst.Write(buf[0:nr])
io.Copy(dst, src) io.Copy(dst, src)
cache.Add(string(dst.(*net.TCPConn).RemoteAddr().String()), string(dst.(*net.TCPConn).RemoteAddr().String())) cache.Add(destAddrPort, destAddrPort)
logrus.Debug(fmt.Sprintf("Not HTTP, Hint: %v, Add LRU Relay Cache: %s", buf[0:7], destAddrPort))
return return
} }
for { for {
@ -201,7 +213,7 @@ func CopyPileline(dst io.Writer, src io.Reader) {
var m int var m int
m, err = src.Read(buf[nr:]) m, err = src.Read(buf[nr:])
if err != nil { if err != nil {
logrus.Error("read error in http accumulation: ", err) logrus.Error(fmt.Sprintf("[%s] read error in http accumulation: %v", destAddrPort, err))
break break
} }
nr += m nr += m
@ -209,7 +221,7 @@ func CopyPileline(dst io.Writer, src io.Reader) {
} }
value, start, end := parser.FindHeader([]byte("User-Agent")) value, start, end := parser.FindHeader([]byte("User-Agent"))
if value != nil && end > start { if value != nil && end > start {
logrus.Debug(fmt.Sprintf("[%s] Hit User-Agent: %s", string(parser.Host()), string(value))) logrus.Debug(fmt.Sprintf("[%s][%s] Hit User-Agent: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), string(value)))
for i := start; i < end; i++ { for i := start; i < end; i++ {
buf[i] = 32 buf[i] = 32
} }
@ -220,10 +232,10 @@ func CopyPileline(dst io.Writer, src io.Reader) {
buf[start+i] = payloadByte[i] buf[start+i] = payloadByte[i]
} }
} else { } else {
logrus.Debug(fmt.Sprintf("[%s] Not found User-Agent, Add LRU Relay Cache", string(parser.Host()))) logrus.Debug(fmt.Sprintf("[%s] Not found User-Agent, Add LRU Relay Cache", destAddrPort))
dst.Write(buf[0:nr]) dst.Write(buf[0:nr])
io.Copy(dst, src) io.Copy(dst, src)
cache.Add(string(dst.(*net.TCPConn).RemoteAddr().String()), string(dst.(*net.TCPConn).RemoteAddr().String())) cache.Add(destAddrPort, destAddrPort)
return return
} }
bodyLen := int(parser.ContentLength()) bodyLen := int(parser.ContentLength())
@ -233,7 +245,7 @@ func CopyPileline(dst io.Writer, src io.Reader) {
_, ew := dst.Write(buf[0:min(httpBodyOffset+bodyLen, nr)]) _, ew := dst.Write(buf[0:min(httpBodyOffset+bodyLen, nr)])
if ew != nil { if ew != nil {
logrus.Error("write error: ", ew) logrus.Error(fmt.Sprintf("[%s][%s] write error: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), ew.Error()))
break break
} }
if httpBodyOffset+bodyLen > nr { if httpBodyOffset+bodyLen > nr {
@ -241,12 +253,12 @@ func CopyPileline(dst io.Writer, src io.Reader) {
for left > 0 { for left > 0 {
m, err := src.Read(buf[0:left]) m, err := src.Read(buf[0:left])
if err != nil { if err != nil {
logrus.Error("read error in large body: ", err) logrus.Error(fmt.Sprintf("[%s][%s] read error in large body: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
break break
} }
_, ew := dst.Write(buf[0:m]) _, ew := dst.Write(buf[0:m])
if ew != nil { if ew != nil {
logrus.Error("write error in large body: ", ew) logrus.Error(fmt.Sprintf("[%s][%s] write error in large body: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), ew.Error()))
break break
} }
left -= m left -= m
@ -263,11 +275,11 @@ func CopyPileline(dst io.Writer, src io.Reader) {
nr += m nr += m
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
logrus.Debug("read EOF in next phase") logrus.Debug(fmt.Sprintf("[%s][%s] read EOF in next phase", destAddrPort, src.(*net.TCPConn).RemoteAddr().String()))
} else if strings.Contains(err.Error(), "use of closed network connection") { } else if strings.Contains(err.Error(), "use of closed network connection") {
logrus.Debug("read closed in next phase: ", err) logrus.Debug(fmt.Sprintf("[%s][%s] read closed in next phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
} else { } else {
logrus.Error("read error in next phase: ", err) logrus.Error(fmt.Sprintf("[%s][%s] read error in next phase: %s", destAddrPort, src.(*net.TCPConn).RemoteAddr().String(), err.Error()))
} }
break break
} }

View File

@ -16,7 +16,7 @@ getcpucore() {
cd /root cd /root
getcpucore getcpucore
version=0.1.1 version=0.1.2
ua3f_tar=ua3f-$version-$cpucore.tar.gz ua3f_tar=ua3f-$version-$cpucore.tar.gz
if id -u shellclash &> /dev/null; then if id -u shellclash &> /dev/null; then