changeset 64:efb5e0b335cf

TCP forwarding works.
author Matt Johnston <matt@ucc.asn.au>
date Thu, 12 Aug 2004 13:48:42 +0000
parents dcc43965928f
children 02e4a7f614f8
files Makefile.in cli-runopts.c cli-session.c cli-tcpfwd.c dbutil.c fake-rfc2553.c fake-rfc2553.h options.h runopts.h session.h svr-tcpfwd.c tcp-accept.c tcp-accept.h tcp-connect.c tcp-connect.h tcpfwd.h
diffstat 16 files changed, 806 insertions(+), 169 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.in	Wed Aug 11 17:26:47 2004 +0000
+++ b/Makefile.in	Thu Aug 12 13:48:42 2004 +0000
@@ -46,8 +46,8 @@
 		dss.h bignum.h signkey.h rsa.h random.h service.h auth.h authpasswd.h \
 		debug.h channel.h chansession.h config.h queue.h sshpty.h \
 		termcodes.h gendss.h genrsa.h authpubkey.h runopts.h includes.h \
-		loginrec.h atomicio.h x11fwd.h agentfwd.h tcp-accept.h compat.h \
-		tcp-connect.h listener.h
+		loginrec.h atomicio.h x11fwd.h agentfwd.h tcpfwd.h compat.h \
+		listener.h
 
 dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS) 
 dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
--- a/cli-runopts.c	Wed Aug 11 17:26:47 2004 +0000
+++ b/cli-runopts.c	Thu Aug 12 13:48:42 2004 +0000
@@ -28,6 +28,7 @@
 #include "buffer.h"
 #include "dbutil.h"
 #include "algo.h"
+#include "tcpfwd.h"
 
 cli_runopts cli_opts; /* GLOBAL */
 
@@ -36,6 +37,9 @@
 #ifdef DROPBEAR_PUBKEY_AUTH
 static void loadidentityfile(const char* filename);
 #endif
+#ifdef ENABLE_CLI_ANYTCPFWD
+static void addforward(char* str, struct TCPFwdList** fwdlist);
+#endif
 
 static void printhelp() {
 
@@ -48,10 +52,10 @@
 #ifdef DROPBEAR_PUBKEY_AUTH
 					"-i <identityfile>   (multiple allowed)\n"
 #endif
-#ifndef DISABLE_REMOTETCPFWD
+#ifdef ENABLE_CLI_LOCALTCPFWD
 					"-L <listenport:remotehsot:reportport> Local port forwarding\n"
 #endif
-#ifndef DISABLE_TCPFWD_DIRECT
+#ifdef ENABLE_CLI_REMOTETCPFWD
 					"-R <listenport:remotehost:remoteport> Remote port forwarding\n"
 #endif
 					,DROPBEAR_VERSION, cli_opts.progname);
@@ -65,15 +69,13 @@
 #ifdef DROPBEAR_PUBKEY_AUTH
 	int nextiskey = 0; /* A flag if the next argument is a keyfile */
 #endif
-#ifdef DROPBEAR_CLI_LOCALTCP
+#ifdef ENABLE_CLI_LOCALTCPFWD
 	int nextislocal = 0;
 #endif
-#ifdef DROPBEAR_CLI_REMOTETCP
+#ifdef ENABLE_CLI_REMOTETCPFWD
 	int nextisremote = 0;
 #endif
 
-
-
 	/* see printhelp() for options */
 	cli_opts.progname = argv[0];
 	cli_opts.remotehost = NULL;
@@ -84,11 +86,11 @@
 #ifdef DROPBEAR_PUBKEY_AUTH
 	cli_opts.pubkeys = NULL;
 #endif
-#ifdef DROPBEAR_CLI_LOCALTCP
-	cli_opts.localports = NULL;
+#ifdef ENABLE_CLI_LOCALTCPFWD
+	cli_opts.localfwds = NULL;
 #endif
-#ifdef DROPBEAR_CLI_REMOTETCP
-	cli_opts.remoteports = NULL;
+#ifdef ENABLE_CLI_REMOTETCPFWD
+	cli_opts.remotefwds = NULL;
 #endif
 	opts.nolocaltcp = 0;
 	opts.noremotetcp = 0;
@@ -107,6 +109,22 @@
 			continue;
 		}
 #endif
