- A nice cleaner structure for tcp (acceptor) forwarding.

- still a checkpoint-ish commit
- sorted out listening on localhost only

--HG--
extra : convert_revision : c030ac0a3950dba81f2324e2ba9d4b77fc8f8149
This commit is contained in:
Matt Johnston 2004-08-11 17:26:47 +00:00
parent a712baa8e5
commit 453261a042
9 changed files with 77 additions and 49 deletions

View File

@ -12,22 +12,26 @@ static const struct ChanType cli_chan_tcplocal = {
NULL NULL
}; };
void setup_localtcp() {
qv
}
static int cli_localtcp(char* port) { static int cli_localtcp(unsigned int listenport, const char* remoteaddr,
unsigned int remoteport) {
struct TCPListener* tcpinfo = NULL; struct TCPListener* tcpinfo = NULL;
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*)); tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener*));
tcpinfo->addr = NULL; tcpinfo->sendaddr = remoteaddr;
tcpinfo->port = port; tcpinfo->sendport = remoteport;
tcpinfo->listenport = listenport;
tcpinfo->chantype = &cli_chan_tcplocal; tcpinfo->chantype = &cli_chan_tcplocal;
ret = listen_tcpfwd(tcpinfo); ret = listen_tcpfwd(tcpinfo);
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
DROPBEAR_LOG(LOG_WARNING, "Failed to listen on port %s", port);
m_free(tcpinfo); m_free(tcpinfo);
} }
return ret; return ret;

View File

