Set tcp priority as follows:

if (connecting || ptys || x11) tos = LOWDELAY;
else if (tcp_forwards) tos = 0;
else tos = BULK;

TCP forwards could be either lowdelay or bulk, hence the default priority.
This commit is contained in:
Matt Johnston 2014-07-16 22:53:32 +08:00
parent f1826ea389
commit da57dd13c5
13 changed files with 120 additions and 25 deletions

View File

@ -29,14 +29,6 @@
#include "buffer.h" #include "buffer.h"
#include "circbuffer.h" #include "circbuffer.h"
/* channel->type values */
#define CHANNEL_ID_NONE 0
#define CHANNEL_ID_SESSION 1
#define CHANNEL_ID_X11 2
#define CHANNEL_ID_AGENT 3
#define CHANNEL_ID_TCPDIRECT 4
#define CHANNEL_ID_TCPFORWARDED 5
#define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1 #define SSH_OPEN_ADMINISTRATIVELY_PROHIBITED 1
#define SSH_OPEN_CONNECT_FAILED 2 #define SSH_OPEN_CONNECT_FAILED 2
#define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3 #define SSH_OPEN_UNKNOWN_CHANNEL_TYPE 3
@ -49,6 +41,13 @@
struct ChanType; struct ChanType;
enum dropbear_channel_prio {
DROPBEAR_CHANNEL_PRIO_INTERACTIVE, /* pty shell, x11 */
DROPBEAR_CHANNEL_PRIO_UNKNOWABLE, /* tcp - can't know what's being forwarded */
DROPBEAR_CHANNEL_PRIO_BULK, /* the rest - probably scp or something */
DROPBEAR_CHANNEL_PRIO_EARLY, /* channel is still being set up */
};
struct Channel { struct Channel {
unsigned int index; /* the local channel index */ unsigned int index; /* the local channel index */
@ -87,6 +86,8 @@ struct Channel {
void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len); void (*read_mangler)(struct Channel*, unsigned char* bytes, int *len);
const struct ChanType* type; const struct ChanType* type;
enum dropbear_channel_prio prio;
}; };
struct ChanType { struct ChanType {
@ -97,7 +98,6 @@ struct ChanType {
int (*check_close)(struct Channel*); int (*check_close)(struct Channel*);
void (*reqhandler)(struct Channel*); void (*reqhandler)(struct Channel*);
void (*closehandler)(struct Channel*); void (*closehandler)(struct Channel*);
}; };
void chaninitialise(const struct ChanType *chantypes[]); void chaninitialise(const struct ChanType *chantypes[]);

View File

@ -41,7 +41,7 @@ static void cli_chansessreq(struct Channel *channel);
static void send_chansess_pty_req(struct Channel *channel); static void send_chansess_pty_req(struct Channel *channel);
static void send_chansess_shell_req(struct Channel *channel); static void send_chansess_shell_req(struct Channel *channel);
static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len); static void cli_escape_handler(struct Channel *channel, unsigned char* buf, int *len);
static int cli_init_netcat(struct Channel *channel);
static void cli_tty_setup(); static void cli_tty_setup();
@ -357,6 +357,11 @@ static int cli_init_stdpipe_sess(struct Channel *channel) {
return 0; return 0;
} }
static int cli_init_netcat(struct Channel *channel) {
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
return cli_init_stdpipe_sess(channel);
}
static int cli_initchansess(struct Channel *channel) { static int cli_initchansess(struct Channel *channel) {
cli_init_stdpipe_sess(channel); cli_init_stdpipe_sess(channel);
@ -369,8 +374,9 @@ static int cli_initchansess(struct Channel *channel) {
if (cli_opts.wantpty) { if (cli_opts.wantpty) {
send_chansess_pty_req(channel); send_chansess_pty_req(channel);
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
} else { } else {
set_sock_priority(ses.sock_out, DROPBEAR_PRIO_BULK); channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
} }
send_chansess_shell_req(channel); send_chansess_shell_req(channel);
@ -389,7 +395,7 @@ static int cli_initchansess(struct Channel *channel) {
static const struct ChanType cli_chan_netcat = { static const struct ChanType cli_chan_netcat = {
0, /* sepfds */ 0, /* sepfds */
"direct-tcpip", "direct-tcpip",
cli_init_stdpipe_sess, /* inithandler */ cli_init_netcat, /* inithandler */
NULL, NULL,
NULL, NULL,
cli_closechansess cli_closechansess

View File

@ -75,9 +75,6 @@ int main(int argc, char ** argv) {
int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport, int sock = connect_remote(cli_opts.remotehost, cli_opts.remoteport,
0, &error); 0, &error);
sock_in = sock_out = sock; sock_in = sock_out = sock;
if (cli_opts.wantpty) {
set_sock_priority(sock, DROPBEAR_PRIO_LOWDELAY);
}
} }
if (sock_in < 0) { if (sock_in < 0) {

View File

@ -52,7 +52,7 @@ static int cli_localtcp(const char* listenaddr,
static const struct ChanType cli_chan_tcplocal = { static const struct ChanType cli_chan_tcplocal = {
1, /* sepfds */ 1, /* sepfds */
"direct-tcpip", "direct-tcpip",
NULL, tcp_prio_inithandler,
NULL, NULL,
NULL, NULL,
NULL NULL
@ -267,6 +267,8 @@ static int newtcpforwarded(struct Channel * channel) {
* progress succeeds */ * progress succeeds */
channel->writefd = sock; channel->writefd = sock;
channel->initconn = 1; channel->initconn = 1;
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
err = SSH_OPEN_IN_PROGRESS; err = SSH_OPEN_IN_PROGRESS;

View File

@ -174,6 +174,8 @@ static struct Channel* newchannel(unsigned int remotechan,
newchan->recvdonelen = 0; newchan->recvdonelen = 0;
newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN; newchan->recvmaxpacket = RECV_MAX_CHANNEL_DATA_LEN;
newchan->prio = DROPBEAR_CHANNEL_PRIO_EARLY; /* inithandler sets it */
ses.channels[i] = newchan; ses.channels[i] = newchan;
ses.chancount++; ses.chancount++;
@ -595,6 +597,8 @@ static void remove_channel(struct Channel * channel) {
m_free(channel); m_free(channel);
ses.chancount--; ses.chancount--;
update_channel_prio();
TRACE(("leave remove_channel")) TRACE(("leave remove_channel"))
} }
@ -885,6 +889,10 @@ void recv_msg_channel_open() {
} }
} }
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
chan_initwritebuf(channel); chan_initwritebuf(channel);
/* success */ /* success */
@ -898,6 +906,8 @@ failure:
cleanup: cleanup:
m_free(type); m_free(type);
update_channel_prio();
TRACE(("leave recv_msg_channel_open")) TRACE(("leave recv_msg_channel_open"))
} }
@ -1013,7 +1023,7 @@ static void close_chan_fd(struct Channel *channel, int fd, int how) {
* for X11, agent, tcp forwarding, and should be filled with channel-specific * for X11, agent, tcp forwarding, and should be filled with channel-specific
* options, with the calling function calling encrypt_packet() after * options, with the calling function calling encrypt_packet() after
* completion. It is mandatory for the caller to encrypt_packet() if * completion. It is mandatory for the caller to encrypt_packet() if
* DROPBEAR_SUCCESS is returned */ * a channel is returned. NULL is returned on failure. */
int send_msg_channel_open_init(int fd, const struct ChanType *type) { int send_msg_channel_open_init(int fd, const struct ChanType *type) {
struct Channel* chan; struct Channel* chan;
@ -1082,6 +1092,10 @@ void recv_msg_channel_open_confirmation() {
} }
} }
if (channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
}
update_channel_prio();
TRACE(("leave recv_msg_channel_open_confirmation")) TRACE(("leave recv_msg_channel_open_confirmation"))
} }
@ -1113,4 +1127,3 @@ void send_msg_request_failure() {
buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE); buf_putbyte(ses.writepayload, SSH_MSG_REQUEST_FAILURE);
encrypt_packet(); encrypt_packet();
} }

View File

@ -59,6 +59,10 @@ void common_session_init(int sock_in, int sock_out) {
ses.sock_out = sock_out; ses.sock_out = sock_out;
ses.maxfd = MAX(sock_in, sock_out); ses.maxfd = MAX(sock_in, sock_out);
ses.socket_prio = DROPBEAR_PRIO_DEFAULT;
/* Sets it to lowdelay */
update_channel_prio();
now = monotonic_now(); now = monotonic_now();
ses.last_packet_time_keepalive_recv = now; ses.last_packet_time_keepalive_recv = now;
ses.last_packet_time_idle = now; ses.last_packet_time_idle = now;
@ -512,3 +516,47 @@ void fill_passwd(const char* username) {
} }
} }
/* Called when channels are modified */
void update_channel_prio() {
enum dropbear_prio new_prio;
int any = 0;
unsigned int i;
TRACE(("update_channel_prio"))
new_prio = DROPBEAR_PRIO_BULK;
for (i = 0; i < ses.chansize; i++) {
struct Channel *channel = ses.channels[i];
if (!channel || channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
if (channel && channel->prio == DROPBEAR_CHANNEL_PRIO_EARLY) {
TRACE(("update_channel_prio: early %d", channel->index))
}
continue;
}
any = 1;
if (channel->prio == DROPBEAR_CHANNEL_PRIO_INTERACTIVE)
{
TRACE(("update_channel_prio: lowdelay %d", channel->index))
new_prio = DROPBEAR_PRIO_LOWDELAY;
break;
} else if (channel->prio == DROPBEAR_CHANNEL_PRIO_UNKNOWABLE
&& new_prio == DROPBEAR_PRIO_BULK)
{
TRACE(("update_channel_prio: unknowable %d", channel->index))
new_prio = DROPBEAR_PRIO_DEFAULT;
}
}
if (any == 0) {
/* lowdelay during setup */
TRACE(("update_channel_prio: not any"))
new_prio = DROPBEAR_PRIO_LOWDELAY;
}
if (new_prio != ses.socket_prio) {
TRACE(("Dropbear priority transitioning %4.4s -> %4.4s", (char*)&ses.socket_prio, (char*)&new_prio))
set_sock_priority(ses.sock_out, new_prio);
ses.socket_prio = new_prio;
}
}