+#ifdef ENABLE_CLI_REMOTETCPFWD
+		if (nextisremote) {
+			TRACE(("nextisremote true"));
+			addforward(argv[i], &cli_opts.remotefwds);
+			nextisremote = 0;
+			continue;
+		}
+#endif
+#ifdef ENABLE_CLI_LOCALTCPFWD
+		if (nextislocal) {
+			TRACE(("nextislocal true"));
+			addforward(argv[i], &cli_opts.localfwds);
+			nextislocal = 0;
+			continue;
+		}
+#endif
 		if (next) {
 			/* The previous flag set a value to assign */
 			*next = argv[i];
@@ -135,6 +153,16 @@
 				case 'T': /* don't want a pty */
 					cli_opts.wantpty = 0;
 					break;
+#ifdef ENABLE_CLI_LOCALTCPFWD
+				case 'L':
+					nextislocal = 1;
+					break;
+#endif
+#ifdef ENABLE_CLI_REMOTETCPFWD
+				case 'R':
+					nextisremote = 1;
+					break;
+#endif
 				default:
 					fprintf(stderr, "Unknown argument '%s'\n", argv[i]);
 					printhelp();
@@ -145,7 +173,7 @@
 			continue; /* next argument */
 
 		} else {
-			TRACE(("non-flag arg"));
+			TRACE(("non-flag arg: '%s'", argv[i]));
 
 			/* Either the hostname or commands */
 
@@ -226,10 +254,14 @@
 
 /* Parses a [user@]hostname argument. userhostarg is the argv[i] corresponding
  * - note that it will be modified */
-static void parsehostname(char* userhostarg) {
+static void parsehostname(char* orighostarg) {
 
 	uid_t uid;
 	struct passwd *pw = NULL; 
+	char *userhostarg = NULL;
+
+	/* We probably don't want to be editing argvs */
+	userhostarg = m_strdup(orighostarg);
 
 	cli_opts.remotehost = strchr(userhostarg, '@');
 	if (cli_opts.remotehost == NULL) {
@@ -257,3 +289,81 @@
 		dropbear_exit("Bad hostname");
 	}
 }
+
+#ifdef ENABLE_CLI_ANYTCPFWD
+/* Turn a "listenport:remoteaddr:remoteport" string into into a forwarding
+ * set, and add it to the forwarding list */
+static void addforward(char* origstr, struct TCPFwdList** fwdlist) {
+
+	char * listenport = NULL;
+	char * connectport = NULL;
+	char * connectaddr = NULL;
+	struct TCPFwdList* newfwd = NULL;
+	char * str = NULL;
+
+	TRACE(("enter addforward"));
+
+	/* We probably don't want to be editing argvs */
+	str = m_strdup(origstr);
+
+	listenport = str;
+
+	connectaddr = strchr(str, ':');
+	if (connectaddr == NULL) {
+		TRACE(("connectaddr == NULL"));
+		goto fail;
+	}
+
+	connectaddr[0] = '\0';
+	connectaddr++;
+
+	connectport = strchr(connectaddr, ':');
+	if (connectport == NULL) {
+		TRACE(("connectport == NULL"));
+		goto fail;
+	}
+
+	connectport[0] = '\0';
+	connectport++;
+
+	newfwd = (struct TCPFwdList*)m_malloc(sizeof(struct TCPFwdList));
+
+	/* Now we check the ports - note that the port ints are unsigned,
+	 * the check later only checks for >= MAX_PORT */
+	newfwd->listenport = strtol(listenport, NULL, 10);
+	if (errno != 0) {
+		TRACE(("bad listenport strtol"));
+		goto fail;
+	}
+
+	newfwd->connectport = strtol(connectport, NULL, 10);
+	if (errno != 0) {
+		TRACE(("bad connectport strtol"));
+		goto fail;
+	}
+
+	newfwd->connectaddr = connectaddr;
+
+	if (newfwd->listenport > 65535) {
+		TRACE(("listenport > 65535"));
+		goto badport;
+	}
+		
+	if (newfwd->connectport > 65535) {
+		TRACE(("connectport > 65535"));
+		goto badport;
+	}
+
+	newfwd->next = *fwdlist;
+	*fwdlist = newfwd;
+
+	TRACE(("leave addforward: done"));
+	return;
+
+fail:
+	dropbear_exit("Bad TCP forward '%s'", origstr);
+
+badport:
+	dropbear_exit("Bad TCP port in '%s'", origstr);
+}
+#endif
--- a/cli-session.c	Wed Aug 11 17:26:47 2004 +0000
+++ b/cli-session.c	Thu Aug 12 13:48:42 2004 +0000
@@ -4,8 +4,7 @@
 #include "kex.h"
 #include "ssh.h"
 #include "packet.h"
-#include "tcp-accept.h"
-#include "tcp-connect.h"
+#include "tcpfwd.h"
 #include "channel.h"
 #include "random.h"
 #include "service.h"
@@ -45,8 +44,9 @@
 };
 
 static const struct ChanType *cli_chantypes[] = {
-	/* &chan_tcpdirect etc, though need to only allow if we've requested
-	 * that forwarding */
+#ifdef ENABLE_CLI_REMOTETCPFWD
+	&cli_chan_tcpremote,
+#endif
 	NULL /* Null termination */
 };
 
@@ -178,6 +178,10 @@
 			*/
 
 		case USERAUTH_SUCCESS_RCVD:
+#ifdef ENABLE_CLI_LOCALTCPFWD
+			TRACE(("recvd USERAUTH_SUCCESS_RCVD"));
+			setup_localtcp();
+#endif
 			cli_send_chansess_request();
 			TRACE(("leave cli_sessionloop: cli_send_chansess_request"));
 			cli_ses.state = SESSION_RUNNING;
@@ -223,7 +227,6 @@
 }
 
 
