📄 channels.c
字号:
}}voidchannel_input_close(int type, u_int32_t seq, void *ctxt){ int id; Channel *c; id = packet_get_int(); packet_check_eom(); c = channel_lookup(id); if (c == NULL) packet_disconnect("Received close for nonexistent channel %d.", id); /* * Send a confirmation that we have closed the channel and no more * data is coming for it. */ packet_start(SSH_MSG_CHANNEL_CLOSE_CONFIRMATION); packet_put_int(c->remote_id); packet_send(); /* * If the channel is in closed state, we have sent a close request, * and the other side will eventually respond with a confirmation. * Thus, we cannot free the channel here, because then there would be * no-one to receive the confirmation. The channel gets freed when * the confirmation arrives. */ if (c->type != SSH_CHANNEL_CLOSED) { /* * Not a closed channel - mark it as draining, which will * cause it to be freed later. */ buffer_clear(&c->input); c->type = SSH_CHANNEL_OUTPUT_DRAINING; }}/* proto version 1.5 overloads CLOSE_CONFIRMATION with OCLOSE */voidchannel_input_oclose(int type, u_int32_t seq, void *ctxt){ int id = packet_get_int(); Channel *c = channel_lookup(id); packet_check_eom(); if (c == NULL) packet_disconnect("Received oclose for nonexistent channel %d.", id); chan_rcvd_oclose(c);}voidchannel_input_close_confirmation(int type, u_int32_t seq, void *ctxt){ int id = packet_get_int(); Channel *c = channel_lookup(id); packet_check_eom(); if (c == NULL) packet_disconnect("Received close confirmation for " "out-of-range channel %d.", id); if (c->type != SSH_CHANNEL_CLOSED) packet_disconnect("Received close confirmation for " "non-closed channel %d (type %d).", id, c->type); channel_free(c);}voidchannel_input_open_confirmation(int type, u_int32_t seq, void *ctxt){ int id, remote_id; Channel *c; id = packet_get_int(); c = channel_lookup(id); if (c==NULL || c->type != SSH_CHANNEL_OPENING) packet_disconnect("Received open confirmation for " "non-opening channel %d.", id); remote_id = packet_get_int(); /* Record the remote channel number and mark that the channel is now open. */ c->remote_id = remote_id; c->type = SSH_CHANNEL_OPEN; if (compat20) { c->remote_window = packet_get_int(); c->remote_maxpacket = packet_get_int(); if (c->confirm) { debug2("callback start"); c->confirm(c->self, c->confirm_ctx); debug2("callback done"); } debug2("channel %d: open confirm rwindow %u rmax %u", c->self, c->remote_window, c->remote_maxpacket); } packet_check_eom();}static char *reason2txt(int reason){ switch (reason) { case SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED: return "administratively prohibited"; case SSH2_OPEN_CONNECT_FAILED: return "connect failed"; case SSH2_OPEN_UNKNOWN_CHANNEL_TYPE: return "unknown channel type"; case SSH2_OPEN_RESOURCE_SHORTAGE: return "resource shortage"; } return "unknown reason";}voidchannel_input_open_failure(int type, u_int32_t seq, void *ctxt){ int id, reason; char *msg = NULL, *lang = NULL; Channel *c; id = packet_get_int(); c = channel_lookup(id); if (c==NULL || c->type != SSH_CHANNEL_OPENING) packet_disconnect("Received open failure for " "non-opening channel %d.", id); if (compat20) { reason = packet_get_int(); if (!(datafellows & SSH_BUG_OPENFAILURE)) { msg = packet_get_string(NULL); lang = packet_get_string(NULL); } logit("channel %d: open failed: %s%s%s", id, reason2txt(reason), msg ? ": ": "", msg ? msg : ""); if (msg != NULL) xfree(msg); if (lang != NULL) xfree(lang); } packet_check_eom(); /* Free the channel. This will also close the socket. */ channel_free(c);}voidchannel_input_window_adjust(int type, u_int32_t seq, void *ctxt){ Channel *c; int id; u_int adjust; if (!compat20) return; /* Get the channel number and verify it. */ id = packet_get_int(); c = channel_lookup(id); if (c == NULL || c->type != SSH_CHANNEL_OPEN) { logit("Received window adjust for " "non-open channel %d.", id); return; } adjust = packet_get_int(); packet_check_eom(); debug2("channel %d: rcvd adjust %u", id, adjust); c->remote_window += adjust;}voidchannel_input_port_open(int type, u_int32_t seq, void *ctxt){ Channel *c = NULL; u_short host_port; char *host, *originator_string; int remote_id, sock = -1; remote_id = packet_get_int(); host = packet_get_string(NULL); host_port = packet_get_int(); if (packet_get_protocol_flags() & SSH_PROTOFLAG_HOST_IN_FWD_OPEN) { originator_string = packet_get_string(NULL); } else { originator_string = xstrdup("unknown (remote did not supply name)"); } packet_check_eom(); sock = channel_connect_to(host, host_port); if (sock != -1) { c = channel_new("connected socket", SSH_CHANNEL_CONNECTING, sock, sock, -1, 0, 0, 0, originator_string, 1); c->remote_id = remote_id; } xfree(originator_string); if (c == NULL) { packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE); packet_put_int(remote_id); packet_send(); } xfree(host);}/* -- tcp forwarding */voidchannel_set_af(int af){ IPv4or6 = af;}static intchannel_setup_fwd_listener(int type, const char *listen_addr, u_short listen_port, const char *host_to_connect, u_short port_to_connect, int gateway_ports){ Channel *c; int sock, r, success = 0, on = 1, wildcard = 0, is_client; struct addrinfo hints, *ai, *aitop; const char *host, *addr; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; host = (type == SSH_CHANNEL_RPORT_LISTENER) ? listen_addr : host_to_connect; is_client = (type == SSH_CHANNEL_PORT_LISTENER); if (host == NULL) { error("No forward host name."); return success; } if (strlen(host) > SSH_CHANNEL_PATH_LEN - 1) { error("Forward host name too long."); return success; } /* * Determine whether or not a port forward listens to loopback, * specified address or wildcard. On the client, a specified bind * address will always override gateway_ports. On the server, a * gateway_ports of 1 (``yes'') will override the client's * specification and force a wildcard bind, whereas a value of 2 * (``clientspecified'') will bind to whatever address the client * asked for. * * Special-case listen_addrs are: * * "0.0.0.0" -> wildcard v4/v6 if SSH_OLD_FORWARD_ADDR * "" (empty string), "*" -> wildcard v4/v6 * "localhost" -> loopback v4/v6 */ addr = NULL; if (listen_addr == NULL) { /* No address specified: default to gateway_ports setting */ if (gateway_ports) wildcard = 1; } else if (gateway_ports || is_client) { if (((datafellows & SSH_OLD_FORWARD_ADDR) && strcmp(listen_addr, "0.0.0.0") == 0) || *listen_addr == '\0' || strcmp(listen_addr, "*") == 0 || (!is_client && gateway_ports == 1)) wildcard = 1; else if (strcmp(listen_addr, "localhost") != 0) addr = listen_addr; } debug3("channel_setup_fwd_listener: type %d wildcard %d addr %s", type, wildcard, (addr == NULL) ? "NULL" : addr); /* * getaddrinfo returns a loopback address if the hostname is * set to NULL and hints.ai_flags is not AI_PASSIVE */ memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_flags = wildcard ? AI_PASSIVE : 0; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%d", listen_port); if ((r = getaddrinfo(addr, strport, &hints, &aitop)) != 0) { if (addr == NULL) { /* This really shouldn't happen */ packet_disconnect("getaddrinfo: fatal error: %s", gai_strerror(r)); } else { verbose("channel_setup_fwd_listener: " "getaddrinfo(%.64s): %s", addr, gai_strerror(r)); packet_send_debug("channel_setup_fwd_listener: " "getaddrinfo(%.64s): %s", addr, gai_strerror(r)); } aitop = NULL; } for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; if (getnameinfo(ai->ai_addr, ai->ai_addrlen, ntop, sizeof(ntop), strport, sizeof(strport), NI_NUMERICHOST|NI_NUMERICSERV) != 0) { error("channel_setup_fwd_listener: getnameinfo failed"); continue; } /* Create a port to listen for the host. */ sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sock < 0) { /* this is no error since kernel may not support ipv6 */ verbose("socket: %.100s", strerror(errno)); continue; } /* * Set socket options. * Allow local port reuse in TIME_WAIT. */ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) error("setsockopt SO_REUSEADDR: %s", strerror(errno)); debug("Local forwarding listening on %s port %s.", ntop, strport); /* Bind the socket to the address. */ if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { /* address can be in use ipv6 address is already bound */ if (!ai->ai_next) error("bind: %.100s", strerror(errno)); else verbose("bind: %.100s", strerror(errno)); close(sock); continue; } /* Start listening for connections on the socket. */ if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { error("listen: %.100s", strerror(errno)); close(sock); continue; } /* Allocate a channel number for the socket. */ c = channel_new("port listener", type, sock, sock, -1, CHAN_TCP_WINDOW_DEFAULT, CHAN_TCP_PACKET_DEFAULT, 0, "port listener", 1); strlcpy(c->path, host, sizeof(c->path)); c->host_port = port_to_connect; c->listening_port = listen_port; success = 1; } if (success == 0) error("channel_setup_fwd_listener: cannot listen to port: %d", listen_port); freeaddrinfo(aitop); return success;}intchannel_cancel_rport_listener(const char *host, u_short port){ u_int i; int found = 0; for(i = 0; i < channels_alloc; i++) { Channel *c = channels[i]; if (c != NULL && c->type == SSH_CHANNEL_RPORT_LISTENER && strncmp(c->path, host, sizeof(c->path)) == 0 && c->listening_port == port) { debug2("%s: close channel %d", __func__, i); channel_free(c); found = 1; } } return (found);}/* protocol local port fwd, used by ssh (and sshd in v1) */intchannel_setup_local_fwd_listener(const char *listen_host, u_short listen_port, const char *host_to_connect, u_short port_to_connect, int gateway_ports){ return channel_setup_fwd_listener(SSH_CHANNEL_PORT_LISTENER, listen_host, listen_port, host_to_connect, port_to_connect, gateway_ports);}/* protocol v2 remote port fwd, used by sshd */intchannel_setup_remote_fwd_listener(const char *listen_address, u_short listen_port, int gateway_ports){ return channel_setup_fwd_listener(SSH_CHANNEL_RPORT_LISTENER, listen_address, listen_port, NULL, 0, gateway_ports);}/* * Initiate forwarding of connections to port "port" on remote host through * the secure channel to host:port from local side. */voidchannel_request_remote_forwarding(const char *listen_host, u_short listen_port, const char *host_to_connect, u_short port_to_connect){ int type, success = 0; /* Record locally that connection to this host/port is permitted. */ if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) fatal("channel_request_remote_forwarding: too many forwards"); /* Send the forward request to the remote side. */ if (compat20) { const char *address_to_bind; if (listen_host == NULL) address_to_bind = "localhost"; else if (*listen_host == '\0' || strcmp(listen_host, "*") == 0) address_to_bind = ""; else address_to_bind = listen_host; packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("tcpip-forward"); packet_put_char(1); /* boolean: want reply */ packet_put_cstring(address_to_bind); packet_put_int(listen_port); packet_send(); packet_write_wait(); /* Assume that server accepts the request */ success = 1; } else { packet_start(SSH_CMSG_PORT_FORWARD_REQUEST); packet_put_int(listen_port); packet_put_cstring(host_to_connect); packet_put_int(port_to_connect); packet_send(); packet_write_wait(); /* Wait for response from the remote side. */ type = packet_read(); switch (type) { case SSH_SMSG_SUCCESS: success = 1; break; case SSH_SMSG_FAILURE: logit("Warning: Server denied remote port forwarding."); break; default: /* Unknown packet */ packet_disconnect("Protocol error for port forward request:" "received packet type %d.", type); } } if (success) { permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host_to_connect); permitted_opens[num_permitted_opens].port_to_connect = port_to_connect; permitted_opens[num_permitted_opens].listen_port = listen_port; num_permitted_opens++; }}/* * Request cancellation of remote forwarding of connection host:port from * local side. */voidchannel_request_rforward_cancel(const char *host, u_short port){ int i; if (!compat20) return; for (i = 0; i < num_permitted_opens; i++) { if (permitted_opens[i].host_to_connect != NULL && permitted_opens[i].listen_port == port) break; } if (i >= num_permitted_opens) { debug("%s: requested forward not found", __func__); return; } packet_start(SSH2_MSG_GLOBAL_REQUEST); packet_put_cstring("cancel-tcpip-forward"); packet_put_char(0); packet_put_cstring(host == NULL ? "" : host); packet_put_int(port); packet_send(); permitted_opens[i].listen_port = 0; permitted_opens[i].por
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -