summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--Makefile.in11
-rw-r--r--cli-authpubkey.c10
-rw-r--r--cli-runopts.c18
-rw-r--r--cli-session.c5
-rw-r--r--cli-tcpfwd.c34
-rw-r--r--common-channel.c43
-rw-r--r--dbutil.c173
-rw-r--r--dbutil.h6
-rw-r--r--listener.c42
-rw-r--r--listener.h10
-rw-r--r--options.h3
-rw-r--r--svr-agentfwd.c8
-rw-r--r--svr-chansession.c2
-rw-r--r--svr-main.c82
-rw-r--r--svr-session.c6
-rw-r--r--svr-tcpfwd.c196
-rw-r--r--svr-x11fwd.c8
-rw-r--r--tcp-accept.c88
-rw-r--r--tcp-accept.h19
-rw-r--r--tcp-connect.c75
-rw-r--r--tcp-connect.h (renamed from tcpfwd-direct.h)3
-rw-r--r--tcpfwd-direct.c159
-rw-r--r--tcpfwd-remote.c317
-rw-r--r--tcpfwd-remote.h6
24 files changed, 673 insertions, 651 deletions
diff --git a/Makefile.in b/Makefile.in
index 2bffe90..af24bb0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -24,15 +24,16 @@ COMMONOBJS=dbutil.o buffer.o \
SVROBJS=svr-kex.o svr-algo.o svr-auth.o sshpty.o \
svr-authpasswd.o svr-authpubkey.o svr-session.o svr-service.o \
- svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o
+ svr-chansession.o svr-runopts.o svr-agentfwd.o svr-main.o svr-x11fwd.o\
+ svr-tcpfwd.o
CLIOBJS=cli-algo.o cli-main.o cli-auth.o cli-authpasswd.o cli-kex.o \
cli-session.o cli-service.o cli-runopts.o cli-chansession.o \
- cli-authpubkey.o
+ cli-authpubkey.o cli-tcpfwd.o
CLISVROBJS=common-session.o packet.o common-algo.o common-kex.o \
common-channel.o common-chansession.o termcodes.o loginrec.o \
- tcpfwd-direct.o tcpfwd-remote.o listener.o process-packet.o \
+ tcp-accept.o tcp-connect.o listener.o process-packet.o \
common-runopts.o
KEYOBJS=dropbearkey.o gendss.o genrsa.o
@@ -45,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 tcpfwd-direct.h compat.h \
- tcpfwd-remote.h listener.h
+ loginrec.h atomicio.h x11fwd.h agentfwd.h tcp-accept.h compat.h \
+ tcp-connect.h listener.h
dropbearobjs=$(COMMONOBJS) $(CLISVROBJS) $(SVROBJS)
dbclientobjs=$(COMMONOBJS) $(CLISVROBJS) $(CLIOBJS)
diff --git a/cli-authpubkey.c b/cli-authpubkey.c
index 6b6ab51..33514ce 100644
--- a/cli-authpubkey.c
+++ b/cli-authpubkey.c
@@ -13,17 +13,22 @@ static void send_msg_userauth_pubkey(sign_key *key, int type, int realsign);
void cli_pubkeyfail() {
struct PubkeyList *keyitem;
+ struct PubkeyList **previtem;
TRACE(("enter cli_pubkeyfail"));
+ previtem = &cli_opts.pubkeys;
+
/* Find the key we failed with, and remove it */
for (keyitem = cli_opts.pubkeys; keyitem != NULL; keyitem = keyitem->next) {
- if (keyitem->next == cli_ses.lastpubkey) {
- keyitem->next = cli_ses.lastpubkey->next;
+ if (keyitem == cli_ses.lastpubkey) {
+ *previtem = keyitem->next;
}
+ previtem = &keyitem;
}
sign_key_free(cli_ses.lastpubkey->key); /* It won't be used again */
m_free(cli_ses.lastpubkey);
+
TRACE(("leave cli_pubkeyfail"));
}
@@ -145,6 +150,7 @@ int cli_auth_pubkey() {
/* Send a trial request */
send_msg_userauth_pubkey(cli_opts.pubkeys->key,
cli_opts.pubkeys->type, 0);
+ cli_ses.lastpubkey = cli_opts.pubkeys;
TRACE(("leave cli_auth_pubkey-success"));
return 1;
} else {
diff --git a/cli-runopts.c b/cli-runopts.c
index eb718a4..4c84cc8 100644
--- a/cli-runopts.c
+++ b/cli-runopts.c
@@ -48,6 +48,12 @@ static void printhelp() {
#ifdef DROPBEAR_PUBKEY_AUTH
"-i <identityfile> (multiple allowed)\n"
#endif
+#ifndef DISABLE_REMOTETCPFWD
+ "-L <listenport:remotehsot:reportport> Local port forwarding\n"
+#endif
+#ifndef DISABLE_TCPFWD_DIRECT
+ "-R <listenport:remotehost:remoteport> Remote port forwarding\n"
+#endif
,DROPBEAR_VERSION, cli_opts.progname);
}
@@ -59,6 +65,12 @@ 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
+ int nextislocal = 0;
+#endif
+#ifdef DROPBEAR_CLI_REMOTETCP
+ int nextisremote = 0;
+#endif
@@ -72,6 +84,12 @@ void cli_getopts(int argc, char ** argv) {
#ifdef DROPBEAR_PUBKEY_AUTH
cli_opts.pubkeys = NULL;
#endif
+#ifdef DROPBEAR_CLI_LOCALTCP
+ cli_opts.localports = NULL;
+#endif
+#ifdef DROPBEAR_CLI_REMOTETCP
+ cli_opts.remoteports = NULL;
+#endif
opts.nolocaltcp = 0;
opts.noremotetcp = 0;
/* not yet
diff --git a/cli-session.c b/cli-session.c
index 973e9c7..22f7001 100644
--- a/cli-session.c
+++ b/cli-session.c
@@ -4,8 +4,8 @@
#include "kex.h"
#include "ssh.h"
#include "packet.h"
-#include "tcpfwd-direct.h"
-#include "tcpfwd-remote.h"
+#include "tcp-accept.h"
+#include "tcp-connect.h"
#include "channel.h"
#include "random.h"
#include "service.h"
@@ -31,7 +31,6 @@ static const packettype cli_packettypes[] = {
{SSH_MSG_KEXDH_REPLY, recv_msg_kexdh_reply}, /* client */
{SSH_MSG_NEWKEYS, recv_msg_newkeys},
{SSH_MSG_SERVICE_ACCEPT, recv_msg_service_accept}, /* client */
- {SSH_MSG_GLOBAL_REQUEST, recv_msg_global_request_remotetcp},
{SSH_MSG_CHANNEL_REQUEST, recv_msg_channel_request},
{SSH_MSG_CHANNEL_OPEN, recv_msg_channel_open},
{SSH_MSG_CHANNEL_EOF, recv_msg_channel_eof},
diff --git a/cli-tcpfwd.c b/cli-tcpfwd.c
new file mode 100644
index 0000000..3dc6e20
--- /dev/null
+++ b/cli-tcpfwd.c
@@ -0,0 +1,34 @@
+#include "includes.h"
+#include "options.h"
+#include "tcp-accept.h"
+#include "tcp-connect.h"
+#include "channel.h"
+
+static const struct ChanType cli_chan_tcplocal = {
+ 1, /* sepfds */
+ "direct-tcpip",
+ NULL,
+ NULL,
+ NULL
+};
+
+
+
+
+static int cli_localtcp(char* port) {
+
+ struct TCPListener* tcpinfo = NULL;
+
+ tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
+ tcpinfo->addr = NULL;
+ tcpinfo->port = port;
+ tcpinfo->chantype = &cli_chan_tcplocal;
+
+ ret = listen_tcpfwd(tcpinfo);
+
+ if (ret == DROPBEAR_FAILURE) {
+ DROPBEAR_LOG(LOG_WARNING, "Failed to listen on port %s", port);
+ m_free(tcpinfo);
+ }
+ return ret;
+}
diff --git a/common-channel.c b/common-channel.c
index fbfb00b..5079031 100644
--- a/common-channel.c
+++ b/common-channel.c
@@ -32,8 +32,6 @@
#include "dbutil.h"
#include "channel.h"
#include "ssh.h"
-#include "tcpfwd-direct.h"
-#include "tcpfwd-remote.h"
#include "listener.h"
static void send_msg_channel_open_failure(unsigned int remotechan, int reason,
@@ -307,13 +305,6 @@ static void send_msg_channel_close(struct Channel *channel) {
if (channel->type->closehandler) {
channel->type->closehandler(channel);
}
-#if 0
- if (channel->type == CHANNEL_ID_SESSION) {
- send_exitsignalstatus(channel);
-
- closechansess(channel);
- }
-#endif
CHECKCLEARTOWRITE();
@@ -545,23 +536,6 @@ void recv_msg_channel_request() {
send_msg_channel_failure(channel);
}
-#if 0
- /* handle according to channel type */
- switch (channel->type) {
-
- case CHANNEL_ID_SESSION:
- TRACE(("continue recv_msg_channel_request: session request"));
- /* XXX server */
- /* Here we need to do things channel-specific style. Function
- * pointer callbacks perhaps */
- chansessionrequest(channel);
- break;
-
- default:
- send_msg_channel_failure(channel);
- }
-#endif
-
TRACE(("leave recv_msg_channel_request"));
}
@@ -797,23 +771,6 @@ void recv_msg_channel_open() {
}
}
-#if 0
- /* type specific initialisation */
- if (typeval == CHANNEL_ID_SESSION) {
- newchansess(channel);
-#ifndef DISABLE_LOCALTCPFWD
- } else if (typeval == CHANNEL_ID_TCPDIRECT) {
- if (ses.opts->nolocaltcp) {
- errtype = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
- } else if (newtcpdirect(channel) == DROPBEAR_FAILURE) {
- errtype = SSH_OPEN_CONNECT_FAILED;
- deletechannel(channel);
- goto failure;
- }
-#endif
- }
-#endif
-
/* success */
send_msg_channel_open_confirmation(channel, channel->recvwindow,
channel->recvmaxpacket);
diff --git a/dbutil.c b/dbutil.c
index dd68416..a377da2 100644
--- a/dbutil.c
+++ b/dbutil.c
@@ -113,8 +113,109 @@ void dropbear_trace(const char* format, ...) {
}
#endif /* DEBUG_TRACE */
+/* Listen on address:port. Unless address is NULL, in which case listen on
+ * everything (ie 0.0.0.0, or ::1 - note that this is IPv? agnostic. Linux is
+ * broken with respect to listening to v6 or v4, so the addresses you get when
+ * people connect will be wrong. It doesn't break things, just looks quite
+ * ugly. Returns the number of sockets bound on success, or -1 on failure. On
+ * failure, if errstring wasn't NULL, it'll be a newly malloced error
+ * string.*/
+int dropbear_listen(const char* address, const char* port,
+ int *socks, unsigned int sockcount, char **errstring, int *maxfd) {
+
+ struct addrinfo hints, *res, *res0;
+ int err;
+ unsigned int nsock;
+ struct linger linger;
+ int val;
+ int sock;
+
+ TRACE(("enter dropbear_listen"));
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_PASSIVE;
+ err = getaddrinfo(address, port, &hints, &res0);
+
+ if (err) {
+ if (errstring != NULL && *errstring == NULL) {
+ int len;
+ len = 20 + strlen(gai_strerror(err));
+ *errstring = (char*)m_malloc(len);
+ snprintf(*errstring, len, "Error resolving: %s", gai_strerror(err));
+ }
+ TRACE(("leave dropbear_listen: failed resolving"));
+ return -1;
+ }
+
+
+ nsock = 0;
+ for (res = res0; res != NULL && nsock < sockcount;
+ res = res->ai_next) {
+
+ /* Get a socket */
+ socks[nsock] = socket(res->ai_family, res->ai_socktype,
+ res->ai_protocol);
+
+ sock = socks[nsock]; /* For clarity */
+
+ if (sock < 0) {
+ err = errno;
+ TRACE(("socket() failed"));
+ continue;
+ }
+
+ /* Various useful socket options */
+ val = 1;
+ /* set to reuse, quick timeout */
+ setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*) &val, sizeof(val));
+ linger.l_onoff = 1;
+ linger.l_linger = 5;
+ setsockopt(sock, SOL_SOCKET, SO_LINGER, (void*)&linger, sizeof(linger));
+
+ /* disable nagle */
+ setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
+
+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) {
+ err = errno;
+ close(sock);
+ TRACE(("bind() failed"));
+ continue;
+ }
+
+ if (listen(sock, 20) < 0) {
+ err = errno;
+ close(sock);
+ TRACE(("listen() failed"));
+ continue;
+ }
+
+ *maxfd = MAX(*maxfd, sock);
+
+ nsock++;
+ }
+
+ if (nsock == 0) {
+ if (errstring != NULL && *errstring == NULL) {
+ int len;
+ len = 20 + strlen(strerror(err));
+ *errstring = (char*)m_malloc(len);
+ snprintf(*errstring, len, "Error connecting: %s", strerror(err));
+ TRACE(("leave dropbear_listen: failure, %s", strerror(err)));
+ return -1;
+ }
+ }
+
+ TRACE(("leave dropbear_listen: success, %d socks bound", nsock));
+ return nsock;
+}
+
/* Connect via TCP to a host. Connection will try ipv4 or ipv6, will
- * return immediately if nonblocking is set */
+ * return immediately if nonblocking is set. On failure, if errstring
+ * wasn't null, it will be a newly malloced error message */
+
+/* TODO: maxfd */
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring) {
@@ -197,58 +298,70 @@ int connect_remote(const char* remotehost, const char* remoteport,
}
freeaddrinfo(res0);
+ if (sock > 0 && errstring != NULL && *errstring != NULL) {
+ m_free(*errstring);
+ }
- TRACE(("leave connect_remote: sock %d", sock));
+ TRACE(("leave connect_remote: sock %d\n", sock));
return sock;
}
/* Return a string representation of the socket address passed. The return
* value is allocated with malloc() */
-unsigned char * getaddrstring(struct sockaddr * addr) {
+unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport) {
- char *retstring;
+ char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
+ char *retstring = NULL;
+ int ret;
+ unsigned int len;
- /* space for "255.255.255.255:65535\0" = 22 */
- retstring = m_malloc(22);
+ len = sizeof(struct sockaddr_storage);
- switch (addr->sa_family) {
- case PF_INET:
- snprintf(retstring, 22, "%s:%hu",
- inet_ntoa(((struct sockaddr_in *)addr)->sin_addr),
- ((struct sockaddr_in *)addr)->sin_port);
- break;
+ ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
+ sbuf, sizeof(sbuf), NI_NUMERICSERV | NI_NUMERICHOST);
- default:
- /* XXX ipv6 */
- strcpy(retstring, "Bad protocol");
+ if (ret != 0) {
+ /* This is a fairly bad failure - it'll fallback to IP if it
+ * just can't resolve */
+ dropbear_exit("failed lookup (%d, %d)", ret, errno);
+ }
+ if (withport) {
+ len = strlen(hbuf) + 2 + strlen(sbuf);
+ retstring = (char*)m_malloc(len);
+ snprintf(retstring, len, "%s:%s", hbuf, sbuf);
+ } else {
+ retstring = m_strdup(hbuf);
}
+
return retstring;
}
/* Get the hostname corresponding to the address addr. On failure, the IP
* address is returned. The return value is allocated with strdup() */
-char* getaddrhostname(struct sockaddr * addr) {
+char* getaddrhostname(struct sockaddr_storage * addr) {
- struct hostent *host = NULL;
- char * retstring;
+ char hbuf[NI_MAXHOST];
+ char sbuf[NI_MAXSERV];
+ int ret;
+ unsigned int len;
-#ifdef DO_HOST_LOOKUP
- host = gethostbyaddr((char*)&((struct sockaddr_in*)addr)->sin_addr,
- sizeof(struct in_addr), AF_INET);
-#endif
-
- if (host == NULL) {
- /* return the address */
- retstring = inet_ntoa(((struct sockaddr_in *)addr)->sin_addr);
- } else {
- /* return the hostname */
- retstring = host->h_name;
+ len = sizeof(struct sockaddr_storage);
+
+ ret = getnameinfo((struct sockaddr*)addr, len, hbuf, sizeof(hbuf),
+ sbuf, sizeof(sbuf), NI_NUMERICSERV);
+
+ if (ret != 0) {
+ /* On some systems (Darwin does it) we get EINTR from getnameinfo
+ * somehow. Eew. So we'll just return the IP, since that doesn't seem
+ * to exhibit that behaviour. */
+ return getaddrstring(addr, 0);
}
- return m_strdup(retstring);
+ return m_strdup(hbuf);
}
+
#ifdef DEBUG_TRACE
void printhex(unsigned char* buf, int len) {
diff --git a/dbutil.h b/dbutil.h
index 21a9955..ce0f311 100644
--- a/dbutil.h
+++ b/dbutil.h
@@ -44,10 +44,12 @@ void dropbear_trace(const char* format, ...);
void printhex(unsigned char* buf, int len);
#endif
char * stripcontrol(const char * text);
-unsigned char * getaddrstring(struct sockaddr * addr);
+unsigned char * getaddrstring(struct sockaddr_storage* addr, int withport);
+int dropbear_listen(const char* address, const char* port,
+ int *socks, unsigned int sockcount, char **errstring, int *maxfd);
int connect_remote(const char* remotehost, const char* remoteport,
int nonblocking, char ** errstring);
-char* getaddrhostname(struct sockaddr * addr);
+char* getaddrhostname(struct sockaddr_storage * addr);
int buf_readfile(buffer* buf, const char* filename);
int buf_getline(buffer * line, FILE * authfile);
diff --git a/listener.c b/listener.c
index 7296a61..3022bd5 100644
--- a/listener.c
+++ b/listener.c
@@ -14,15 +14,16 @@ void listeners_initialise() {
void set_listener_fds(fd_set * readfds) {
- unsigned int i;
+ unsigned int i, j;
struct Listener *listener;
/* check each in turn */
for (i = 0; i < ses.listensize; i++) {
listener = ses.listeners[i];
if (listener != NULL) {
- TRACE(("set listener fd %d", listener->sock));
- FD_SET(listener->sock, readfds);
+ for (j = 0; j < listener->nsocks; j++) {
+ FD_SET(listener->socks[j], readfds);
+ }
}
}
}
@@ -30,16 +31,19 @@ void set_listener_fds(fd_set * readfds) {
void handle_listeners(fd_set * readfds) {
- unsigned int i;
+ unsigned int i, j;
struct Listener *listener;
+ int sock;
/* check each in turn */
for (i = 0; i < ses.listensize; i++) {
listener = ses.listeners[i];
if (listener != NULL) {
- TRACE(("handle listener num %d fd %d", i, listener->sock));
- if (FD_ISSET(listener->sock, readfds)) {
- listener->accepter(listener);
+ for (j = 0; j < listener->nsocks; j++) {
+ sock = listener->socks[j];
+ if (FD_ISSET(sock, readfds)) {
+ listener->accepter(listener, sock);
+ }
}
}
}
@@ -48,8 +52,9 @@ void handle_listeners(fd_set * readfds) {
/* accepter(int fd, void* typedata) is a function to accept connections,
* cleanup(void* typedata) happens when cleaning up */
-struct Listener* new_listener(int sock, int type, void* typedata,
- void (*accepter)(struct Listener*),
+struct Listener* new_listener(int socks[], unsigned int nsocks,
+ int type, void* typedata,
+ void (*accepter)(struct Listener*, int sock),
void (*cleanup)(struct Listener*)) {
unsigned int i, j;
@@ -65,7 +70,9 @@ struct Listener* new_listener(int sock, int type, void* typedata,
if (i == ses.listensize) {
if (ses.listensize > MAX_LISTENERS) {
TRACE(("leave newlistener: too many already"));
- close(sock);
+ for (j = 0; j < nsocks; j++) {
+ close(socks[i]);
+ }
return NULL;
}
@@ -80,15 +87,18 @@ struct Listener* new_listener(int sock, int type, void* typedata,
}
}
- ses.maxfd = MAX(ses.maxfd, sock);
+ for (j = 0; j < nsocks; j++) {
+ ses.maxfd = MAX(ses.maxfd, socks[j]);
+ }
- TRACE(("new listener num %d fd %d", i, sock));
+ TRACE(("new listener num %d ", i));
newlisten = (struct Listener*)m_malloc(sizeof(struct Listener));
newlisten->index = i;
newlisten->type = type;
newlisten->typedata = typedata;
- newlisten->sock = sock;
+ newlisten->nsocks = nsocks;
+ memcpy(newlisten->socks, socks, nsocks * sizeof(int));
newlisten->accepter = accepter;
newlisten->cleanup = cleanup;
@@ -116,11 +126,15 @@ struct Listener * get_listener(int type, void* typedata,
void remove_listener(struct Listener* listener) {
+ unsigned int j;
+
if (listener->cleanup) {
listener->cleanup(listener);
}
- close(listener->sock);
+ for (j = 0; j < listener->nsocks; j++) {
+ close(listener->socks[j]);
+ }
ses.listeners[listener->index] = NULL;
m_free(listener);
diff --git a/listener.h b/listener.h
index bda24ff..c634ead 100644
--- a/listener.h
+++ b/listener.h
@@ -6,11 +6,12 @@
struct Listener {
- int sock;
+ int socks[DROPBEAR_MAX_SOCKS];
+ unsigned int nsocks;
int index; /* index in the array of listeners */
- void (*accepter)(struct Listener*);
+ void (*accepter)(struct Listener*, int sock);
void (*cleanup)(struct Listener*);
int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT,
@@ -25,8 +26,9 @@ void listeners_initialise();
void handle_listeners(fd_set * readfds);
void set_listener_fds(fd_set * readfds);
-struct Listener* new_listener(int sock, int type, void* typedata,
- void (*accepter)(struct Listener*),
+struct Listener* new_listener(int socks[], unsigned int nsocks,
+ int type, void* typedata,
+ void (*accepter)(struct Listener*, int sock),
void (*cleanup)(struct Listener*));
struct Listener * get_listener(int type, void* typedata,
diff --git a/options.h b/options.h
index d4abf09..99115db 100644
--- a/options.h
+++ b/options.h
@@ -280,6 +280,9 @@
/* For a 4096 bit DSS key, empirically determined to be 1590 bytes */
#define MAX_PRIVKEY_SIZE 1600
+#define DROPBEAR_MAX_SOCKS 2 /* IPv4, IPv6 are all we'll get for now. Revisit
+ in a few years time.... */
+
#ifndef ENABLE_X11FWD
#define DISABLE_X11FWD
#endif
diff --git a/svr-agentfwd.c b/svr-agentfwd.c
index 0dad2a4..b588586 100644
--- a/svr-agentfwd.c
+++ b/svr-agentfwd.c
@@ -44,7 +44,7 @@
static int send_msg_channel_open_agent(int fd);
static int bindagent(int fd, struct ChanSess * chansess);
-static void agentaccept(struct Listener * listener);
+static void agentaccept(struct Listener * listener, int sock);
/* Handles client requests to start agent forwarding, sets up listening socket.
* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
@@ -78,7 +78,7 @@ int agentreq(struct ChanSess * chansess) {
}
/* pass if off to listener */
- chansess->agentlistener = new_listener( fd, 0, chansess,
+ chansess->agentlistener = new_listener( &fd, 1, 0, chansess,
agentaccept, NULL);
if (chansess->agentlistener == NULL) {
@@ -97,11 +97,11 @@ fail:
/* accepts a connection on the forwarded socket and opens a new channel for it
* back to the client */
/* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
-static void agentaccept(struct Listener * listener) {
+static void agentaccept(struct Listener * listener, int sock) {
int fd;
- fd = accept(listener->sock, NULL, NULL);
+ fd = accept(sock, NULL, NULL);
if (fd < 0) {
TRACE(("accept failed"));
return;
diff --git a/svr-chansession.c b/svr-chansession.c
index 9639961..a0e877c 100644
--- a/svr-chansession.c
+++ b/svr-chansession.c
@@ -408,6 +408,8 @@ static void get_termmodes(struct ChanSess *chansess) {
}
len = buf_getint(ses.payload);
+ TRACE(("term mode str %d p->l %d p->p %d",
+ len, ses.payload->len , ses.payload->pos));
if (len != ses.payload->len - ses.payload->pos) {
dropbear_exit("bad term mode string");
}
diff --git a/svr-main.c b/svr-main.c
index 312e47c..6a49626 100644
--- a/svr-main.c
+++ b/svr-main.c
@@ -29,7 +29,7 @@
#include "signkey.h"
#include "runopts.h"
-static int listensockets(int *sock, int *maxfd);
+static int listensockets(int *sock, int sockcount, int *maxfd);
static void sigchld_handler(int dummy);
static void sigsegv_handler(int);
static void sigintterm_handler(int fish);
@@ -49,10 +49,10 @@ int main(int argc, char ** argv)
unsigned int i, j;
int val;
int maxsock = -1;
- struct sockaddr remoteaddr;
+ struct sockaddr_storage remoteaddr;
int remoteaddrlen;
int listensocks[MAX_LISTEN_ADDR];
- unsigned int listensockcount = 0;
+ int listensockcount = 0;
FILE * pidfile;
int childsock;
@@ -127,7 +127,10 @@ int main(int argc, char ** argv)
/* Set up the listening sockets */
/* XXX XXX ports */
- listensockcount = listensockets(listensocks, &maxsock);
+ listensockcount = listensockets(listensocks, MAX_LISTEN_ADDR, &maxsock);
+ if (listensockcount < 0) {
+ dropbear_exit("No listening ports available.");
+ }
/* incoming connection select loop */
for(;;) {
@@ -138,7 +141,7 @@ int main(int argc, char ** argv)
seltimeout.tv_usec = 0;
/* listening sockets */
- for (i = 0; i < listensockcount; i++) {
+ for (i = 0; i < (unsigned int)listensockcount; i++) {
FD_SET(listensocks[i], &fds);
}
@@ -179,12 +182,12 @@ int main(int argc, char ** argv)
}
/* handle each socket which has something to say */
- for (i = 0; i < listensockcount; i++) {
+ for (i = 0; i < (unsigned int)listensockcount; i++) {
if (!FD_ISSET(listensocks[i], &fds))
continue;
/* child connection XXX - ip6 stuff here */
- remoteaddrlen = sizeof(struct sockaddr_in);
+ remoteaddrlen = sizeof(remoteaddr);
childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen);
if (childsock < 0) {
@@ -222,7 +225,7 @@ int main(int argc, char ** argv)
monstartup((u_long)&_start, (u_long)&etext);
#endif /* DEBUG_FORKGPROF */
- addrstring = getaddrstring(&remoteaddr);
+ addrstring = getaddrstring(&remoteaddr, 1);
dropbear_log(LOG_INFO, "Child connection from %s", addrstring);
m_free(addrstring);
@@ -231,7 +234,7 @@ int main(int argc, char ** argv)
}
/* make sure we close sockets */
- for (i = 0; i < listensockcount; i++) {
+ for (i = 0; i < (unsigned int)listensockcount; i++) {
if (m_close(listensocks[i]) == DROPBEAR_FAILURE) {
dropbear_exit("Couldn't close socket");
}
@@ -289,59 +292,30 @@ static void sigintterm_handler(int fish) {
}
/* Set up listening sockets for all the requested ports */
-static int listensockets(int *sock, int *maxfd) {
+static int listensockets(int *sock, int sockcount, int *maxfd) {
- int listensock; /* listening fd */
- struct sockaddr_in listen_addr;
- struct linger linger;
unsigned int i;
- int val;
+ char portstring[6];
+ char* errstring = NULL;
+ unsigned int sockpos = 0;
+ int nsock;
for (i = 0; i < svr_opts.portcount; i++) {
- /* iterate through all the sockets to listen on */
- listensock = socket(PF_INET, SOCK_STREAM, 0);
- if (listensock < 0) {
- dropbear_exit("Failed to create socket");
- }
-
- val = 1;
- /* set to reuse, quick timeout */
- setsockopt(listensock, SOL_SOCKET, SO_REUSEADDR,
- (void*) &val, sizeof(val));
- linger.l_onoff = 1;
- linger.l_linger = 5;
- setsockopt(listensock, SOL_SOCKET, SO_LINGER,
- (void*)&linger, sizeof(linger));
-
- /* disable nagle */
- setsockopt(listensock, IPPROTO_TCP, TCP_NODELAY,
- (void*)&val, sizeof(val));
-
- memset((void*)&listen_addr, 0x0, sizeof(listen_addr));
- listen_addr.sin_family = AF_INET;
- listen_addr.sin_port = htons(svr_opts.ports[i]);
- listen_addr.sin_addr.s_addr = htonl(INADDR_ANY);
- memset(&(listen_addr.sin_zero), '\0', 8);
-
- if (bind(listensock, (struct sockaddr *)&listen_addr,
- sizeof(listen_addr)) < 0) {
- dropbear_exit("Bind failed port %d", svr_opts.ports[i]);
- }
+ snprintf(portstring, sizeof(portstring), "%d", svr_opts.ports[i]);
+ nsock = dropbear_listen(NULL, portstring, &sock[sockpos],
+ sockcount - sockpos,
+ &errstring, maxfd);
- /* listen */
- if (listen(listensock, 20) < 0) { /* TODO set listen count */
- dropbear_exit("Listen failed");
+ if (nsock < 0) {
+ dropbear_log(LOG_WARNING, "Failed listening on port %s: %s",
+ portstring, errstring);
+ m_free(errstring);
+ continue;
}
- /* nonblock */
- if (fcntl(listensock, F_SETFL, O_NONBLOCK) < 0) {
- dropbear_exit("Failed to set non-blocking");
- }
+ sockpos += nsock;
- sock[i] = listensock;
- *maxfd = MAX(listensock, *maxfd);
}
-
- return svr_opts.portcount;
+ return sockpos;
}
diff --git a/svr-session.c b/svr-session.c
index e63ba32..d46adf4 100644
--- a/svr-session.c
+++ b/svr-session.c
@@ -35,10 +35,10 @@
#include "channel.h"
#include "chansession.h"
#include "atomicio.h"
-#include "tcpfwd-direct.h"
+#include "tcp-accept.h"
+#include "tcp-connect.h"
#include "service.h"
#include "auth.h"
-#include "tcpfwd-remote.h"
#include "runopts.h"
static void svr_remoteclosed();
@@ -65,7 +65,7 @@ static const packettype svr_packettypes[] = {
static const struct ChanType *svr_chantypes[] = {
&svrchansess,
- &chan_tcpdirect,
+ &svr_chan_tcpdirect,
NULL /* Null termination is mandatory. */
};
diff --git a/svr-tcpfwd.c b/svr-tcpfwd.c
new file mode 100644
index 0000000..499ee46
--- /dev/null
+++ b/svr-tcpfwd.c
@@ -0,0 +1,196 @@
+#include "includes.h"
+#include "ssh.h"
+#include "tcp-accept.h"
+#include "tcp-connect.h"
+#include "dbutil.h"
+#include "session.h"
+#include "buffer.h"
+#include "packet.h"
+#include "listener.h"
+#include "runopts.h"
+
+#ifndef DISABLE_SVR_REMOTETCPFWD
+
+static void send_msg_request_success();
+static void send_msg_request_failure();
+static int svr_cancelremotetcp();
+static int svr_remotetcpreq();
+
+
+const struct ChanType svr_chan_tcpdirect = {
+ 1, /* sepfds */
+ "direct-tcpip",
+ newtcpdirect, /* init */
+ NULL, /* checkclose */
+ NULL, /* reqhandler */
+ NULL /* closehandler */
+};
+
+static const struct ChanType svr_chan_tcpremote = {
+ 1, /* sepfds */
+ "forwarded-tcpip",
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+/* At the moment this is completely used for tcp code (with the name reflecting
+ * that). If new request types are added, this should be replaced with code
+ * similar to the request-switching in chansession.c */
+void recv_msg_global_request_remotetcp() {
+
+ unsigned char* reqname = NULL;
+ unsigned int namelen;
+ unsigned int wantreply = 0;
+ int ret = DROPBEAR_FAILURE;
+
+ TRACE(("enter recv_msg_global_request_remotetcp"));
+
+ if (opts.noremotetcp) {
+ TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"));
+ goto out;
+ }
+
+ reqname = buf_getstring(ses.payload, &namelen);
+ wantreply = buf_getbyte(ses.payload);
+
+ if (namelen > MAXNAMLEN) {
+ TRACE(("name len is wrong: %d", namelen));
+ goto out;
+ }
+
+ if (strcmp("tcpip-forward", reqname) == 0) {
+ ret = svr_remotetcpreq();
+ } else if (strcmp("cancel-tcpip-forward", reqname) == 0) {
+ ret = svr_cancelremotetcp();
+ } else {
+ TRACE(("reqname isn't tcpip-forward: '%s'", reqname));
+ }
+
+out:
+ if (wantreply) {
+ if (ret == DROPBEAR_SUCCESS) {
+ send_msg_request_success();
+ } else {
+ send_msg_request_failure();
+ }
+ }
+
+ m_free(reqname);
+
+ TRACE(("leave recv_msg_global_request"));
+}
+
+
+static void send_msg_request_success() {
+
+ CHECKCLEARTOWRITE();
+ buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
+ encrypt_packet();
+
+}
+
+static void send_msg_request_failure() {
+
+ CHECKCLEARTOWRITE();
+ buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
+ encrypt_packet();
+
+}
+
+static int matchtcp(void* typedata1, void* typedata2) {
+
+ const struct TCPListener *info1 = (struct TCPListener*)typedata1;
+ const struct TCPListener *info2 = (struct TCPListener*)typedata2;
+
+ return (info1->port == info2->port)
+ && (info1->chantype == info2->chantype)
+ && (strcmp(info1->addr, info2->addr) == 0);
+}
+
+static int svr_cancelremotetcp() {
+
+ int ret = DROPBEAR_FAILURE;
+ unsigned char * bindaddr = NULL;
+ unsigned int addrlen;
+ unsigned int port;
+ struct Listener * listener = NULL;
+ struct TCPListener tcpinfo;
+
+ TRACE(("enter cancelremotetcp"));
+
+ bindaddr = buf_getstring(ses.payload, &addrlen);
+ if (addrlen > MAX_IP_LEN) {
+ TRACE(("addr len too long: %d", addrlen));
+ goto out;
+ }
+
+ port = buf_getint(ses.payload);
+
+ tcpinfo.addr = bindaddr;
+ tcpinfo.port = port;
+ listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
+ if (listener) {
+ remove_listener( listener );
+ ret = DROPBEAR_SUCCESS;
+ }
+
+out:
+ m_free(bindaddr);
+ TRACE(("leave cancelremotetcp"));
+ return ret;
+}
+
+static int svr_remotetcpreq() {
+
+ int ret = DROPBEAR_FAILURE;
+ unsigned char * bindaddr = NULL;
+ unsigned int addrlen;
+ struct TCPListener *tcpinfo = NULL;
+ unsigned int port;
+
+ TRACE(("enter remotetcpreq"));
+
+ bindaddr = buf_getstring(ses.payload, &addrlen);
+ if (addrlen > MAX_IP_LEN) {
+ TRACE(("addr len too long: %d", addrlen));
+ goto out;
+ }
+
+ port = buf_getint(ses.payload);
+
+ if (port == 0) {
+ dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported");
+ goto out;
+ }
+
+ if (port < 1 || port > 65535) {
+ TRACE(("invalid port: %d", port));
+ goto out;
+ }
+
+ if (!ses.allowprivport && port < IPPORT_RESERVED) {
+ TRACE(("can't assign port < 1024 for non-root"));
+ goto out;
+ }
+
+ tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
+ tcpinfo->addr = bindaddr;
+ tcpinfo->port = port;
+ tcpinfo->localport = -1;
+ tcpinfo->chantype = &svr_chan_tcpremote;
+
+ ret = listen_tcpfwd(tcpinfo);
+
+out:
+ if (ret == DROPBEAR_FAILURE) {
+ /* we only free it if a listener wasn't created, since the listener
+ * has to remember it if it's to be cancelled */
+ m_free(tcpinfo->addr);
+ m_free(tcpinfo);
+ }
+ TRACE(("leave remotetcpreq"));
+ return ret;
+}
+#endif
diff --git a/svr-x11fwd.c b/svr-x11fwd.c
index aa0ba2d..0f4f71e 100644
--- a/svr-x11fwd.c
+++ b/svr-x11fwd.c
@@ -37,7 +37,7 @@
#define X11BASEPORT 6000
#define X11BINDBASE 6010
-static void x11accept(struct Listener* listener);
+static void x11accept(struct Listener* listener, int sock);
static int bindport(int fd);
static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr);
@@ -82,7 +82,7 @@ int x11req(struct ChanSess * chansess) {
/* listener code will handle the socket now.
* No cleanup handler needed, since listener_remove only happens
* from our cleanup anyway */
- chansess->x11listener = new_listener( fd, 0, chansess, x11accept, NULL);
+ chansess->x11listener = new_listener( &fd, 1, 0, chansess, x11accept, NULL);
if (chansess->x11listener == NULL) {
goto fail;
}
@@ -100,7 +100,7 @@ fail:
/* accepts a new X11 socket */
/* returns DROPBEAR_FAILURE or DROPBEAR_SUCCESS */
-static void x11accept(struct Listener* listener) {
+static void x11accept(struct Listener* listener, int sock) {
int fd;
struct sockaddr_in addr;
@@ -110,7 +110,7 @@ static void x11accept(struct Listener* listener) {
len = sizeof(addr);
- fd = accept(listener->sock, (struct sockaddr*)&addr, &len);
+ fd = accept(sock, (struct sockaddr*)&addr, &len);
if (fd < 0) {
return;
}
diff --git a/tcp-accept.c b/tcp-accept.c
new file mode 100644
index 0000000..1fb80dd
--- /dev/null
+++ b/tcp-accept.c
@@ -0,0 +1,88 @@
+#include "includes.h"
+#include "ssh.h"
+#include "tcp-accept.h"
+#include "dbutil.h"
+#include "session.h"
+#include "buffer.h"
+#include "packet.h"
+#include "listener.h"
+#include "runopts.h"
+
+#ifndef DISABLE_TCP_ACCEPT
+
+static void accept_tcp(struct Listener *listener, int sock) {
+
+ int fd;
+ struct sockaddr_storage addr;
+ int len;
+ char ipstring[NI_MAXHOST], portstring[NI_MAXSERV];
+ struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);
+
+ len = sizeof(addr);
+
+ fd = accept(sock, (struct sockaddr*)&addr, &len);
+ if (fd < 0) {
+ return;
+ }
+
+ if (getnameinfo((struct sockaddr*)&addr, len, ipstring, sizeof(ipstring),
+ portstring, sizeof(portstring),
+ NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
+ return;
+ }
+
+ if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {
+
+ buf_putstring(ses.writepayload, tcpinfo->addr, strlen(tcpinfo->addr));
+ buf_putint(ses.writepayload, tcpinfo->port);
+ buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
+ buf_putint(ses.writepayload, atol(portstring));
+ encrypt_packet();
+
+ } else {
+ /* XXX debug? */
+ close(fd);
+ }
+}
+
+static void cleanup_tcp(struct Listener *listener) {
+
+ struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);
+
+ m_free(tcpinfo->addr);
+ m_free(tcpinfo);
+}
+
+
+int listen_tcpfwd(struct TCPListener* tcpinfo) {
+
+ char portstring[6]; /* "65535\0" */
+ int socks[DROPBEAR_MAX_SOCKS];
+ struct Listener *listener = NULL;
+ int nsocks;
+
+ 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->port);
+ nsocks = dropbear_listen(tcpinfo->addr, portstring, socks,
+ DROPBEAR_MAX_SOCKS, NULL, &ses.maxfd);
+ if (nsocks < 0) {
+ TRACE(("leave listen_tcpfwd: dropbear_listen failed"));
+ return DROPBEAR_FAILURE;
+ }
+
+ listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo,
+ accept_tcp, cleanup_tcp);
+
+ if (listener == NULL) {
+ m_free(tcpinfo);
+ TRACE(("leave listen_tcpfwd: listener failed"));
+ return DROPBEAR_FAILURE;
+ }
+
+ TRACE(("leave listen_tcpfwd: success"));
+ return DROPBEAR_SUCCESS;
+}
+
+#endif /* DISABLE_REMOTETCPFWD */
diff --git a/tcp-accept.h b/tcp-accept.h
new file mode 100644
index 0000000..96ddb76
--- /dev/null
+++ b/tcp-accept.h
@@ -0,0 +1,19 @@
+#ifndef _REMOTETCPFWD_H
+#define _REMOTETCPFWD_H
+
+struct TCPListener {
+
+ /* Local ones */
+ unsigned char *localaddr; /* Can be NULL */
+ unsigned int localport;
+ /* Remote ones: */
+ unsigned char *remoteaddr;
+ unsigned int remoteport;
+ 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
new file mode 100644
index 0000000..00dbd8a
--- /dev/null
+++ b/tcp-connect.c
@@ -0,0 +1,75 @@
+#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[6];
+ 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/tcpfwd-direct.h b/tcp-connect.h
index 20cd278..40ce22b 100644
--- a/tcpfwd-direct.h
+++ b/tcp-connect.h
@@ -28,7 +28,8 @@
#include "includes.h"
#include "channel.h"
-extern const struct ChanType chan_tcpdirect;
+extern const struct ChanType svr_chan_tcpdirect;
+int newtcpdirect(struct Channel * channel);
#endif
#endif
diff --git a/tcpfwd-direct.c b/tcpfwd-direct.c
deleted file mode 100644
index b611283..0000000
--- a/tcpfwd-direct.c
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "includes.h"
-#include "session.h"
-#include "dbutil.h"
-#include "channel.h"
-#include "tcpfwd-direct.h"
-#include "runopts.h"
-
-#ifndef DISABLE_TCPFWD_DIRECT
-static int newtcpdirect(struct Channel * channel);
-static int newtcp(const char * host, int port);
-
-const struct ChanType chan_tcpdirect = {
- 1, /* sepfds */
- "direct-tcpip",
- newtcpdirect, /* init */
- NULL, /* checkclose */
- NULL, /* reqhandler */
- NULL /* closehandler */
-};
-
-
-/* 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[6];
- 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;
-}
-
-/* Initiate a new TCP connection - this is non-blocking, so the socket
- * returned will need to be checked for success when it is first written.
- * Similarities with OpenSSH's connect_to() are not coincidental.
- * Returns -1 on failure */
-#if 0
-static int newtcp(const char * host, int port) {
-
- int sock = -1;
- char portstring[6];
- struct addrinfo *res = NULL, *ai;
- int val;
-
- struct addrinfo hints;
-
- TRACE(("enter newtcp"));
-
- memset(&hints, 0, sizeof(hints));
- /* TCP, either ip4 or ip6 */
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_family = PF_UNSPEC;
-
- snprintf(portstring, sizeof(portstring), "%d", port);
- if (getaddrinfo(host, portstring, &hints, &res) != 0) {
- if (res) {
- freeaddrinfo(res);
- }
- TRACE(("leave newtcp: failed getaddrinfo"));
- return -1;
- }
-
- /* Use the first socket that works */
- for (ai = res; ai != NULL; ai = ai->ai_next) {
-
- if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) {
- continue;
- }
-
- sock = socket(ai->ai_family, SOCK_STREAM, 0);
- if (sock < 0) {
- TRACE(("TCP socket() failed"));
- continue;
- }
-
- if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
- close(sock);
- TRACE(("TCP non-blocking failed"));
- continue;
- }
-
- /* non-blocking, so it might return without success (EINPROGRESS) */
- if (connect(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- if (errno == EINPROGRESS) {
- TRACE(("connect in progress"));
- } else {
- close(sock);
- TRACE(("TCP connect failed"));
- continue;
- }
- }
- break;
- }
-
- freeaddrinfo(res);
-
- if (ai == NULL) {
- return -1;
- }
-
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void*)&val, sizeof(val));
- return sock;
-}
-#endif
-#endif /* DISABLE_TCPFWD_DIRECT */
diff --git a/tcpfwd-remote.c b/tcpfwd-remote.c
deleted file mode 100644
index d0a67a1..0000000
--- a/tcpfwd-remote.c
+++ /dev/null
@@ -1,317 +0,0 @@
-#include "includes.h"
-#include "ssh.h"
-#include "tcpfwd-remote.h"
-#include "dbutil.h"
-#include "session.h"
-#include "buffer.h"
-#include "packet.h"
-#include "listener.h"
-#include "runopts.h"
-
-#ifndef DISABLE_REMOTETCPFWD
-
-struct RemoteTCP {
-
- unsigned char* addr;
- unsigned int port;
-
-};
-
-static void send_msg_request_success();
-static void send_msg_request_failure();
-static int cancelremotetcp();
-static int remotetcpreq();
-static int listen_tcpfwd(unsigned char* bindaddr, unsigned int port);
-static void acceptremote(struct Listener *listener);
-
-/* At the moment this is completely used for tcp code (with the name reflecting
- * that). If new request types are added, this should be replaced with code
- * similar to the request-switching in chansession.c */
-void recv_msg_global_request_remotetcp() {
-
- unsigned char* reqname = NULL;
- unsigned int namelen;
- unsigned int wantreply = 0;
- int ret = DROPBEAR_FAILURE;
-
- TRACE(("enter recv_msg_global_request_remotetcp"));
-
- if (opts.noremotetcp) {
- TRACE(("leave recv_msg_global_request_remotetcp: remote tcp forwarding disabled"));
- goto out;
- }
-
- reqname = buf_getstring(ses.payload, &namelen);
- wantreply = buf_getbyte(ses.payload);
-
- if (namelen > MAXNAMLEN) {
- TRACE(("name len is wrong: %d", namelen));
- goto out;
- }
-
- if (strcmp("tcpip-forward", reqname) == 0) {
- ret = remotetcpreq();
- } else if (strcmp("cancel-tcpip-forward", reqname) == 0) {
- ret = cancelremotetcp();
- } else {
- TRACE(("reqname isn't tcpip-forward: '%s'", reqname));
- }
-
-out:
- if (wantreply) {
- if (ret == DROPBEAR_SUCCESS) {
- send_msg_request_success();
- } else {
- send_msg_request_failure();
- }
- }
-
- m_free(reqname);
-
- TRACE(("leave recv_msg_global_request"));
-}
-
-static const struct ChanType chan_tcpremote = {
- 1, /* sepfds */
- "forwarded-tcpip",
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-
-static void acceptremote(struct Listener *listener) {
-
- int fd;
- struct sockaddr addr;
- int len;
- char ipstring[NI_MAXHOST], portstring[NI_MAXSERV];
- struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata);
-
- len = sizeof(addr);
-
- fd = accept(listener->sock, &addr, &len);
- if (fd < 0) {
- return;
- }
-
- if (getnameinfo(&addr, len, ipstring, sizeof(ipstring), portstring,
- sizeof(portstring), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
- return;
- }
-
- if (send_msg_channel_open_init(fd, &chan_tcpremote) == DROPBEAR_SUCCESS) {
-
- buf_putstring(ses.writepayload, tcpinfo->addr,
- strlen(tcpinfo->addr));
- buf_putint(ses.writepayload, tcpinfo->port);
- buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
- buf_putint(ses.writepayload, atol(portstring));
- encrypt_packet();
-
- } else {
- /* XXX debug? */
- close(fd);
- }
-}
-
-static void cleanupremote(struct Listener *listener) {
-
- struct RemoteTCP *tcpinfo = (struct RemoteTCP*)(listener->typedata);
-
- m_free(tcpinfo->addr);
- m_free(tcpinfo);
-}
-
-static void send_msg_request_success() {
-
- CHECKCLEARTOWRITE();
- buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_SUCCESS);
- encrypt_packet();
-
-}
-
-static void send_msg_request_failure() {
-
- CHECKCLEARTOWRITE();
- buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
- encrypt_packet();
-
-}
-
-static int matchtcp(void* typedata1, void* typedata2) {
-
- const struct RemoteTCP *info1 = (struct RemoteTCP*)typedata1;
- const struct RemoteTCP *info2 = (struct RemoteTCP*)typedata2;
-
- return info1->port == info2->port
- && (strcmp(info1->addr, info2->addr) == 0);
-}
-
-static int cancelremotetcp() {
-
- int ret = DROPBEAR_FAILURE;
- unsigned char * bindaddr = NULL;
- unsigned int addrlen;
- unsigned int port;
- struct Listener * listener = NULL;
- struct RemoteTCP tcpinfo;
-
- TRACE(("enter cancelremotetcp"));
-
- bindaddr = buf_getstring(ses.payload, &addrlen);
- if (addrlen > MAX_IP_LEN) {
- TRACE(("addr len too long: %d", addrlen));
- goto out;
- }
-
- port = buf_getint(ses.payload);
-
- tcpinfo.addr = bindaddr;
- tcpinfo.port = port;
- listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
- if (listener) {
- remove_listener( listener );
- ret = DROPBEAR_SUCCESS;
- }
-
-out:
- m_free(bindaddr);
- TRACE(("leave cancelremotetcp"));
- return ret;
-}
-
-static int remotetcpreq() {
-
- int ret = DROPBEAR_FAILURE;
- unsigned char * bindaddr = NULL;
- unsigned int addrlen;
- unsigned int port;
-
- TRACE(("enter remotetcpreq"));
-
- bindaddr = buf_getstring(ses.payload, &addrlen);
- if (addrlen > MAX_IP_LEN) {
- TRACE(("addr len too long: %d", addrlen));
- goto out;
- }
-
- port = buf_getint(ses.payload);
-
- if (port == 0) {
- dropbear_log(LOG_INFO, "Server chosen tcpfwd ports are unsupported");
- goto out;
- }
-
- if (port < 1 || port > 65535) {
- TRACE(("invalid port: %d", port));
- goto out;
- }
-
- if (!ses.allowprivport && port < IPPORT_RESERVED) {
- TRACE(("can't assign port < 1024 for non-root"));
- goto out;
- }
-
- ret = listen_tcpfwd(bindaddr, port);
-
-out:
- if (ret == DROPBEAR_FAILURE) {
- /* we only free it if a listener wasn't created, since the listener
- * has to remember it if it's to be cancelled */
- m_free(bindaddr);
- }
- TRACE(("leave remotetcpreq"));
- return ret;
-}
-
-static int listen_tcpfwd(unsigned char* bindaddr, unsigned int port) {
-
- struct RemoteTCP * tcpinfo = NULL;
- char portstring[6]; /* "65535\0" */
- struct addrinfo *res = NULL, *ai = NULL;
- struct addrinfo hints;
- int sock = -1;
- struct Listener *listener = NULL;
-
- 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", port);
- memset(&hints, 0x0, sizeof(hints));
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_family = PF_INET;
- hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
-
- if (getaddrinfo(bindaddr, portstring, &hints, &res) < 0) {
- TRACE(("leave listen_tcpfwd: getaddrinfo failed: %s",
- strerror(errno)));
- goto done;
- }
-
- /* find the first one which works */
- for (ai = res; ai != NULL; ai = ai->ai_next) {
- if (ai->ai_family != PF_INET && ai->ai_family != PF_INET6) {
- continue;
- }
-
- sock = socket(ai->ai_family, SOCK_STREAM, 0);
- if (sock < 0) {
- TRACE(("socket failed: %s", strerror(errno)));
- goto fail;
- }
-
- if (bind(sock, ai->ai_addr, ai->ai_addrlen) < 0) {
- TRACE(("bind failed: %s", strerror(errno)));
- goto fail;
- }
-
- if (listen(sock, 20) < 0) {
- TRACE(("listen failed: %s", strerror(errno)));
- goto fail;
- }
-
- if (fcntl(sock, F_SETFL, O_NONBLOCK) < 0) {
- TRACE(("fcntl nonblocking failed: %s", strerror(errno)));
- goto fail;
- }
-
- /* success */
- break;
-
-fail:
- close(sock);
- }
-
-
- if (ai == NULL) {
- TRACE(("no successful sockets"));
- goto done;
- }
-
- tcpinfo = (struct RemoteTCP*)m_malloc(sizeof(struct RemoteTCP));
- tcpinfo->addr = bindaddr;
- tcpinfo->port = port;
-
- listener = new_listener(sock, CHANNEL_ID_TCPFORWARDED, tcpinfo,
- acceptremote, cleanupremote);
-
- if (listener == NULL) {
- m_free(tcpinfo);
- }
-
-done:
- if (res) {
- freeaddrinfo(res);
- }
-
- TRACE(("leave listen_tcpfwd"));
- if (listener == NULL) {
- return DROPBEAR_FAILURE;
- } else {
- return DROPBEAR_SUCCESS;
- }
-}
-
-#endif /* DISABLE_REMOTETCPFWD */
diff --git a/tcpfwd-remote.h b/tcpfwd-remote.h
deleted file mode 100644
index 64dbed3..0000000
--- a/tcpfwd-remote.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef _REMOTETCPFWD_H
-#define _REMOTETCPFWD_H
-
-void recv_msg_global_request_remotetcp();
-
-#endif /* _REMOTETCPFWD_H */