Skip to content

Commit

Permalink
fix: peek size change to 8
Browse files Browse the repository at this point in the history
  • Loading branch information
huhu415 committed Nov 24, 2024
1 parent 4746a4c commit 2e6e235
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 92 deletions.
2 changes: 1 addition & 1 deletion .goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ release:
header: |
## 🥳Changes
- 增加了http to websocket功能
- 修复了pg数据库连接不上问题
```sh
tar -xzvf uaProxy-linux-xxxxxxx.tar.gz # 解压
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
10 changes: 6 additions & 4 deletions handle/handle.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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)
Expand Down
88 changes: 48 additions & 40 deletions handle/tools.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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)
}

Expand Down
100 changes: 54 additions & 46 deletions handle/tools_test.go
Original file line number Diff line number Diff line change
@@ -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))
}
})
}
Expand Down

0 comments on commit 2e6e235

Please sign in to comment.