From 4aafeb0da2462faa3e4b191cd56ed6bba362e0fa Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 7 Jun 2006 14:10:21 +0000 Subject: Add -P pidfile patch from Swen Schillig --HG-- extra : convert_revision : 2dd1bf9162d8fc4c14b33c5b3c6ca3cbe2ecd587 --- runopts.h | 1 + 1 file changed, 1 insertion(+) (limited to 'runopts.h') diff --git a/runopts.h b/runopts.h index 5107a9d..1e102e6 100644 --- a/runopts.h +++ b/runopts.h @@ -83,6 +83,7 @@ typedef struct svr_runopts { sign_key *hostkey; buffer * banner; + char * pidfile; } svr_runopts; -- cgit v1.2.3 From be2b7d9725f8adef1b75bddc9944f69b87219120 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 7 Jun 2006 15:01:20 +0000 Subject: Add -N "no remote command" dbclient option. Document -N in dbclient.1 and -P in dropbear.8 --HG-- extra : convert_revision : 7cada79bf8f61e09a72e5d492170bd10ab0acee3 --- cli-runopts.c | 5 +++++ cli-session.c | 8 +++++--- dbclient.1 | 3 +++ dropbear.8 | 4 ++++ dropbearkey.c | 3 +-- runopts.h | 1 + 6 files changed, 19 insertions(+), 5 deletions(-) (limited to 'runopts.h') diff --git a/cli-runopts.c b/cli-runopts.c index 54d4875..2e7c0ac 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -50,6 +50,7 @@ static void printhelp() { "-l \n" "-t Allocate a pty\n" "-T Don't allocate a pty\n" + "-N Don't run a remote command\n" #ifdef ENABLE_CLI_PUBKEY_AUTH "-i (multiple allowed)\n" #endif @@ -88,6 +89,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.remoteport = NULL; cli_opts.username = NULL; cli_opts.cmd = NULL; + cli_opts.no_cmd = 0; cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ #ifdef ENABLE_CLI_PUBKEY_AUTH cli_opts.privkeys = NULL; @@ -163,6 +165,9 @@ void cli_getopts(int argc, char ** argv) { case 'T': /* don't want a pty */ cli_opts.wantpty = 0; break; + case 'N': + cli_opts.no_cmd = 1; + break; #ifdef ENABLE_CLI_LOCALTCPFWD case 'L': nextislocal = 1; diff --git a/cli-session.c b/cli-session.c index 35510fa..c47bd3b 100644 --- a/cli-session.c +++ b/cli-session.c @@ -218,13 +218,15 @@ static void cli_sessionloop() { #ifdef ENABLE_CLI_REMOTETCPFWD setup_remotetcp(); #endif - cli_send_chansess_request(); - TRACE(("leave cli_sessionloop: cli_send_chansess_request")) + if (!cli_opts.no_cmd) { + cli_send_chansess_request(); + } + TRACE(("leave cli_sessionloop: running")) cli_ses.state = SESSION_RUNNING; return; case SESSION_RUNNING: - if (ses.chancount < 1) { + if (ses.chancount < 1 && !cli_opts.no_cmd) { cli_finished(); } diff --git a/dbclient.1 b/dbclient.1 index 4d7cc3c..27e2d20 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -60,6 +60,9 @@ Allocate a pty. .B \-T Don't allocate a pty. .TP +.B \-N +Don't request a remote shell or run any commands. Any command arguments are ignored. +.TP .B \-g Allow non-local hosts to connect to forwarded ports. Applies to -L and -R forwarded ports, though remote connections to -R forwarded ports may be limited diff --git a/dropbear.8 b/dropbear.8 index 38cf7e2..fbbb26b 100644 --- a/dropbear.8 +++ b/dropbear.8 @@ -72,6 +72,10 @@ Use this option to run under TCP/IP servers like inetd, tcpsvd, or tcpserver. In program mode the \-F option is implied, and \-p options are ignored. .TP +.B \-P \fIpidfile +Specify a pidfile to create when running as a daemon. If not specified, the +default is /var/run/dropbear.pid +.TP .B \-a Allow remote hosts to connect to forwarded ports. .SH AUTHOR diff --git a/dropbearkey.c b/dropbearkey.c index 0825053..280e1b3 100644 --- a/dropbearkey.c +++ b/dropbearkey.c @@ -321,8 +321,7 @@ static void printpubkey(sign_key * key, int keytype) { /* a user@host comment is informative */ username = ""; pw = getpwuid(getuid()); - if (pw) - { + if (pw) { username = pw->pw_name; } diff --git a/runopts.h b/runopts.h index 1e102e6..cb5e4ca 100644 --- a/runopts.h +++ b/runopts.h @@ -102,6 +102,7 @@ typedef struct cli_runopts { char *cmd; int wantpty; + int no_cmd; #ifdef ENABLE_CLI_PUBKEY_AUTH struct SignKeyList *privkeys; /* Keys to use for public-key auth */ #endif -- cgit v1.2.3 From c81e058bb05b274b9a88e684ffd95a03a0ac4377 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 7 Jun 2006 15:47:04 +0000 Subject: add -f background option to dbclient --HG-- extra : convert_revision : 5ef61c30c0a634ac0da22a8c694ce235690e8170 --- cli-runopts.c | 10 ++++++++++ cli-session.c | 17 +++++++++++++++++ dbclient.1 | 4 ++++ runopts.h | 1 + 4 files changed, 32 insertions(+) (limited to 'runopts.h') diff --git a/cli-runopts.c b/cli-runopts.c index 2e7c0ac..a4a8a58 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -51,6 +51,7 @@ static void printhelp() { "-t Allocate a pty\n" "-T Don't allocate a pty\n" "-N Don't run a remote command\n" + "-f Run in background after auth\n" #ifdef ENABLE_CLI_PUBKEY_AUTH "-i (multiple allowed)\n" #endif @@ -90,6 +91,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.username = NULL; cli_opts.cmd = NULL; cli_opts.no_cmd = 0; + cli_opts.backgrounded = 0; cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ #ifdef ENABLE_CLI_PUBKEY_AUTH cli_opts.privkeys = NULL; @@ -168,6 +170,9 @@ void cli_getopts(int argc, char ** argv) { case 'N': cli_opts.no_cmd = 1; break; + case 'f': + cli_opts.backgrounded = 1; + break; #ifdef ENABLE_CLI_LOCALTCPFWD case 'L': nextislocal = 1; @@ -274,6 +279,11 @@ void cli_getopts(int argc, char ** argv) { cli_opts.wantpty = 0; } } + + if (cli_opts.backgrounded && cli_opts.cmd == NULL + && cli_opts.no_cmd == 0) { + dropbear_exit("command required for -f"); + } } #ifdef ENABLE_CLI_PUBKEY_AUTH diff --git a/cli-session.c b/cli-session.c index c47bd3b..be36bec 100644 --- a/cli-session.c +++ b/cli-session.c @@ -212,6 +212,23 @@ static void cli_sessionloop() { */ case USERAUTH_SUCCESS_RCVD: + + if (cli_opts.backgrounded) { + int devnull; + // keeping stdin open steals input from the terminal and + // is confusing, though stdout/stderr could be useful. + devnull = open(_PATH_DEVNULL, O_RDONLY); + if (devnull < 0) { + dropbear_exit("opening /dev/null: %d %s", + errno, strerror(errno)); + } + dup2(devnull, STDIN_FILENO); + if (daemon(0, 1) < 0) { + dropbear_exit("Backgrounding failed: %d %s", + errno, strerror(errno)); + } + } + #ifdef ENABLE_CLI_LOCALTCPFWD setup_localtcp(); #endif diff --git a/dbclient.1 b/dbclient.1 index 27e2d20..acff59d 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -63,6 +63,10 @@ Don't allocate a pty. .B \-N Don't request a remote shell or run any commands. Any command arguments are ignored. .TP +.B \-f +Fork into the background after authentication. A command argument (or -N) is required. +This is useful when using password authentication. +.TP .B \-g Allow non-local hosts to connect to forwarded ports. Applies to -L and -R forwarded ports, though remote connections to -R forwarded ports may be limited diff --git a/runopts.h b/runopts.h index cb5e4ca..c3db42c 100644 --- a/runopts.h +++ b/runopts.h @@ -103,6 +103,7 @@ typedef struct cli_runopts { char *cmd; int wantpty; int no_cmd; + int backgrounded; #ifdef ENABLE_CLI_PUBKEY_AUTH struct SignKeyList *privkeys; /* Keys to use for public-key auth */ #endif -- cgit v1.2.3 From cd0a08896c83ab20f7cc04e755ce38b1525d47a3 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 11 Feb 2007 08:50:21 +0000 Subject: Add '-y' option to dbclient to accept the host key without checking - patch from Luciano Miguel Ferreira Rocha. --HG-- extra : convert_revision : 924b731b50d4147eed8e9382c98a2573259a6cad --- cli-kex.c | 45 +++++++++++++++++++++++++++------------------ cli-runopts.c | 5 +++++ runopts.h | 1 + 3 files changed, 33 insertions(+), 18 deletions(-) (limited to 'runopts.h') diff --git a/cli-kex.c b/cli-kex.c index 467ae23..d8e15b6 100644 --- a/cli-kex.c +++ b/cli-kex.c @@ -119,6 +119,13 @@ static void ask_to_confirm(unsigned char* keyblob, unsigned int keybloblen) { char response = 'z'; fp = sign_key_fingerprint(keyblob, keybloblen); + if (cli_opts.always_accept_key) { + fprintf(stderr, "\nHost '%s' key accepted unconditionally.\n(fingerprint %s)\n", + cli_opts.remotehost, + fp); + m_free(fp); + return; + } fprintf(stderr, "\nHost '%s' is not in the trusted hosts file.\n(fingerprint %s)\nDo you want to continue connecting? (y/n)\n", cli_opts.remotehost, fp); @@ -268,24 +275,26 @@ static void checkhostkey(unsigned char* keyblob, unsigned int keybloblen) { goto out; } - /* put the new entry in the file */ - fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */ - buf_setpos(line, 0); - buf_setlen(line, 0); - buf_putbytes(line, ses.remotehost, hostlen); - buf_putbyte(line, ' '); - buf_putbytes(line, algoname, algolen); - buf_putbyte(line, ' '); - len = line->size - line->pos; - TRACE(("keybloblen %d, len %d", keybloblen, len)) - /* The only failure with base64 is buffer_overflow, but buf_getwriteptr - * will die horribly in the case anyway */ - base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len); - buf_incrwritepos(line, len); - buf_putbyte(line, '\n'); - buf_setpos(line, 0); - fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile); - /* We ignore errors, since there's not much we can do about them */ + if (!cli_opts.always_accept_key) { + /* put the new entry in the file */ + fseek(hostsfile, 0, SEEK_END); /* In case it wasn't opened append */ + buf_setpos(line, 0); + buf_setlen(line, 0); + buf_putbytes(line, ses.remotehost, hostlen); + buf_putbyte(line, ' '); + buf_putbytes(line, algoname, algolen); + buf_putbyte(line, ' '); + len = line->size - line->pos; + TRACE(("keybloblen %d, len %d", keybloblen, len)) + /* The only failure with base64 is buffer_overflow, but buf_getwriteptr + * will die horribly in the case anyway */ + base64_encode(keyblob, keybloblen, buf_getwriteptr(line, len), &len); + buf_incrwritepos(line, len); + buf_putbyte(line, '\n'); + buf_setpos(line, 0); + fwrite(buf_getptr(line, line->len), line->len, 1, hostsfile); + /* We ignore errors, since there's not much we can do about them */ + } out: if (hostsfile != NULL) { diff --git a/cli-runopts.c b/cli-runopts.c index 1a077b9..fc67850 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -52,6 +52,7 @@ static void printhelp() { "-T Don't allocate a pty\n" "-N Don't run a remote command\n" "-f Run in background after auth\n" + "-y Always accept remote host key if unknown\n" #ifdef ENABLE_CLI_PUBKEY_AUTH "-i (multiple allowed)\n" #endif @@ -93,6 +94,7 @@ void cli_getopts(int argc, char ** argv) { cli_opts.no_cmd = 0; cli_opts.backgrounded = 0; cli_opts.wantpty = 9; /* 9 means "it hasn't been touched", gets set later */ + cli_opts.always_accept_key = 0; #ifdef ENABLE_CLI_PUBKEY_AUTH cli_opts.privkeys = NULL; #endif @@ -148,6 +150,9 @@ void cli_getopts(int argc, char ** argv) { /* A flag *waves* */ switch (argv[i][1]) { + case 'y': /* always accept the remote hostkey */ + cli_opts.always_accept_key = 1; + break; case 'p': /* remoteport */ next = &cli_opts.remoteport; break; diff --git a/runopts.h b/runopts.h index c3db42c..459edfe 100644 --- a/runopts.h +++ b/runopts.h @@ -102,6 +102,7 @@ typedef struct cli_runopts { char *cmd; int wantpty; + int always_accept_key; int no_cmd; int backgrounded; #ifdef ENABLE_CLI_PUBKEY_AUTH -- cgit v1.2.3 From 66643fa5c723da2dc781c5eeae2e008c280a7b1c Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 22 Feb 2007 14:52:46 +0000 Subject: Add -p [address:]port option for binding to addresses, patch from Max-Gerd Retzlaff --HG-- extra : convert_revision : a9b0496634cdd25647b65e585cc3240f3fa699ee --- options.h | 5 +++++ runopts.h | 1 + svr-main.c | 4 ++-- svr-runopts.c | 69 ++++++++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 60 insertions(+), 19 deletions(-) (limited to 'runopts.h') diff --git a/options.h b/options.h index 0349fa9..94d0cb1 100644 --- a/options.h +++ b/options.h @@ -14,6 +14,11 @@ #define DROPBEAR_DEFPORT "22" #endif +#ifndef DROPBEAR_DEFADDRESS +/* Listen on all interfaces */ +#define DROPBEAR_DEFADDRESS "" +#endif + /* Default hostkey paths - these can be specified on the command line */ #ifndef DSS_PRIV_FILENAME #define DSS_PRIV_FILENAME "/etc/dropbear/dropbear_dss_host_key" diff --git a/runopts.h b/runopts.h index 5107a9d..05e6cf4 100644 --- a/runopts.h +++ b/runopts.h @@ -55,6 +55,7 @@ typedef struct svr_runopts { /* ports is an array of the portcount listening ports */ char *ports[DROPBEAR_MAX_PORTS]; unsigned int portcount; + char *addresses[DROPBEAR_MAX_PORTS]; int inetdmode; diff --git a/svr-main.c b/svr-main.c index e06eb5e..13a4ebf 100644 --- a/svr-main.c +++ b/svr-main.c @@ -397,9 +397,9 @@ static size_t listensockets(int *sock, size_t sockcount, int *maxfd) { for (i = 0; i < svr_opts.portcount; i++) { - TRACE(("listening on '%s'", svr_opts.ports[i])) + TRACE(("listening on '%s:%s'", svr_opts.addresses[i], svr_opts.ports[i])) - nsock = dropbear_listen("", svr_opts.ports[i], &sock[sockpos], + nsock = dropbear_listen(svr_opts.addresses[i], svr_opts.ports[i], &sock[sockpos], sockcount - sockpos, &errstring, maxfd); diff --git a/svr-runopts.c b/svr-runopts.c index 8d8b8df..d300834 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -32,6 +32,7 @@ svr_runopts svr_opts; /* GLOBAL */ static void printhelp(const char * progname); +static void addportandaddress(char* spec); static void printhelp(const char * progname) { @@ -70,8 +71,10 @@ static void printhelp(const char * progname) { "-k Disable remote port forwarding\n" "-a Allow connections to forwarded ports from any host\n" #endif - "-p port Listen on specified tcp port, up to %d can be specified\n" - " (default %s if none specified)\n" + "-p [address:]port\n" + " Listen on specified tcp port (and optionally address),\n" + " up to %d can be specified\n" + " (default port is %s if none specified)\n" #ifdef INETD_MODE "-i Start for inetd\n" #endif @@ -92,6 +95,7 @@ void svr_getopts(int argc, char ** argv) { unsigned int i; char ** next = 0; + int nextisport = 0; /* see printhelp() for options */ svr_opts.rsakeyfile = NULL; @@ -126,6 +130,12 @@ void svr_getopts(int argc, char ** argv) { #endif for (i = 1; i < (unsigned int)argc; i++) { + if (nextisport) { + addportandaddress(argv[i]); + nextisport = 0; + continue; + } + if (next) { *next = argv[i]; if (*next == NULL) { @@ -177,14 +187,8 @@ void svr_getopts(int argc, char ** argv) { break; #endif case 'p': - if (svr_opts.portcount < DROPBEAR_MAX_PORTS) { - svr_opts.ports[svr_opts.portcount] = NULL; - next = &svr_opts.ports[svr_opts.portcount]; - /* Note: if it doesn't actually get set, we'll - * decrement it after the loop */ - svr_opts.portcount++; - } - break; + nextisport = 1; + break; #ifdef DO_MOTD /* motd is displayed by default, -m turns it off */ case 'm': @@ -223,15 +227,10 @@ void svr_getopts(int argc, char ** argv) { /* Set up listening ports */ if (svr_opts.portcount == 0) { svr_opts.ports[0] = m_strdup(DROPBEAR_DEFPORT); + svr_opts.addresses[0] = m_strdup(DROPBEAR_DEFADDRESS); svr_opts.portcount = 1; - } else { - /* we may have been given a -p option but no argument to go with - * it */ - if (svr_opts.ports[svr_opts.portcount-1] == NULL) { - svr_opts.portcount--; - } } - + if (svr_opts.dsskeyfile == NULL) { svr_opts.dsskeyfile = DSS_PRIV_FILENAME; } @@ -261,6 +260,42 @@ void svr_getopts(int argc, char ** argv) { } +static void addportandaddress(char* spec) { + + char *myspec = NULL; + + if (svr_opts.portcount < DROPBEAR_MAX_PORTS) { + + /* We don't free it, it becomes part of the runopt state */ + myspec = m_strdup(spec); + + /* search for ':', that separates address and port */ + svr_opts.ports[svr_opts.portcount] = strchr(myspec, ':'); + + if (svr_opts.ports[svr_opts.portcount] == NULL) { + /* no ':' -> the whole string specifies just a port */ + svr_opts.ports[svr_opts.portcount] = myspec; + } else { + /* Split the address/port */ + svr_opts.ports[svr_opts.portcount][0] = '\0'; + svr_opts.ports[svr_opts.portcount]++; + svr_opts.addresses[svr_opts.portcount] = myspec; + } + + if (svr_opts.addresses[svr_opts.portcount] == NULL) { + /* no address given -> fill in the default address */ + svr_opts.addresses[svr_opts.portcount] = m_strdup(DROPBEAR_DEFADDRESS); + } + + if (svr_opts.ports[svr_opts.portcount][0] == '\0') { + /* empty port -> exit */ + dropbear_exit("Bad port"); + } + + svr_opts.portcount++; + } +} + static void disablekey(int type, const char* filename) { int i; -- cgit v1.2.3 From e3e4445dc1e86652d1e855bd320f8077523d2d59 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 25 Jul 2007 15:44:25 +0000 Subject: Add -W argument and document it. --HG-- extra : convert_revision : 98d4c0f15480bf749c451034cbc565d7e9d3b8dc --- cli-chansession.c | 2 +- cli-runopts.c | 17 ++++++++++++++++- common-channel.c | 11 ++++++----- dbclient.1 | 5 +++++ dropbear.8 | 5 +++++ options.h | 8 +++++--- runopts.h | 1 + svr-runopts.c | 19 +++++++++++++++++-- 8 files changed, 56 insertions(+), 12 deletions(-) (limited to 'runopts.h') diff --git a/cli-chansession.c b/cli-chansession.c index e4ec45c..c92f902 100644 --- a/cli-chansession.c +++ b/cli-chansession.c @@ -350,7 +350,7 @@ static int cli_initchansess(struct Channel *channel) { channel->errfd = STDERR_FILENO; setnonblocking(STDERR_FILENO); - channel->extrabuf = cbuf_new(RECV_MAX_WINDOW); + channel->extrabuf = cbuf_new(opts.recv_window); if (cli_opts.wantpty) { send_chansess_pty_req(channel); diff --git a/cli-runopts.c b/cli-runopts.c index 3e9b5ab..f38ccd2 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -63,10 +63,11 @@ static void printhelp() { #ifdef ENABLE_CLI_REMOTETCPFWD "-R Remote port forwarding\n" #endif + "-W (default %d, larger may be faster)\n" #ifdef DEBUG_TRACE "-v verbose\n" #endif - ,DROPBEAR_VERSION, cli_opts.progname); + ,DROPBEAR_VERSION, cli_opts.progname, DEFAULT_RECV_WINDOW); } void cli_getopts(int argc, char ** argv) { @@ -109,6 +110,8 @@ void cli_getopts(int argc, char ** argv) { opts.ipv4 = 1; opts.ipv6 = 1; */ + opts.recv_window = DEFAULT_RECV_WINDOW; + char* recv_window_arg = NULL; /* Iterate all the arguments */ for (i = 1; i < (unsigned int)argc; i++) { @@ -201,6 +204,9 @@ void cli_getopts(int argc, char ** argv) { case 'u': /* backwards compatibility with old urandom option */ break; + case 'W': + next = &recv_window_arg; + break; #ifdef DEBUG_TRACE case 'v': debug_trace = 1; @@ -292,6 +298,15 @@ void cli_getopts(int argc, char ** argv) { && cli_opts.no_cmd == 0) { dropbear_exit("command required for -f"); } + + if (recv_window_arg) + { + opts.recv_window = atol(recv_window_arg); + if (opts.recv_window == 0) + { + dropbear_exit("Bad recv window '%s'", recv_window_arg); + } + } } #ifdef ENABLE_CLI_PUBKEY_AUTH diff --git a/common-channel.c b/common-channel.c index ed6e5a2..97fd4a8 100644 --- a/common-channel.c +++ b/common-channel.c @@ -34,6 +34,7 @@ #include "channel.h" #include "ssh.h" #include "listener.h" +#include "runopts.h" static void send_msg_channel_open_failure(unsigned int remotechan, int reason, const unsigned char *text, const unsigned char *lang); @@ -150,9 +151,9 @@ struct Channel* newchannel(unsigned int remotechan, newchan->await_open = 0; newchan->flushing = 0; - newchan->writebuf = cbuf_new(RECV_MAX_WINDOW); + newchan->writebuf = cbuf_new(opts.recv_window); newchan->extrabuf = NULL; /* The user code can set it up */ - newchan->recvwindow = RECV_MAX_WINDOW; + newchan->recvwindow = opts.recv_window; newchan->recvdonelen = 0; newchan->recvmaxpacket = RECV_MAX_PAYLOAD_LEN; @@ -421,7 +422,7 @@ static void writechannel(struct Channel* channel, int fd, circbuffer *cbuf) { channel->recvdonelen = 0; } - dropbear_assert(channel->recvwindow <= RECV_MAX_WINDOW); + dropbear_assert(channel->recvwindow <= opts.recv_window); dropbear_assert(channel->recvwindow <= cbuf_getavail(channel->writebuf)); dropbear_assert(channel->extrabuf == NULL || channel->recvwindow <= cbuf_getavail(channel->extrabuf)); @@ -710,7 +711,7 @@ void common_recv_msg_channel_data(struct Channel *channel, int fd, dropbear_assert(channel->recvwindow >= datalen); channel->recvwindow -= datalen; - dropbear_assert(channel->recvwindow <= RECV_MAX_WINDOW); + dropbear_assert(channel->recvwindow <= opts.recv_window); TRACE(("leave recv_msg_channel_data")) } @@ -970,7 +971,7 @@ int send_msg_channel_open_init(int fd, const struct ChanType *type) { buf_putbyte(ses.writepayload, SSH_MSG_CHANNEL_OPEN); buf_putstring(ses.writepayload, type->name, strlen(type->name)); buf_putint(ses.writepayload, chan->index); - buf_putint(ses.writepayload, RECV_MAX_WINDOW); + buf_putint(ses.writepayload, opts.recv_window); buf_putint(ses.writepayload, RECV_MAX_PAYLOAD_LEN); TRACE(("leave send_msg_channel_open_init()")) diff --git a/dbclient.1 b/dbclient.1 index 4145342..3e67c08 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -74,6 +74,11 @@ by the ssh server. .B \-y Always accept hostkeys if they are unknown. If a hostkey mismatch occurs the connection will abort as normal. +.TP +.B \-W \fIwindowsize +Specify the per-channel receive window buffer size. Increasing this +may improve network performance at the expense of memory use. Use -h to see the +default buffer size. .SH AUTHOR Matt Johnston (matt@ucc.asn.au). .br diff --git a/dropbear.8 b/dropbear.8 index ef0caf3..70dfb3e 100644 --- a/dropbear.8 +++ b/dropbear.8 @@ -82,6 +82,11 @@ default is /var/run/dropbear.pid .TP .B \-a Allow remote hosts to connect to forwarded ports. +.TP +.B \-W \fIwindowsize +Specify the per-channel receive window buffer size. Increasing this +may improve network performance at the expense of memory use. Use -h to see the +default buffer size. .SH AUTHOR Matt Johnston (matt@ucc.asn.au). .br diff --git a/options.h b/options.h index 15d4522..939206a 100644 --- a/options.h +++ b/options.h @@ -220,8 +220,10 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ usage and network performance: */ /* Size of the network receive window. This amount of memory is allocated as a per-channel receive buffer. Increasing this value can make a - significant difference to network performance. */ -#define RECV_MAX_WINDOW 8192 + significant difference to network performance. 24kB was empirically + chosen for a 100mbit ethernet network. The value can be altered at + runtime with the -W argument. */ +#define DEFAULT_RECV_WINDOW 24576 /* Maximum size of a received SSH data packet - this _MUST_ be >= 32768 in order to interoperate with other implementations */ #define RECV_MAX_PAYLOAD_LEN 32768 @@ -339,7 +341,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define TRANS_MAX_WINDOW 500000000 /* 500MB is sufficient, stopping overflow */ #define TRANS_MAX_WIN_INCR 500000000 /* overflow prevention */ -#define RECV_WINDOWEXTEND (RECV_MAX_WINDOW / 3) /* We send a "window extend" every +#define RECV_WINDOWEXTEND (opts.recv_window / 3) /* We send a "window extend" every RECV_WINDOWEXTEND bytes */ #define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11 diff --git a/runopts.h b/runopts.h index ed34658..e430371 100644 --- a/runopts.h +++ b/runopts.h @@ -36,6 +36,7 @@ typedef struct runopts { #if defined(ENABLE_SVR_REMOTETCPFWD) || defined(ENABLE_CLI_LOCALTCPFWD) int listen_fwd_all; #endif + unsigned int recv_window; } runopts; diff --git a/svr-runopts.c b/svr-runopts.c index dde0b07..f78461b 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -80,6 +80,7 @@ static void printhelp(const char * progname) { #ifdef INETD_MODE "-i Start for inetd\n" #endif + "-W (default %d, larger may be faster)\n" #ifdef DEBUG_TRACE "-v verbose\n" #endif @@ -90,7 +91,7 @@ static void printhelp(const char * progname) { #ifdef DROPBEAR_RSA RSA_PRIV_FILENAME, #endif - DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE); + DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE, DEFAULT_RECV_WINDOW); } void svr_getopts(int argc, char ** argv) { @@ -128,6 +129,8 @@ void svr_getopts(int argc, char ** argv) { #ifndef DISABLE_SYSLOG svr_opts.usingsyslog = 1; #endif + opts.recv_window = DEFAULT_RECV_WINDOW; + char* recv_window_arg = NULL; #ifdef ENABLE_SVR_REMOTETCPFWD opts.listen_fwd_all = 0; #endif @@ -204,6 +207,9 @@ void svr_getopts(int argc, char ** argv) { case 'w': svr_opts.norootlogin = 1; break; + case 'W': + next = &recv_window_arg; + break; #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) case 's': svr_opts.noauthpass = 1; @@ -265,8 +271,17 @@ void svr_getopts(int argc, char ** argv) { svr_opts.bannerfile); } buf_setpos(svr_opts.banner, 0); - } + } + + if (recv_window_arg) + { + opts.recv_window = atol(recv_window_arg); + if (opts.recv_window == 0) + { + dropbear_exit("Bad recv window '%s'", recv_window_arg); + } + } } static void addportandaddress(char* spec) { -- cgit v1.2.3 From 75ec4d6510aba8780effddb53eee4a0296015608 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Wed, 8 Aug 2007 15:12:06 +0000 Subject: - Add -K keepalive flag for dropbear and dbclient - Try to reduce the frequency of select() timeouts - Add a max receive window size of 1MB --HG-- extra : convert_revision : 9aa22036cb511cddb35fbc0e09ad05acb39b64d1 --- cli-runopts.c | 21 ++++++++++++++++++--- common-kex.c | 7 +------ common-session.c | 46 ++++++++++++++++++++++++++++++++++------------ dbclient.1 | 7 +++++++ dropbear.8 | 7 +++++++ includes.h | 1 + kex.h | 2 +- options.h | 7 ++++--- packet.c | 2 ++ process-packet.c | 2 +- runopts.h | 1 + session.h | 9 +++++++-- svr-auth.c | 2 +- svr-main.c | 8 ++------ svr-runopts.c | 27 +++++++++++++++++++++------ svr-session.c | 8 +------- 16 files changed, 109 insertions(+), 48 deletions(-) (limited to 'runopts.h') diff --git a/cli-runopts.c b/cli-runopts.c index f38ccd2..68990fa 100644 --- a/cli-runopts.c +++ b/cli-runopts.c @@ -63,11 +63,14 @@ static void printhelp() { #ifdef ENABLE_CLI_REMOTETCPFWD "-R Remote port forwarding\n" #endif - "-W (default %d, larger may be faster)\n" + "-W (default %d, larger may be faster, max 1MB)\n" + "-K (0 is never, default %d)\n" #ifdef DEBUG_TRACE "-v verbose\n" #endif - ,DROPBEAR_VERSION, cli_opts.progname, DEFAULT_RECV_WINDOW); + ,DROPBEAR_VERSION, cli_opts.progname, + DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE); + } void cli_getopts(int argc, char ** argv) { @@ -112,6 +115,7 @@ void cli_getopts(int argc, char ** argv) { */ opts.recv_window = DEFAULT_RECV_WINDOW; char* recv_window_arg = NULL; + char* keepalive_arg = NULL; /* Iterate all the arguments */ for (i = 1; i < (unsigned int)argc; i++) { @@ -207,6 +211,9 @@ void cli_getopts(int argc, char ** argv) { case 'W': next = &recv_window_arg; break; + case 'K': + next = &keepalive_arg; + break; #ifdef DEBUG_TRACE case 'v': debug_trace = 1; @@ -302,11 +309,19 @@ void cli_getopts(int argc, char ** argv) { if (recv_window_arg) { opts.recv_window = atol(recv_window_arg); - if (opts.recv_window == 0) + if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) { dropbear_exit("Bad recv window '%s'", recv_window_arg); } } + if (keepalive_arg) { + opts.keepalive_secs = strtoul(keepalive_arg, NULL, 10); + if (opts.keepalive_secs == 0 && errno == EINVAL) + { + dropbear_exit("Bad keepalive '%s'", keepalive_arg); + } + } + } #ifdef ENABLE_CLI_PUBKEY_AUTH diff --git a/common-kex.c b/common-kex.c index dd36cd1..e9c655d 100644 --- a/common-kex.c +++ b/common-kex.c @@ -188,8 +188,6 @@ void kexfirstinitialise() { /* Reset the kex state, ready for a new negotiation */ static void kexinitialise() { - struct timeval tv; - TRACE(("kexinitialise()")) /* sent/recv'd MSG_KEXINIT */ @@ -206,10 +204,7 @@ static void kexinitialise() { ses.kexstate.datatrans = 0; ses.kexstate.datarecv = 0; - if (gettimeofday(&tv, 0) < 0) { - dropbear_exit("Error getting time"); - } - ses.kexstate.lastkextime = tv.tv_sec; + ses.kexstate.lastkextime = time(NULL); } diff --git a/common-session.c b/common-session.c index 9b248cf..79313f2 100644 --- a/common-session.c +++ b/common-session.c @@ -34,8 +34,10 @@ #include "kex.h" #include "channel.h" #include "atomicio.h" +#include "runopts.h" static void checktimeouts(); +static long select_timeout(); static int ident_readln(int fd, char* buf, int count); struct sshsession ses; /* GLOBAL */ @@ -59,7 +61,8 @@ void common_session_init(int sock, char* remotehost) { ses.sock = sock; ses.maxfd = sock; - ses.connecttimeout = 0; + ses.connect_time = 0; + ses.last_packet_time = 0; if (pipe(ses.signal_pipe) < 0) { dropbear_exit("signal pipe failed"); @@ -129,7 +132,7 @@ void session_loop(void(*loophandler)()) { /* main loop, select()s for all sockets in use */ for(;;) { - timeout.tv_sec = SELECT_TIMEOUT; + timeout.tv_sec = select_timeout(); timeout.tv_usec = 0; FD_ZERO(&writefd); FD_ZERO(&readfd); @@ -359,20 +362,22 @@ static int ident_readln(int fd, char* buf, int count) { return pos+1; } +void send_msg_ignore() { + CHECKCLEARTOWRITE(); + buf_putbyte(ses.writepayload, SSH_MSG_IGNORE); + buf_putstring(ses.writepayload, "", 0); + encrypt_packet(); +} + /* Check all timeouts which are required. Currently these are the time for * user authentication, and the automatic rekeying. */ static void checktimeouts() { - struct timeval tv; - long secs; - - if (gettimeofday(&tv, 0) < 0) { - dropbear_exit("Error getting time"); - } + time_t now; - secs = tv.tv_sec; + now = time(NULL); - if (ses.connecttimeout != 0 && secs > ses.connecttimeout) { + if (ses.connect_time != 0 && now - ses.connect_time >= AUTH_TIMEOUT) { dropbear_close("Timeout before auth"); } @@ -382,10 +387,27 @@ static void checktimeouts() { } if (!ses.kexstate.sentkexinit - && (secs - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT - || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)){ + && (now - ses.kexstate.lastkextime >= KEX_REKEY_TIMEOUT + || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) { TRACE(("rekeying after timeout or max data reached")) send_msg_kexinit(); } + + if (opts.keepalive_secs > 0 + && now - ses.last_packet_time >= opts.keepalive_secs) { + send_msg_ignore(); + } } +static long select_timeout() { + /* determine the minimum timeout that might be required, so + as to avoid waking when unneccessary */ + long ret = LONG_MAX; + if (KEX_REKEY_TIMEOUT > 0) + ret = MIN(KEX_REKEY_TIMEOUT, ret); + if (AUTH_TIMEOUT > 0) + ret = MIN(AUTH_TIMEOUT, ret); + if (opts.keepalive_secs > 0) + ret = MIN(opts.keepalive_secs, ret); + return ret; +} diff --git a/dbclient.1 b/dbclient.1 index 3e67c08..e72f249 100644 --- a/dbclient.1 +++ b/dbclient.1 @@ -79,6 +79,13 @@ connection will abort as normal. Specify the per-channel receive window buffer size. Increasing this may improve network performance at the expense of memory use. Use -h to see the default buffer size. +.TP +.B \-K \fItimeout_seconds +Ensure that traffic is transmitted at a certain interval in seconds. This is +useful for working around firewalls or routers that drop connections after +a certain period of inactivity. The trade-off is that a session may be +closed if there is a temporary lapse of network connectivity. A setting +if 0 disables keepalives. .SH AUTHOR Matt Johnston (matt@ucc.asn.au). .br diff --git a/dropbear.8 b/dropbear.8 index 70dfb3e..c9c2e79 100644 --- a/dropbear.8 +++ b/dropbear.8 @@ -87,6 +87,13 @@ Allow remote hosts to connect to forwarded ports. Specify the per-channel receive window buffer size. Increasing this may improve network performance at the expense of memory use. Use -h to see the default buffer size. +.TP +.B \-K \fItimeout_seconds +Ensure that traffic is transmitted at a certain interval in seconds. This is +useful for working around firewalls or routers that drop connections after +a certain period of inactivity. The trade-off is that a session may be +closed if there is a temporary lapse of network connectivity. A setting +if 0 disables keepalives. .SH AUTHOR Matt Johnston (matt@ucc.asn.au). .br diff --git a/includes.h b/includes.h index 017de66..03cb1cf 100644 --- a/includes.h +++ b/includes.h @@ -56,6 +56,7 @@ #include #include #include +#include #ifdef HAVE_UTMP_H #include diff --git a/kex.h b/kex.h index 448ad1b..d3dd187 100644 --- a/kex.h +++ b/kex.h @@ -53,7 +53,7 @@ struct KEXState { unsigned donefirstkex : 1; /* Set to 1 after the first kex has completed, ie the transport layer has been set up */ - long lastkextime; /* time of the last kex */ + time_t lastkextime; /* time of the last kex */ unsigned int datatrans; /* data transmitted since last kex */ unsigned int datarecv; /* data received since last kex */ diff --git a/options.h b/options.h index 939206a..722a43a 100644 --- a/options.h +++ b/options.h @@ -231,6 +231,9 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ though increasing it may not make a significant difference. */ #define TRANS_MAX_PAYLOAD_LEN 16384 +/* Ensure that data is transmitted every KEEPALIVE seconds. This can +be overridden at runtime with -K. 0 disables keepalives */ +#define DEFAULT_KEEPALIVE 0 /******************************************************************* * You shouldn't edit below here unless you know you need to. @@ -287,9 +290,6 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define _PATH_CP "/bin/cp" -/* Timeouts in seconds */ -#define SELECT_TIMEOUT 20 - /* success/failure defines */ #define DROPBEAR_SUCCESS 0 #define DROPBEAR_FAILURE -1 @@ -343,6 +343,7 @@ etc) slower (perhaps by 50%). Recommended for most small systems. */ #define RECV_WINDOWEXTEND (opts.recv_window / 3) /* We send a "window extend" every RECV_WINDOWEXTEND bytes */ +#define MAX_RECV_WINDOW (1024*1024) /* 1 MB should be enough */ #define MAX_CHANNELS 100 /* simple mem restriction, includes each tcp/x11 connection, so can't be _too_ small */ diff --git a/packet.c b/packet.c index 87921f3..28c7346 100644 --- a/packet.c +++ b/packet.c @@ -71,6 +71,8 @@ void write_packet() { dropbear_exit("error writing"); } } + + ses.last_packet_time = time(NULL); if (written == 0) { ses.remoteclosed(); diff --git a/process-packet.c b/process-packet.c index ba39d9f..d96c1cb 100644 --- a/process-packet.c +++ b/process-packet.c @@ -56,8 +56,8 @@ void process_packet() { switch(type) { case SSH_MSG_IGNORE: + goto out; case SSH_MSG_DEBUG: - TRACE(("received SSH_MSG_IGNORE or SSH_MSG_DEBUG")) goto out; case SSH_MSG_UNIMPLEMENTED: diff --git a/runopts.h b/runopts.h index e430371..d6e8917 100644 --- a/runopts.h +++ b/runopts.h @@ -37,6 +37,7 @@ typedef struct runopts { int listen_fwd_all; #endif unsigned int recv_window; + time_t keepalive_secs; } runopts; diff --git a/session.h b/session.h index 8a95614..e11c959 100644 --- a/session.h +++ b/session.h @@ -45,6 +45,7 @@ void common_session_init(int sock, char* remotehost); void session_loop(void(*loophandler)()); void common_session_cleanup(); void session_identification(); +void send_msg_ignore(); /* Server */ @@ -92,8 +93,9 @@ struct sshsession { /* Is it a client or server? */ unsigned char isserver; - long connecttimeout; /* time to disconnect if we have a timeout (for - userauth etc), or 0 for no timeout */ + time_t connect_time; /* time the connection was established + (cleared after auth once we're not + respecting AUTH_TIMEOUT any more) */ int sock; @@ -131,6 +133,9 @@ struct sshsession { int signal_pipe[2]; /* stores endpoints of a self-pipe used for race-free signal handling */ + + time_t last_packet_time; /* time of the last packet transmission, for + keepalive purposes */ /* KEX/encryption related */ struct KEXState kexstate; diff --git a/svr-auth.c b/svr-auth.c index d0eba9b..ea31e79 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -357,7 +357,7 @@ void send_msg_userauth_success() { encrypt_packet(); ses.authstate.authdone = 1; - ses.connecttimeout = 0; + ses.connect_time = 0; if (ses.authstate.pw->pw_uid == 0) { diff --git a/svr-main.c b/svr-main.c index 9e0578e..f7ce221 100644 --- a/svr-main.c +++ b/svr-main.c @@ -111,7 +111,6 @@ static void main_inetd() { #ifdef NON_INETD_MODE void main_noinetd() { fd_set fds; - struct timeval seltimeout; unsigned int i, j; int val; int maxsock = -1; @@ -175,9 +174,6 @@ void main_noinetd() { FD_ZERO(&fds); - seltimeout.tv_sec = 60; - seltimeout.tv_usec = 0; - /* listening sockets */ for (i = 0; i < listensockcount; i++) { FD_SET(listensocks[i], &fds); @@ -191,7 +187,7 @@ void main_noinetd() { } } - val = select(maxsock+1, &fds, NULL, NULL, &seltimeout); + val = select(maxsock+1, &fds, NULL, NULL, NULL); if (exitflag) { unlink(svr_opts.pidfile); @@ -199,7 +195,7 @@ void main_noinetd() { } if (val == 0) { - /* timeout reached */ + /* timeout reached - shouldn't happen. eh */ continue; } diff --git a/svr-runopts.c b/svr-runopts.c index f78461b..83c75c3 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -80,7 +80,8 @@ static void printhelp(const char * progname) { #ifdef INETD_MODE "-i Start for inetd\n" #endif - "-W (default %d, larger may be faster)\n" + "-W (default %d, larger may be faster, max 1MB)\n" + "-K (0 is never, default %d)\n" #ifdef DEBUG_TRACE "-v verbose\n" #endif @@ -91,7 +92,8 @@ static void printhelp(const char * progname) { #ifdef DROPBEAR_RSA RSA_PRIV_FILENAME, #endif - DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE, DEFAULT_RECV_WINDOW); + DROPBEAR_MAX_PORTS, DROPBEAR_DEFPORT, DROPBEAR_PIDFILE, + DEFAULT_RECV_WINDOW, DEFAULT_KEEPALIVE); } void svr_getopts(int argc, char ** argv) { @@ -99,6 +101,8 @@ void svr_getopts(int argc, char ** argv) { unsigned int i; char ** next = 0; int nextisport = 0; + char* recv_window_arg = NULL; + char* keepalive_arg = NULL; /* see printhelp() for options */ svr_opts.rsakeyfile = NULL; @@ -130,7 +134,8 @@ void svr_getopts(int argc, char ** argv) { svr_opts.usingsyslog = 1; #endif opts.recv_window = DEFAULT_RECV_WINDOW; - char* recv_window_arg = NULL; + opts.keepalive_secs = DEFAULT_KEEPALIVE; + #ifdef ENABLE_SVR_REMOTETCPFWD opts.listen_fwd_all = 0; #endif @@ -210,6 +215,9 @@ void svr_getopts(int argc, char ** argv) { case 'W': next = &recv_window_arg; break; + case 'K': + next = &keepalive_arg; + break; #if defined(ENABLE_SVR_PASSWORD_AUTH) || defined(ENABLE_SVR_PAM_AUTH) case 's': svr_opts.noauthpass = 1; @@ -274,14 +282,21 @@ void svr_getopts(int argc, char ** argv) { } - if (recv_window_arg) - { + if (recv_window_arg) { opts.recv_window = atol(recv_window_arg); - if (opts.recv_window == 0) + if (opts.recv_window == 0 || opts.recv_window > MAX_RECV_WINDOW) { dropbear_exit("Bad recv window '%s'", recv_window_arg); } } + + if (keepalive_arg) { + opts.keepalive_secs = strtoul(keepalive_arg, NULL, 10); + if (opts.keepalive_secs == 0 && errno == EINVAL) + { + dropbear_exit("Bad keepalive '%s'", keepalive_arg); + } + } } static void addportandaddress(char* spec) { diff --git a/svr-session.c b/svr-session.c index 3701597..18fab6b 100644 --- a/svr-session.c +++ b/svr-session.c @@ -77,8 +77,6 @@ static const struct ChanType *svr_chantypes[] = { void svr_session(int sock, int childpipe, char* remotehost, char *addrstring) { - struct timeval timeout; - reseedrandom(); crypto_init(); @@ -91,11 +89,7 @@ void svr_session(int sock, int childpipe, chaninitialise(svr_chantypes); svr_chansessinitialise(); - if (gettimeofday(&timeout, 0) < 0) { - dropbear_exit("Error getting time"); - } - - ses.connecttimeout = timeout.tv_sec + AUTH_TIMEOUT; + ses.connect_time = time(NULL); /* set up messages etc */ ses.remoteclosed = svr_remoteclosed; -- cgit v1.2.3