TCP forwarding works.

--HG--
extra : convert_revision : 57dfb36d0d482ad84f31506904eb67863bd303ab
This commit is contained in:
Matt Johnston 2004-08-12 13:48:42 +00:00
parent 453261a042
commit e1057cd477
15 changed files with 777 additions and 140 deletions

View File

@ -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)

View File

@ -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;
@ -106,6 +108,22 @@ void cli_getopts(int argc, char ** argv) {
nextiskey = 0;
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 */
@ -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

View File

@ -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() {

View File

@ -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;
}

View File

@ -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;
}

224
fake-rfc2553.c Normal file
View File

@ -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 */

161
fake-rfc2553.h Normal file
View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

View File

@ -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);
/* Client */
void setup_localtcp();
extern const struct ChanType cli_chan_tcpremote;
/* Common */
int listen_tcpfwd(struct TCPListener* tcpinfo);
#endif
#endif