-
 /* called when the remote side closes the connection */
 static void cli_remoteclosed() {
 
--- a/cli-tcpfwd.c	Wed Aug 11 17:26:47 2004 +0000
+++ b/cli-tcpfwd.c	Thu Aug 12 13:48:42 2004 +0000
@@ -1,20 +1,54 @@
 #include "includes.h"
 #include "options.h"
-#include "tcp-accept.h"
-#include "tcp-connect.h"
+#include "dbutil.h"
+#include "tcpfwd.h"
 #include "channel.h"
+#include "runopts.h"
+#include "session.h"
+#include "ssh.h"
 
+static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
+		unsigned int remoteport);
+static int newtcpforwarded(struct Channel * channel);
+
+const struct ChanType cli_chan_tcpremote = {
+	1, /* sepfds */
+	"forwarded-tcpip",
+	newtcpforwarded,
+	NULL,
+	NULL,
+	NULL
+};
 static const struct ChanType cli_chan_tcplocal = {
 	1, /* sepfds */
 	"direct-tcpip",
 	NULL,
 	NULL,
+	NULL,
 	NULL
 };
 
 void setup_localtcp() {
 
-	qv
+	int ret;
+
+	if (cli_opts.localfwds == NULL) {
+		TRACE(("cli_opts.localfwds == NULL"));
+	}
+
+	while (cli_opts.localfwds != NULL) {
+		ret = cli_localtcp(cli_opts.localfwds->listenport,
+				cli_opts.localfwds->connectaddr,
+				cli_opts.localfwds->connectport);
+		if (ret == DROPBEAR_FAILURE) {
+			dropbear_log(LOG_WARNING, "Failed local port forward %d:%s:%d",
+					cli_opts.localfwds->listenport,
+					cli_opts.localfwds->connectaddr,
+					cli_opts.localfwds->connectport);
+		}
+
+		cli_opts.localfwds = cli_opts.localfwds->next;
+	}
 
 }
 
@@ -22,6 +56,10 @@
 		unsigned int remoteport) {
 
 	struct TCPListener* tcpinfo = NULL;
+	int ret;
+
+	TRACE(("enter cli_localtcp: %d %s %d", listenport, remoteaddr,
+				remoteport));
 
 	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
 	tcpinfo->sendaddr = remoteaddr;
@@ -34,5 +72,91 @@
 	if (ret == DROPBEAR_FAILURE) {
 		m_free(tcpinfo);
 	}
+	TRACE(("leave cli_localtcp: %d", ret));
 	return ret;
 }
+
+static void send_msg_global_request_remotetcp(int port) {
+
+	TRACE(("enter send_msg_global_request_remotetcp"));
+
+	CHECKCLEARTOWRITE();
+	buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
+	buf_putstring(ses.writepayload, "tcpip-forward", 13);
+	buf_putbyte(ses.writepayload, 0);
+	buf_putstring(ses.writepayload, "0.0.0.0", 7); /* TODO: IPv6? */
+	buf_putint(ses.writepayload, port);
+
+	encrypt_packet();
+
+	TRACE(("leave send_msg_global_request_remotetcp"));
+}
+
+void setup_remotetcp() {
+
+	struct TCPFwdList * iter = NULL;
+
+	if (cli_opts.remotefwds == NULL) {
+		TRACE(("cli_opts.remotefwds == NULL"));
+	}
+
+	iter = cli_opts.remotefwds;
+
+	while (iter != NULL) {
+		send_msg_global_request_remotetcp(iter->listenport);
+		iter = iter->next;
+	}
+}
+
+static int newtcpforwarded(struct Channel * channel) {
+
+	unsigned int origport;
+	struct TCPFwdList * iter = NULL;
+	char portstring[NI_MAXSERV];
+	int sock;
+	int ret = DROPBEAR_FAILURE;
+
+	/* We don't care what address they connected to */
+	buf_eatstring(ses.payload);
+
+	origport = buf_getint(ses.payload);
+
+	/* Find which port corresponds */
+	iter = cli_opts.remotefwds;
+
+	while (iter != NULL) {
+		if (origport == iter->listenport) {
+			break;
+		}
+		iter = iter->next;
+	}
+
+	if (iter == NULL) {
+		/* We didn't request forwarding on that port */
+		dropbear_log(LOG_INFO, "Server send unrequested port, from port %d", 
+										origport);
+		goto out;
+	}
+	
+	snprintf(portstring, sizeof(portstring), "%d", iter->connectport);
+	sock = connect_remote(iter->connectaddr, portstring, 1, NULL);
+	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:
+	TRACE(("leave newtcpdirect: ret %d", ret));
+	return ret;
+}
--- a/dbutil.c	Wed Aug 11 17:26:47 2004 +0000
+++ b/dbutil.c	Thu Aug 12 13:48:42 2004 +0000
@@ -185,7 +185,7 @@
 		if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
 			err = errno;
 			close(sock);
-			TRACE(("bind() failed"));
+			TRACE(("bind(%s) failed", port));
 			continue;
 		}
 
@@ -206,7 +206,7 @@
 			int len;
 			len = 20 + strlen(strerror(err));
 			*errstring = (char*)m_malloc(len);
-			snprintf(*errstring, len, "Error connecting: %s", strerror(err));
+			snprintf(*errstring, len, "Error listening: %s", strerror(err));
 			TRACE(("leave dropbear_listen: failure, %s", strerror(err)));
 			return -1;
 		}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fake-rfc2553.c	Thu Aug 12 13:48:42 2004 +0000
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
+ * Copyright (C) 1999 WIDE Project.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Pseudo-implementation of RFC2553 name / address resolution functions
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For example, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ */
+
+#include "includes.h"
+
+RCSID("$Id: fake-rfc2553.c,v 1.5 2003/09/22 02:08:23 dtucker Exp $");
+
+#ifndef HAVE_GETNAMEINFO
+int getnameinfo(const struct sockaddr *sa, size_t salen, char *host, 
+                size_t hostlen, char *serv, size_t servlen, int flags)
+{
+	struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+	struct hostent *hp;
+	char tmpserv[16];
+
+	if (serv != NULL) {
+		snprintf(tmpserv, sizeof(tmpserv), "%d", ntohs(sin->sin_port));
+		if (strlcpy(serv, tmpserv, servlen) >= servlen)
+			return (EAI_MEMORY);
+	}
+
+	if (host != NULL) {
+		if (flags & NI_NUMERICHOST) {
+			if (strlcpy(host, inet_ntoa(sin->sin_addr),
+			    hostlen) >= hostlen)
+				return (EAI_MEMORY);
+			else
+				return (0);
+		} else {
+			hp = gethostbyaddr((char *)&sin->sin_addr, 
+			    sizeof(struct in_addr), AF_INET);
+			if (hp == NULL)
+				return (EAI_NODATA);
+			
+			if (strlcpy(host, hp->h_name, hostlen) >= hostlen)
+				return (EAI_MEMORY);
+			else
+				return (0);
+		}
+	}
+	return (0);
+}
+#endif /* !HAVE_GETNAMEINFO */
+
+#ifndef HAVE_GAI_STRERROR
+#ifdef HAVE_CONST_GAI_STRERROR_PROTO
+const char *
+#else
+char *
+#endif
+gai_strerror(int err)
+{
+	switch (err) {
+	case EAI_NODATA:
+		return ("no address associated with name");
+	case EAI_MEMORY:
+		return ("memory allocation failure.");
+	case EAI_NONAME:
+		return ("nodename nor servname provided, or not known");
+	default:
+		return ("unknown/invalid error.");
+	}
+}    
+#endif /* !HAVE_GAI_STRERROR */
+
+#ifndef HAVE_FREEADDRINFO
+void
+freeaddrinfo(struct addrinfo *ai)
+{
+	struct addrinfo *next;
+
+	for(; ai != NULL;) {
+		next = ai->ai_next;
+		free(ai);
+		ai = next;
+	}
+}
+#endif /* !HAVE_FREEADDRINFO */
+
+#ifndef HAVE_GETADDRINFO
+static struct
+addrinfo *malloc_ai(int port, u_long addr, const struct addrinfo *hints)
+{
+	struct addrinfo *ai;
+
+	ai = malloc(sizeof(*ai) + sizeof(struct sockaddr_in));
+	if (ai == NULL)
+		return (NULL);
+	
+	memset(ai, '\0', sizeof(*ai) + sizeof(struct sockaddr_in));
+	
+	ai->ai_addr = (struct sockaddr *)(ai + 1);
+	/* XXX -- ssh doesn't use sa_len */
+	ai->ai_addrlen = sizeof(struct sockaddr_in);
+	ai->ai_addr->sa_family = ai->ai_family = AF_INET;
+
+	((struct sockaddr_in *)(ai)->ai_addr)->sin_port = port;
+	((struct sockaddr_in *)(ai)->ai_addr)->sin_addr.s_addr = addr;
+	
+	/* XXX: the following is not generally correct, but does what we want */
+	if (hints->ai_socktype)
+		ai->ai_socktype = hints->ai_socktype;
+	else
+		ai->ai_socktype = SOCK_STREAM;
+
+	if (hints->ai_protocol)
+		ai->ai_protocol = hints->ai_protocol;
+
+	return (ai);
+}
+
+int
+getaddrinfo(const char *hostname, const char *servname, 
+    const struct addrinfo *hints, struct addrinfo **res)
+{
+	struct hostent *hp;
+	struct servent *sp;
+	struct in_addr in;
+	int i;
+	long int port;
+	u_long addr;
+
+	port = 0;
+	if (servname != NULL) {
+		char *cp;
+
+		port = strtol(servname, &cp, 10);
+		if (port > 0 && port <= 65535 && *cp == '\0')
+			port = htons(port);
+		else if ((sp = getservbyname(servname, NULL)) != NULL)
+			port = sp->s_port;
+		else
+			port = 0;
+	}
+
+	if (hints && hints->ai_flags & AI_PASSIVE) {
+		addr = htonl(0x00000000);
+		if (hostname && inet_aton(hostname, &in) != 0)
+			addr = in.s_addr;
+		*res = malloc_ai(port, addr, hints);
+		if (*res == NULL) 
+			return (EAI_MEMORY);
+		return (0);
+	}
+		
+	if (!hostname) {
+		*res = malloc_ai(port, htonl(0x7f000001), hints);
+		if (*res == NULL) 
+			return (EAI_MEMORY);
+		return (0);
+	}
+	
+	if (inet_aton(hostname, &in)) {
+		*res = malloc_ai(port, in.s_addr, hints);
+		if (*res == NULL) 
+			return (EAI_MEMORY);
+		return (0);
+	}
+	
+	/* Don't try DNS if AI_NUMERICHOST is set */
+	if (hints && hints->ai_flags & AI_NUMERICHOST)
+		return (EAI_NONAME);
+	
+	hp = gethostbyname(hostname);
+	if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
+		struct addrinfo *cur, *prev;
+
+		cur = prev = *res = NULL;
+		for (i = 0; hp->h_addr_list[i]; i++) {
+			struct in_addr *in = (struct in_addr *)hp->h_addr_list[i];
+
+			cur = malloc_ai(port, in->s_addr, hints);
+			if (cur == NULL) {
+				if (*res != NULL)
+					freeaddrinfo(*res);
+				return (EAI_MEMORY);
+			}
+			if (prev)
+				prev->ai_next = cur;
+			else
+				*res = cur;
+
+			prev = cur;
+		}
+		return (0);
+	}
+	
+	return (EAI_NODATA);
+}
+#endif /* !HAVE_GETADDRINFO */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/fake-rfc2553.h	Thu Aug 12 13:48:42 2004 +0000
@@ -0,0 +1,161 @@
+/* $Id: fake-rfc2553.h,v 1.9 2004/03/10 10:06:33 dtucker Exp $ */
+
+/*
+ * Copyright (C) 2000-2003 Damien Miller.  All rights reserved.
+ * Copyright (C) 1999 WIDE Project.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Pseudo-implementation of RFC2553 name / address resolution functions
+ *
+ * But these functions are not implemented correctly. The minimum subset
+ * is implemented for ssh use only. For example, this routine assumes
+ * that ai_family is AF_INET. Don't use it for another purpose.
+ */
+
+#ifndef _FAKE_RFC2553_H
+#define _FAKE_RFC2553_H
+
+#include "includes.h"
+#include "sys/types.h"
+
+/*
+ * First, socket and INET6 related definitions 
+ */
+#ifndef HAVE_STRUCT_SOCKADDR_STORAGE
+# define	_SS_MAXSIZE	128	/* Implementation specific max size */
+# define       _SS_PADSIZE     (_SS_MAXSIZE - sizeof (struct sockaddr))
+struct sockaddr_storage {
+	struct sockaddr	ss_sa;
+	char		__ss_pad2[_SS_PADSIZE];
+};
+# define ss_family ss_sa.sa_family
+#endif /* !HAVE_STRUCT_SOCKADDR_STORAGE */
+
+#ifndef IN6_IS_ADDR_LOOPBACK
+# define IN6_IS_ADDR_LOOPBACK(a) \
+	(((u_int32_t *)(a))[0] == 0 && ((u_int32_t *)(a))[1] == 0 && \
+	 ((u_int32_t *)(a))[2] == 0 && ((u_int32_t *)(a))[3] == htonl(1))
+#endif /* !IN6_IS_ADDR_LOOPBACK */
+
+#ifndef HAVE_STRUCT_IN6_ADDR
+struct in6_addr {
+	u_int8_t	s6_addr[16];
+};
+#endif /* !HAVE_STRUCT_IN6_ADDR */
+
+#ifndef HAVE_STRUCT_SOCKADDR_IN6
+struct sockaddr_in6 {
+	unsigned short	sin6_family;
+	u_int16_t	sin6_port;
+	u_int32_t	sin6_flowinfo;
+	struct in6_addr	sin6_addr;
+};
+#endif /* !HAVE_STRUCT_SOCKADDR_IN6 */
+
+#ifndef AF_INET6
+/* Define it to something that should never appear */
+#define AF_INET6 AF_MAX
+#endif
+
+/*
+ * Next, RFC2553 name / address resolution API
+ */
+
+#ifndef NI_NUMERICHOST
+# define NI_NUMERICHOST    (1)
+#endif
+#ifndef NI_NAMEREQD
+# define NI_NAMEREQD       (1<<1)
+#endif
+#ifndef NI_NUMERICSERV
+# define NI_NUMERICSERV    (1<<2)
+#endif
+
+#ifndef AI_PASSIVE
+# define AI_PASSIVE		(1)
+#endif
+#ifndef AI_CANONNAME
+# define AI_CANONNAME		(1<<1)
+#endif
+#ifndef AI_NUMERICHOST
+# define AI_NUMERICHOST		(1<<2)
+#endif
+
+#ifndef NI_MAXSERV
+# define NI_MAXSERV 32
+#endif /* !NI_MAXSERV */
+#ifndef NI_MAXHOST
+# define NI_MAXHOST 1025
+#endif /* !NI_MAXHOST */
+
+#ifndef EAI_NODATA
+# define EAI_NODATA	1
+# define EAI_MEMORY	2
+# define EAI_NONAME	3
+#endif
+
+#ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+	int	ai_flags;	/* AI_PASSIVE, AI_CANONNAME */
+	int	ai_family;	/* PF_xxx */
+	int	ai_socktype;	/* SOCK_xxx */
+	int	ai_protocol;	/* 0 or IPPROTO_xxx for IPv4 and IPv6 */
+	size_t	ai_addrlen;	/* length of ai_addr */
+	char	*ai_canonname;	/* canonical name for hostname */
+	struct sockaddr *ai_addr;	/* binary address */
+	struct addrinfo *ai_next;	/* next structure in linked list */
+};
+#endif /* !HAVE_STRUCT_ADDRINFO */
+
+#ifndef HAVE_GETADDRINFO
+#ifdef getaddrinfo
+# undef getaddrinfo
+#endif
+#define getaddrinfo(a,b,c,d)	(ssh_getaddrinfo(a,b,c,d))
+int getaddrinfo(const char *, const char *, 
+    const struct addrinfo *, struct addrinfo **);
+#endif /* !HAVE_GETADDRINFO */
+
+#if !defined(HAVE_GAI_STRERROR) && !defined(HAVE_CONST_GAI_STRERROR_PROTO)
+#define gai_strerror(a)		(ssh_gai_strerror(a))
+char *gai_strerror(int);
+#endif /* !HAVE_GAI_STRERROR */
+
+#ifndef HAVE_FREEADDRINFO
+#define freeaddrinfo(a)		(ssh_freeaddrinfo(a))
+void freeaddrinfo(struct addrinfo *);
+#endif /* !HAVE_FREEADDRINFO */
+
+#ifndef HAVE_GETNAMEINFO
+#define getnameinfo(a,b,c,d,e,f,g) (ssh_getnameinfo(a,b,c,d,e,f,g))
+int getnameinfo(const struct sockaddr *, size_t, char *, size_t, 
+    char *, size_t, int);
+#endif /* !HAVE_GETNAMEINFO */
+
+#endif /* !_FAKE_RFC2553_H */
+
--- a/options.h	Wed Aug 11 17:26:47 2004 +0000
+++ b/options.h	Thu Aug 12 13:48:42 2004 +0000
@@ -51,10 +51,13 @@
 #define ENABLE_X11FWD
 
 /* Enable TCP Fowarding */
