ssh channel功能实现源码分析

一、相关资料

可以从下面地址下载工程源码l
ssh使用的RFC协议在下面文档中描述

使用channel的原因通常是两台主机A、B不能直接联通,但是它们都和M联通,并且M机器上运行了sshd服务器,也就是一方可以通过ssh和中转机联通。此时可以使用中转机M来联通A和B两台机器。

二、命令行参数(-L/-R)的处理

openssh-8.0ssh.c
void
add_local_forward(Options *options, const struct Forward *newfwd)
{
……
options->local_forwards = xreallocarray(options->local_forwards,
options->num_local_forwards + 1,
……
}

void
add_remote_forward(Options *options, const struct Forward *newfwd)
{
……
options->remote_forwards = xreallocarray(options->remote_forwards,
options->num_remote_forwards + 1,
sizeof(*options->remote_forwards));
……
}

三、Local端口有连接时处理

1、ssh客户端的处理


openssh-8.0channels.c
static void
channel_post_port_listener(struct ssh *ssh, Channel *c,
fd_set *readset, fd_set *writeset)
{
……
} else {
nextstate = SSH_CHANNEL_OPENING;
rtype = "direct-tcpip";
}

addrlen = sizeof(addr);
newsock = accept(c->sock, (struct sockaddr *)&addr, &addrlen);
……
if (nextstate != SSH_CHANNEL_DYNAMIC)
port_open_helper(ssh, nc, rtype);
}
……
}

static void
port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
{
……
open_preamble(ssh, __func__, c, rtype);
if (strcmp(rtype, "direct-tcpip") == 0) {
/* target host, port */
if ((r = sshpkt_put_cstring(ssh, c->path)) != 0 ||
(r = sshpkt_put_u32(ssh, c->host_port)) != 0) {
fatal("%s: channel %i: reply %s", __func__,
c->self, ssh_err(r));
}
}
……
}
static void
open_preamble(struct ssh *ssh, const char *where, Channel *c, const char *type)
{
int r;

if ((r = sshpkt_start(ssh, SSH2_MSG_CHANNEL_OPEN)) != 0 ||
(r = sshpkt_put_cstring(ssh, type)) != 0 ||
(r = sshpkt_put_u32(ssh, c->self)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_window)) != 0 ||
(r = sshpkt_put_u32(ssh, c->local_maxpacket)) != 0) {
fatal("%s: channel %i: open: %s", where, c->self, ssh_err(r));
}
}

2、sshd对于SSH2_MSG_CHANNEL_OPEN命令的处理

static int
server_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
{
……
} else if (strcmp(ctype, "direct-tcpip") == 0) {
c = server_request_direct_tcpip(ssh, &reason, &errmsg);
}
……
}

static Channel *
server_request_direct_tcpip(struct ssh *ssh, int *reason, const char **errmsg)
{
……
c = channel_connect_to_port(ssh, target, target_port,
"direct-tcpip", "direct-tcpip", reason, errmsg);
……
}

四、服务器端(Remote)有连接时处理

1、客户端对-R命令行参数的处理

int
channel_request_remote_forwarding(struct ssh *ssh, struct Forward *fwd)
{
……
if ((r = sshpkt_start(ssh, SSH2_MSG_GLOBAL_REQUEST)) != 0 ||
(r = sshpkt_put_cstring(ssh, "tcpip-forward")) != 0 ||
(r = sshpkt_put_u8(ssh, 1)) != 0 || /* want reply */
(r = sshpkt_put_cstring(ssh,
channel_rfwd_bind_host(fwd->listen_host))) != 0 ||
(r = sshpkt_put_u32(ssh, fwd->listen_port)) != 0 ||
(r = sshpkt_send(ssh)) != 0 ||
(r = ssh_packet_write_wait(ssh)) != 0)
fatal("%s: request tcpip-forward: %s",
__func__, ssh_err(r));
……
}

3、sshd对该命令的处理

static int
server_input_global_request(int type, u_int32_t seq, struct ssh *ssh)
{
……
/* -R style forwarding */
if (strcmp(rtype, "tcpip-forward") == 0) {
……
ssh_packet_send_debug(ssh, "Server has disabled port forwarding.");
} else {
/* Start listening on the port */
success = channel_setup_remote_fwd_listener(ssh, &fwd,
&allocated_listen_port, &options.fwd_opts);
}
……
}
……
}

4、当有连接到sshd所在服务器指定端口时

static void
port_open_helper(struct ssh *ssh, Channel *c, char *rtype)
{
……
open_preamble(ssh, __func__, c, rtype);
……
if ((r = sshpkt_send(ssh)) != 0)
fatal("%s: channel %i: send %s", __func__, c->self, ssh_err(r));
free(remote_ipaddr);
free(local_ipaddr);
}

5、ssh客户端对于连接的处理

/* XXXX move to generic input handler */
static int
client_input_channel_open(int type, u_int32_t seq, struct ssh *ssh)
{
……
if (strcmp(ctype, "forwarded-tcpip") == 0) {
c = client_request_forwarded_tcpip(ssh, ctype, rchan, rwindow,
rmaxpack);
……
}

原文地址:https://www.cnblogs.com/tsecer/p/11364643.html