📄 channels.c
字号:
case SSH_CHANNEL_LARVAL: case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_OPEN: case SSH_CHANNEL_X11_OPEN: return i; case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING: if (!compat13) fatal("cannot happen: OUT_DRAIN"); return i; default: fatal("channel_find_open: bad channel type %d", c->type); /* NOTREACHED */ } } return -1;}/* * Returns a message describing the currently open forwarded connections, * suitable for sending to the client. The message contains crlf pairs for * newlines. */char *channel_open_message(void){ Buffer buffer; Channel *c; char buf[1024], *cp; int i; buffer_init(&buffer); snprintf(buf, sizeof buf, "The following connections are open:\r\n"); buffer_append(&buffer, buf, strlen(buf)); for (i = 0; i < channels_alloc; i++) { c = channels[i]; if (c == NULL) continue; switch (c->type) { case SSH_CHANNEL_X11_LISTENER: case SSH_CHANNEL_PORT_LISTENER: case SSH_CHANNEL_RPORT_LISTENER: case SSH_CHANNEL_CLOSED: case SSH_CHANNEL_AUTH_SOCKET: case SSH_CHANNEL_ZOMBIE: continue; case SSH_CHANNEL_LARVAL: case SSH_CHANNEL_OPENING: case SSH_CHANNEL_CONNECTING: case SSH_CHANNEL_DYNAMIC: case SSH_CHANNEL_OPEN: case SSH_CHANNEL_X11_OPEN: case SSH_CHANNEL_INPUT_DRAINING: case SSH_CHANNEL_OUTPUT_DRAINING: snprintf(buf, sizeof buf, " #%d %.300s (t%d r%d i%d/%d o%d/%d fd %d/%d)\r\n", c->self, c->remote_name, c->type, c->remote_id, c->istate, buffer_len(&c->input), c->ostate, buffer_len(&c->output), c->rfd, c->wfd); buffer_append(&buffer, buf, strlen(buf)); continue; default: fatal("channel_open_message: bad channel type %d", c->type); /* NOTREACHED */ } } buffer_append(&buffer, "\0", 1); cp = xstrdup(buffer_ptr(&buffer)); buffer_free(&buffer); return cp;}voidchannel_send_open(int id){ Channel *c = channel_lookup(id); if (c == NULL) { log("channel_send_open: %d: bad id", id); return; } debug2("channel %d: send open", id); packet_start(SSH2_MSG_CHANNEL_OPEN); packet_put_cstring(c->ctype); packet_put_int(c->self); packet_put_int(c->local_window); packet_put_int(c->local_maxpacket); packet_send();}voidchannel_request_start(int id, char *service, int wantconfirm){ Channel *c = channel_lookup(id); if (c == NULL) { log("channel_request_start: %d: unknown channel id", id); return; } debug("channel %d: request %s", id, service) ; packet_start(SSH2_MSG_CHANNEL_REQUEST); packet_put_int(c->remote_id); packet_put_cstring(service); packet_put_char(wantconfirm);}voidchannel_register_confirm(int id, channel_callback_fn *fn){ Channel *c = channel_lookup(id); if (c == NULL) { log("channel_register_comfirm: %d: bad id", id); return; } c->confirm = fn;}voidchannel_register_cleanup(int id, channel_callback_fn *fn){ Channel *c = channel_lookup(id); if (c == NULL) { log("channel_register_cleanup: %d: bad id", id); return; } c->detach_user = fn;}voidchannel_cancel_cleanup(int id){ Channel *c = channel_lookup(id); if (c == NULL) { log("channel_cancel_cleanup: %d: bad id", id); return; } c->detach_user = NULL;}voidchannel_register_filter(int id, channel_filter_fn *fn){ Channel *c = channel_lookup(id); if (c == NULL) { log("channel_register_filter: %d: bad id", id); return; } c->input_filter = fn;}voidchannel_set_fds(int id, int rfd, int wfd, int efd, int extusage, int nonblock, u_int window_max){ Channel *c = channel_lookup(id); if (c == NULL || c->type != SSH_CHANNEL_LARVAL) fatal("channel_activate for non-larval channel %d.", id); channel_register_fds(c, rfd, wfd, efd, extusage, nonblock); c->type = SSH_CHANNEL_OPEN; c->local_window = c->local_window_max = window_max; packet_start(SSH2_MSG_CHANNEL_WINDOW_ADJUST); packet_put_int(c->remote_id); packet_put_int(c->local_window); packet_send();}/* * 'channel_pre*' are called just before select() to add any bits relevant to * channels in the select bitmasks. *//* * 'channel_post*': perform any appropriate operations for channels which * have events pending. */typedef void chan_fn(Channel *c, fd_set * readset, fd_set * writeset);chan_fn *channel_pre[SSH_CHANNEL_MAX_TYPE];chan_fn *channel_post[SSH_CHANNEL_MAX_TYPE];static voidchannel_pre_listener(Channel *c, fd_set * readset, fd_set * writeset){ FD_SET(c->sock, readset);}static voidchannel_pre_connecting(Channel *c, fd_set * readset, fd_set * writeset){ debug3("channel %d: waiting for connection", c->self); FD_SET(c->sock, writeset);}static voidchannel_pre_open_13(Channel *c, fd_set * readset, fd_set * writeset){ if (buffer_len(&c->input) < packet_get_maxsize()) FD_SET(c->sock, readset); if (buffer_len(&c->output) > 0) FD_SET(c->sock, writeset);}static voidchannel_pre_open(Channel *c, fd_set * readset, fd_set * writeset){ u_int limit = compat20 ? c->remote_window : packet_get_maxsize(); if (c->istate == CHAN_INPUT_OPEN && limit > 0 && buffer_len(&c->input) < limit) FD_SET(c->rfd, readset); if (c->ostate == CHAN_OUTPUT_OPEN || c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { if (buffer_len(&c->output) > 0) { FD_SET(c->wfd, writeset); } else if (c->ostate == CHAN_OUTPUT_WAIT_DRAIN) { if (CHANNEL_EFD_OUTPUT_ACTIVE(c)) debug2("channel %d: obuf_empty delayed efd %d/(%d)", c->self, c->efd, buffer_len(&c->extended)); else chan_obuf_empty(c); } } /** XXX check close conditions, too */ if (compat20 && c->efd != -1) { if (c->extended_usage == CHAN_EXTENDED_WRITE && buffer_len(&c->extended) > 0) FD_SET(c->efd, writeset); else if (!(c->flags & CHAN_EOF_SENT) && c->extended_usage == CHAN_EXTENDED_READ && buffer_len(&c->extended) < c->remote_window) FD_SET(c->efd, readset); }}static voidchannel_pre_input_draining(Channel *c, fd_set * readset, fd_set * writeset){ if (buffer_len(&c->input) == 0) { packet_start(SSH_MSG_CHANNEL_CLOSE); packet_put_int(c->remote_id); packet_send(); c->type = SSH_CHANNEL_CLOSED; debug("channel %d: closing after input drain.", c->self); }}static voidchannel_pre_output_draining(Channel *c, fd_set * readset, fd_set * writeset){ if (buffer_len(&c->output) == 0) chan_mark_dead(c); else FD_SET(c->sock, writeset);}/* * This is a special state for X11 authentication spoofing. An opened X11 * connection (when authentication spoofing is being done) remains in this * state until the first packet has been completely read. The authentication * data in that packet is then substituted by the real data if it matches the * fake data, and the channel is put into normal mode. * XXX All this happens at the client side. * Returns: 0 = need more data, -1 = wrong cookie, 1 = ok */static intx11_open_helper(Buffer *b){ u_char *ucp; u_int proto_len, data_len; /* Check if the fixed size part of the packet is in buffer. */ if (buffer_len(b) < 12) return 0; /* Parse the lengths of variable-length fields. */ ucp = buffer_ptr(b); if (ucp[0] == 0x42) { /* Byte order MSB first. */ proto_len = 256 * ucp[6] + ucp[7]; data_len = 256 * ucp[8] + ucp[9]; } else if (ucp[0] == 0x6c) { /* Byte order LSB first. */ proto_len = ucp[6] + 256 * ucp[7]; data_len = ucp[8] + 256 * ucp[9]; } else { debug("Initial X11 packet contains bad byte order byte: 0x%x", ucp[0]); return -1; } /* Check if the whole packet is in buffer. */ if (buffer_len(b) < 12 + ((proto_len + 3) & ~3) + ((data_len + 3) & ~3)) return 0; /* Check if authentication protocol matches. */ if (proto_len != strlen(x11_saved_proto) || memcmp(ucp + 12, x11_saved_proto, proto_len) != 0) { debug("X11 connection uses different authentication protocol."); return -1; } /* Check if authentication data matches our fake data. */ if (data_len != x11_fake_data_len || memcmp(ucp + 12 + ((proto_len + 3) & ~3), x11_fake_data, x11_fake_data_len) != 0) { debug("X11 auth data does not match fake data."); return -1; } /* Check fake data length */ if (x11_fake_data_len != x11_saved_data_len) { error("X11 fake_data_len %d != saved_data_len %d", x11_fake_data_len, x11_saved_data_len); return -1; } /* * Received authentication protocol and data match * our fake data. Substitute the fake data with real * data. */ memcpy(ucp + 12 + ((proto_len + 3) & ~3), x11_saved_data, x11_saved_data_len); return 1;}static voidchannel_pre_x11_open_13(Channel *c, fd_set * readset, fd_set * writeset){ int ret = x11_open_helper(&c->output); if (ret == 1) { /* Start normal processing for the channel. */ c->type = SSH_CHANNEL_OPEN; channel_pre_open_13(c, readset, writeset); } else if (ret == -1) { /* * We have received an X11 connection that has bad * authentication information. */ log("X11 connection rejected because of wrong authentication."); buffer_clear(&c->input); buffer_clear(&c->output); channel_close_fd(&c->sock); c->sock = -1; c->type = SSH_CHANNEL_CLOSED; packet_start(SSH_MSG_CHANNEL_CLOSE); packet_put_int(c->remote_id); packet_send(); }}static voidchannel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset){ int ret = x11_open_helper(&c->output); /* c->force_drain = 1; */ if (ret == 1) { c->type = SSH_CHANNEL_OPEN; channel_pre_open(c, readset, writeset); } else if (ret == -1) { log("X11 connection rejected because of wrong authentication."); debug("X11 rejected %d i%d/o%d", c->self, c->istate, c->ostate); chan_read_failed(c); buffer_clear(&c->input); chan_ibuf_empty(c); buffer_clear(&c->output); /* for proto v1, the peer will send an IEOF */ if (compat20) chan_write_failed(c); else c->type = SSH_CHANNEL_OPEN; debug("X11 closed %d i%d/o%d", c->self, c->istate, c->ostate); }}/* try to decode a socks4 header */static intchannel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset){ char *p, *host; int len, have, i, found; char username[256]; struct { u_int8_t version; u_int8_t command; u_int16_t dest_port; struct in_addr dest_addr; } s4_req, s4_rsp; debug2("channel %d: decode socks4", c->self); have = buffer_len(&c->input); len = sizeof(s4_req); if (have < len) return 0; p = buffer_ptr(&c->input); for (found = 0, i = len; i < have; i++) { if (p[i] == '\0') { found = 1; break; } if (i > 1024) { /* the peer is probably sending garbage */ debug("channel %d: decode socks4: too long", c->self); return -1; } } if (!found) return 0; buffer_get(&c->input, (char *)&s4_req.version, 1); buffer_get(&c->input, (char *)&s4_req.command, 1); buffer_get(&c->input, (char *)&s4_req.dest_port, 2); buffer_get(&c->input, (char *)&s4_req.dest_addr, 4); have = buffer_len(&c->input); p = buffer_ptr(&c->input); len = strlen(p); debug2("channel %d: decode socks4: user %s/%d", c->self, p, len); if (len > have) fatal("channel %d: decode socks4: len %d > have %d", c->self, len, have); strlcpy(username, p, sizeof(username)); buffer_consume(&c->input, len); buffer_consume(&c->input, 1); /* trailing '\0' */ host = inet_ntoa(s4_req.dest_addr); strlcpy(c->path, host, sizeof(c->path)); c->host_port = ntohs(s4_req.dest_port); debug("channel %d: dynamic request: socks4 host %s port %u command %u", c->self, host, c->host_port, s4_req.command); if (s4_req.command != 1) { debug("channel %d: cannot handle: socks4 cn %d", c->self, s4_req.command); return -1; } s4_rsp.version = 0; /* vn: 0 for reply */ s4_rsp.command = 90; /* cd: req granted */ s4_rsp.dest_port = 0; /* ignored */ s4_rsp.dest_addr.s_addr = INADDR_ANY; /* ignored */ buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); return 1;}/* dynamic port forwarding */static voidchannel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset){ u_char *p; int have, ret; have = buffer_len(&c->input); c->delayed = 0; debug2("channel %d: pre_dynamic: have %d", c->self, have); /* buffer_dump(&c->input); */ /* check if the fixed size part of the packet is in buffer. */ if (have < 4) { /* need more */ FD_SET(c->sock, readset); return; } /* try to guess the protocol */ p = buffer_ptr(&c->input); switch (p[0]) { case 0x04: ret = channel_decode_socks4(c, readset, writeset); break; default: ret = -1; break; } if (ret < 0) { chan_mark_dead(c); } else if (ret == 0) { debug2("channel %d: pre_dynamic: need more", c->self); /* need more */ FD_SET(c->sock, readset); } else { /* switch to the next state */ c->type = SSH_CHANNEL_OPENING; port_open_helper(c, "direct-tcpip"); }}/* This is our fake X11 server socket. */static voidchannel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset){ Channel *nc; struct sockaddr addr; int newsock; socklen_t addrlen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -