# HG changeset patch # User Matt Johnston # Date 1092318522 0 # Node ID efb5e0b335cf39501732be4783555ae4d8a39b81 # Parent dcc43965928f0a764d1a9b2252ce0f3924448936 TCP forwarding works. diff -r dcc43965928f -r efb5e0b335cf Makefile.in --- 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) diff -r dcc43965928f -r efb5e0b335cf cli-runopts.c --- 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 (multiple allowed)\n" #endif -#ifndef DISABLE_REMOTETCPFWD +#ifdef ENABLE_CLI_LOCALTCPFWD "-L Local port forwarding\n" #endif -#ifndef DISABLE_TCPFWD_DIRECT +#ifdef ENABLE_CLI_REMOTETCPFWD "-R 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 diff -r dcc43965928f -r efb5e0b335cf cli-session.c --- 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() { diff -r dcc43965928f -r efb5e0b335cf cli-tcpfwd.c --- 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; +} diff -r dcc43965928f -r efb5e0b335cf dbutil.c --- 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; } diff -r dcc43965928f -r efb5e0b335cf fake-rfc2553.c --- /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 */ diff -r dcc43965928f -r efb5e0b335cf fake-rfc2553.h --- /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 */ + diff -r dcc43965928f -r efb5e0b335cf options.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 diff -r dcc43965928f -r efb5e0b335cf runopts.h --- 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 */ diff -r dcc43965928f -r efb5e0b335cf session.h --- 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; diff -r dcc43965928f -r efb5e0b335cf svr-tcpfwd.c --- 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 diff -r dcc43965928f -r efb5e0b335cf tcp-accept.c --- 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 diff -r dcc43965928f -r efb5e0b335cf tcp-accept.h --- 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 */ diff -r dcc43965928f -r efb5e0b335cf tcp-connect.c --- 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 */ diff -r dcc43965928f -r efb5e0b335cf tcp-connect.h --- 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 diff -r dcc43965928f -r efb5e0b335cf tcpfwd.h --- /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