#define BUG_SSH2_DERIVEKEY 32
#define BUG_SSH2_REKEY 64
#define BUG_SSH2_PK_SESSIONID 128
+#define BUG_SSH2_MAXPKT 256
/*
* Codes for terminal modes.
* A channel is completely finished with when all four bits are set.
*/
int closes;
+ /*
+ * True if this channel is causing the underlying connection to be
+ * throttled.
+ */
+ int throttling_conn;
union {
- struct ssh1_data_channel {
- int throttling;
- } v1;
struct ssh2_data_channel {
bufchain outbuffer;
unsigned remwindow, remmaxpkt;
void *x11auth;
int version;
- int v1_throttle_count;
+ int conn_throttle_count;
int overall_bufsize;
int throttled_all;
int v1_stdout_throttling;
ssh->remote_bugs |= BUG_SSH2_REKEY;
logevent("We believe remote version has SSH-2 rekey bug");
}
+
+ if (ssh->cfg.sshbug_maxpkt2 == FORCE_ON ||
+ (ssh->cfg.sshbug_maxpkt2 == AUTO &&
+ (wc_match("1.36_sshlib GlobalSCAPE", imp)))) {
+ /*
+ * This version ignores our makpkt and needs to be throttled.
+ */
+ ssh->remote_bugs |= BUG_SSH2_MAXPKT;
+ logevent("We believe remote version ignores SSH-2 maximum packet size");
+ }
}
/*
SockAddr addr;
const char *err;
- ssh->savedhost = snewn(1 + strlen(host), char);
- strcpy(ssh->savedhost, host);
+ if (*ssh->cfg.loghost) {
+ char *colon;
- if (port < 0)
- port = 22; /* default ssh port */
- ssh->savedport = port;
+ ssh->savedhost = dupstr(ssh->cfg.loghost);
+ ssh->savedport = 22; /* default ssh port */
+
+ /*
+ * A colon suffix on savedhost also lets us affect
+ * savedport.
+ *
+ * (FIXME: do something about IPv6 address literals here.)
+ */
+ colon = strrchr(ssh->savedhost, ':');
+ if (colon) {
+ *colon++ = '\0';
+ if (*colon)
+ ssh->savedport = atoi(colon);
+ }
+ } else {
+ ssh->savedhost = dupstr(host);
+ if (port < 0)
+ port = 22; /* default ssh port */
+ ssh->savedport = port;
+ }
/*
* Try to find host.
ssh_send_verstring(ssh, NULL);
}
+ /*
+ * loghost, if configured, overrides realhost.
+ */
+ if (*ssh->cfg.loghost) {
+ sfree(*realhost);
+ *realhost = dupstr(ssh->cfg.loghost);
+ }
+
return NULL;
}
/*
* Throttle or unthrottle the SSH connection.
*/
-static void ssh1_throttle(Ssh ssh, int adjust)
+static void ssh_throttle_conn(Ssh ssh, int adjust)
{
- int old_count = ssh->v1_throttle_count;
- ssh->v1_throttle_count += adjust;
- assert(ssh->v1_throttle_count >= 0);
- if (ssh->v1_throttle_count && !old_count) {
+ int old_count = ssh->conn_throttle_count;
+ ssh->conn_throttle_count += adjust;
+ assert(ssh->conn_throttle_count >= 0);
+ if (ssh->conn_throttle_count && !old_count) {
ssh_set_frozen(ssh, 1);
- } else if (!ssh->v1_throttle_count && old_count) {
+ } else if (!ssh->conn_throttle_count && old_count) {
ssh_set_frozen(ssh, 0);
}
}
void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)
{
Ssh ssh = c->ssh;
+ int buflimit;
if (ssh->state == SSH_STATE_CLOSED)
return;
if (ssh->version == 1) {
- if (c->v.v1.throttling && bufsize < SSH1_BUFFER_LIMIT) {
- c->v.v1.throttling = 0;
- ssh1_throttle(ssh, -1);
- }
+ buflimit = SSH1_BUFFER_LIMIT;
} else {
- ssh2_set_window(c, c->v.v2.locmaxwin - bufsize);
+ buflimit = c->v.v2.locmaxwin;
+ ssh2_set_window(c, bufsize < buflimit ? buflimit - bufsize : 0);
+ }
+ if (c->throttling_conn && bufsize <= buflimit) {
+ c->throttling_conn = 0;
+ ssh_throttle_conn(ssh, -1);
}
}
string, stringlen);
if (!ssh->v1_stdout_throttling && bufsize > SSH1_BUFFER_LIMIT) {
ssh->v1_stdout_throttling = 1;
- ssh1_throttle(ssh, +1);
+ ssh_throttle_conn(ssh, +1);
}
}
c->halfopen = FALSE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
- c->v.v1.throttling = 0;
+ c->throttling_conn = 0;
c->type = CHAN_X11; /* identify channel type */
add234(ssh->channels, c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
c->halfopen = FALSE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
- c->v.v1.throttling = 0;
+ c->throttling_conn = 0;
c->type = CHAN_AGENT; /* identify channel type */
c->u.a.lensofar = 0;
add234(ssh->channels, c);
c->halfopen = FALSE;
c->localid = alloc_channel_id(ssh);
c->closes = 0;
- c->v.v1.throttling = 0;
+ c->throttling_conn = 0;
c->type = CHAN_SOCKDATA; /* identify channel type */
add234(ssh->channels, c);
send_packet(ssh, SSH1_MSG_CHANNEL_OPEN_CONFIRMATION,
c->remoteid = localid;
c->halfopen = FALSE;
c->type = CHAN_SOCKDATA;
- c->v.v1.throttling = 0;
+ c->throttling_conn = 0;
pfd_confirm(c->u.pfd.s);
}
bufsize = 0; /* agent channels never back up */
break;
}
- if (!c->v.v1.throttling && bufsize > SSH1_BUFFER_LIMIT) {
- c->v.v1.throttling = 1;
- ssh1_throttle(ssh, +1);
+ if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {
+ c->throttling_conn = 1;
+ ssh_throttle_conn(ssh, +1);
}
}
}
}
/*
+ * Set up most of a new ssh_channel for SSH-2.
+ */
+static void ssh2_channel_init(struct ssh_channel *c)
+{
+ Ssh ssh = c->ssh;
+ c->localid = alloc_channel_id(ssh);
+ c->closes = 0;
+ c->throttling_conn = FALSE;
+ c->v.v2.locwindow = c->v.v2.locmaxwin = c->v.v2.remlocwin =
+ ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;
+ c->v.v2.winadj_head = c->v.v2.winadj_tail = NULL;
+ c->v.v2.throttle_state = UNTHROTTLED;
+ bufchain_init(&c->v.v2.outbuffer);
+}
+
+/*
* Potentially enlarge the window on an SSH-2 channel.
*/
static void ssh2_set_window(struct ssh_channel *c, int newwin)
return;
/*
+ * If the remote end has a habit of ignoring maxpkt, limit the
+ * window so that it has no choice (assuming it doesn't ignore the
+ * window as well).
+ */
+ if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT)
+ newwin = OUR_V2_MAXPKT;
+
+
+ /*
* Only send a WINDOW_ADJUST if there's significantly more window
* available than the other end thinks there is. This saves us
* sending a WINDOW_ADJUST for every character in a shell session.
*/
ssh2_set_window(c, bufsize < c->v.v2.locmaxwin ?
c->v.v2.locmaxwin - bufsize : 0);
+ /*
+ * If we're either buffering way too much data, or if we're
+ * buffering anything at all and we're in "simple" mode,
+ * throttle the whole channel.
+ */
+ if ((bufsize > c->v.v2.locmaxwin ||
+ (ssh->cfg.ssh_simple && bufsize > 0)) &&
+ !c->throttling_conn) {
+ c->throttling_conn = 1;
+ ssh_throttle_conn(ssh, +1);
+ }
}
}
int msglen = 0, core = FALSE;
/* ICK: older versions of OpenSSH (e.g. 3.4p1)
* provide an `int' for the signal, despite its
- * having been a `string' in the drafts since at
+ * having been a `string' in the drafts of RFC 4254 since at
* least 2001. (Fixed in session.c 1.147.) Try to
* infer which we can safely parse it as. */
{
fmt_sig = dupprintf(" %d", signum);
ssh->exitcode = 128 + signum;
} else {
- /* As per the drafts. */
+ /* As per RFC 4254. */
char *sig;
int siglen;
ssh_pkt_getstring(pktin, &sig, &siglen);
logeventf(ssh, "Rejected channel open: %s", error);
sfree(c);
} else {
- c->localid = alloc_channel_id(ssh);
- c->closes = 0;
- c->v.v2.locwindow = c->v.v2.locmaxwin = OUR_V2_WINSIZE;
+ ssh2_channel_init(c);
c->v.v2.remwindow = winsize;
c->v.v2.remmaxpkt = pktsize;
- c->v.v2.remlocwin = OUR_V2_WINSIZE;
- c->v.v2.winadj_head = c->v.v2.winadj_tail = NULL;
- c->v.v2.throttle_state = UNTHROTTLED;
- bufchain_init(&c->v.v2.outbuffer);
add234(ssh->channels, c);
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_CONFIRMATION);
ssh2_pkt_adduint32(pktout, c->remoteid);
*/
ssh->mainchan = snew(struct ssh_channel);
ssh->mainchan->ssh = ssh;
- ssh->mainchan->localid = alloc_channel_id(ssh);
+ ssh2_channel_init(ssh->mainchan);
logeventf(ssh,
"Opening direct-tcpip channel to %s:%d in place of session",
ssh->cfg.ssh_nc_host, ssh->cfg.ssh_nc_port);
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring(s->pktout, "direct-tcpip");
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
- ssh->mainchan->v.v2.locwindow = ssh->mainchan->v.v2.locmaxwin =
- ssh->mainchan->v.v2.remlocwin =
- ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;
- ssh->mainchan->v.v2.winadj_head = NULL;
- ssh->mainchan->v.v2.winadj_tail = NULL;
- ssh->mainchan->v.v2.throttle_state = UNTHROTTLED;
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */
ssh2_pkt_addstring(s->pktout, ssh->cfg.ssh_nc_host);
ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
ssh->mainchan->halfopen = FALSE;
ssh->mainchan->type = CHAN_MAINSESSION;
- ssh->mainchan->closes = 0;
ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
- bufchain_init(&ssh->mainchan->v.v2.outbuffer);
add234(ssh->channels, ssh->mainchan);
update_specials_menu(ssh->frontend);
logevent("Opened direct-tcpip channel");
} else {
ssh->mainchan = snew(struct ssh_channel);
ssh->mainchan->ssh = ssh;
- ssh->mainchan->localid = alloc_channel_id(ssh);
+ ssh2_channel_init(ssh->mainchan);
s->pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring(s->pktout, "session");
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->localid);
- ssh->mainchan->v.v2.locwindow = ssh->mainchan->v.v2.locmaxwin =
- ssh->mainchan->v.v2.remlocwin =
- ssh->cfg.ssh_simple ? OUR_V2_BIGWIN : OUR_V2_WINSIZE;
- ssh->mainchan->v.v2.winadj_head = NULL;
- ssh->mainchan->v.v2.winadj_tail = NULL;
- ssh->mainchan->v.v2.throttle_state = UNTHROTTLED;
ssh2_pkt_adduint32(s->pktout, ssh->mainchan->v.v2.locwindow);/* our window size */
ssh2_pkt_adduint32(s->pktout, OUR_V2_MAXPKT); /* our max pkt size */
ssh2_pkt_send(ssh, s->pktout);
ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
ssh->mainchan->halfopen = FALSE;
ssh->mainchan->type = CHAN_MAINSESSION;
- ssh->mainchan->closes = 0;
ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
ssh->mainchan->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
- bufchain_init(&ssh->mainchan->v.v2.outbuffer);
add234(ssh->channels, ssh->mainchan);
update_specials_menu(ssh->frontend);
logevent("Opened channel for session");
{
/* log reason code in disconnect message */
char *buf, *msg;
- int nowlen, reason, msglen;
+ int reason, msglen;
reason = ssh_pkt_getuint32(pktin);
ssh_pkt_getstring(pktin, &msg, &msglen);
}
logevent(buf);
sfree(buf);
- buf = dupprintf("Disconnection message text: %n%.*s",
- &nowlen, msglen, msg);
+ buf = dupprintf("Disconnection message text: %.*s",
+ msglen, msg);
logevent(buf);
- bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
+ bombout(("Server sent disconnect message\ntype %d (%s):\n\"%.*s\"",
reason,
(reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?
ssh2_disconnect_reasons[reason] : "unknown",
- buf+nowlen));
+ msglen, msg));
sfree(buf);
}
ssh->send_ok = 0;
ssh->editing = 0;
ssh->echoing = 0;
- ssh->v1_throttle_count = 0;
+ ssh->conn_throttle_count = 0;
ssh->overall_bufsize = 0;
ssh->fallback_cmd = 0;
static const struct telnet_special ssh2_session_specials[] = {
{NULL, TS_SEP},
{"Break", TS_BRK},
- /* These are the signal names defined by draft-ietf-secsh-connect-23.
+ /* These are the signal names defined by RFC 4254.
* They include all the ISO C signals, but are a subset of the POSIX
* required signals. */
{"SIGINT (Interrupt)", TS_SIGINT},
Ssh ssh = (Ssh) handle;
struct ssh_channel *c;
c = snew(struct ssh_channel);
- c->ssh = ssh;
- if (c) {
- c->halfopen = TRUE;
- c->localid = alloc_channel_id(ssh);
- c->closes = 0;
- c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
- c->u.pfd.s = s;
- bufchain_init(&c->v.v2.outbuffer);
- add234(ssh->channels, c);
- }
+ c->ssh = ssh;
+ ssh2_channel_init(c);
+ c->halfopen = TRUE;
+ c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */
+ c->u.pfd.s = s;
+ add234(ssh->channels, c);
return c;
}
static void ssh_unthrottle(void *handle, int bufsize)
{
Ssh ssh = (Ssh) handle;
+ int buflimit;
+
if (ssh->version == 1) {
if (ssh->v1_stdout_throttling && bufsize < SSH1_BUFFER_LIMIT) {
ssh->v1_stdout_throttling = 0;
- ssh1_throttle(ssh, -1);
+ ssh_throttle_conn(ssh, -1);
}
} else {
- if (ssh->mainchan)
+ if (ssh->mainchan) {
ssh2_set_window(ssh->mainchan,
- ssh->mainchan->v.v2.locmaxwin - bufsize);
+ bufsize < ssh->mainchan->v.v2.locmaxwin ?
+ ssh->mainchan->v.v2.locmaxwin - bufsize : 0);
+ if (ssh->cfg.ssh_simple)
+ buflimit = 0;
+ else
+ buflimit = ssh->mainchan->v.v2.locmaxwin;
+ if (ssh->mainchan->throttling_conn && bufsize <= buflimit) {
+ ssh->mainchan->throttling_conn = 0;
+ ssh_throttle_conn(ssh, -1);
+ }
+ }
}
}
pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN);
ssh2_pkt_addstring(pktout, "direct-tcpip");
ssh2_pkt_adduint32(pktout, c->localid);
- c->v.v2.locwindow = c->v.v2.locmaxwin = OUR_V2_WINSIZE;
- c->v.v2.remlocwin = OUR_V2_WINSIZE;
- c->v.v2.winadj_head = c->v.v2.winadj_head = NULL;
- c->v.v2.throttle_state = UNTHROTTLED;
ssh2_pkt_adduint32(pktout, c->v.v2.locwindow);/* our window size */
ssh2_pkt_adduint32(pktout, OUR_V2_MAXPKT); /* our max pkt size */
ssh2_pkt_addstring(pktout, hostname);