summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMatt Johnston <matt@ucc.asn.au>2004-08-12 13:48:42 +0000
committerMatt Johnston <matt@ucc.asn.au>2004-08-12 13:48:42 +0000
commite1057cd47720a03512e3ed0d5bbc2d5296b94fc2 (patch)
tree4908aee50c5555c9964030148934641fba2c1a51
parent453261a0420a1e4ee5d0feb3df6806c39ae3e0ff (diff)
TCP forwarding works.
--HG-- extra : convert_revision : 57dfb36d0d482ad84f31506904eb67863bd303ab
-rw-r--r--Makefile.in4
-rw-r--r--cli-runopts.c134
-rw-r--r--cli-session.c13
-rw-r--r--cli-tcpfwd.c130
-rw-r--r--dbutil.c4
-rw-r--r--fake-rfc2553.c224
-rw-r--r--fake-rfc2553.h161
-rw-r--r--options.h15
-rw-r--r--runopts.h9
-rw-r--r--session.h1
-rw-r--r--svr-tcpfwd.c72
-rw-r--r--tcp-accept.c4
-rw-r--r--tcp-accept.h25
-rw-r--r--tcp-connect.c75
-rw-r--r--tcpfwd.h (renamed from tcp-connect.h)46
15 files changed, 777 insertions, 140 deletions
diff --git a/Makefile.in b/Makefile.in
index af24bb0..68ef5d8 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -46,8 +46,8 @@ HEADERS=options.h dbutil.h session.h packet.h algo.h ssh.h buffer.h kex.h \
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)
diff --git a/cli-runopts.c b/cli-runopts.c
index 4c84cc8..26eb634 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -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 @@ static void parsehostname(char* userhostarg);
#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 @@ static void printhelp() {
#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 @@ void cli_getopts(int argc, char ** argv) {
#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 @@ void cli_getopts(int argc, char ** argv) {
#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 @@ void cli_getopts(int argc, char ** argv) {
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 @@ void cli_getopts(int argc, char ** argv) {
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 @@ void cli_getopts(int argc, char ** argv) {
continue; /* next argument */
} else {
- TRACE(("non-flag arg"));
+ TRACE(("non-flag arg: '%s'", argv[i]));
/* Either the hostname or commands */
@@ -226,10 +254,14 @@ static void loadidentityfile(const char* filename) {
/* 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 @@ static void parsehostname(char* userhostarg) {
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
diff --git a/cli-session.c b/cli-session.c
index 22f7001..318bc64 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -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 packettype cli_packettypes[] = {
};
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 @@ static void cli_sessionloop() {
*/
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 @@ static void cli_finished() {
}
-
/* called when the remote side closes the connection */
static void cli_remoteclosed() {
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c
index 955ffab..f32a53f 100644
--- a/cli-tcpfwd.c
+++ b/cli-tcpfwd.c
@@ -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 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
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 @@ static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
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;
}
diff --git a/dbutil.c b/dbutil.c
index 72d25e7..b5cd2b0 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -185,7 +185,7 @@ int dropbear_listen(const char* address, const char* port,
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 dropbear_listen(const char* address, const char* port,
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;
}
diff --git a/fake-rfc2553.c b/fake-rfc2553.c
new file mode 100644
index 0000000..0186b53
--- /dev/null
+++ b/fake-rfc2553.c
@@ -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 */
diff --git a/fake-rfc2553.h b/fake-rfc2553.h
new file mode 100644
index 0000000..baea070
--- /dev/null
+++ b/fake-rfc2553.h
@@ -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 */
+
diff --git a/options.h b/options.h
index 99115db..c841332 100644
--- a/options.h
+++ b/options.h
@@ -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
diff --git a/runopts.h b/runopts.h
index c74dab5..a160a29 100644
--- a/runopts.h
+++ b/runopts.h
@@ -29,6 +29,7 @@
#include "signkey.h"
#include "buffer.h"
#include "auth.h"
+#include "tcpfwd.h"
typedef struct runopts {
@@ -90,8 +91,14 @@ typedef struct cli_runopts {
char *cmd;
int wantpty;
- struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
#ifdef DROPBEAR_PUBKEY_AUTH
+ struct PubkeyList *pubkeys; /* Keys to use for public-key auth */
+#endif
+#ifdef ENABLE_CLI_REMOTETCPFWD
+ struct TCPFwdList * remotefwds;
+#endif
+#ifdef ENABLE_CLI_LOCALTCPFWD
+ struct TCPFwdList * localfwds;
#endif
/* XXX TODO */
diff --git a/session.h b/session.h
index 4a9d4ed..6a6ed07 100644
--- a/session.h
+++ b/session.h
@@ -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;
diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c
index 46c7129..0eccae4 100644
--- a/svr-tcpfwd.c
+++ b/svr-tcpfwd.c
@@ -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_success();
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 @@ static int svr_remotetcpreq() {
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 @@ out:
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
diff --git a/tcp-accept.c b/tcp-accept.c
index 8f8b5c0..6b82914 100644
--- a/tcp-accept.c
+++ b/tcp-accept.c
@@ -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 @@ int listen_tcpfwd(struct TCPListener* tcpinfo) {
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
diff --git a/tcp-accept.h b/tcp-accept.h
deleted file mode 100644
index 8c795dc..0000000
--- a/tcp-accept.h
+++ /dev/null
@@ -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 */
diff --git a/tcp-connect.c b/tcp-connect.c
deleted file mode 100644
index d24f32d..0000000
--- a/tcp-connect.c
+++ /dev/null
@@ -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 */
diff --git a/tcp-connect.h b/tcpfwd.h
index 40ce22b..569d59d 100644
--- a/tcp-connect.h
+++ b/tcpfwd.h
@@ -21,15 +21,49 @@
* 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
+#ifndef _TCPFWD_H
+#define _TCPFWD_H
-#include "includes.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;
-int newtcpdirect(struct Channel * channel);
-#endif
+/* Client */
+void setup_localtcp();
+extern const struct ChanType cli_chan_tcpremote;
+
+/* Common */
+int listen_tcpfwd(struct TCPListener* tcpinfo);
+
+
#endif