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

Diff for /src/usr.bin/ssh/packet.c between version 1.97.2.2 and 1.98

version 1.97.2.2, 2003/09/16 21:20:26 version 1.98, 2002/10/23 10:32:13
Line 39 
Line 39 
 #include "includes.h"  #include "includes.h"
 RCSID("$OpenBSD$");  RCSID("$OpenBSD$");
   
 #include <sys/queue.h>  
   
 #include "xmalloc.h"  #include "xmalloc.h"
 #include "buffer.h"  #include "buffer.h"
 #include "packet.h"  #include "packet.h"
Line 108 
Line 106 
 static int packet_compression = 0;  static int packet_compression = 0;
   
 /* default maximum packet size */  /* default maximum packet size */
 u_int max_packet_size = 32768;  int max_packet_size = 32768;
   
 /* Flag indicating whether this module has been initialized. */  /* Flag indicating whether this module has been initialized. */
 static int initialized = 0;  static int initialized = 0;
Line 118 
Line 116 
   
 /* Session key information for Encryption and MAC */  /* Session key information for Encryption and MAC */
 Newkeys *newkeys[MODE_MAX];  Newkeys *newkeys[MODE_MAX];
 static struct packet_state {  static u_int32_t read_seqnr = 0;
         u_int32_t seqnr;  static u_int32_t send_seqnr = 0;
         u_int32_t packets;  
         u_int64_t blocks;  
 } p_read, p_send;  
   
 static u_int64_t max_blocks_in, max_blocks_out;  
 static u_int32_t rekey_limit;  
   
 /* Session key for protocol v1 */  /* Session key for protocol v1 */
 static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];  static u_char ssh1_key[SSH_SESSION_KEY_LENGTH];
 static u_int ssh1_keylen;  static u_int ssh1_keylen;
Line 134 
Line 126 
 /* roundup current message to extra_pad bytes */  /* roundup current message to extra_pad bytes */
 static u_char extra_pad = 0;  static u_char extra_pad = 0;
   
 struct packet {  
         TAILQ_ENTRY(packet) next;  
         u_char type;  
         Buffer payload;  
 };  
 TAILQ_HEAD(, packet) outgoing;  
   
 /*  /*
  * Sets the descriptors used for communication.  Disables encryption until   * Sets the descriptors used for communication.  Disables encryption until
  * packet_set_encryption_key is called.   * packet_set_encryption_key is called.
Line 163 
Line 148 
                 buffer_init(&output);                  buffer_init(&output);
                 buffer_init(&outgoing_packet);                  buffer_init(&outgoing_packet);
                 buffer_init(&incoming_packet);                  buffer_init(&incoming_packet);
                 TAILQ_INIT(&outgoing);  
         }          }
         /* Kludge: arrange the close function to be called from fatal(). */          /* Kludge: arrange the close function to be called from fatal(). */
         fatal_add_cleanup((void (*) (void *)) packet_close, NULL);          fatal_add_cleanup((void (*) (void *)) packet_close, NULL);
Line 265 
Line 249 
         cipher_set_keyiv(cc, dat);          cipher_set_keyiv(cc, dat);
 }  }
 int  int
 packet_get_ssh1_cipher(void)  packet_get_ssh1_cipher()
 {  {
         return (cipher_get_number(receive_context.cipher));          return (cipher_get_number(receive_context.cipher));
 }  }
   
 void  
 packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets)  
 {  
         struct packet_state *state;  
   
         state = (mode == MODE_IN) ? &p_read : &p_send;  u_int32_t
         *seqnr = state->seqnr;  packet_get_seqnr(int mode)
         *blocks = state->blocks;  {
         *packets = state->packets;          return (mode == MODE_IN ? read_seqnr : send_seqnr);
 }  }
   
 void  void
 packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets)  packet_set_seqnr(int mode, u_int32_t seqnr)
 {  {
         struct packet_state *state;          if (mode == MODE_IN)
                   read_seqnr = seqnr;
         state = (mode == MODE_IN) ? &p_read : &p_send;          else if (mode == MODE_OUT)
         state->seqnr = seqnr;                  send_seqnr = seqnr;
         state->blocks = blocks;          else
         state->packets = packets;                  fatal("packet_set_seqnr: bad mode %d", mode);
 }  }
   
 /* returns 1 if connection is via ipv4 */  /* returns 1 if connection is via ipv4 */
Line 577 
Line 557 
         Mac *mac;          Mac *mac;
         Comp *comp;          Comp *comp;
         CipherContext *cc;          CipherContext *cc;
         u_int64_t *max_blocks;  
         int encrypt;          int encrypt;
   
         debug2("set_newkeys: mode %d", mode);          debug("newkeys: mode %d", mode);
   
         if (mode == MODE_OUT) {          if (mode == MODE_OUT) {
                 cc = &send_context;                  cc = &send_context;
                 encrypt = CIPHER_ENCRYPT;                  encrypt = CIPHER_ENCRYPT;
                 p_send.packets = p_send.blocks = 0;  
                 max_blocks = &max_blocks_out;  
         } else {          } else {
                 cc = &receive_context;                  cc = &receive_context;
                 encrypt = CIPHER_DECRYPT;                  encrypt = CIPHER_DECRYPT;
                 p_read.packets = p_read.blocks = 0;  
                 max_blocks = &max_blocks_in;  
         }          }
         if (newkeys[mode] != NULL) {          if (newkeys[mode] != NULL) {
                 debug("set_newkeys: rekeying");                  debug("newkeys: rekeying");
                 cipher_cleanup(cc);                  cipher_cleanup(cc);
                 enc  = &newkeys[mode]->enc;                  enc  = &newkeys[mode]->enc;
                 mac  = &newkeys[mode]->mac;                  mac  = &newkeys[mode]->mac;
Line 630 
Line 605 
                         buffer_compress_init_recv();                          buffer_compress_init_recv();
                 comp->enabled = 1;                  comp->enabled = 1;
         }          }
         /*  
          * The 2^(blocksize*2) limit is too expensive for 3DES,  
          * blowfish, etc, so enforce a 1GB limit for small blocksizes.  
          */  
         if (enc->block_size >= 16)  
                 *max_blocks = (u_int64_t)1 << (enc->block_size*2);  
         else  
                 *max_blocks = ((u_int64_t)1 << 30) / enc->block_size;  
         if (rekey_limit)  
                 *max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size);  
 }  }
   
 /*  /*
  * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)   * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
  */   */
 static void  static void
 packet_send2_wrapped(void)  packet_send2(void)
 {  {
         u_char type, *cp, *macbuf = NULL;          u_char type, *cp, *macbuf = NULL;
         u_char padlen, pad;          u_char padlen, pad;
Line 728 
Line 693 
   
         /* compute MAC over seqnr and packet(length fields, payload, padding) */          /* compute MAC over seqnr and packet(length fields, payload, padding) */
         if (mac && mac->enabled) {          if (mac && mac->enabled) {
                 macbuf = mac_compute(mac, p_send.seqnr,                  macbuf = mac_compute(mac, send_seqnr,
                     buffer_ptr(&outgoing_packet),                      buffer_ptr(&outgoing_packet),
                     buffer_len(&outgoing_packet));                      buffer_len(&outgoing_packet));
                 DBG(debug("done calc MAC out #%d", p_send.seqnr));                  DBG(debug("done calc MAC out #%d", send_seqnr));
         }          }
         /* encrypt packet and append to output buffer. */          /* encrypt packet and append to output buffer. */
         cp = buffer_append_space(&output, buffer_len(&outgoing_packet));          cp = buffer_append_space(&output, buffer_len(&outgoing_packet));
Line 745 
Line 710 
         buffer_dump(&output);          buffer_dump(&output);
 #endif  #endif
         /* increment sequence number for outgoing packets */          /* increment sequence number for outgoing packets */
         if (++p_send.seqnr == 0)          if (++send_seqnr == 0)
                 logit("outgoing seqnr wraps around");                  log("outgoing seqnr wraps around");
         if (++p_send.packets == 0)  
                 if (!(datafellows & SSH_BUG_NOREKEY))  
                         fatal("XXX too many packets with same key");  
         p_send.blocks += (packet_length + 4) / block_size;  
         buffer_clear(&outgoing_packet);          buffer_clear(&outgoing_packet);
   
         if (type == SSH2_MSG_NEWKEYS)          if (type == SSH2_MSG_NEWKEYS)
                 set_newkeys(MODE_OUT);                  set_newkeys(MODE_OUT);
 }  }
   
 static void  
 packet_send2(void)  
 {  
         static int rekeying = 0;  
         struct packet *p;  
         u_char type, *cp;  
   
         cp = buffer_ptr(&outgoing_packet);  
         type = cp[5];  
   
         /* during rekeying we can only send key exchange messages */  
         if (rekeying) {  
                 if (!((type >= SSH2_MSG_TRANSPORT_MIN) &&  
                     (type <= SSH2_MSG_TRANSPORT_MAX))) {  
                         debug("enqueue packet: %u", type);  
                         p = xmalloc(sizeof(*p));  
                         p->type = type;  
                         memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));  
                         buffer_init(&outgoing_packet);  
                         TAILQ_INSERT_TAIL(&outgoing, p, next);  
                         return;  
                 }  
         }  
   
         /* rekeying starts with sending KEXINIT */  
         if (type == SSH2_MSG_KEXINIT)  
                 rekeying = 1;  
   
         packet_send2_wrapped();  
   
         /* after a NEWKEYS message we can send the complete queue */  
         if (type == SSH2_MSG_NEWKEYS) {  
                 rekeying = 0;  
                 while ((p = TAILQ_FIRST(&outgoing))) {  
                         type = p->type;  
                         debug("dequeue packet: %u", type);  
                         buffer_free(&outgoing_packet);  
                         memcpy(&outgoing_packet, &p->payload,  
                             sizeof(Buffer));  
                         TAILQ_REMOVE(&outgoing, p, next);  
                         xfree(p);  
                         packet_send2_wrapped();  
                 }  
         }  
 }  
   
 void  void
 packet_send(void)  packet_send(void)
 {  {
Line 864 
Line 779 
                 /* Read data from the socket. */                  /* Read data from the socket. */
                 len = read(connection_in, buf, sizeof(buf));                  len = read(connection_in, buf, sizeof(buf));
                 if (len == 0) {                  if (len == 0) {
                         logit("Connection closed by %.200s", get_remote_ipaddr());                          log("Connection closed by %.200s", get_remote_ipaddr());
                         fatal_cleanup();                          fatal_cleanup();
                 }                  }
                 if (len < 0)                  if (len < 0)
Line 1046 
Line 961 
          * increment sequence number for incoming packet           * increment sequence number for incoming packet
          */           */
         if (mac && mac->enabled) {          if (mac && mac->enabled) {
                 macbuf = mac_compute(mac, p_read.seqnr,                  macbuf = mac_compute(mac, read_seqnr,
                     buffer_ptr(&incoming_packet),                      buffer_ptr(&incoming_packet),
                     buffer_len(&incoming_packet));                      buffer_len(&incoming_packet));
                 if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)                  if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0)
                         packet_disconnect("Corrupted MAC on input.");                          packet_disconnect("Corrupted MAC on input.");
                 DBG(debug("MAC #%d ok", p_read.seqnr));                  DBG(debug("MAC #%d ok", read_seqnr));
                 buffer_consume(&input, mac->mac_len);                  buffer_consume(&input, mac->mac_len);
         }          }
         if (seqnr_p != NULL)          if (seqnr_p != NULL)
                 *seqnr_p = p_read.seqnr;                  *seqnr_p = read_seqnr;
         if (++p_read.seqnr == 0)          if (++read_seqnr == 0)
                 logit("incoming seqnr wraps around");                  log("incoming seqnr wraps around");
         if (++p_read.packets == 0)  
                 if (!(datafellows & SSH_BUG_NOREKEY))  
                         fatal("XXX too many packets with same key");  
         p_read.blocks += (packet_length + 4) / block_size;  
   
         /* get padlen */          /* get padlen */
         cp = buffer_ptr(&incoming_packet);          cp = buffer_ptr(&incoming_packet);
Line 1126 
Line 1037 
                         case SSH2_MSG_DISCONNECT:                          case SSH2_MSG_DISCONNECT:
                                 reason = packet_get_int();                                  reason = packet_get_int();
                                 msg = packet_get_string(NULL);                                  msg = packet_get_string(NULL);
                                 logit("Received disconnect from %s: %u: %.400s",                                  log("Received disconnect from %s: %u: %.400s",
                                     get_remote_ipaddr(), reason, msg);                                      get_remote_ipaddr(), reason, msg);
                                 xfree(msg);                                  xfree(msg);
                                 fatal_cleanup();                                  fatal_cleanup();
Line 1152 
Line 1063 
                                 break;                                  break;
                         case SSH_MSG_DISCONNECT:                          case SSH_MSG_DISCONNECT:
                                 msg = packet_get_string(NULL);                                  msg = packet_get_string(NULL);
                                 logit("Received disconnect from %s: %.400s",                                  log("Received disconnect from %s: %.400s",
                                     get_remote_ipaddr(), msg);                                      get_remote_ipaddr(), msg);
                                 fatal_cleanup();                                  fatal_cleanup();
                                 xfree(msg);                                  xfree(msg);
Line 1310 
Line 1221 
         vsnprintf(buf, sizeof(buf), fmt, args);          vsnprintf(buf, sizeof(buf), fmt, args);
         va_end(args);          va_end(args);
   
         /* Display the error locally */  
         logit("Disconnecting: %.100s", buf);  
   
         /* Send the disconnect message to the other side, and wait for it to get sent. */          /* Send the disconnect message to the other side, and wait for it to get sent. */
         if (compat20) {          if (compat20) {
                 packet_start(SSH2_MSG_DISCONNECT);                  packet_start(SSH2_MSG_DISCONNECT);
Line 1332 
Line 1240 
         /* Close the connection. */          /* Close the connection. */
         packet_close();          packet_close();
   
           /* Display the error locally and exit. */
           log("Disconnecting: %.100s", buf);
         fatal_cleanup();          fatal_cleanup();
 }  }
   
Line 1398 
Line 1308 
                 return buffer_len(&output) < 128 * 1024;                  return buffer_len(&output) < 128 * 1024;
 }  }
   
 static void  
 packet_set_tos(int interactive)  
 {  
         int tos = interactive ? IPTOS_LOWDELAY : IPTOS_THROUGHPUT;  
   
         if (!packet_connection_is_on_socket() ||  
             !packet_connection_is_ipv4())  
                 return;  
         if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &tos,  
             sizeof(tos)) < 0)  
                 error("setsockopt IP_TOS %d: %.100s:",  
                     tos, strerror(errno));  
 }  
   
 /* Informs that the current session is interactive.  Sets IP flags for that. */  /* Informs that the current session is interactive.  Sets IP flags for that. */
   
 void  void
 packet_set_interactive(int interactive)  packet_set_interactive(int interactive)
 {  {
         static int called = 0;          static int called = 0;
           int lowdelay = IPTOS_LOWDELAY;
           int throughput = IPTOS_THROUGHPUT;
   
         if (called)          if (called)
                 return;                  return;
Line 1429 
Line 1327 
         /* Only set socket options if using a socket.  */          /* Only set socket options if using a socket.  */
         if (!packet_connection_is_on_socket())          if (!packet_connection_is_on_socket())
                 return;                  return;
         if (interactive)          /*
            * IPTOS_LOWDELAY and IPTOS_THROUGHPUT are IPv4 only
            */
           if (interactive) {
                   /*
                    * Set IP options for an interactive connection.  Use
                    * IPTOS_LOWDELAY and TCP_NODELAY.
                    */
                   if (packet_connection_is_ipv4()) {
                           if (setsockopt(connection_in, IPPROTO_IP, IP_TOS,
                               &lowdelay, sizeof(lowdelay)) < 0)
                                   error("setsockopt IPTOS_LOWDELAY: %.100s",
                                       strerror(errno));
                   }
                 set_nodelay(connection_in);                  set_nodelay(connection_in);
         packet_set_tos(interactive);          } else if (packet_connection_is_ipv4()) {
                   /*
                    * Set IP options for a non-interactive connection.  Use
                    * IPTOS_THROUGHPUT.
                    */
                   if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &throughput,
                       sizeof(throughput)) < 0)
                           error("setsockopt IPTOS_THROUGHPUT: %.100s", strerror(errno));
           }
 }  }
   
 /* Returns true if the current connection is interactive. */  /* Returns true if the current connection is interactive. */
Line 1442 
Line 1361 
         return interactive_mode;          return interactive_mode;
 }  }
   
 u_int  int
 packet_set_maxsize(u_int s)  packet_set_maxsize(int s)
 {  {
         static int called = 0;          static int called = 0;
   
         if (called) {          if (called) {
                 logit("packet_set_maxsize: called twice: old %d new %d",                  log("packet_set_maxsize: called twice: old %d new %d",
                     max_packet_size, s);                      max_packet_size, s);
                 return -1;                  return -1;
         }          }
         if (s < 4 * 1024 || s > 1024 * 1024) {          if (s < 4 * 1024 || s > 1024 * 1024) {
                 logit("packet_set_maxsize: bad size %d", s);                  log("packet_set_maxsize: bad size %d", s);
                 return -1;                  return -1;
         }          }
         called = 1;          called = 1;
Line 1494 
Line 1413 
                 packet_put_char(rand & 0xff);                  packet_put_char(rand & 0xff);
                 rand >>= 8;                  rand >>= 8;
         }          }
 }  
   
 #define MAX_PACKETS     (1<<31)  
 int  
 packet_need_rekeying(void)  
 {  
         if (datafellows & SSH_BUG_NOREKEY)  
                 return 0;  
         return  
             (p_send.packets > MAX_PACKETS) ||  
             (p_read.packets > MAX_PACKETS) ||  
             (max_blocks_out && (p_send.blocks > max_blocks_out)) ||  
             (max_blocks_in  && (p_read.blocks > max_blocks_in));  
 }  
   
 void  
 packet_set_rekey_limit(u_int32_t bytes)  
 {  
         rekey_limit = bytes;  
 }  }

Legend:
Removed from v.1.97.2.2  
changed lines
  Added in v.1.98