⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 channels.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (p[0] != 0x05)		return -1;	have = buffer_len(&c->input);	if (!(c->flags & SSH_SOCKS5_AUTHDONE)) {		/* format: ver | nmethods | methods */		if (have < 2)			return 0;		nmethods = p[1];		if (have < nmethods + 2)			return 0;		/* look for method: "NO AUTHENTICATION REQUIRED" */		for (found = 0, i = 2 ; i < nmethods + 2; i++) {			if (p[i] == SSH_SOCKS5_NOAUTH ) {				found = 1;				break;			}		}		if (!found) {			debug("channel %d: method SSH_SOCKS5_NOAUTH not found",			    c->self);			return -1;		}		buffer_consume(&c->input, nmethods + 2);		buffer_put_char(&c->output, 0x05);		/* version */		buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH);	/* method */		FD_SET(c->sock, writeset);		c->flags |= SSH_SOCKS5_AUTHDONE;		debug2("channel %d: socks5 auth done", c->self);		return 0;				/* need more */	}	debug2("channel %d: socks5 post auth", c->self);	if (have < sizeof(s5_req)+1)		return 0;			/* need more */	memcpy((char *)&s5_req, p, sizeof(s5_req));	if (s5_req.version != 0x05 ||	    s5_req.command != SSH_SOCKS5_CONNECT ||	    s5_req.reserved != 0x00) {		debug2("channel %d: only socks5 connect supported", c->self);		return -1;	}	switch(s5_req.atyp){	case SSH_SOCKS5_IPV4:		addrlen = 4;		af = AF_INET;		break;	case SSH_SOCKS5_DOMAIN:		addrlen = p[sizeof(s5_req)];		af = -1;		break;	case SSH_SOCKS5_IPV6:		addrlen = 16;		af = AF_INET6;		break;	default:		debug2("channel %d: bad socks5 atyp %d", c->self, s5_req.atyp);		return -1;	}	if (have < 4 + addrlen + 2)		return 0;	buffer_consume(&c->input, sizeof(s5_req));	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)		buffer_consume(&c->input, 1);    /* host string length */	buffer_get(&c->input, (char *)&dest_addr, addrlen);	buffer_get(&c->input, (char *)&dest_port, 2);	dest_addr[addrlen] = '\0';	if (s5_req.atyp == SSH_SOCKS5_DOMAIN)		strlcpy(c->path, (char *)dest_addr, sizeof(c->path));	else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL)		return -1;	c->host_port = ntohs(dest_port);	debug2("channel %d: dynamic request: socks5 host %s port %u command %u",	    c->self, c->path, c->host_port, s5_req.command);	s5_rsp.version = 0x05;	s5_rsp.command = SSH_SOCKS5_SUCCESS;	s5_rsp.reserved = 0;			/* ignored */	s5_rsp.atyp = SSH_SOCKS5_IPV4;	((struct in_addr *)&dest_addr)->s_addr = INADDR_ANY;	dest_port = 0;				/* ignored */	buffer_append(&c->output, (char *)&s5_rsp, sizeof(s5_rsp));	buffer_append(&c->output, (char *)&dest_addr, sizeof(struct in_addr));	buffer_append(&c->output, (char *)&dest_port, sizeof(dest_port));	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 < 3) {		/* 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;	case 0x05:		ret = channel_decode_socks5(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;	char buf[16384], *remote_ipaddr;	int remote_port;	if (FD_ISSET(c->sock, readset)) {		debug("X11 connection requested.");		addrlen = sizeof(addr);		newsock = accept(c->sock, &addr, &addrlen);		if (c->single_connection) {			debug2("single_connection: closing X11 listener.");			channel_close_fd(&c->sock);			chan_mark_dead(c);		}		if (newsock < 0) {			error("accept: %.100s", strerror(errno));			return;		}		set_nodelay(newsock);		remote_ipaddr = get_peer_ipaddr(newsock);		remote_port = get_peer_port(newsock);		snprintf(buf, sizeof buf, "X11 connection from %.200s port %d",		    remote_ipaddr, remote_port);		nc = channel_new("accepted x11 socket",		    SSH_CHANNEL_OPENING, newsock, newsock, -1,		    c->local_window_max, c->local_maxpacket, 0, buf, 1);		if (compat20) {			packet_start(SSH2_MSG_CHANNEL_OPEN);			packet_put_cstring("x11");			packet_put_int(nc->self);			packet_put_int(nc->local_window_max);			packet_put_int(nc->local_maxpacket);			/* originator ipaddr and port */			packet_put_cstring(remote_ipaddr);			if (datafellows & SSH_BUG_X11FWD) {				debug2("ssh2 x11 bug compat mode");			} else {				packet_put_int(remote_port);			}			packet_send();		} else {			packet_start(SSH_SMSG_X11_OPEN);			packet_put_int(nc->self);			if (packet_get_protocol_flags() &			    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)				packet_put_cstring(buf);			packet_send();		}		xfree(remote_ipaddr);	}}static voidport_open_helper(Channel *c, char *rtype){	int direct;	char buf[1024];	char *remote_ipaddr = get_peer_ipaddr(c->sock);	u_short remote_port = get_peer_port(c->sock);	direct = (strcmp(rtype, "direct-tcpip") == 0);	snprintf(buf, sizeof buf,	    "%s: listening port %d for %.100s port %d, "	    "connect from %.200s port %d",	    rtype, c->listening_port, c->path, c->host_port,	    remote_ipaddr, remote_port);	xfree(c->remote_name);	c->remote_name = xstrdup(buf);	if (compat20) {		packet_start(SSH2_MSG_CHANNEL_OPEN);		packet_put_cstring(rtype);		packet_put_int(c->self);		packet_put_int(c->local_window_max);		packet_put_int(c->local_maxpacket);		if (direct) {			/* target host, port */			packet_put_cstring(c->path);			packet_put_int(c->host_port);		} else {			/* listen address, port */			packet_put_cstring(c->path);			packet_put_int(c->listening_port);		}		/* originator host and port */		packet_put_cstring(remote_ipaddr);		packet_put_int(remote_port);		packet_send();	} else {		packet_start(SSH_MSG_PORT_OPEN);		packet_put_int(c->self);		packet_put_cstring(c->path);		packet_put_int(c->host_port);		if (packet_get_protocol_flags() &		    SSH_PROTOFLAG_HOST_IN_FWD_OPEN)			packet_put_cstring(c->remote_name);		packet_send();	}	xfree(remote_ipaddr);}/* * This socket is listening for connections to a forwarded TCP/IP port. */static voidchannel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset){	Channel *nc;	struct sockaddr addr;	int newsock, nextstate;	socklen_t addrlen;	char *rtype;	if (FD_ISSET(c->sock, readset)) {		debug("Connection to port %d forwarding "		    "to %.100s port %d requested.",		    c->listening_port, c->path, c->host_port);		if (c->type == SSH_CHANNEL_RPORT_LISTENER) {			nextstate = SSH_CHANNEL_OPENING;			rtype = "forwarded-tcpip";		} else {			if (c->host_port == 0) {				nextstate = SSH_CHANNEL_DYNAMIC;				rtype = "dynamic-tcpip";			} else {				nextstate = SSH_CHANNEL_OPENING;				rtype = "direct-tcpip";			}		}		addrlen = sizeof(addr);		newsock = accept(c->sock, &addr, &addrlen);		if (newsock < 0) {			error("accept: %.100s", strerror(errno));			return;		}		set_nodelay(newsock);		nc = channel_new(rtype, nextstate, newsock, newsock, -1,		    c->local_window_max, c->local_maxpacket, 0, rtype, 1);		nc->listening_port = c->listening_port;		nc->host_port = c->host_port;		strlcpy(nc->path, c->path, sizeof(nc->path));		if (nextstate == SSH_CHANNEL_DYNAMIC) {			/*			 * do not call the channel_post handler until			 * this flag has been reset by a pre-handler.			 * otherwise the FD_ISSET calls might overflow			 */			nc->delayed = 1;		} else {			port_open_helper(nc, rtype);		}	}}/* * This is the authentication agent socket listening for connections from * clients. */static voidchannel_post_auth_listener(Channel *c, fd_set * readset, fd_set * writeset){	Channel *nc;	int newsock;	struct sockaddr addr;	socklen_t addrlen;	if (FD_ISSET(c->sock, readset)) {		addrlen = sizeof(addr);		newsock = accept(c->sock, &addr, &addrlen);		if (newsock < 0) {			error("accept from auth socket: %.100s", strerror(errno));			return;		}		nc = channel_new("accepted auth socket",		    SSH_CHANNEL_OPENING, newsock, newsock, -1,		    c->local_window_max, c->local_maxpacket,		    0, "accepted auth socket", 1);		if (compat20) {			packet_start(SSH2_MSG_CHANNEL_OPEN);			packet_put_cstring("auth-agent@openssh.com");			packet_put_int(nc->self);			packet_put_int(c->local_window_max);			packet_put_int(c->local_maxpacket);		} else {			packet_start(SSH_SMSG_AGENT_OPEN);			packet_put_int(nc->self);		}		packet_send();	}}static voidchannel_post_connecting(Channel *c, fd_set * readset, fd_set * writeset){	int err = 0;	socklen_t sz = sizeof(err);	if (FD_ISSET(c->sock, writeset)) {		if (getsockopt(c->sock, SOL_SOCKET, SO_ERROR, &err, &sz) < 0) {			err = errno;			error("getsockopt SO_ERROR failed");		}		if (err == 0) {			debug("channel %d: connected", c->self);			c->type = SSH_CHANNEL_OPEN;			if (compat20) {				packet_start(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);				packet_put_int(c->remote_id);				packet_put_int(c->self);				packet_put_int(c->local_window);				packet_put_int(c->local_maxpacket);			} else {				packet_start(SSH_MSG_CHANNEL_OPEN_CONFIRMATION);				packet_put_int(c->remote_id);				packet_put_int(c->self);			}		} else {			debug("channel %d: not connected: %s",			    c->self, strerror(err));			if (compat20) {				packet_start(SSH2_MSG_CHANNEL_OPEN_FAILURE);				packet_put_int(c->remote_id);				packet_put_int(SSH2_OPEN_CONNECT_FAILED);				if (!(datafellows & SSH_BUG_OPENFAILURE)) {					packet_put_cstring(strerror(err));					packet_put_cstring("");				}			} else {				packet_start(SSH_MSG_CHANNEL_OPEN_FAILURE);				packet_put_int(c->remote_id);			}			chan_mark_dead(c);		}		packet_send();	}}static intchannel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset){	char buf[16*1024];	int len;	if (c->rfd != -1 &&	    FD_ISSET(c->rfd, readset)) {		len = read(c->rfd, buf, sizeof(buf));		if (len < 0 && (errno == EINTR || errno == EAGAIN))			return 1;		if (len <= 0) {			debug2("channel %d: read<=0 rfd %d len %d",			    c->self, c->rfd, len);			if (c->type != SSH_CHANNEL_OPEN) {				debug2("channel %d: not open", c->self);				chan_mark_dead(c);				return -1;			} else if (compat13) {				buffer_clear(&c->output);				c->type = SSH_CHANNEL_INPUT_DRAINING;				debug2("channel %d: input draining.", c->self);			} else {				chan_read_failed(c);			}			return -1;		}		if (c->input_filter != NULL) {			if (c->input_filter(c, buf, len) == -1) {				debug2("channel %d: filter stops", c->self);				chan_read_failed(c);			}		} else {			buffer_append(&c->input, buf, len);		}	}	return 1;}static intchannel_handle_wfd(Channel *c, fd_set * readset, fd_set * writeset){	struct termios tio;	u_char *data;	u_int dlen;	int len;	/* Send buffered output data to the socket. */	if (c->wfd != -1 &&	    FD_ISSET(c->wfd, writeset) &&	    buffer_len(&c->output) > 0) {		data = buffer_ptr(&c->output);		dlen = buffer_len(&c->output);#ifdef _AIX		/* XXX: Later AIX versions can't push as much data to tty */		if (compat20 && c->wfd_isatty)			dlen = MIN(dlen, 8*1024);#endif		len = write(c->wfd, data, dlen);		if (len < 0 && (errno == EINTR || errno == EAGAIN))			return 1;		if (len <= 0) {			if (c->type != SSH_CHANNEL_OPEN) {				debug2("channel %d: not open", c->self);				chan_mark_dead(c);				return -1;			} else if (compat13) {				buffer_clear(&c->output);				debug2("channel %d: input draining.", c->self);				c->type = SSH_CHANNEL_INPUT_DRAINING;			} else {				chan_write_failed(c);			}			return -1;		}		if (compat20 && c->isatty && dlen >= 1 && data[0] != '\r') {			if (tcgetattr(c->wfd, &tio) == 0 &&			    !(tio.c_lflag & ECHO) && (tio.c_lflag & ICANON)) {				/*				 * Simulate echo to reduce the impact of				 * traffic analysis. We need to match the				 * size of a SSH2_MSG_CHANNEL_DATA message				 * (4 byte channel id + data)				 */				packet_send_ignore(4 + len);				packet_send();			}		}		buffer_consume(&c->output, len);		if (compat20 && len > 0) {			c->local_consumed += len;		}	}	return 1;}static intchannel_handle_efd(Channel *c, fd_set * readset, fd_set * writeset){	char buf[16*1024];	int len;/** XXX handle drain efd, too */	if (c->efd != -1) {		if (c->extended_usage == CHAN_EXTENDED_WRITE &&		    FD_ISSET(c->efd, writeset) &&		    buffer_len(&c->extended) > 0) {			len = write(c->efd, buffer_ptr(&c->extended),			    buffer_len(&c->extended));			debug2("channel %d: written %d to efd %d",			    c->self, len, c->efd);			if (len < 0 && (errno == EINTR || errno == EAGAIN))				return 1;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -