Re: dbclient can't connect to cisco
Il 16/11/18 15:25, Matt Johnston ha scritto: The problem is that waiting for the remote banner is still adding a round trip of delay. That's fine for a local network, but me -> dropbear.nl is half a second, that's no good. As long as we let the Cisco speak first, it is happy. So why don't we read a env var to optionally wait for incoming data before we send our first packet? All remains the same, we just swap who speaks first: it should not add any relevant delay. Cheers, TRACE (6250) 0.000821: -> KEXINIT TRACE2 (6250) 0.000824: update_timeout limit 0, now 19720, last 19720, timeout 28800 TRACE (6250) 0.000833: enter set_connect_fds TRACE (6250) 0.000843: setnonblocking: 8 TRACE (6250) 0.000848: leave setnonblocking TRACE (6250) 0.002446: maybe_empty_reply_queue - no data allowed TRACE (6250) 0.002484: enter handle_connect_fds TRACE (6250) 0.002500: handling 10.36.10.1 port 22 socket 8 TRACE (6250) 0.002525: update_channel_prio TRACE (6250) 0.002543: update_channel_prio: not any TRACE (6250) 0.002560: Dropbear priority transitioning 10 -> 11 TRACE (6250) 0.002612: Couldn't set IPV6_TCLASS (Protocol not available) TRACE (6250) 0.002620: leave handle_connect_fds - success TRACE2 (6250) 0.002624: enter cli_sessionloop (the patch is here) TRACE2 (6250) 0.002629: enter wait server TRACE2 (6250) 0.004485: leave wait server: ok TRACE2 (6250) 0.004521: exit cli_sessionloop: no real packets yet TRACE2 (6250) 0.004545: enter write_packet TRACE2 (6250) 0.004571: write_packet writev #0 type 0 len 26/26 TRACE2 (6250) 0.004591: write_packet writev #1 type 20 len 608/608 TRACE2 (6250) 0.004620: write_packet writev #2 type 30 len 48/48 TRACE (6250) 0.004688: empty queue dequeing TRACE2 (6250) 0.004693: leave write_packet TRACE2 (6250) 0.004700: update_timeout limit 0, now 19720, last 19720, timeout 28800 TRACE (6250) 0.004707: enter set_connect_fds TRACE (6250) 0.004716: enter ident_readln TRACE (6250) 0.004738: leave ident_readln: return 19 TRACE (6250) 0.004743: remoteident: SSH-2.0-Cisco-1.25 TRACE (6250) 0.004749: maybe_empty_reply_queue - no data allowed TRACE (6250) 0.004754: enter handle_connect_fds TRACE (6250) 0.004761: leave handle_connect_fds - end iter TRACE2 (6250) 0.004765: enter cli_sessionloop TRACE2 (6250) 0.004770: exit cli_sessionloop: no real packets yet TRACE2 (6250) 0.004777: update_timeout limit 0, now 19720, last 19720, timeout 28800 TRACE (6250) 0.004785: enter set_connect_fds TRACE2 (6250) 0.006470: enter read_packet TRACE2 (6250) 0.006512: packet size is 312, block 8 mac 0 TRACE2 (6250) 0.006541: enter decrypt_packet TRACE2 (6250) 0.006557: leave writemac TRACE2 (6250) 0.006577: leave decrypt_packet TRACE2 (6250) 0.006598: leave read_packet TRACE2 (6250) 0.006617: enter process_packet TRACE (6250) 0.006638: process_packet: packet type = 20, len 308 TRACE (6250) 0.006661: got expected packet 20 during kexinit TRACE (6250) 0.006703: <- KEXINIT diff -Naubr dropbear-2018.76.old/cli-session.c dropbear-2018.76.new/cli-session.c --- dropbear-2018.76.old/cli-session.c 2018-02-27 15:25:10.0 +0100 +++ dropbear-2018.76.new/cli-session.c 2018-11-16 19:35:07.781047284 +0100 @@ -140,6 +140,7 @@ #endif static void cli_session_init(pid_t proxy_cmd_pid) { + char *wait; cli_ses.state = STATE_NOTHING; cli_ses.kex_state = KEX_NOTHING; @@ -174,6 +175,11 @@ ses.packettypes = cli_packettypes; ses.isserver = 0; + if ((wait = getenv("DROPBEAR_WAIT_SERVER"))) { + ses.waitserver = strtol(wait, NULL, 10); + } else { + ses.waitserver = 0; + } #if DROPBEAR_KEX_FIRST_FOLLOWS ses.send_kex_first_guess = cli_send_kex_first_guess; @@ -201,10 +207,23 @@ /* This function drives the progress of the session - it initiates KEX, * service, userauth and channel requests */ static void cli_sessionloop() { + struct timeval wait_to; + fd_set wait_fd; TRACE2(("enter cli_sessionloop")) if (ses.lastpacket == 0) { + /* Wait for the server to speak first, making Cisco SSH servers happy */ + if (ses.waitserver > 0) { + TRACE2(("enter wait server")) + wait_to.tv_sec = ses.waitserver < 600 ? ses.waitserver : 600; + wait_to.tv_usec = 0; + FD_ZERO(_fd); + FD_SET(ses.sock_in, _fd); + ses.waitserver = select(ses.sock_in + 1, _fd, NULL, NULL, _to); + TRACE2(("leave wait server: %s", ses.waitserver > 0 ? "ok" : ses.waitserver == 0 ? "timeout" : "error")) + ses.waitserver = 0; + } TRACE2(("exit cli_sessionloop: no real packets yet")) return; } diff -Naubr dropbear-2018.76.old/session.h dropbear-2018.76.new/session.h --- dropbear-2018.76.old/session.h 2018-02-27 15:25:12.0 +0100 +++
Re: dbclient can't connect to cisco
> On Fri 16/11/2018, at 2:26 am, Nik Soggia wrote: > > So in the end if I delay the kexinit until there is some data on the wire I > will pull the rabbit out of the cylinder. The problem is that waiting for the remote banner is still adding a round trip of delay. That's fine for a local network, but me -> dropbear.nl is half a second, that's no good. Cheers, Matt
Re: dbclient can't connect to cisco
Il 14/11/18 16:13, Matt Johnston ha scritto: I'm not keen on changing dbclient, the current implementation saves a network roundtrip. It's perfectly reasonable according to the spec. If you have Cisco support could you report it to them? Unfortunately I don't have Cisco support. I think they did it on purpose, maybe to stop some kind of attack (back in the old days sendmail's greet_pause was enough to spot spambots). rfc4253: 5.2. New Client, Old Server RFC's are always right, it's definitely a cisco bug/feature! I'll try to register and report the problem to them, just for fun. Thank you, cheers -- /\/ / /-<
Re: dbclient can't connect to cisco
On Wed, Nov 14, 2018 at 06:20:59PM +0300, Konstantin Tokarev wrote: > Note that OpenSSH enables a couple of workarounds for Cisco-1.* > > https://github.com/openssh/openssh-portable/blob/master/compat.c#L88 The tricky thing is that dbclient can't do anything to work around it here. We haven't yet received the version banner when we send the first key exchange packet. Cheers, Matt
Re: dbclient can't connect to cisco
14.11.2018, 18:16, "Matt Johnston" : > Hi Nik, > >> dbclient sends "SSH-2.0-dropbear_2018.76\r\n" and kexinit >> cisco sends "SSH-2.0-Cisco-1.25\r\n" >> then cisco waits "ip ssh time-out" seconds and then closes the TCP socket. >> >> my conjecture is that cisco empties its receive buffer after sendind the >> identification string and then waits for the lost kexinit. >> To prove my idea I added a sleep() after the first write_packet(), and >> dbclient was able to connect to cisco (ios 12.4 and 15.1). > > Yes, it seems some Cisco SSH versions are buggy. Older IOS is possibly OK (I > did a bit of investigation about a year ago when someone reported similar). > > I'm not keen on changing dbclient, the current implementation saves a network > roundtrip. It's perfectly reasonable according to the spec. If you have Cisco > support could you report it to them? Note that OpenSSH enables a couple of workarounds for Cisco-1.* https://github.com/openssh/openssh-portable/blob/master/compat.c#L88 > > Cheers, > Matt > > rfc4253: > 5.2. New Client, Old Server > > Since the new client MAY immediately send additional data after its > identification string (before receiving the server's identification > string), ... -- Regards, Konstantin
Re: dbclient can't connect to cisco
Hi Nik, > > dbclient sends "SSH-2.0-dropbear_2018.76\r\n" and kexinit > cisco sends "SSH-2.0-Cisco-1.25\r\n" > then cisco waits "ip ssh time-out" seconds and then closes the TCP socket. > > my conjecture is that cisco empties its receive buffer after sendind the > identification string and then waits for the lost kexinit. > To prove my idea I added a sleep() after the first write_packet(), and > dbclient was able to connect to cisco (ios 12.4 and 15.1). Yes, it seems some Cisco SSH versions are buggy. Older IOS is possibly OK (I did a bit of investigation about a year ago when someone reported similar). I'm not keen on changing dbclient, the current implementation saves a network roundtrip. It's perfectly reasonable according to the spec. If you have Cisco support could you report it to them? Cheers, Matt rfc4253: 5.2. New Client, Old Server Since the new client MAY immediately send additional data after its identification string (before receiving the server's identification string), ...
dbclient can't connect to cisco
Hi, openssh can connect to cisco appliances and dbclient can't (but cisco ssh client can connect to dropbear). Thanks to tcpdump I think that I found the problem: openssh sends "SSH-2.0-OpenSSH_7.4 \r\n" cisco sends "SSH-2.0-Cisco-1.25\r\n" openssh sends kexinit cisco sends kexinit, then all runs fine. dbclient sends "SSH-2.0-dropbear_2018.76\r\n" and kexinit cisco sends "SSH-2.0-Cisco-1.25\r\n" then cisco waits "ip ssh time-out" seconds and then closes the TCP socket. my conjecture is that cisco empties its receive buffer after sendind the identification string and then waits for the lost kexinit. To prove my idea I added a sleep() after the first write_packet(), and dbclient was able to connect to cisco (ios 12.4 and 15.1). I took just a quick look at your sources and I think that waiting for a identification string before sending kexinit is a lot of work, am I right? diff -Naubr dropbear-2018.76.old/packet.c dropbear-2018.76.new/packet.c --- dropbear-2018.76.old/packet.c2018-02-27 15:25:12.0 +0100 +++ dropbear-2018.76.new/packet.c2018-11-13 14:52:43.696775952 +0100 @@ -54,10 +54,13 @@ #endif /* non-blocking function writing out a current encrypted packet */ +int ciscobug = 1; void write_packet() { ssize_t written; #ifdef HAVE_WRITEV +#endif +#if defined(KEEP_CALM_AND_NEVER_USE_WRITEV) /* 50 is somewhat arbitrary */ unsigned int iov_count = 50; struct iovec iov[50]; @@ -71,6 +74,8 @@ dropbear_assert(!isempty()); #if defined(HAVE_WRITEV) && (defined(IOV_MAX) || defined(UIO_MAXIOV)) +#endif +#if defined(KEEP_CALM_AND_NEVER_USE_WRITEV) packet_queue_to_iovec(, iov, _count); /* This may return EAGAIN. The main loop sometimes @@ -106,6 +111,8 @@ dropbear_assert(len > 0); /* Try to write as much as possible */ written = write(ses.sock_out, buf_getptr(writebuf, len), len); +sleep(ciscobug); +ciscobug = 0; if (written < 0) { if (errno == EINTR || errno == EAGAIN) { -- /\/ / /-<