一尘不染

无需阅读就可以窥视Conn

go

我有一个服务器net.Conn,我想在读取字节之前先查看一下它,以检查它是客户端尝试使用的纯文本协议还是SSL / TLS。

检查http://golang.org/pkg/net/,似乎该Conn界面没有类似的内容。我知道我可以使用iobuf.Reader,但是我想通过TLS
Conn来tls.Conn(conn, config)证明客户端使用的是SSL /
TLS,并且iobuf.Reader可以从原始目录中读取Conn,因此握手tls.Conn将失败。

那么,有什么方法可以窥探ConnGo语言(类似于MSG_PEEKC / C
++套接字)吗?或者,在tls.Conn从底层读取前几个字节后创建一个Conn


阅读 258

收藏
2020-07-02

共1个答案

一尘不染

您已经很接近解决方案了-
唯一出错的地方Conn就是首先阅读本身。你是正确的bufio.ReaderPeek方法是要走的路。诀窍是首先使缓冲的读取器生效,然后调用Peek缓冲的读取器,而不是从原始读取器进行读取Conn。这是一种bufferedConn可以满足您需要的类型:

type bufferedConn struct {
    r        *bufio.Reader
    net.Conn // So that most methods are embedded
}

func newBufferedConn(c net.Conn) bufferedConn {
    return bufferedConn{bufio.NewReader(c), c}
}

func newBufferedConnSize(c net.Conn, n int) bufferedConn {
    return bufferedConn{bufio.NewReaderSize(c, n), c}
}

func (b bufferedConn) Peek(n int) ([]byte, error) {
    return b.r.Peek(n)
}

func (b bufferedConn) Read(p []byte) (int, error) {
    return b.r.Read(p)
}

这样做是允许你访问所有的正常net.Conn方法(通过嵌入net.Conn-你也可以写的包装功能,但是这是一个极大的方便,更清洁),并另外提供访问bufferedReaderPeekRead方法(这一点很重要ReadBE在上调用bufferedReader,而不是直接在上调用,net.Conn因为Peek将数据存储在缓冲区中,因此后续调用Read需要能够首先从该缓冲区中读取任何数据,然后再返回基础net.Conn)。

newBufferedConnSize鉴于当前的默认缓冲区大小为4096字节,该函数可能是不必要的,但是从技术上讲,如果您要依赖能够以Peek给定大小进行调用并且不让它返回错误(特别是ErrBufferFull),则应显式设置它的大小至少要与您打算窥视的字节数一样大。

Go Playground上检查一下。

2020-07-02