特征1
使用tls_enable加密后,首次连接会一个0x17的头部。
pkg/util/net/tls.go,frp自实现tls,所以存在很强的特征
这个0x17只有再发起连接时会有,后续均为tls加密传输,所以我们需要修改此处就够了
第一步:修改byte内容,然后新增一个以该byte开头,后续内容随机的字节切片。
pkg/util/net/tls.go
1 2 3 4 | var ( FRPTLSHeadByte = byte(0x91) FRPTLSHeadBytes = bytes.Join([][]byte{[]byte{FRPTLSHeadByte}, random.RandBytes(10)}, []byte{}) ) |
第二步: 然后就是调用位置的调整,要注意下面buf虽然是设定成FRPTLSHeadBytes长度,但判断比较的时候只判断第一个字节,因为后面的每次运行都是随机生成的,服务端和客户端是不一样的。
所以这里的判断依据就是:长度一致,首字节一致则表示tls接收无问题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | func WrapTLSClientConn(c net.Conn, tlsConfig *tls.Config) (out net.Conn) { // lz5205201 c.Write(FRPTLSHeadBytes) // lz5205202 out = tls.Client(c, tlsConfig) return } func CheckAndEnableTLSServerConnWithTimeout(c net.Conn, tlsConfig *tls.Config, tlsOnly bool, timeout time.Duration) (out net.Conn, err error) { // lz5205201 headLen := len(FRPTLSHeadBytes) sc, r := gnet.NewSharedConnSize(c, 1 + headLen) buf := make([]byte, headLen) var n int c.SetReadDeadline(time.Now().Add(timeout)) n, err = r.Read(buf) c.SetReadDeadline(time.Time{}) if err != nil { return } if n == headLen && buf[0] == FRPTLSHeadBytes[0] { // lz5205202 out = tls.Server(c, tlsConfig) } else { if tlsOnly { err = fmt.Errorf("non-TLS connection received on a TlsOnly server") return } out = sc } return } |
server/service.go
1 2 3 | svr.tlsListener = svr.muxer.Listen(1, uint32(len(tNet.FRPTLSHeadBytes)), func(data []byte) bool { return data[0] == tNet.FRPTLSHeadBytes[0] }) |
数据包如下,前11字节就表示使用tls。
https://www.anquanke.com/post/id/231685
PS: 新版本frp已经优化该特征