ssh channel功能实现源码分析
一、相关资料
可以从下面地址下载工程源码l
ssh使用的RFC协议在下面文档中描述
使用channel的原因通常是两台主机A、B不能直接联通,但是它们都和M联通,并且M机器上运行了sshd服务器,也就是一方可以通过ssh和中转机联通。此时可以使用中转机M来联通A和B两台机器。
二、命令行参数(-L/-R)的处理
openssh-8.0\ssh.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.0\channels.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);
……
}