mirror of
https://github.com/clearml/dropbear
synced 2025-01-31 02:46:58 +00:00
a9c38fb37f
--HG-- extra : convert_revision : 2903853ba24669d01547710986ad531357602633
160 lines
3.5 KiB
C
160 lines
3.5 KiB
C
#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 */
|