@ -114,10 +114,8 @@ void dropbear_trace(const char* format, ...) {
#endif /* DEBUG_TRACE */ #endif /* DEBUG_TRACE */
/* Listen on address:port. Unless address is NULL, in which case listen on /* 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 * everything. If called with address == "", we'll listen on localhost/loopback.
* broken with respect to listening to v6 or v4, so the addresses you get when * Returns the number of sockets bound on success, or -1 on failure. On
* 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 * failure, if errstring wasn't NULL, it'll be a newly malloced error
* string.*/ * string.*/
int dropbear_listen(const char* address, const char* port, int dropbear_listen(const char* address, const char* port,
@ -135,7 +133,14 @@ int dropbear_listen(const char* address, const char* port,
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */ hints.ai_family = AF_UNSPEC; /* TODO: let them flag v4 only etc */
hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (address && address[0] == '\0') {
TRACE(("dropbear_listen: local loopback"));
address = NULL;
} else {
TRACE(("dropbear_listen: not local loopback"));
hints.ai_flags = AI_PASSIVE;
}
err = getaddrinfo(address, port, &hints, &res0); err = getaddrinfo(address, port, &hints, &res0);
if (err) { if (err) {

View File

@ -42,7 +42,7 @@ void handle_listeners(fd_set * readfds) {
for (j = 0; j < listener->nsocks; j++) { for (j = 0; j < listener->nsocks; j++) {
sock = listener->socks[j]; sock = listener->socks[j];
if (FD_ISSET(sock, readfds)) { if (FD_ISSET(sock, readfds)) {
listener->accepter(listener, sock); listener->acceptor(listener, sock);
} }
} }
} }
@ -50,11 +50,11 @@ void handle_listeners(fd_set * readfds) {
} }
/* accepter(int fd, void* typedata) is a function to accept connections, /* acceptor(int fd, void* typedata) is a function to accept connections,
* cleanup(void* typedata) happens when cleaning up */ * cleanup(void* typedata) happens when cleaning up */
struct Listener* new_listener(int socks[], unsigned int nsocks, struct Listener* new_listener(int socks[], unsigned int nsocks,
int type, void* typedata, int type, void* typedata,
void (*accepter)(struct Listener*, int sock), void (*acceptor)(struct Listener* listener, int sock),
void (*cleanup)(struct Listener*)) { void (*cleanup)(struct Listener*)) {
unsigned int i, j; unsigned int i, j;
@ -99,7 +99,7 @@ struct Listener* new_listener(int socks[], unsigned int nsocks,
newlisten->typedata = typedata; newlisten->typedata = typedata;
newlisten->nsocks = nsocks; newlisten->nsocks = nsocks;
memcpy(newlisten->socks, socks, nsocks * sizeof(int)); memcpy(newlisten->socks, socks, nsocks * sizeof(int));
newlisten->accepter = accepter; newlisten->acceptor = acceptor;
newlisten->cleanup = cleanup; newlisten->cleanup = cleanup;
ses.listeners[i] = newlisten; ses.listeners[i] = newlisten;

View File

@ -11,7 +11,7 @@ struct Listener {
int index; /* index in the array of listeners */ int index; /* index in the array of listeners */
void (*accepter)(struct Listener*, int sock); void (*acceptor)(struct Listener*, int sock);
void (*cleanup)(struct Listener*); void (*cleanup)(struct Listener*);
int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT, int type; /* CHANNEL_ID_X11, CHANNEL_ID_AGENT,
@ -28,7 +28,7 @@ void set_listener_fds(fd_set * readfds);
struct Listener* new_listener(int socks[], unsigned int nsocks, struct Listener* new_listener(int socks[], unsigned int nsocks,
int type, void* typedata, int type, void* typedata,
void (*accepter)(struct Listener*, int sock), void (*acceptor)(struct Listener* listener, int sock),
void (*cleanup)(struct Listener*)); void (*cleanup)(struct Listener*));
struct Listener * get_listener(int type, void* typedata, struct Listener * get_listener(int type, void* typedata,

View File

@ -188,7 +188,8 @@ int main(int argc, char ** argv)
/* child connection XXX - ip6 stuff here */ /* child connection XXX - ip6 stuff here */
remoteaddrlen = sizeof(remoteaddr); remoteaddrlen = sizeof(remoteaddr);
childsock = accept(listensocks[i], &remoteaddr, &remoteaddrlen); childsock = accept(listensocks[i],
(struct sockaddr*)&remoteaddr, &remoteaddrlen);
if (childsock < 0) { if (childsock < 0) {
/* accept failed */ /* accept failed */
@ -295,7 +296,7 @@ static void sigintterm_handler(int fish) {
static int listensockets(int *sock, int sockcount, int *maxfd) { static int listensockets(int *sock, int sockcount, int *maxfd) {
unsigned int i; unsigned int i;
char portstring[6]; char portstring[NI_MAXSERV];
char* errstring = NULL; char* errstring = NULL;
unsigned int sockpos = 0; unsigned int sockpos = 0;
int nsock; int nsock;

View File

@ -104,9 +104,9 @@ static int matchtcp(void* typedata1, void* typedata2) {
const struct TCPListener *info1 = (struct TCPListener*)typedata1; const struct TCPListener *info1 = (struct TCPListener*)typedata1;
const struct TCPListener *info2 = (struct TCPListener*)typedata2; const struct TCPListener *info2 = (struct TCPListener*)typedata2;
return (info1->port == info2->port) return (info1->sendport == info2->sendport)
&& (info1->chantype == info2->chantype) && (info1->chantype == info2->chantype)
&& (strcmp(info1->addr, info2->addr) == 0); && (strcmp(info1->sendaddr, info2->sendaddr) == 0);
} }
static int svr_cancelremotetcp() { static int svr_cancelremotetcp() {
@ -128,8 +128,8 @@ static int svr_cancelremotetcp() {
port = buf_getint(ses.payload); port = buf_getint(ses.payload);
tcpinfo.addr = bindaddr; tcpinfo.sendaddr = bindaddr;
tcpinfo.port = port; tcpinfo.sendport = port;
listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp); listener = get_listener(CHANNEL_ID_TCPFORWARDED, &tcpinfo, matchtcp);
if (listener) { if (listener) {
remove_listener( listener ); remove_listener( listener );
@ -152,6 +152,7 @@ static int svr_remotetcpreq() {
TRACE(("enter remotetcpreq")); TRACE(("enter remotetcpreq"));
/* NOTE: at this stage, we ignore bindaddr. see below and listen_tcpfwd */
bindaddr = buf_getstring(ses.payload, &addrlen); bindaddr = buf_getstring(ses.payload, &addrlen);
if (addrlen > MAX_IP_LEN) { if (addrlen > MAX_IP_LEN) {
TRACE(("addr len too long: %d", addrlen)); TRACE(("addr len too long: %d", addrlen));
@ -176,18 +177,20 @@ static int svr_remotetcpreq() {
} }
tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener)); tcpinfo = (struct TCPListener*)m_malloc(sizeof(struct TCPListener));
tcpinfo->addr = bindaddr; tcpinfo->sendaddr = bindaddr;
tcpinfo->port = port; TRACE(("sendport = %d", port));
tcpinfo->localport = -1; tcpinfo->sendport = port;
tcpinfo->chantype = &svr_chan_tcpremote; tcpinfo->chantype = &svr_chan_tcpremote;
/* Note: bindaddr is actually ignored by listen_tcpfwd, since
* we only want to bind to localhost */
ret = listen_tcpfwd(tcpinfo); ret = listen_tcpfwd(tcpinfo);
out: out:
if (ret == DROPBEAR_FAILURE) { if (ret == DROPBEAR_FAILURE) {
/* we only free it if a listener wasn't created, since the listener /* we only free it if a listener wasn't created, since the listener
* has to remember it if it's to be cancelled */ * has to remember it if it's to be cancelled */
m_free(tcpinfo->addr); m_free(tcpinfo->sendaddr);
m_free(tcpinfo); m_free(tcpinfo);
} }
TRACE(("leave remotetcpreq")); TRACE(("leave remotetcpreq"));

View File

@ -10,7 +10,16 @@
#ifndef DISABLE_TCP_ACCEPT #ifndef DISABLE_TCP_ACCEPT
static void accept_tcp(struct Listener *listener, int sock) {
static void cleanup_tcp(struct Listener *listener) {
struct TCPListener *tcpinfo = (struct TCPListener*)(listener->typedata);
m_free(tcpinfo->sendaddr);
m_free(tcpinfo);
}
static void tcp_acceptor(struct Listener *listener, int sock) {
int fd; int fd;
struct sockaddr_storage addr; struct sockaddr_storage addr;
@ -33,10 +42,12 @@ static void accept_tcp(struct Listener *listener, int sock) {
if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) { if (send_msg_channel_open_init(fd, tcpinfo->chantype) == DROPBEAR_SUCCESS) {
buf_putstring(ses.writepayload, tcpinfo->addr, strlen(tcpinfo->addr)); buf_putstring(ses.writepayload, tcpinfo->sendaddr,
buf_putint(ses.writepayload, tcpinfo->port); strlen(tcpinfo->sendaddr));
buf_putint(ses.writepayload, tcpinfo->sendport);
buf_putstring(ses.writepayload, ipstring, strlen(ipstring)); buf_putstring(ses.writepayload, ipstring, strlen(ipstring));
buf_putint(ses.writepayload, atol(portstring)); buf_putint(ses.writepayload, atol(portstring));
encrypt_packet(); encrypt_packet();
} else { } else {
@ -45,35 +56,33 @@ static void accept_tcp(struct Listener *listener, int sock) {
} }
} }
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) { int listen_tcpfwd(struct TCPListener* tcpinfo) {
char portstring[6]; /* "65535\0" */ char portstring[NI_MAXSERV];
int socks[DROPBEAR_MAX_SOCKS]; int socks[DROPBEAR_MAX_SOCKS];
struct Listener *listener = NULL; struct Listener *listener = NULL;
int nsocks; int nsocks;
char* errstring = NULL;
TRACE(("enter listen_tcpfwd")); TRACE(("enter listen_tcpfwd"));
/* first we try to bind, so don't need to do so much cleanup on failure */ /* first we try to bind, so don't need to do so much cleanup on failure */
snprintf(portstring, sizeof(portstring), "%d", tcpinfo->port); snprintf(portstring, sizeof(portstring), "%d", tcpinfo->sendport);
nsocks = dropbear_listen(tcpinfo->addr, portstring, socks,
DROPBEAR_MAX_SOCKS, NULL, &ses.maxfd); /* XXX Note: we're just listening on localhost, no matter what they tell
* us. If someone wants to make it listen otherways, then change
* the "" argument. but that requires UI changes too */
nsocks = dropbear_listen("", portstring, socks,
DROPBEAR_MAX_SOCKS, &errstring, &ses.maxfd);
if (nsocks < 0) { if (nsocks < 0) {
dropbear_log(LOG_INFO, "TCP forward failed: %s", errstring);
m_free(errstring);
TRACE(("leave listen_tcpfwd: dropbear_listen failed")); TRACE(("leave listen_tcpfwd: dropbear_listen failed"));
return DROPBEAR_FAILURE; return DROPBEAR_FAILURE;
} }
listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo, listener = new_listener(socks, nsocks, CHANNEL_ID_TCPFORWARDED, tcpinfo,
accept_tcp, cleanup_tcp); tcp_acceptor, cleanup_tcp);
if (listener == NULL) { if (listener == NULL) {
m_free(tcpinfo); m_free(tcpinfo);

View File

@ -3,12 +3,18 @@
struct TCPListener { struct TCPListener {
/* Local ones */ /* sendaddr/sendport are what we send in the channel init request. For a
unsigned char *localaddr; /* Can be NULL */ * forwarded-tcpip request, it's the addr/port we were binding to.
unsigned int localport; * For a direct-tcpip request, it's the addr/port we want the other
/* Remote ones: */ * end to connect to */
unsigned char *remoteaddr;
unsigned int remoteport; 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; const struct ChanType *chantype;
}; };

View File

@ -15,7 +15,7 @@ int newtcpdirect(struct Channel * channel) {
unsigned int destport; unsigned int destport;
unsigned char* orighost = NULL; unsigned char* orighost = NULL;
unsigned int origport; unsigned int origport;
char portstring[6]; char portstring[NI_MAXSERV];
int sock; int sock;
int len; int len;
int ret = DROPBEAR_FAILURE; int ret = DROPBEAR_FAILURE;