diff localtcpfwd.c @ 4:fe6bca95afa7

Makefile.in contains updated files required
author Matt Johnston <matt@ucc.asn.au>
date Tue, 01 Jun 2004 02:46:09 +0000
parents
children 425ed5c20157
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/localtcpfwd.c	Tue Jun 01 02:46:09 2004 +0000
@@ -0,0 +1,142 @@
+#include "includes.h"
+#include "session.h"
+#include "dbutil.h"
+#include "localtcpfwd.h"
+
+#ifndef DISABLE_LOCALTCPFWD
+static int newtcp(const char * host, int port);
+
+/* Called upon creating a new direct tcp channel (ie we connect out to an
+ * address */
+int newtcpdirect(struct Channel * channel) {
+
+	unsigned char* desthost = NULL;
+	unsigned int destport;
+	unsigned char* orighost = NULL;
+	unsigned int origport;
+	int sock;
+	int len;
+	int ret = DROPBEAR_FAILURE;
+
+	if (ses.opts->nolocaltcp) {
+		TRACE(("leave newtcpdirect: local tcp forwarding disabled"));
+		goto out;
+	}
+
+	desthost = buf_getstring(ses.payload, &len);
+	if (len > MAX_HOST_LEN) {
+		TRACE(("leave newtcpdirect: desthost too long"));
+		goto out;
+	}
+
+	destport = buf_getint(ses.payload);
+	
+	orighost = buf_getstring(ses.payload, &len);
+	if (len > MAX_HOST_LEN) {
+		TRACE(("leave newtcpdirect: orighost too long"));
+		goto out;
+	}
+
+	origport = buf_getint(ses.payload);
+
+	/* best be sure */
+	if (origport > 65535 || destport > 65535) {
+		TRACE(("leave newtcpdirect: port > 65535"));
+		goto out;
+	}
+
+	sock = newtcp(desthost, destport);
+	if (sock < 0) {
+		TRACE(("leave newtcpdirect: sock failed"));
+		goto out;
+	}
+
+	ses.maxfd = MAX(ses.maxfd, sock);
+
+	/* Note that infd is actually the "outgoing" direction on the
+	 * tcp connection, vice versa for outfd.
+	 * We don't set outfd, that will get set after the connection's
+	 * progress succeeds */
+	channel->infd = sock;
+	channel->initconn = 1;
+	
+	ret = DROPBEAR_SUCCESS;
+
+out:
+	m_free(desthost);
+	m_free(orighost);
+	TRACE(("leave newtcpdirect: ret %d", ret));
+	return ret;
+}
+
+/* Initiate a new TCP connection - this is non-blocking, so the socket
+ * returned will need to be checked for success when it is first written.
+ * Similarities with OpenSSH's connect_to() are not coincidental.
+ * Returns -1 on failure */
+static int newtcp(const char * host, int port) {
+
+	int sock = -1;
+	char portstring[6];
+	struct addrinfo *res = NULL, *ai;
+	int val;
+
+	struct addrinfo hints;
+
+	TRACE(("enter newtcp"));
+
+	memset(&hints, 0, sizeof(hints));
+	/* TCP, either ip4 or ip6 */
+	hints.ai_socktype = SOCK_STREAM;
+	hints.ai_family = PF_UNSPEC;
+
+	snprintf(portstring, sizeof(portstring), "%d", port);
+	if (getaddrinfo(host, portstring, &hints, &res) != 0) {
+		if (res) {
+			freeaddrinfo(res);
+		}
+		TRACE(("leave newtcp: failed getaddrinfo"));
+		return -1;
+	}
+
+	/* Use the first socket that works */
+	for (ai = res; ai != NULL; ai = ai->ai_next) {
+		
+		if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) {
+			continue;
+		}
+
+		sock = socket(ai->ai_family, SOCK_STREAM, 0);
+		if (sock < 0) {
+			TRACE(("TCP socket() failed"));
+			continue;
+		}
+
+		if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
+			close(sock);
+			TRACE(("TCP non-blocking failed"));
+			continue;
+		}
+
+		/* non-blocking, so it might return without success (EINPROGRESS) */
+		if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
+			if (errno == EINPROGRESS) {
+				TRACE(("connect in progress"));
+			} else {
+				close(sock);
+				TRACE(("TCP connect failed"));
+				continue;
+			}
+		} 
+		break;
+	}
+
+	freeaddrinfo(res);
+	
+	if (ai == NULL) {
+		return -1;
+	}
+
+	setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
+	return sock;
+}
+#endif /* DISABLE_LOCALTCPFWD */