From 2e6e235d5e05dfbde32641de8373e815c6b2ff03 Mon Sep 17 00:00:00 2001 From: huhu415 Date: Sun, 24 Nov 2024 19:16:30 +0800 Subject: [PATCH] fix: peek size change to 8 --- .goreleaser.yaml | 2 +- README.md | 2 +- handle/handle.go | 10 +++-- handle/tools.go | 88 ++++++++++++++++++++----------------- handle/tools_test.go | 100 +++++++++++++++++++++++-------------------- 5 files changed, 110 insertions(+), 92 deletions(-) diff --git a/.goreleaser.yaml b/.goreleaser.yaml index b6ab937..d03d62a 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -59,7 +59,7 @@ release: header: | ## 🥳Changes - - 增加了http to websocket功能 + - 修复了pg数据库连接不上问题 ```sh tar -xzvf uaProxy-linux-xxxxxxx.tar.gz # 解压 diff --git a/README.md b/README.md index 972d7bb..a25f248 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ iptables -t nat -A uaProxy -p tcp -j RETURN -m mark --mark 0xff # 直连 SO_MARK 为 0xff 的流量(0xff 是 16 进制数,数值上等同与上面配置的 255),此规则目的是避免代理本机(网关)流量出现回环问题 iptables -t nat -A uaProxy -p tcp -j REDIRECT --to-ports 12345 # 其余流量转发到 12345 端口(即 uaProxy默认开启的redir-port) iptables -t nat -A PREROUTING -p tcp -j uaProxy # 对局域网其他设备进行透明代理 -iptables -t nat -A OUTPUT -p tcp -j uaProxy # 对本机进行透明代理, 可以不加, 建议加 +iptables -t nat -A OUTPUT -p tcp -j uaProxy # 对本机进行透明代理. 可以不加, 建议加, 加之后nmap等类似工具会失效 ``` > 设置前, 确保已经清空了`iptables`规则, 以免影响正常使用: `iptables -t nat -F` diff --git a/handle/handle.go b/handle/handle.go index b7a8e2e..de2096a 100644 --- a/handle/handle.go +++ b/handle/handle.go @@ -11,9 +11,11 @@ import ( "github.com/sirupsen/logrus" ) +const PEEKSIZE = 8 // 不能太小, 如果是1的话, 容易全部都判定为http方法 + func HandleConnection(clientConn net.Conn) { defer clientConn.Close() - logrus.Debugf("clientConn. remoteAdd: %s", clientConn.RemoteAddr().String()) + // logrus.Debugf("clientConn. remoteAdd: %s", clientConn.RemoteAddr().String()) serverConn, err := GetDestConn(clientConn) if err != nil { @@ -23,11 +25,11 @@ func HandleConnection(clientConn net.Conn) { defer serverConn.Close() bufioReader := bufio.NewReader(clientConn) - peekBuff, _ := bufioReader.Peek(10) - logrus.Debug(string(peekBuff)) + peekBuff, _ := bufioReader.Peek(PEEKSIZE) + logrus.Debugf("locationIp: %s, remoteIp: %s, peekBuff: %v", clientConn.RemoteAddr().String(), serverConn.RemoteAddr().String(), peekBuff) go io.Copy(clientConn, serverConn) - if len(peekBuff) > 0 && isEnglishLetter(peekBuff[0]) && isHTTP(peekBuff) { + if len(peekBuff) > 0 && isEnglishBigLetter(peekBuff[0]) && isHTTP(peekBuff) { handleHTTPConnection(bufioReader, serverConn) } else { handleNonHTTPConnection(bufioReader, serverConn) diff --git a/handle/tools.go b/handle/tools.go index 4e71244..16522f3 100644 --- a/handle/tools.go +++ b/handle/tools.go @@ -10,55 +10,62 @@ import ( "github.com/v2fly/v2ray-core/v5/transport/internet/tcp" ) -var anyMethodSet = map[string]struct{}{ - http.MethodGet: {}, - http.MethodPost: {}, - http.MethodPut: {}, - http.MethodPatch: {}, - http.MethodHead: {}, - http.MethodOptions: {}, - http.MethodDelete: {}, - http.MethodTrace: {}, - http.MethodConnect: {}, - "PROPFIND": {}, - "PROPPATCH": {}, - "MKCOL": {}, - "COPY": {}, - "MOVE": {}, - "LOCK": {}, - "UNLOCK": {}, - "LINK": {}, - "UNLINK": {}, - "PURGE": {}, - "VIEW": {}, - "REPORT": {}, - "SEARCH": {}, - "CHECKOUT": {}, - "CHECKIN": {}, - "MERGE": {}, - "SUBSCRIBE": {}, - "UNSUBSCRIBE": {}, - "NOTIFY": {}, +var anyMethod = [][]byte{ + []byte(http.MethodGet), + []byte(http.MethodPost), + []byte(http.MethodPut), + []byte(http.MethodPatch), + []byte(http.MethodHead), + []byte(http.MethodOptions), + []byte(http.MethodDelete), + []byte(http.MethodTrace), + []byte(http.MethodConnect), + []byte("PROPFIND"), + []byte("PROPPATCH"), + []byte("MKCOL"), + []byte("COPY"), + []byte("MOVE"), + []byte("LOCK"), + []byte("UNLOCK"), + []byte("LINK"), + []byte("UNLINK"), + []byte("PURGE"), + []byte("VIEW"), + []byte("REPORT"), + []byte("SEARCH"), + []byte("CHECKOUT"), + []byte("CHECKIN"), + []byte("MERGE"), + []byte("SUBSCRIBE"), + []byte("UNSUBSCRIBE"), + []byte("NOTIFY"), } func isHTTP(peek []byte) bool { - tempPeekString := strings.ToUpper(string(peek)) - logrus.Debug(tempPeekString) - - first, _, ok := strings.Cut(tempPeekString, " ") - if !ok { + if len(peek) == 0 { return false } - if _, ok := anyMethodSet[first]; !ok { - return false + for _, method := range anyMethod { + if compareMethod(peek, method) { + return true + } + } + return false +} + +func compareMethod(peek, method []byte) bool { + for i := 0; i < len(peek) && i < len(method); i++ { + if peek[i] != method[i] { + return false + } } return true } -func isEnglishLetter(b byte) bool { - // 检查是否为大写字母或小写字母 - return (b >= 'A' && b <= 'Z') || (b >= 'a' && b <= 'z') +func isEnglishBigLetter(b byte) bool { + // 检查是否为大写字母 + return (b >= 'A' && b <= 'Z') } func GetDestConn(clientConn net.Conn) (net.Conn, error) { @@ -68,9 +75,10 @@ func GetDestConn(clientConn net.Conn) (net.Conn, error) { dest, err = tcp.GetOriginalDestination(clientConn) if err != nil { logrus.Errorf("failed to get original destination") + return nil, err } - logrus.Debugf("%s, ip: %s, port: %s", dest.Network, dest.Address.IP().String(), dest.Port) + logrus.Debugf("clientIp: %s, remoteIp: %s:%s", clientConn.RemoteAddr().String(), dest.Address.IP().String(), dest.Port) return dialDestination(dest) } diff --git a/handle/tools_test.go b/handle/tools_test.go index ec686c0..695f4a7 100644 --- a/handle/tools_test.go +++ b/handle/tools_test.go @@ -1,54 +1,62 @@ package handle -import "testing" +import ( + "testing" +) -func Test_isHTTP(t *testing.T) { - tests := []struct { - peek []byte - want bool - }{ - { - peek: []byte("GET /path "), // 10 bytes - want: true, - }, - { - peek: []byte("POST /path "), // 10 bytes - want: true, - }, - { - peek: []byte("put /path "), // 10 bytes - want: true, - }, - { - peek: []byte(" "), // 10 spaces - want: false, - }, - { - peek: []byte("INVALID /p "), // 10 bytes - want: false, - }, - { - peek: []byte("GET "), // 10 bytes - want: true, - }, - { - peek: []byte("GET /p?k=v"), // 10 bytes - want: true, - }, - { - peek: []byte("DELETE /pa"), // 10 bytes - want: true, - }, - { - peek: []byte("PROPPATCH 123123"), // 10 bytes - want: true, - }, +func Test_isHTTP_Fail(t *testing.T) { + // 失败测试用例 - 这些都不是有效的 HTTP 请求 + failTests := [][]byte{ + []byte("INVALID /path HTTP/1.1"), + []byte("NOT-HTTP /index.html"), + []byte("HELLO WORLD"), + []byte("SSL-13"), + []byte("12345"), + []byte(""), + []byte(" "), + []byte("GEET /index.html"), + []byte("HTTP1.1 /index.html"), // 缺少空格 + []byte("\r\n"), // 只有换行 + []byte("get /index.html"), // 方法名小写 } - for _, tt := range tests { - t.Run("isHttp", func(t *testing.T) { - if got := isHTTP(tt.peek); got != tt.want { - t.Errorf("isHTTP() = %v, want %v", got, tt.want) + // 测试失败用例 + for _, tt := range failTests { + methodLine := tt + if len(tt) > PEEKSIZE { + methodLine = tt[:PEEKSIZE] + } + t.Run("Should Fail: "+string(methodLine), func(t *testing.T) { + if got := isHTTP(methodLine); got != false { + t.Errorf("raw = %v, input = %v, want false for input: %s", tt, got, string(methodLine)) + } + }) + } +} + +func Test_isHTTP_Success(t *testing.T) { + // 成功测试用例 - 这些都是有效的 HTTP 请求开头 + successTests := [][]byte{ + []byte("PROPPATCH /api/data HTTP/1.1"), + []byte("SUBSCRIBE /api/data HTTP/1.1"), + []byte("UNSUBSCRIBE /api/data HTTP/1.1"), + []byte("CHECKOUT /api/data HTTP/1.1"), + []byte("CHECKOUT /api/data HTTP/1.1"), + []byte("GET /index.html HTTP/1.1"), + []byte("POST /api/data HTTP/1.1"), + []byte("HEAD /test HTTP/1.0"), + []byte("PUT /update HTTP/1.1"), + []byte("DELETE /remove HTTP/1.1"), + []byte("OPTIONS /check HTTP/1.1"), + []byte("PATCH /modify HTTP/1.1"), + } + + // 测试成功用例 + for _, tt := range successTests { + methodLine := tt[:PEEKSIZE] + t.Run("Should Success: "+string(methodLine), func(t *testing.T) { + if got := isHTTP(methodLine); got != true { + t.Errorf("raw = %v, input = %v, want true for input: %s", tt, got, string(methodLine)) } }) }