comparison common-session.c @ 939:a0819ecfee0b

Make -K keepalive behave like OpenSSH's ServerAliveInterval
author Matt Johnston <matt@ucc.asn.au>
date Wed, 09 Jul 2014 00:15:20 +0800
parents 9d40ed1da686
children e9dfb6d15193
comparison
equal deleted inserted replaced
938:c88dce72f6d2 939:a0819ecfee0b
49 /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */ 49 /* this is set when we get SIGINT or SIGTERM, the handler is in main.c */
50 int exitflag = 0; /* GLOBAL */ 50 int exitflag = 0; /* GLOBAL */
51 51
52 /* called only at the start of a session, set up initial state */ 52 /* called only at the start of a session, set up initial state */
53 void common_session_init(int sock_in, int sock_out) { 53 void common_session_init(int sock_in, int sock_out) {
54 time_t now;
54 55
55 TRACE(("enter session_init")) 56 TRACE(("enter session_init"))
56 57
57 ses.sock_in = sock_in; 58 ses.sock_in = sock_in;
58 ses.sock_out = sock_out; 59 ses.sock_out = sock_out;
59 ses.maxfd = MAX(sock_in, sock_out); 60 ses.maxfd = MAX(sock_in, sock_out);
60 61
61 ses.connect_time = 0; 62 now = monotonic_now();
62 ses.last_trx_packet_time = 0; 63 ses.connect_time = now;
63 ses.last_packet_time = 0; 64 ses.last_packet_time_keepalive_recv = now;
65 ses.last_packet_time_idle = now;
66 ses.last_packet_time_any_sent = 0;
67 ses.last_packet_time_keepalive_sent = 0;
64 68
65 if (pipe(ses.signal_pipe) < 0) { 69 if (pipe(ses.signal_pipe) < 0) {
66 dropbear_exit("Signal pipe failed"); 70 dropbear_exit("Signal pipe failed");
67 } 71 }
68 setnonblocking(ses.signal_pipe[0]); 72 setnonblocking(ses.signal_pipe[0]);
385 buf[pos] = '\0'; 389 buf[pos] = '\0';
386 TRACE(("leave ident_readln: return %d", pos+1)) 390 TRACE(("leave ident_readln: return %d", pos+1))
387 return pos+1; 391 return pos+1;
388 } 392 }
389 393
390 void send_msg_ignore() { 394 static void send_msg_keepalive() {
391 CHECKCLEARTOWRITE(); 395 CHECKCLEARTOWRITE();
392 buf_putbyte(ses.writepayload, SSH_MSG_IGNORE); 396 time_t old_time_idle = ses.last_packet_time_idle;
393 buf_putstring(ses.writepayload, "", 0); 397 /* Try to force a response from the other end. Some peers will
398 reply with SSH_MSG_REQUEST_FAILURE, some will reply with SSH_MSG_UNIMPLEMENTED */
399 buf_putbyte(ses.writepayload, SSH_MSG_GLOBAL_REQUEST);
400 /* A short string */
401 buf_putstring(ses.writepayload, "[email protected]", 0);
402 buf_putbyte(ses.writepayload, 1); /* want_reply */
394 encrypt_packet(); 403 encrypt_packet();
404
405 ses.last_packet_time_keepalive_sent = monotonic_now();
406
407 /* keepalives shouldn't update idle timeout, reset it back */
408 ses.last_packet_time_idle = old_time_idle;
395 } 409 }
396 410
397 /* Check all timeouts which are required. Currently these are the time for 411 /* Check all timeouts which are required. Currently these are the time for
398 * user authentication, and the automatic rekeying. */ 412 * user authentication, and the automatic rekeying. */
399 static void checktimeouts() { 413 static void checktimeouts() {
400 414
401 time_t now; 415 time_t now;
402 now = monotonic_now(); 416 now = monotonic_now();
403 417
404 if (ses.connect_time != 0 && now - ses.connect_time >= AUTH_TIMEOUT) { 418 if (now - ses.connect_time >= AUTH_TIMEOUT) {
405 dropbear_close("Timeout before auth"); 419 dropbear_close("Timeout before auth");
406 } 420 }
407 421
408 /* we can't rekey if we haven't done remote ident exchange yet */ 422 /* we can't rekey if we haven't done remote ident exchange yet */
409 if (ses.remoteident == NULL) { 423 if (ses.remoteident == NULL) {
415 || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) { 429 || ses.kexstate.datarecv+ses.kexstate.datatrans >= KEX_REKEY_DATA)) {
416 TRACE(("rekeying after timeout or max data reached")) 430 TRACE(("rekeying after timeout or max data reached"))
417 send_msg_kexinit(); 431 send_msg_kexinit();
418 } 432 }
419 433
420 if (opts.keepalive_secs > 0 434 if (opts.keepalive_secs > 0) {
421 && now - ses.last_trx_packet_time >= opts.keepalive_secs) { 435 /* Send keepalives if we've been idle */
422 send_msg_ignore(); 436 if (now - ses.last_packet_time_any_sent >= opts.keepalive_secs) {
423 } 437 send_msg_keepalive();
424 438 }
425 if (opts.idle_timeout_secs > 0 && ses.last_packet_time > 0 439
426 && now - ses.last_packet_time >= opts.idle_timeout_secs) { 440 /* Also send an explicit keepalive message to trigger a response
441 if the remote end hasn't sent us anything */
442 if (now - ses.last_packet_time_keepalive_recv >= opts.keepalive_secs
443 && now - ses.last_packet_time_keepalive_sent >= opts.keepalive_secs) {
444 send_msg_keepalive();
445 }
446
447 if (now - ses.last_packet_time_keepalive_recv
448 >= opts.keepalive_secs * DEFAULT_KEEPALIVE_LIMIT) {
449 dropbear_exit("Keepalive timeout");
450 }
451 }
452
453 if (opts.idle_timeout_secs > 0
454 && now - ses.last_packet_time_idle >= opts.idle_timeout_secs) {
427 dropbear_close("Idle timeout"); 455 dropbear_close("Idle timeout");
428 } 456 }
429 } 457 }
430 458
431 static long select_timeout() { 459 static long select_timeout() {