-/* OpenSSH's "-L" style forwarding (client port forwarded via server) */
-#define ENABLE_LOCALTCPFWD
-/* OpenSSH's "-R" style forwarding (server port forwarded via client) */
-#define ENABLE_REMOTETCPFWD
+/* "-L" style forwarding (client listening port forwarded via server) */
+#define ENABLE_CLI_LOCALTCPFWD
+/* "-R" style forwarding (server listening port forwarded via client) */
+#define ENABLE_CLI_REMOTETCPFWD
+
+#define ENABLE_SVR_LOCALTCPFWD
+#define ENABLE_SVR_REMOTETCPFWD
 
 /* Enable Authentication Agent Forwarding */
 #define ENABLE_AGENTFWD
@@ -299,6 +302,10 @@
 #define DISABLE_REMOTETCPFWD
 #endif
 
+#if defined(ENABLE_CLI_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD)
+#define ENABLE_CLI_ANYTCPFWD 
+#endif
+
 #if defined(ENABLE_REMOTETCPFWD) || defined(ENABLE_LOCALTCPFWD) || \
 	defined(ENABLE_AGENTFWD) || defined(ENABLE_X11FWD)
 #define USING_LISTENERS
--- a/runopts.h	Wed Aug 11 17:26:47 2004 +0000
+++ b/runopts.h	Thu Aug 12 13:48:42 2004 +0000
@@ -29,6 +29,7 @@
 #include "signkey.h"
 #include "buffer.h"
 #include "auth.h"
+#include "tcpfwd.h"
 
 typedef struct runopts {
 
@@ -90,8 +91,14 @@
 
 	char *cmd;
 	int wantpty;
+#ifdef DROPBEAR_PUBKEY_AUTH
 	struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
-#ifdef DROPBEAR_PUBKEY_AUTH
+#endif
+#ifdef ENABLE_CLI_REMOTETCPFWD
+	struct TCPFwdList * remotefwds;
+#endif
+#ifdef ENABLE_CLI_LOCALTCPFWD
+	struct TCPFwdList * localfwds;
 #endif
 	/* XXX TODO */
 
--- a/session.h	Wed Aug 11 17:26:47 2004 +0000
+++ b/session.h	Thu Aug 12 13:48:42 2004 +0000
@@ -35,6 +35,7 @@
 #include "queue.h"
 #include "listener.h"
 #include "packet.h"
+#include "tcpfwd.h"
 
 extern int sessinitdone; /* Is set to 0 somewhere */
 extern int exitflag;
--- a/svr-tcpfwd.c	Wed Aug 11 17:26:47 2004 +0000
+++ b/svr-tcpfwd.c	Thu Aug 12 13:48:42 2004 +0000
@@ -1,7 +1,6 @@
 #include "includes.h"
 #include "ssh.h"
-#include "tcp-accept.h"
-#include "tcp-connect.h"
+#include "tcpfwd.h"
 #include "dbutil.h"
 #include "session.h"
 #include "buffer.h"
@@ -15,6 +14,7 @@
 static void send_msg_request_failure();
 static int svr_cancelremotetcp();
 static int svr_remotetcpreq();
+static int newtcpdirect(struct Channel * channel);
 
 
 const struct ChanType svr_chan_tcpdirect = {
@@ -178,8 +178,8 @@
 
 	tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
 	tcpinfo->sendaddr = bindaddr;
-	TRACE(("sendport = %d", port));
 	tcpinfo->sendport = port;
+	tcpinfo->listenport = port;
 	tcpinfo->chantype = &svr_chan_tcpremote;
 
 	/* Note: bindaddr is actually ignored by listen_tcpfwd, since
@@ -196,4 +196,70 @@
 	TRACE(("leave remotetcpreq"));
 	return ret;
 }
+
+/* Called upon creating a new direct tcp channel (ie we connect out to an
+ * address */
+static int newtcpdirect(struct Channel * channel) {
+
+	unsigned char* desthost = NULL;
+	unsigned int destport;
+	unsigned char* orighost = NULL;
+	unsigned int origport;
+	char portstring[NI_MAXSERV];
+	int sock;
+	int len;
+	int ret = DROPBEAR_FAILURE;
+
+	if (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;
+	}
+
+	snprintf(portstring, sizeof(portstring), "%d", destport);
+	sock = connect_remote(desthost, portstring, 1, NULL);
+	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;
+}
+
 #endif
--- a/tcp-accept.c	Wed Aug 11 17:26:47 2004 +0000
+++ b/tcp-accept.c	Thu Aug 12 13:48:42 2004 +0000
@@ -1,6 +1,6 @@
 #include "includes.h"
 #include "ssh.h"
-#include "tcp-accept.h"
+#include "tcpfwd.h"
 #include "dbutil.h"
 #include "session.h"
 #include "buffer.h"
@@ -67,7 +67,7 @@
 	TRACE(("enter listen_tcpfwd"));
 
 	/* first we try to bind, so don't need to do so much cleanup on failure */
-	snprintf(portstring, sizeof(portstring), "%d", tcpinfo->sendport);
+	snprintf(portstring, sizeof(portstring), "%d", tcpinfo->listenport);
 
 	/* XXX Note: we're just listening on localhost, no matter what they tell
 	 * us. If someone wants to make it listen otherways, then change
--- a/tcp-accept.h	Wed Aug 11 17:26:47 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,25 +0,0 @@
-#ifndef _REMOTETCPFWD_H
-#define _REMOTETCPFWD_H
-
-struct TCPListener {
-
-	/* sendaddr/sendport are what we send in the channel init request. For a 
-	 * forwarded-tcpip request, it's the addr/port we were binding to.
-	 * For a direct-tcpip request, it's the addr/port we want the other
-	 * end to connect to */
-	
-	unsigned char *sendaddr;
-	unsigned int sendport;
-
-	/* This is for direct-tcpip (ie the client listening), and specifies the
-	 * port to listen on. Is unspecified for the server */
-	unsigned int listenport;
-
-	const struct ChanType *chantype;
-
-};
-
-void recv_msg_global_request_remotetcp();
-int listen_tcpfwd(struct TCPListener* tcpinfo);
-
-#endif /* _REMOTETCPFWD_H */
--- a/tcp-connect.c	Wed Aug 11 17:26:47 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-#include "includes.h"
-#include "session.h"
-#include "dbutil.h"
-#include "channel.h"
-#include "tcp-connect.h"
-#include "runopts.h"
-
-#ifndef DISABLE_TCP_CONNECT
-
-/* 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;
-	char portstring[NI_MAXSERV];
-	int sock;
-	int len;
-	int ret = DROPBEAR_FAILURE;
-
-	if (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;
-	}
-
-	snprintf(portstring, sizeof(portstring), "%d", destport);
-	sock = connect_remote(desthost, portstring, 1, NULL);
-	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;
-}
-
-#endif /* DISABLE_TCPFWD_DIRECT */
--- a/tcp-connect.h	Wed Aug 11 17:26:47 2004 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Dropbear - a SSH2 server
- * 
- * Copyright (c) 2002,2003 Matt Johnston
- * All rights reserved.
- * 
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- * 
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- * 
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE. */
-#ifndef _TCPFWD_DIRECT_H_
-#define _TCPFWD_DIRECT_H_
-#ifndef DISABLE_TCFWD_DIRECT
-
-#include "includes.h"
-#include "channel.h"
-
-extern const struct ChanType svr_chan_tcpdirect;
-int newtcpdirect(struct Channel * channel);
-
-#endif
-#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tcpfwd.h	Thu Aug 12 13:48:42 2004 +0000
@@ -0,0 +1,69 @@
+/*
+ * Dropbear - a SSH2 server
+ * 
+ * Copyright (c) 2002,2003 Matt Johnston
+ * All rights reserved.
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ * 
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE. */
+#ifndef _TCPFWD_H
+#define _TCPFWD_H
+
+#include "channel.h"
+
+struct TCPListener {
+
+	/* sendaddr/sendport are what we send in the channel init request. For a 
+	 * forwarded-tcpip request, it's the addr/port we were binding to.
+	 * For a direct-tcpip request, it's the addr/port we want the other
+	 * end to connect to */
+	
+	unsigned char *sendaddr;
+	unsigned int sendport;
+
+	/* This is for direct-tcpip (ie the client listening), and specifies the
+	 * port to listen on. Is unspecified for the server */
+	unsigned int listenport;
+
+	const struct ChanType *chantype;
+
+};
+
+/* A link in a list of forwards */
+struct TCPFwdList {
+
+	char* connectaddr;
+	unsigned int connectport;
+	unsigned int listenport;
+	struct TCPFwdList * next;
+
+};
+
+/* Server */
+void recv_msg_global_request_remotetcp();
+extern const struct ChanType svr_chan_tcpdirect;
+
+/* Client */
+void setup_localtcp();
+extern const struct ChanType cli_chan_tcpremote;
+
+/* Common */
+int listen_tcpfwd(struct TCPListener* tcpinfo);
+
+
+#endif