Skip to content
This repository has been archived by the owner on Apr 19, 2024. It is now read-only.

Commit

Permalink
Log the server's diagnostics if main channel open fails.
Browse files Browse the repository at this point in the history
This has been a FIXME in the code for ages, because back when the main
channel was always a pty session or a program run in a pipe, there
weren't that many circumstances in which the actual CHANNEL_OPEN could
return failure, so it never seemed like a priority to get round to
pulling the error information out of the CHANNEL_OPEN_FAILURE response
message and including it in PuTTY or Plink's local error message.

However, 'plink -nc' is the real reason why this is actually
important; if you tell the SSH server to make a direct-tcpip network
connection as its main channel, then that can fail for all the usual
network-unreliability reasons, and you actually do want to know which
(did you misspell the hostname, or is the target server refusing
connections, or has network connectivity failed?). This actually bit
me today when I had such a network failure, and had to debug it by
pulling that information manually out of a packet log. Time to
eliminate that FIXME.

So I've pulled the error-extracting code out of the previous handler
for OPEN_FAILURE on non-main channels into a separate function, and
arranged to call that function if the main channel open fails too. In
the process I've made a couple of minor tweaks, e.g. if the server
sends back a reason code we haven't heard of, we say _what_ that
reason code was, and also we at least make a token effort to spot if
we see a packet other than OPEN_{CONFIRMATION,FAILURE} reaching the
main loop in response to the main channel-open.
  • Loading branch information
sgtatham committed Jun 15, 2017
1 parent f31a72b commit a9e1053
Showing 1 changed file with 42 additions and 19 deletions.
61 changes: 42 additions & 19 deletions ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -8496,18 +8496,37 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
ssh_channel_try_eof(c); /* in case we had a pending EOF */
}

static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
static char *ssh2_channel_open_failure_error_text(struct Packet *pktin)
{
static const char *const reasons[] = {
"<unknown reason code>",
"Administratively prohibited",
"Connect failed",
"Unknown channel type",
"Resource shortage",
NULL,
"Administratively prohibited",
"Connect failed",
"Unknown channel type",
"Resource shortage",
};
unsigned reason_code;
const char *reason_code_string;
char reason_code_buf[256];
char *reason_string;
int reason_length;

reason_code = ssh_pkt_getuint32(pktin);
if (reason_code < lenof(reasons) && reasons[reason_code]) {
reason_code_string = reasons[reason_code];
} else {
reason_code_string = reason_code_buf;
sprintf(reason_code_buf, "unknown reason code %#x", reason_code);
}

ssh_pkt_getstring(pktin, &reason_string, &reason_length);

return dupprintf("%s [%.*s]", reason_code_string,
reason_length, NULLTOEMPTY(reason_string));
}

static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
{
struct ssh_channel *c;

c = ssh_channel_msg(ssh, pktin);
Expand All @@ -8516,14 +8535,9 @@ static void ssh2_msg_channel_open_failure(Ssh ssh, struct Packet *pktin)
assert(c->halfopen); /* ssh_channel_msg will have enforced this */

if (c->type == CHAN_SOCKDATA) {
reason_code = ssh_pkt_getuint32(pktin);
if (reason_code >= lenof(reasons))
reason_code = 0; /* ensure reasons[reason_code] in range */
ssh_pkt_getstring(pktin, &reason_string, &reason_length);
logeventf(ssh, "Forwarded connection refused by server: %s [%.*s]",
reasons[reason_code], reason_length,
NULLTOEMPTY(reason_string));

char *errtext = ssh2_channel_open_failure_error_text(pktin);
logeventf(ssh, "Forwarded connection refused by server: %s", errtext);
sfree(errtext);
pfd_close(c->u.pfd.pf);
} else if (c->type == CHAN_ZOMBIE) {
/*
Expand Down Expand Up @@ -10727,15 +10741,24 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,
ssh->ncmode = FALSE;
}
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
bombout(("Server refused to open channel"));
if (pktin->type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION &&
pktin->type != SSH2_MSG_CHANNEL_OPEN_FAILURE) {
bombout(("Server sent strange packet %d in response to main "
"channel open request", pktin->type));
crStopV;
/* FIXME: error data comes back in FAILURE packet */
}
}
if (ssh_pkt_getuint32(pktin) != ssh->mainchan->localid) {
bombout(("Server's channel confirmation cited wrong channel"));
bombout(("Server's response to main channel open cited wrong"
" channel number"));
crStopV;
}
if (pktin->type == SSH2_MSG_CHANNEL_OPEN_FAILURE) {
char *errtext = ssh2_channel_open_failure_error_text(pktin);
bombout(("Server refused to open main channel: %s", errtext));
sfree(errtext);
crStopV;
}

ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
ssh->mainchan->halfopen = FALSE;
ssh->mainchan->type = CHAN_MAINSESSION;
Expand Down

0 comments on commit a9e1053

Please sign in to comment.