📄 channels.c
字号:
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; } if (c == NULL) { xfree(originator_string); 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 success, sock, on = 1; struct addrinfo hints, *ai, *aitop; const char *host; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; success = 0; host = (type == SSH_CHANNEL_RPORT_LISTENER) ? listen_addr : host_to_connect; 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; } /* * 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 = gateway_ports ? AI_PASSIVE : 0; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%d", listen_port); if (getaddrinfo(NULL, strport, &hints, &aitop) != 0) packet_disconnect("getaddrinfo: fatal error"); 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, SOCK_STREAM, 0); 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 */ verbose("bind: %.100s", strerror(errno)); close(sock); continue; } /* Start listening for connections on the socket. */ if (listen(sock, 5) < 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, xstrdup("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;}/* protocol local port fwd, used by ssh (and sshd in v1) */intchannel_setup_local_fwd_listener(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, NULL, 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(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 = "0.0.0.0"; 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: log("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++; }}/* * This is called after receiving CHANNEL_FORWARDING_REQUEST. This initates * listening for the port, and sends back a success reply (or disconnect * message if there was an error). This never returns if there was an error. */voidchannel_input_port_forward_request(int is_root, int gateway_ports){ u_short port, host_port; char *hostname; /* Get arguments from the packet. */ port = packet_get_int(); hostname = packet_get_string(NULL); host_port = packet_get_int(); /* * Check that an unprivileged user is not trying to forward a * privileged port. */ if (port < IPPORT_RESERVED && !is_root) packet_disconnect("Requested forwarding of port %d but user is not root.", port); /* Initiate forwarding */ channel_setup_local_fwd_listener(port, hostname, host_port, gateway_ports); /* Free the argument string. */ xfree(hostname);}/* * Permits opening to any host/port if permitted_opens[] is empty. This is * usually called by the server, because the user could connect to any port * anyway, and the server has no way to know but to trust the client anyway. */voidchannel_permit_all_opens(void){ if (num_permitted_opens == 0) all_opens_permitted = 1;}voidchannel_add_permitted_opens(char *host, int port){ if (num_permitted_opens >= SSH_MAX_FORWARDS_PER_DIRECTION) fatal("channel_request_remote_forwarding: too many forwards"); debug("allow port forwarding to host %s port %d", host, port); permitted_opens[num_permitted_opens].host_to_connect = xstrdup(host); permitted_opens[num_permitted_opens].port_to_connect = port; num_permitted_opens++; all_opens_permitted = 0;}voidchannel_clear_permitted_opens(void){ int i; for (i = 0; i < num_permitted_opens; i++) xfree(permitted_opens[i].host_to_connect); num_permitted_opens = 0;}/* return socket to remote host, port */static intconnect_to(const char *host, u_short port){ struct addrinfo hints, *ai, *aitop; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; int gaierr; int sock = -1; memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%d", port); if ((gaierr = getaddrinfo(host, strport, &hints, &aitop)) != 0) { error("connect_to %.100s: unknown host (%s)", host, gai_strerror(gaierr)); return -1; } 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("connect_to: getnameinfo failed"); continue; } sock = socket(ai->ai_family, SOCK_STREAM, 0); if (sock < 0) { if (ai->ai_next == NULL) error("socket: %.100s", strerror(errno)); else verbose("socket: %.100s", strerror(errno)); continue; } if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) fatal("connect_to: F_SETFL: %s", strerror(errno)); if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0 && errno != EINPROGRESS) { error("connect_to %.100s port %s: %.100s", ntop, strport, strerror(errno)); close(sock); continue; /* fail -- try next */ } break; /* success */ } freeaddrinfo(aitop); if (!ai) { error("connect_to %.100s port %d: failed.", host, port); return -1; } /* success */ set_nodelay(sock); return sock;}intchannel_connect_by_listen_address(u_short listen_port){ int i; for (i = 0; i < num_permitted_opens; i++) if (permitted_opens[i].listen_port == listen_port) return connect_to( permitted_opens[i].host_to_connect, permitted_opens[i].port_to_connect); error("WARNING: Server requests forwarding for unknown listen_port %d", listen_port); return -1;}/* Check if connecting to that port is permitted and connect. */intchannel_connect_to(const char *host, u_short port){ int i, permit; permit = all_opens_permitted; if (!permit) { for (i = 0; i < num_permitted_opens; i++) if (permitted_opens[i].port_to_connect == port && strcmp(permitted_opens[i].host_to_connect, host) == 0) permit = 1; } if (!permit) { log("Received request to connect to host %.100s port %d, " "but the request was denied.", host, port); return -1; } return connect_to(host, port);}/* -- X11 forwarding *//* * Creates an internet domain socket for listening for X11 connections. * Returns 0 and a suitable display number for the DISPLAY variable * stored in display_numberp , or -1 if an error occurs. */intx11_create_display_inet(int x11_display_offset, int x11_use_localhost, int single_connection, u_int *display_numberp){ Channel *nc = NULL; int display_number, sock; u_short port; struct addrinfo hints, *ai, *aitop; char strport[NI_MAXSERV]; int gaierr, n, num_socks = 0, socks[NUM_SOCKS]; for (display_number = x11_display_offset; display_number < MAX_DISPLAYS; display_number++) { port = 6000 + display_number; memset(&hints, 0, sizeof(hints)); hints.ai_family = IPv4or6; hints.ai_flags = x11_use_localhost ? 0: AI_PASSIVE; hints.ai_socktype = SOCK_STREAM; snprintf(strport, sizeof strport, "%d", port); if ((gaierr = getaddrinfo(NULL, strport, &hints, &aitop)) != 0) { error("getaddrinfo: %.100s", gai_strerror(gaierr)); return -1; } for (ai = aitop; ai; ai = ai->ai_next) { if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) continue; sock = socket(ai->ai_family, SOCK_STREAM, 0); if (sock < 0) { error("socket: %.100s", strerror(errno)); return -1; } if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) { debug("bind port %d: %.100s", port, strerror(errno)); close(sock); if (ai->ai_next) continue; for (n = 0; n < num_socks; n++) { close(socks[n]); } num_socks = 0; break; } socks[num_socks++] = sock; if (num_socks == NUM_SOCKS) break; } freeaddrinfo(aitop); if (num_socks > 0) break; } if (display_number >= MAX_DISPLAYS) { error("Failed to allocate internet-domain X11 display socket."); return -1; } /* Start listening for connections on the socket. */ for (n = 0; n < num_socks; n++) { sock = socks[n]; if (listen(sock, 5) < 0) { error("listen: %.100s", strerror(errno)); close(sock); return -1; } } /* Allocate a channel for each socket. */ for (n = 0; n < num_socks; n++) { sock = socks[n]; nc = channel_new("x11 listener", SSH_CHANNEL_X11_LISTENER, sock, sock, -1, CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT, 0, xstrdup("X11 inet listener"), 1); nc->single_connection = single_connection; } /* Return the display number for the DISPLAY environment variable. */ *display_numberp = display_number; return (0);}static intconnect_local_xsocket(u_int dnr){ int sock; struct sockaddr_un addr; sock = socket(AF_UNIX, SOCK_STREAM, 0); if (sock < 0) error("socket: %.100s", strerror(errno)); memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; snprintf(addr.sun_path, sizeof addr.sun_path, _PATH_UNIX_X, dnr); if (connect(sock, (struct sockaddr *) & addr, sizeof(addr)) == 0) return sock; close(sock); error("connect %.100s: %.100s", addr.sun_path, strerror(errno)); return -1;}intx11_connect_display(void){ int display_number, sock = 0; const char *display; char buf[1024], *cp; struct addrinfo hints, *ai, *aitop; char strport[NI_MAXSERV]; int gaierr; /* Try to open a socket for the local X server. */ display = getenv("DISPLAY"); if (!display) { error("DISPLAY not set."); return -1; } /* * Now we decode the value of the DISPLAY variable and make a * connection to the real X server. */ /* * Check if it is a unix domain socket. Unix domain displays are in * one of the following formats: unix:d[.s], :d[.s], ::d[.s] */ if (strncmp(display, "unix:", 5) == 0 || display[0] == ':') { /* Connect to the unix domain socket. */ if (sscanf(strrchr(display, ':') + 1, "%d", &display_number) != 1) { error("Could not parse display number from DISPLAY: %
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -