]> andersk Git - gssapi-openssh.git/blobdiff - openssh/packet.c
Merged hpn13v5 to trunk.
[gssapi-openssh.git] / openssh / packet.c
index 36656baf4d08671bf601353b88f77a8b8195f4b0..695a0b35a0d93752bf64ef4a9a4e65cf9207a507 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: packet.c,v 1.148 2007/06/07 19:37:34 pvalchev Exp $ */
+/* $OpenBSD: packet.c,v 1.157 2008/07/10 18:08:11 markus Exp $ */
 /*
  * Author: Tatu Ylonen <ylo@cs.hut.fi>
  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
@@ -136,12 +136,18 @@ static int server_side = 0;
 /* Set to true if we are authenticated. */
 static int after_authentication = 0;
 
+int keep_alive_timeouts = 0;
+
+/* Set to the maximum time that we will wait to send or receive a packet */
+static int packet_timeout_ms = -1;
+
 /* Session key information for Encryption and MAC */
 Newkeys *newkeys[MODE_MAX];
 static struct packet_state {
        u_int32_t seqnr;
        u_int32_t packets;
        u_int64_t blocks;
+       u_int64_t bytes;
 } p_read, p_send;
 
 static u_int64_t max_blocks_in, max_blocks_out;
@@ -186,7 +192,21 @@ packet_set_connection(int fd_in, int fd_out)
                buffer_init(&outgoing_packet);
                buffer_init(&incoming_packet);
                TAILQ_INIT(&outgoing);
+               p_send.packets = p_read.packets = 0;
+       }
+}
+
+void
+packet_set_timeout(int timeout, int count)
+{
+       if (timeout == 0 || count == 0) {
+               packet_timeout_ms = -1;
+               return;
        }
+       if ((INT_MAX / 1000) / count < timeout)
+               packet_timeout_ms = INT_MAX;
+       else
+               packet_timeout_ms = timeout * count * 1000;
 }
 
 /* Returns 1 if remote host is connected via socket, 0 if not. */
@@ -293,18 +313,25 @@ packet_get_ssh1_cipher(void)
 }
 
 void
-packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets)
+packet_get_state(int mode, u_int32_t *seqnr, u_int64_t *blocks, u_int32_t *packets,
+    u_int64_t *bytes)
 {
        struct packet_state *state;
 
        state = (mode == MODE_IN) ? &p_read : &p_send;
-       *seqnr = state->seqnr;
-       *blocks = state->blocks;
-       *packets = state->packets;
+       if (seqnr)
+               *seqnr = state->seqnr;
+       if (blocks)
+               *blocks = state->blocks;
+       if (packets)
+               *packets = state->packets;
+       if (bytes)
+               *bytes = state->bytes;
 }
 
 void
-packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets)
+packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets,
+    u_int64_t bytes)
 {
        struct packet_state *state;
 
@@ -312,6 +339,7 @@ packet_set_state(int mode, u_int32_t seqnr, u_int64_t blocks, u_int32_t packets)
        state->seqnr = seqnr;
        state->blocks = blocks;
        state->packets = packets;
+       state->bytes = bytes;
 }
 
 /* returns 1 if connection is via ipv4 */
@@ -590,7 +618,8 @@ packet_send1(void)
        fprintf(stderr, "encrypted: ");
        buffer_dump(&output);
 #endif
-
+       p_send.packets++;
+       p_send.bytes += len + buffer_len(&outgoing_packet);
        buffer_clear(&outgoing_packet);
 
        /*
@@ -710,7 +739,7 @@ packet_enable_delayed_compress(void)
 /*
  * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
  */
-static void
+static int
 packet_send2_wrapped(void)
 {
        u_char type, *cp, *macbuf = NULL;
@@ -816,17 +845,20 @@ packet_send2_wrapped(void)
                if (!(datafellows & SSH_BUG_NOREKEY))
                        fatal("XXX too many packets with same key");
        p_send.blocks += (packet_length + 4) / block_size;
+       p_send.bytes += packet_length + 4;
        buffer_clear(&outgoing_packet);
 
        if (type == SSH2_MSG_NEWKEYS)
                set_newkeys(MODE_OUT);
        else if (type == SSH2_MSG_USERAUTH_SUCCESS && server_side)
                packet_enable_delayed_compress();
+       return(packet_length);
 }
 
