插座 – 偷看康恩而不读书

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

检查http://golang.org/pkg/net/,似乎Conn界面没有这样的东西.我知道我可以使用iobuf.Reader,但我想通过tls.Conn(conn,config)获得TLS Conn,如果事实证明客户端使用SSL / TLS,并且iobuf.Reader将从原始读取Conn,因此tls.Conn中的握手会失败.

那么有没有办法窥探Conn in Go(类似于C/C++套接字中的MSG_PEEK)?或者,在我读出底层Conn的前几个字节之后创建一个tls.Conn?

最佳答案
你非常接近一个解决方案 – 你唯一错的就是首先从康恩本身读书.你是对的,bufio.Reader的Peek方法是要走的路.诀窍是首先制作缓冲读卡器并在缓冲读卡器上调用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 – 你也可以编写包装函数,但这更容易和更清晰),并且还提供对bufferedReader的Peek和读取方法(重要的是在bufferedReader上调用Read,而不是直接在net.Conn上调用,因为Peek将数据存储在缓冲区中,因此后续调用Read需要能够先从此缓冲区中读取任何数据,然后再回退到底层网.康宁).

鉴于当前的默认缓冲区大小为4096字节,newBufferedConnSize函数可能是不必要的,但从技术上讲,如果您将依赖于能够以给定大小调用Peek并且没有返回错误(特别是ErrBufferFull),那么您应该将其明确设置为一个至少与您要查看的字节数一样大的大小.

请查看Go Playground.

转载注明原文:插座 – 偷看康恩而不读书 - 代码日志