View File

@ -62,9 +62,9 @@ extern int debug_trace;
#endif #endif
enum dropbear_prio { enum dropbear_prio {
DROPBEAR_PRIO_DEFAULT, DROPBEAR_PRIO_DEFAULT = 'dffd',
DROPBEAR_PRIO_LOWDELAY, DROPBEAR_PRIO_LOWDELAY = 'lddl',
DROPBEAR_PRIO_BULK, DROPBEAR_PRIO_BULK = 'bllb',
}; };
char * stripcontrol(const char * text); char * stripcontrol(const char * text);

View File

@ -48,6 +48,8 @@ void session_cleanup();
void send_session_identification(); void send_session_identification();
void send_msg_ignore(); void send_msg_ignore();
void update_channel_prio();
const char* get_user_shell(); const char* get_user_shell();
void fill_passwd(const char* username); void fill_passwd(const char* username);
@ -186,7 +188,9 @@ struct sshsession {
unsigned int chancount; /* the number of Channel*s in use */ unsigned int chancount; /* the number of Channel*s in use */
const struct ChanType **chantypes; /* The valid channel types */ const struct ChanType **chantypes; /* The valid channel types */
/* TCP priority level for the main "port 22" tcp socket */
enum dropbear_prio socket_prio;
/* TCP forwarding - where manage listeners */ /* TCP forwarding - where manage listeners */
struct Listener ** listeners; struct Listener ** listeners;
unsigned int listensize; unsigned int listensize;

View File

@ -253,6 +253,8 @@ static int newchansess(struct Channel *channel) {
chansess->agentdir = NULL; chansess->agentdir = NULL;
#endif #endif
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
return 0; return 0;
} }
@ -668,8 +670,11 @@ static int sessioncommand(struct Channel *channel, struct ChanSess *chansess,
if (chansess->term == NULL) { if (chansess->term == NULL) {
/* no pty */ /* no pty */
set_sock_priority(ses.sock_out, DROPBEAR_PRIO_BULK);
ret = noptycommand(channel, chansess); ret = noptycommand(channel, chansess);
if (ret == DROPBEAR_SUCCESS) {
channel->prio = DROPBEAR_CHANNEL_PRIO_BULK;
update_channel_prio();
}
} else { } else {
/* want pty */ /* want pty */
ret = ptycommand(channel, chansess); ret = ptycommand(channel, chansess);

View File

@ -53,7 +53,7 @@ static int newtcpdirect(struct Channel * channel);
static const struct ChanType svr_chan_tcpremote = { static const struct ChanType svr_chan_tcpremote = {
1, /* sepfds */ 1, /* sepfds */
"forwarded-tcpip", "forwarded-tcpip",
NULL, tcp_prio_inithandler,
NULL, NULL,
NULL, NULL,
NULL NULL
@ -240,6 +240,8 @@ static int newtcpdirect(struct Channel * channel) {
int len; int len;
int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int err = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
TRACE(("newtcpdirect channel %d", channel->index))
if (svr_opts.nolocaltcp || !svr_pubkey_allows_tcpfwd()) { if (svr_opts.nolocaltcp || !svr_pubkey_allows_tcpfwd()) {
TRACE(("leave newtcpdirect: local tcp forwarding disabled")) TRACE(("leave newtcpdirect: local tcp forwarding disabled"))
goto out; goto out;
@ -281,6 +283,8 @@ static int newtcpdirect(struct Channel * channel) {
* progress succeeds */ * progress succeeds */
channel->writefd = sock; channel->writefd = sock;
channel->initconn = 1; channel->initconn = 1;
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
err = SSH_OPEN_IN_PROGRESS; err = SSH_OPEN_IN_PROGRESS;

View File

@ -182,10 +182,15 @@ void x11cleanup(struct ChanSess *chansess) {
} }
} }
static int x11_inithandler(struct Channel *channel) {
channel->prio = DROPBEAR_CHANNEL_PRIO_INTERACTIVE;
return 0;
}
static const struct ChanType chan_x11 = { static const struct ChanType chan_x11 = {
0, /* sepfds */ 0, /* sepfds */
"x11", "x11",
NULL, /* inithandler */ x11_inithandler, /* inithandler */
NULL, /* checkclose */ NULL, /* checkclose */
NULL, /* reqhandler */ NULL, /* reqhandler */
NULL /* closehandler */ NULL /* closehandler */

View File

@ -30,6 +30,7 @@
#include "buffer.h" #include "buffer.h"
#include "packet.h" #include "packet.h"
#include "listener.h" #include "listener.h"
#include "listener.h"
#include "runopts.h" #include "runopts.h"
#ifdef DROPBEAR_TCP_ACCEPT #ifdef DROPBEAR_TCP_ACCEPT
@ -44,6 +45,13 @@ static void cleanup_tcp(struct Listener *listener) {
m_free(tcpinfo); m_free(tcpinfo);
} }
int tcp_prio_inithandler(struct Channel* channel)
{
TRACE(("tcp_prio_inithandler channel %d", channel->index))
channel->prio = DROPBEAR_CHANNEL_PRIO_UNKNOWABLE;
return 0;
}
static void tcp_acceptor(struct Listener *listener, int sock) { static void tcp_acceptor(struct Listener *listener, int sock) {
int fd; int fd;

View File

@ -70,5 +70,8 @@ void cli_recv_msg_request_failure();
/* Common */ /* Common */
int listen_tcpfwd(struct TCPListener* tcpinfo); int listen_tcpfwd(struct TCPListener* tcpinfo);
int tcp_prio_inithandler(struct Channel* chan);
#define CHANNEL_ID_TCPFORWARDED 'tcpf'
#endif #endif