-static void
+static int
 packet_send2(void)
 {
+        static int packet_length = 0;
        static int rekeying = 0;
        struct packet *p;
        u_char type, *cp;
@@ -844,7 +876,7 @@ packet_send2(void)
                        memcpy(&p->payload, &outgoing_packet, sizeof(Buffer));
                        buffer_init(&outgoing_packet);
                        TAILQ_INSERT_TAIL(&outgoing, p, next);
-                       return;
+                       return(sizeof(Buffer));
                }
        }
 
@@ -852,7 +884,7 @@ packet_send2(void)
        if (type == SSH2_MSG_KEXINIT)
                rekeying = 1;
 
-       packet_send2_wrapped();
+       packet_length = packet_send2_wrapped();
 
        /* after a NEWKEYS message we can send the complete queue */
        if (type == SSH2_MSG_NEWKEYS) {
@@ -865,19 +897,22 @@ packet_send2(void)
                            sizeof(Buffer));
                        TAILQ_REMOVE(&outgoing, p, next);
                        xfree(p);
-                       packet_send2_wrapped();
+                       packet_length += packet_send2_wrapped();
                }
        }
+       return(packet_length);
 }
 
-void
+int
 packet_send(void)
 {
+  int packet_len = 0;
        if (compat20)
-               packet_send2();
+               packet_len = packet_send2();
        else
                packet_send1();
        DBG(debug("packet_send done"));
+       return(packet_len);
 }
 
 /*
@@ -889,9 +924,11 @@ packet_send(void)
 int
 packet_read_seqnr(u_int32_t *seqnr_p)
 {
-       int type, len;
+       int type, len, ret, ms_remain;
        fd_set *setp;
        char buf[8192];
+       struct timeval timeout, start, *timeoutp = NULL;
+
        DBG(debug("packet_read()"));
 
        setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS),
@@ -923,11 +960,35 @@ packet_read_seqnr(u_int32_t *seqnr_p)
                    sizeof(fd_mask));
                FD_SET(connection_in, setp);
 
+               if (packet_timeout_ms > 0) {
+                       ms_remain = packet_timeout_ms;
+                       timeoutp = &timeout;
+               }
                /* Wait for some data to arrive. */
-               while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
-                   (errno == EAGAIN || errno == EINTR))
-                       ;
-
+               for (;;) {
+                       if (packet_timeout_ms != -1) {
+                               ms_to_timeval(&timeout, ms_remain);
+                               gettimeofday(&start, NULL);
+                       }
+                       if ((ret = select(connection_in + 1, setp, NULL,
+                           NULL, timeoutp)) >= 0)
+                               break;
+                       if (errno != EAGAIN && errno != EINTR &&
+                           errno != EWOULDBLOCK)
+                               break;
+                       if (packet_timeout_ms == -1)
+                               continue;
+                       ms_subtract_diff(&start, &ms_remain);
+                       if (ms_remain <= 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out while "
+                           "waiting to read", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
                /* Read data from the socket. */
                len = read(connection_in, buf, sizeof(buf));
                if (len == 0) {
@@ -1052,6 +1113,8 @@ packet_read_poll1(void)
                buffer_append(&incoming_packet, buffer_ptr(&compression_buffer),
                    buffer_len(&compression_buffer));
        }
+       p_read.packets++;
+       p_read.bytes += padded_len + 4;
        type = buffer_get_char(&incoming_packet);
        if (type < SSH_MSG_MIN || type > SSH_MSG_MAX)
                packet_disconnect("Invalid ssh1 packet type: %d", type);
@@ -1140,6 +1203,7 @@ packet_read_poll2(u_int32_t *seqnr_p)
                if (!(datafellows & SSH_BUG_NOREKEY))
                        fatal("XXX too many packets with same key");
        p_read.blocks += (packet_length + 4) / block_size;
+       p_read.bytes += packet_length + 4;
 
        /* get padlen */
        cp = buffer_ptr(&incoming_packet);
@@ -1192,10 +1256,13 @@ packet_read_poll_seqnr(u_int32_t *seqnr_p)
        for (;;) {
                if (compat20) {
                        type = packet_read_poll2(seqnr_p);
-                       if (type)
+                       if (type) {
+                               keep_alive_timeouts = 0;
                                DBG(debug("received packet type %d", type));
+                       }
                        switch (type) {
                        case SSH2_MSG_IGNORE:
+                               debug3("Received SSH2_MSG_IGNORE");
                                break;
                        case SSH2_MSG_DEBUG:
                                packet_get_char();
@@ -1328,6 +1395,12 @@ packet_get_string(u_int *length_ptr)
        return buffer_get_string(&incoming_packet, length_ptr);
 }
 
+void *
+packet_get_string_ptr(u_int *length_ptr)
+{
+       return buffer_get_string_ptr(&incoming_packet, length_ptr);
+}
+
 /*
  * Sends a diagnostic message from the server to the client.  This message
  * can be sent at any time (but not while constructing another message). The
@@ -1415,46 +1488,81 @@ packet_disconnect(const char *fmt,...)
 
 /* Checks if there is any buffered output, and tries to write some of the output. */
 
-void
+int
 packet_write_poll(void)
 {
-       int len = buffer_len(&output);
+       int len = 0;
+       len = buffer_len(&output);
 
        if (len > 0) {
                len = write(connection_out, buffer_ptr(&output), len);
-               if (len <= 0) {
-                       if (errno == EAGAIN)
-                               return;
-                       else
-                               fatal("Write failed: %.100s", strerror(errno));
+               if (len == -1) {
+                       if (errno == EINTR || errno == EAGAIN ||
+                           errno == EWOULDBLOCK)
+                               return (0);
+                       fatal("Write failed: %.100s", strerror(errno));
                }
+               if (len == 0)
+                       fatal("Write connection closed");
                buffer_consume(&output, len);
        }
+       return(len);
 }
 
+
 /*
  * Calls packet_write_poll repeatedly until all pending output data has been
  * written.
  */
 
-void
+int
 packet_write_wait(void)
 {
        fd_set *setp;
+       int ret, ms_remain;
+       struct timeval start, timeout, *timeoutp = NULL;
+       u_int bytes_sent = 0;
 
        setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS),
            sizeof(fd_mask));
-       packet_write_poll();
+       bytes_sent += packet_write_poll();
        while (packet_have_data_to_write()) {
                memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
                    sizeof(fd_mask));
                FD_SET(connection_out, setp);
-               while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
-                   (errno == EAGAIN || errno == EINTR))
-                       ;
-               packet_write_poll();
+
+               if (packet_timeout_ms > 0) {
+                       ms_remain = packet_timeout_ms;
+                       timeoutp = &timeout;
+               }
+               for (;;) {
+                       if (packet_timeout_ms != -1) {
+                               ms_to_timeval(&timeout, ms_remain);
+                               gettimeofday(&start, NULL);
+                       }
+                       if ((ret = select(connection_out + 1, NULL, setp,
+                           NULL, timeoutp)) >= 0)
+                               break;
+                       if (errno != EAGAIN && errno != EINTR &&
+                           errno != EWOULDBLOCK)
+                               break;
+                       if (packet_timeout_ms == -1)
+                               continue;
+                       ms_subtract_diff(&start, &ms_remain);
+                       if (ms_remain <= 0) {
+                               ret = 0;
+                               break;
+                       }
+               }
+               if (ret == 0) {
+                       logit("Connection to %.200s timed out while "
+                           "waiting to write", get_remote_ipaddr());
+                       cleanup_exit(255);
+               }
+               bytes_sent += packet_write_poll();
        }
        xfree(setp);
+       return (bytes_sent);
 }
 
 /* Returns true if there is buffered data to write to the connection. */
@@ -1575,8 +1683,8 @@ packet_send_ignore(int nbytes)
                rnd >>= 8;
        }
 }
-int rekey_requested = 0;
 
+int rekey_requested = 0;
 void
 packet_request_rekeying(void)
 {
@@ -1618,3 +1726,9 @@ packet_set_authenticated(void)
 {
        after_authentication = 1;
 }
+
+int
+packet_authentication_state(void)
+{
+       return(after_authentication);
+}
This page took 0.04966 seconds and 4 git commands to generate.