ikilobyte/netman

TLS相关

raymondheavy opened this issue · 9 comments

baseconnect.go这个文件中

_```
// Read 读取数据
func (c *BaseConnect) Read(bs []byte) (int, error) {

n, err := unix.Read(c.fd, bs)

// 已完成了TLS握手
if c.handshakeCompleted {
	if n >= 0 {
		c.tlsRawSize += n
	}
}

想问下,if c.handshakeCompleted后计算收到的业务数据长度。有没有一种可能性,就是在握手结束时最后一次Read会读取部分业务数据?

@raymondheavy

如果c.handshakeCompletedtrue,那就一定完成了TLS握手,如果false则还在握手阶段,不会出现握手结束时最后一次Read会读取部分业务数据

TLS握手实现细节

netman/eventloop/epoll.go

Lines 84 to 103 in 3ce691c

// 1、判断是否开启tls
if conn.GetTLSEnable() && conn.GetHandshakeCompleted() == false {
tlsConnect := conn.GetTLSLayer()
if err := tlsConnect.Handshake(); err != nil {
// 断开连接
_ = conn.Close()
util.Logger.Errorf("tls handshake error %v", err)
continue
}
// 1、设置状态
conn.SetHandshakeCompleted()
// 2、设置当前FD为非阻塞模式
if err := unix.SetNonblock(connFd, true); err != nil {
_ = conn.Close()
continue
}
}

tlsConnect.Handshake() 实际上是调用的标准库的方法,标准库的conn会调用baseConnect.Read,此时c.handshakeCompleted一定是false,欢迎交流

	if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
		if e, ok := err.(net.Error); !ok || !e.Temporary() {
			c.in.setErrorLocked(err)
		}
		return err
	}

// ReadFrom reads data from r until EOF and appends it to the buffer, growing
// the buffer as needed. The return value n is the number of bytes read. Any
// error except io.EOF encountered during the read is also returned. If the
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
	b.lastRead = opInvalid
	for {
		i := b.grow(MinRead)
		b.buf = b.buf[:i]
		m, e := r.Read(b.buf[i:cap(b.buf)])
		if m < 0 {
			panic(errNegativeRead)
		}

		b.buf = b.buf[:i+m]
		n += int64(m)
		if e == io.EOF {
			return n, nil // e is EOF, so return nil explicitly
		}
		if e != nil {
			return n, e
		}
	}
}

在标准库tls中,read传入的buf大小不一定就是最后一次需要的大小,可能是大于这个需要数据大小的吧。如果对端在握手最后一次交互后,立即发送了业务数据。此时socket缓冲区中既有握手,也有业务数据,如果read传入的读buf大于剩余的握手大小,不就把业务数据也读取了吗?

在使用TLS后,应用层的read操作并不是直接从socket中读取,而是从TLS层的buf中读取,流程就变成了 app -> tls -> socket

即使tls在握手时读了应用层的业务数据,tls也会保存在buf中,应用层写数据也是一样的,先到写到tls层,tls加密后再发送出去

那如果读了,c.tlsRawSize 这个值的准确性呢?

这个值确实不准了,是遇到了什么问题吗

主要是想学习下,如何精确切分握手和后续的业务数据的。看了代码之后,对这个地方有些疑问