[BACK]Return to clientloop.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/clientloop.c between version 1.392 and 1.393

version 1.392, 2023/04/03 08:10:54 version 1.393, 2023/08/28 03:31:16
Line 498 
Line 498 
         schedule_server_alive_check();          schedule_server_alive_check();
 }  }
   
   /* Try to send a dummy keystroke */
   static int
   send_chaff(struct ssh *ssh)
   {
           int r;
   
           if ((ssh->kex->flags & KEX_HAS_PING) == 0)
                   return 0;
           /* XXX probabilistically send chaff? */
           /*
            * a SSH2_MSG_CHANNEL_DATA payload is 9 bytes:
            *    4 bytes channel ID + 4 bytes string length + 1 byte string data
            * simulate that here.
            */
           if ((r = sshpkt_start(ssh, SSH2_MSG_PING)) != 0 ||
               (r = sshpkt_put_cstring(ssh, "PING!")) != 0 ||
               (r = sshpkt_send(ssh)) != 0)
                   fatal_fr(r, "send packet");
           return 1;
   }
   
 /*  /*
    * Performs keystroke timing obfuscation. Returns non-zero if the
    * output fd should be polled.
    */
   static int
   obfuscate_keystroke_timing(struct ssh *ssh, struct timespec *timeout)
   {
           static int active;
           static struct timespec next_interval, chaff_until;
           struct timespec now, tmp;
           int just_started = 0, had_keystroke = 0;
           static unsigned long long nchaff;
           char *stop_reason = NULL;
           long long n;
   
           monotime_ts(&now);
   
           if (options.obscure_keystroke_timing_interval <= 0)
                   return 1;       /* disabled in config */
   
           if (!channel_still_open(ssh) || quit_pending) {
                   /* Stop if no channels left of we're waiting for one to close */
                   stop_reason = "no active channels";
           } else if (ssh_packet_is_rekeying(ssh)) {
                   /* Stop if we're rekeying */
                   stop_reason = "rekeying started";
           } else if (!ssh_packet_interactive_data_to_write(ssh) &&
               ssh_packet_have_data_to_write(ssh)) {
                   /* Stop if the output buffer has more than a few keystrokes */
                   stop_reason = "output buffer filling";
           } else if (active && ssh_packet_have_data_to_write(ssh)) {
                   /* Still in active mode and have a keystroke queued. */
                   had_keystroke = 1;
           } else if (active) {
                   if (timespeccmp(&now, &chaff_until, >=)) {
                           /* Stop if there have been no keystrokes for a while */
                           stop_reason = "chaff time expired";
                   } else if (timespeccmp(&now, &next_interval, >=)) {
                           /* Otherwise if we were due to send, then send chaff */
                           if (send_chaff(ssh))
                                   nchaff++;
                   }
           }
   
           if (stop_reason != NULL) {
                   active = 0;
                   debug3_f("stopping: %s (%llu chaff packets sent)",
                       stop_reason, nchaff);
                   return 1;
           }
   
           /*
            * If we're in interactive mode, and only have a small amount
            * of outbound data, then we assume that the user is typing
            * interactively. In this case, start quantising outbound packets to
            * fixed time intervals to hide inter-keystroke timing.
            */
           if (!active && ssh_packet_interactive_data_to_write(ssh)) {
                   debug3_f("starting: interval %d",
                       options.obscure_keystroke_timing_interval);
                   just_started = had_keystroke = active = 1;
                   nchaff = 0;
                   ms_to_timespec(&tmp, options.obscure_keystroke_timing_interval);
                   timespecadd(&now, &tmp, &next_interval);
           }
   
           /* Don't hold off if obfuscation inactive */
           if (!active)
                   return 1;
   
           if (had_keystroke) {
                   /*
                    * Arrange to send chaff packets for a random interval after
                    * the last keystroke was sent.
                    */
                   ms_to_timespec(&tmp, SSH_KEYSTROKE_CHAFF_MIN_MS +
                       arc4random_uniform(SSH_KEYSTROKE_CHAFF_RNG_MS));
                   timespecadd(&now, &tmp, &chaff_until);
           }
   
           ptimeout_deadline_monotime_tsp(timeout, &next_interval);
   
           if (just_started)
                   return 1;
   
           /* Don't arm output fd for poll until the timing interval has elapsed */
           if (timespeccmp(&now, &next_interval, <))
                   return 0;
   
           /* Calculate number of intervals missed since the last check */
           n = (now.tv_sec - next_interval.tv_sec) * 1000 * 1000 * 1000;
           n += now.tv_nsec - next_interval.tv_nsec;
           n /= options.obscure_keystroke_timing_interval * 1000 * 1000;
           n = (n < 0) ? 1 : n + 1;
   
           /* Advance to the next interval */
           ms_to_timespec(&tmp, options.obscure_keystroke_timing_interval * n);
           timespecadd(&now, &tmp, &next_interval);
           return 1;
   }
   
   /*
  * Waits until the client can do something (some data becomes available on   * Waits until the client can do something (some data becomes available on
  * one of the file descriptors).   * one of the file descriptors).
  */   */
Line 508 
Line 630 
     int *conn_in_readyp, int *conn_out_readyp)      int *conn_in_readyp, int *conn_out_readyp)
 {  {
         struct timespec timeout;          struct timespec timeout;
         int ret;          int ret, oready;
         u_int p;          u_int p;
   
         *conn_in_readyp = *conn_out_readyp = 0;          *conn_in_readyp = *conn_out_readyp = 0;
Line 528 
Line 650 
                 return;                  return;
         }          }
   
           oready = obfuscate_keystroke_timing(ssh, &timeout);
   
         /* Monitor server connection on reserved pollfd entries */          /* Monitor server connection on reserved pollfd entries */
         (*pfdp)[0].fd = connection_in;          (*pfdp)[0].fd = connection_in;
         (*pfdp)[0].events = POLLIN;          (*pfdp)[0].events = POLLIN;
         (*pfdp)[1].fd = connection_out;          (*pfdp)[1].fd = connection_out;
         (*pfdp)[1].events = ssh_packet_have_data_to_write(ssh) ? POLLOUT : 0;          (*pfdp)[1].events = (oready && ssh_packet_have_data_to_write(ssh)) ?
               POLLOUT : 0;
   
         /*          /*
          * Wait for something to happen.  This will suspend the process until           * Wait for something to happen.  This will suspend the process until
Line 549 
Line 674 
                     ssh_packet_get_rekey_timeout(ssh));                      ssh_packet_get_rekey_timeout(ssh));
         }          }
   
         ret = poll(*pfdp, *npfd_activep, ptimeout_get_ms(&timeout));          ret = ppoll(*pfdp, *npfd_activep, ptimeout_get_tsp(&timeout), NULL);
   
         if (ret == -1) {          if (ret == -1) {
                 /*                  /*

Legend:
Removed from v.1.392  
changed lines
  Added in v.1.393