chisel 分析4 面向对象

其核心初始化 clientconn  server conn如下(serverconn和clientconn逻辑差不多)

// NewClientConn establishes an authenticated SSH connection using c
// as the underlying transport.  The Request and NewChannel channels
// must be serviced or the connection will hang.
func NewClientConn(c net.Conn, addr string, config *ClientConfig) (Conn, <-chan NewChannel, <-chan *Request, error) {
	fullConf := *config
	fullConf.SetDefaults()
	if fullConf.HostKeyCallback == nil {
		c.Close()
		return nil, nil, nil, errors.New("ssh: must specify HostKeyCallback")
	}

	conn := &connection{
		sshConn: sshConn{conn: c, user: fullConf.User},
	}

	if err := conn.clientHandshake(addr, &fullConf); err != nil {
		c.Close()
		return nil, nil, nil, fmt.Errorf("ssh: handshake failed: %v", err)
	}
	conn.mux = newMux(conn.transport)
	return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
}
// clientHandshake performs the client side key exchange. See RFC 4253 Section
// 7.
func (c *connection) clientHandshake(dialAddress string, config *ClientConfig) error {
	if config.ClientVersion != "" {
		c.clientVersion = []byte(config.ClientVersion)
	} else {
		c.clientVersion = []byte(packageVersion)
	}
	fmt.Printf("client version:%s\n", c.clientVersion)
	var err error
	c.serverVersion, err = exchangeVersions(c.sshConn.conn, c.clientVersion)
	if err != nil {
		return err
	}
	fmt.Printf("serverVersion :%s  dialAddress:%s remote:%+v\n", c.serverVersion, dialAddress, c.sshConn.RemoteAddr())
	tr := newTransport(c.sshConn.conn, config.Rand, true /* is client */)
	c.transport = newClientTransport( tr, c.clientVersion, c.serverVersion, config, dialAddress, c.sshConn.RemoteAddr())
	if err := c.transport.waitSession(); err != nil {
		return err
	}

	c.sessionID = c.transport.getSessionID()
	return c.clientAuthenticate(config)
}

其主要是依赖connection将mux、 sshconn、handshakeTransport相互组织在一起

// A connection represents an incoming connection.
type connection struct {
	transport *handshakeTransport
	sshConn

	// The connection protocol.
	*mux
}
如何组织:
1、初始化conn,然后将net.Con赋值给conn的sshCon
2、conn.clientHandshake 的时候将 net.Conn 封装成newTransport,让后将Transport封装成 newClientTransport,然后执行ssh handshake逻辑。
3、使用newmux 将conn.transport 封装成mux 并填充conn的mux
  3.1 初始化mux的时候,会生成channel list,每次创建channel会挂在此channel list上
 
  这其中开启mux的loop协程读取transport的报文,然后解析送到各个channel。然后调用channel的读写函数,channel读取数据解析根据type进一步处理。
如果是要转发的数据,channel也有自己的buf pending 缓存。channel会将数据write 到pending里面,然后channel 在读取数据时,直接从pending里面读取
 
  时间上handshakeTransport里面也有一层 chan  buf 缓存,每个handshakeTransport 也会有自己的readloop协程读取Tr流里面的内容,然后将数据放入incoming chan;
每次mux调用handshakeTransport的readpacket的时候实际上就是从incoming的chan里面读取数据。
 
对于handshakeTransport以及Transport开启的协程读取数据则涉及到ssh加解密过程。涉及到cipher等逻辑。不看了
 

 

posted @ 2024-01-08 11:40  codestacklinuxer  阅读(8)  评论(0编辑  收藏  举报