version 1.160, 2009/02/13 11:50:21 |
version 1.161, 2009/05/25 06:48:01 |
|
|
|
|
#define PACKET_MAX_SIZE (256 * 1024) |
#define PACKET_MAX_SIZE (256 * 1024) |
|
|
/* |
struct packet_state { |
* This variable contains the file descriptors used for communicating with |
u_int32_t seqnr; |
* the other side. connection_in is used for reading; connection_out for |
u_int32_t packets; |
* writing. These can be the same descriptor, in which case it is assumed to |
u_int64_t blocks; |
* be a socket. |
u_int64_t bytes; |
*/ |
}; |
static int connection_in = -1; |
|
static int connection_out = -1; |
|
|
|
/* Protocol flags for the remote side. */ |
struct packet { |
static u_int remote_protocol_flags = 0; |
TAILQ_ENTRY(packet) next; |
|
u_char type; |
|
Buffer payload; |
|
}; |
|
|
/* Encryption context for receiving data. This is only used for decryption. */ |
struct session_state { |
static CipherContext receive_context; |
/* |
|
* This variable contains the file descriptors used for |
|
* communicating with the other side. connection_in is used for |
|
* reading; connection_out for writing. These can be the same |
|
* descriptor, in which case it is assumed to be a socket. |
|
*/ |
|
int connection_in; |
|
int connection_out; |
|
|
/* Encryption context for sending data. This is only used for encryption. */ |
/* Protocol flags for the remote side. */ |
static CipherContext send_context; |
u_int remote_protocol_flags; |
|
|
/* Buffer for raw input data from the socket. */ |
/* Encryption context for receiving data. Only used for decryption. */ |
Buffer input; |
CipherContext receive_context; |
|
|
/* Buffer for raw output data going to the socket. */ |
/* Encryption context for sending data. Only used for encryption. */ |
Buffer output; |
CipherContext send_context; |
|
|
/* Buffer for the partial outgoing packet being constructed. */ |
/* Buffer for raw input data from the socket. */ |
static Buffer outgoing_packet; |
Buffer input; |
|
|
/* Buffer for the incoming packet currently being processed. */ |
/* Buffer for raw output data going to the socket. */ |
static Buffer incoming_packet; |
Buffer output; |
|
|
/* Scratch buffer for packet compression/decompression. */ |
/* Buffer for the partial outgoing packet being constructed. */ |
static Buffer compression_buffer; |
Buffer outgoing_packet; |
static int compression_buffer_ready = 0; |
|
|
|
/* Flag indicating whether packet compression/decompression is enabled. */ |
/* Buffer for the incoming packet currently being processed. */ |
static int packet_compression = 0; |
Buffer incoming_packet; |
|
|
/* default maximum packet size */ |
/* Scratch buffer for packet compression/decompression. */ |
u_int max_packet_size = 32768; |
Buffer compression_buffer; |
|
int compression_buffer_ready; |
|
|
/* Flag indicating whether this module has been initialized. */ |
/* |
static int initialized = 0; |
* Flag indicating whether packet compression/decompression is |
|
* enabled. |
|
*/ |
|
int packet_compression; |
|
|
/* Set to true if the connection is interactive. */ |
/* default maximum packet size */ |
static int interactive_mode = 0; |
u_int max_packet_size; |
|
|
/* Set to true if we are the server side. */ |
/* Flag indicating whether this module has been initialized. */ |
static int server_side = 0; |
int initialized; |
|
|
/* Set to true if we are authenticated. */ |
/* Set to true if the connection is interactive. */ |
static int after_authentication = 0; |
int interactive_mode; |
|
|
int keep_alive_timeouts = 0; |
/* Set to true if we are the server side. */ |
|
int server_side; |
|
|
/* Set to the maximum time that we will wait to send or receive a packet */ |
/* Set to true if we are authenticated. */ |
static int packet_timeout_ms = -1; |
int after_authentication; |
|
|
/* Session key information for Encryption and MAC */ |
int keep_alive_timeouts; |
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; |
/* The maximum time that we will wait to send or receive a packet */ |
static u_int32_t rekey_limit; |
int packet_timeout_ms; |
|
|
/* Session key for protocol v1 */ |
/* Session key information for Encryption and MAC */ |
static u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
Newkeys *newkeys[MODE_MAX]; |
static u_int ssh1_keylen; |
struct packet_state p_read, p_send; |
|
|
/* roundup current message to extra_pad bytes */ |
u_int64_t max_blocks_in, max_blocks_out; |
static u_char extra_pad = 0; |
u_int32_t rekey_limit; |
|
|
/* XXX discard incoming data after MAC error */ |
/* Session key for protocol v1 */ |
static u_int packet_discard = 0; |
u_char ssh1_key[SSH_SESSION_KEY_LENGTH]; |
static Mac *packet_discard_mac = NULL; |
u_int ssh1_keylen; |
|
|
struct packet { |
/* roundup current message to extra_pad bytes */ |
TAILQ_ENTRY(packet) next; |
u_char extra_pad; |
u_char type; |
|
Buffer payload; |
/* XXX discard incoming data after MAC error */ |
|
u_int packet_discard; |
|
Mac *packet_discard_mac; |
|
|
|
/* Used in packet_read_poll2() */ |
|
u_int packlen; |
|
|
|
TAILQ_HEAD(, packet) outgoing; |
}; |
}; |
TAILQ_HEAD(, packet) outgoing; |
|
|
|
|
static struct session_state *active_state; |
|
|
|
static struct session_state * |
|
alloc_session_state() |
|
{ |
|
struct session_state *s = xcalloc(1, sizeof(*s)); |
|
|
|
s->connection_in = -1; |
|
s->connection_out = -1; |
|
s->max_packet_size = 32768; |
|
s->packet_timeout_ms = -1; |
|
return s; |
|
} |
|
|
/* |
/* |
* 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. |
|
|
|
|
if (none == NULL) |
if (none == NULL) |
fatal("packet_set_connection: cannot load cipher 'none'"); |
fatal("packet_set_connection: cannot load cipher 'none'"); |
connection_in = fd_in; |
if (active_state == NULL) |
connection_out = fd_out; |
active_state = alloc_session_state(); |
cipher_init(&send_context, none, (const u_char *)"", |
active_state->connection_in = fd_in; |
|
active_state->connection_out = fd_out; |
|
cipher_init(&active_state->send_context, none, (const u_char *)"", |
0, NULL, 0, CIPHER_ENCRYPT); |
0, NULL, 0, CIPHER_ENCRYPT); |
cipher_init(&receive_context, none, (const u_char *)"", |
cipher_init(&active_state->receive_context, none, (const u_char *)"", |
0, NULL, 0, CIPHER_DECRYPT); |
0, NULL, 0, CIPHER_DECRYPT); |
newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL; |
active_state->newkeys[MODE_IN] = active_state->newkeys[MODE_OUT] = NULL; |
if (!initialized) { |
if (!active_state->initialized) { |
initialized = 1; |
active_state->initialized = 1; |
buffer_init(&input); |
buffer_init(&active_state->input); |
buffer_init(&output); |
buffer_init(&active_state->output); |
buffer_init(&outgoing_packet); |
buffer_init(&active_state->outgoing_packet); |
buffer_init(&incoming_packet); |
buffer_init(&active_state->incoming_packet); |
TAILQ_INIT(&outgoing); |
TAILQ_INIT(&active_state->outgoing); |
p_send.packets = p_read.packets = 0; |
active_state->p_send.packets = active_state->p_read.packets = 0; |
} |
} |
} |
} |
|
|
|
|
packet_set_timeout(int timeout, int count) |
packet_set_timeout(int timeout, int count) |
{ |
{ |
if (timeout == 0 || count == 0) { |
if (timeout == 0 || count == 0) { |
packet_timeout_ms = -1; |
active_state->packet_timeout_ms = -1; |
return; |
return; |
} |
} |
if ((INT_MAX / 1000) / count < timeout) |
if ((INT_MAX / 1000) / count < timeout) |
packet_timeout_ms = INT_MAX; |
active_state->packet_timeout_ms = INT_MAX; |
else |
else |
packet_timeout_ms = timeout * count * 1000; |
active_state->packet_timeout_ms = timeout * count * 1000; |
} |
} |
|
|
static void |
static void |
packet_stop_discard(void) |
packet_stop_discard(void) |
{ |
{ |
if (packet_discard_mac) { |
if (active_state->packet_discard_mac) { |
char buf[1024]; |
char buf[1024]; |
|
|
memset(buf, 'a', sizeof(buf)); |
memset(buf, 'a', sizeof(buf)); |
while (buffer_len(&incoming_packet) < PACKET_MAX_SIZE) |
while (buffer_len(&active_state->incoming_packet) < |
buffer_append(&incoming_packet, buf, sizeof(buf)); |
PACKET_MAX_SIZE) |
(void) mac_compute(packet_discard_mac, |
buffer_append(&active_state->incoming_packet, buf, |
p_read.seqnr, |
sizeof(buf)); |
buffer_ptr(&incoming_packet), |
(void) mac_compute(active_state->packet_discard_mac, |
|
active_state->p_read.seqnr, |
|
buffer_ptr(&active_state->incoming_packet), |
PACKET_MAX_SIZE); |
PACKET_MAX_SIZE); |
} |
} |
logit("Finished discarding for %.200s", get_remote_ipaddr()); |
logit("Finished discarding for %.200s", get_remote_ipaddr()); |
|
|
if (enc == NULL || !cipher_is_cbc(enc->cipher)) |
if (enc == NULL || !cipher_is_cbc(enc->cipher)) |
packet_disconnect("Packet corrupt"); |
packet_disconnect("Packet corrupt"); |
if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) |
if (packet_length != PACKET_MAX_SIZE && mac && mac->enabled) |
packet_discard_mac = mac; |
active_state->packet_discard_mac = mac; |
if (buffer_len(&input) >= discard) |
if (buffer_len(&active_state->input) >= discard) |
packet_stop_discard(); |
packet_stop_discard(); |
packet_discard = discard - buffer_len(&input); |
active_state->packet_discard = discard - |
|
buffer_len(&active_state->input); |
} |
} |
|
|
/* Returns 1 if remote host is connected via socket, 0 if not. */ |
/* Returns 1 if remote host is connected via socket, 0 if not. */ |
|
|
socklen_t fromlen, tolen; |
socklen_t fromlen, tolen; |
|
|
/* filedescriptors in and out are the same, so it's a socket */ |
/* filedescriptors in and out are the same, so it's a socket */ |
if (connection_in == connection_out) |
if (active_state->connection_in == active_state->connection_out) |
return 1; |
return 1; |
fromlen = sizeof(from); |
fromlen = sizeof(from); |
memset(&from, 0, sizeof(from)); |
memset(&from, 0, sizeof(from)); |
if (getpeername(connection_in, (struct sockaddr *)&from, &fromlen) < 0) |
if (getpeername(active_state->connection_in, (struct sockaddr *)&from, |
|
&fromlen) < 0) |
return 0; |
return 0; |
tolen = sizeof(to); |
tolen = sizeof(to); |
memset(&to, 0, sizeof(to)); |
memset(&to, 0, sizeof(to)); |
if (getpeername(connection_out, (struct sockaddr *)&to, &tolen) < 0) |
if (getpeername(active_state->connection_out, (struct sockaddr *)&to, |
|
&tolen) < 0) |
return 0; |
return 0; |
if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) |
if (fromlen != tolen || memcmp(&from, &to, fromlen) != 0) |
return 0; |
return 0; |
|
|
CipherContext *cc; |
CipherContext *cc; |
|
|
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
cc = &send_context; |
cc = &active_state->send_context; |
else |
else |
cc = &receive_context; |
cc = &active_state->receive_context; |
|
|
cipher_get_keyiv(cc, iv, len); |
cipher_get_keyiv(cc, iv, len); |
} |
} |
|
|
CipherContext *cc; |
CipherContext *cc; |
|
|
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
cc = &send_context; |
cc = &active_state->send_context; |
else |
else |
cc = &receive_context; |
cc = &active_state->receive_context; |
|
|
return (cipher_get_keycontext(cc, dat)); |
return (cipher_get_keycontext(cc, dat)); |
} |
} |
|
|
CipherContext *cc; |
CipherContext *cc; |
|
|
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
cc = &send_context; |
cc = &active_state->send_context; |
else |
else |
cc = &receive_context; |
cc = &active_state->receive_context; |
|
|
cipher_set_keycontext(cc, dat); |
cipher_set_keycontext(cc, dat); |
} |
} |
|
|
CipherContext *cc; |
CipherContext *cc; |
|
|
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
cc = &send_context; |
cc = &active_state->send_context; |
else |
else |
cc = &receive_context; |
cc = &active_state->receive_context; |
|
|
return (cipher_get_keyiv_len(cc)); |
return (cipher_get_keyiv_len(cc)); |
} |
} |
|
|
CipherContext *cc; |
CipherContext *cc; |
|
|
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
cc = &send_context; |
cc = &active_state->send_context; |
else |
else |
cc = &receive_context; |
cc = &active_state->receive_context; |
|
|
cipher_set_keyiv(cc, dat); |
cipher_set_keyiv(cc, dat); |
} |
} |
|
|
int |
int |
packet_get_ssh1_cipher(void) |
packet_get_ssh1_cipher(void) |
{ |
{ |
return (cipher_get_number(receive_context.cipher)); |
return (cipher_get_number(active_state->receive_context.cipher)); |
} |
} |
|
|
void |
void |
|
|
{ |
{ |
struct packet_state *state; |
struct packet_state *state; |
|
|
state = (mode == MODE_IN) ? &p_read : &p_send; |
state = (mode == MODE_IN) ? |
|
&active_state->p_read : &active_state->p_send; |
if (seqnr) |
if (seqnr) |
*seqnr = state->seqnr; |
*seqnr = state->seqnr; |
if (blocks) |
if (blocks) |
|
|
{ |
{ |
struct packet_state *state; |
struct packet_state *state; |
|
|
state = (mode == MODE_IN) ? &p_read : &p_send; |
state = (mode == MODE_IN) ? |
|
&active_state->p_read : &active_state->p_send; |
state->seqnr = seqnr; |
state->seqnr = seqnr; |
state->blocks = blocks; |
state->blocks = blocks; |
state->packets = packets; |
state->packets = packets; |
|
|
socklen_t tolen = sizeof(to); |
socklen_t tolen = sizeof(to); |
|
|
memset(&to, 0, sizeof(to)); |
memset(&to, 0, sizeof(to)); |
if (getsockname(connection_out, (struct sockaddr *)&to, &tolen) < 0) |
if (getsockname(active_state->connection_out, (struct sockaddr *)&to, |
|
&tolen) < 0) |
return 0; |
return 0; |
if (to.ss_family != AF_INET) |
if (to.ss_family != AF_INET) |
return 0; |
return 0; |
|
|
packet_set_nonblocking(void) |
packet_set_nonblocking(void) |
{ |
{ |
/* Set the socket into non-blocking mode. */ |
/* Set the socket into non-blocking mode. */ |
set_nonblock(connection_in); |
set_nonblock(active_state->connection_in); |
|
|
if (connection_out != connection_in) |
if (active_state->connection_out != active_state->connection_in) |
set_nonblock(connection_out); |
set_nonblock(active_state->connection_out); |
} |
} |
|
|
/* Returns the socket used for reading. */ |
/* Returns the socket used for reading. */ |
|
|
int |
int |
packet_get_connection_in(void) |
packet_get_connection_in(void) |
{ |
{ |
return connection_in; |
return active_state->connection_in; |
} |
} |
|
|
/* Returns the descriptor used for writing. */ |
/* Returns the descriptor used for writing. */ |
|
|
int |
int |
packet_get_connection_out(void) |
packet_get_connection_out(void) |
{ |
{ |
return connection_out; |
return active_state->connection_out; |
} |
} |
|
|
/* Closes the connection and clears and frees internal data structures. */ |
/* Closes the connection and clears and frees internal data structures. */ |
|
|
void |
void |
packet_close(void) |
packet_close(void) |
{ |
{ |
if (!initialized) |
if (!active_state->initialized) |
return; |
return; |
initialized = 0; |
active_state->initialized = 0; |
if (connection_in == connection_out) { |
if (active_state->connection_in == active_state->connection_out) { |
shutdown(connection_out, SHUT_RDWR); |
shutdown(active_state->connection_out, SHUT_RDWR); |
close(connection_out); |
close(active_state->connection_out); |
} else { |
} else { |
close(connection_in); |
close(active_state->connection_in); |
close(connection_out); |
close(active_state->connection_out); |
} |
} |
buffer_free(&input); |
buffer_free(&active_state->input); |
buffer_free(&output); |
buffer_free(&active_state->output); |
buffer_free(&outgoing_packet); |
buffer_free(&active_state->outgoing_packet); |
buffer_free(&incoming_packet); |
buffer_free(&active_state->incoming_packet); |
if (compression_buffer_ready) { |
if (active_state->compression_buffer_ready) { |
buffer_free(&compression_buffer); |
buffer_free(&active_state->compression_buffer); |
buffer_compress_uninit(); |
buffer_compress_uninit(); |
} |
} |
cipher_cleanup(&send_context); |
cipher_cleanup(&active_state->send_context); |
cipher_cleanup(&receive_context); |
cipher_cleanup(&active_state->receive_context); |
} |
} |
|
|
/* Sets remote side protocol flags. */ |
/* Sets remote side protocol flags. */ |
|
|
void |
void |
packet_set_protocol_flags(u_int protocol_flags) |
packet_set_protocol_flags(u_int protocol_flags) |
{ |
{ |
remote_protocol_flags = protocol_flags; |
active_state->remote_protocol_flags = protocol_flags; |
} |
} |
|
|
/* Returns the remote protocol flags set earlier by the above function. */ |
/* Returns the remote protocol flags set earlier by the above function. */ |
|
|
u_int |
u_int |
packet_get_protocol_flags(void) |
packet_get_protocol_flags(void) |
{ |
{ |
return remote_protocol_flags; |
return active_state->remote_protocol_flags; |
} |
} |
|
|
/* |
/* |
|
|
static void |
static void |
packet_init_compression(void) |
packet_init_compression(void) |
{ |
{ |
if (compression_buffer_ready == 1) |
if (active_state->compression_buffer_ready == 1) |
return; |
return; |
compression_buffer_ready = 1; |
active_state->compression_buffer_ready = 1; |
buffer_init(&compression_buffer); |
buffer_init(&active_state->compression_buffer); |
} |
} |
|
|
void |
void |
packet_start_compression(int level) |
packet_start_compression(int level) |
{ |
{ |
if (packet_compression && !compat20) |
if (active_state->packet_compression && !compat20) |
fatal("Compression already enabled."); |
fatal("Compression already enabled."); |
packet_compression = 1; |
active_state->packet_compression = 1; |
packet_init_compression(); |
packet_init_compression(); |
buffer_compress_init_send(level); |
buffer_compress_init_send(level); |
buffer_compress_init_recv(); |
buffer_compress_init_recv(); |
|
|
fatal("packet_set_encryption_key: keylen too small: %d", keylen); |
fatal("packet_set_encryption_key: keylen too small: %d", keylen); |
if (keylen > SSH_SESSION_KEY_LENGTH) |
if (keylen > SSH_SESSION_KEY_LENGTH) |
fatal("packet_set_encryption_key: keylen too big: %d", keylen); |
fatal("packet_set_encryption_key: keylen too big: %d", keylen); |
memcpy(ssh1_key, key, keylen); |
memcpy(active_state->ssh1_key, key, keylen); |
ssh1_keylen = keylen; |
active_state->ssh1_keylen = keylen; |
cipher_init(&send_context, cipher, key, keylen, NULL, 0, CIPHER_ENCRYPT); |
cipher_init(&active_state->send_context, cipher, key, keylen, NULL, |
cipher_init(&receive_context, cipher, key, keylen, NULL, 0, CIPHER_DECRYPT); |
0, CIPHER_ENCRYPT); |
|
cipher_init(&active_state->receive_context, cipher, key, keylen, NULL, |
|
0, CIPHER_DECRYPT); |
} |
} |
|
|
u_int |
u_int |
packet_get_encryption_key(u_char *key) |
packet_get_encryption_key(u_char *key) |
{ |
{ |
if (key == NULL) |
if (key == NULL) |
return (ssh1_keylen); |
return (active_state->ssh1_keylen); |
memcpy(key, ssh1_key, ssh1_keylen); |
memcpy(key, active_state->ssh1_key, active_state->ssh1_keylen); |
return (ssh1_keylen); |
return (active_state->ssh1_keylen); |
} |
} |
|
|
/* Start constructing a packet to send. */ |
/* Start constructing a packet to send. */ |
|
|
len = compat20 ? 6 : 9; |
len = compat20 ? 6 : 9; |
memset(buf, 0, len - 1); |
memset(buf, 0, len - 1); |
buf[len - 1] = type; |
buf[len - 1] = type; |
buffer_clear(&outgoing_packet); |
buffer_clear(&active_state->outgoing_packet); |
buffer_append(&outgoing_packet, buf, len); |
buffer_append(&active_state->outgoing_packet, buf, len); |
} |
} |
|
|
/* Append payload. */ |
/* Append payload. */ |
|
|
{ |
{ |
char ch = value; |
char ch = value; |
|
|
buffer_append(&outgoing_packet, &ch, 1); |
buffer_append(&active_state->outgoing_packet, &ch, 1); |
} |
} |
|
|
void |
void |
packet_put_int(u_int value) |
packet_put_int(u_int value) |
{ |
{ |
buffer_put_int(&outgoing_packet, value); |
buffer_put_int(&active_state->outgoing_packet, value); |
} |
} |
|
|
void |
void |
packet_put_string(const void *buf, u_int len) |
packet_put_string(const void *buf, u_int len) |
{ |
{ |
buffer_put_string(&outgoing_packet, buf, len); |
buffer_put_string(&active_state->outgoing_packet, buf, len); |
} |
} |
|
|
void |
void |
packet_put_cstring(const char *str) |
packet_put_cstring(const char *str) |
{ |
{ |
buffer_put_cstring(&outgoing_packet, str); |
buffer_put_cstring(&active_state->outgoing_packet, str); |
} |
} |
|
|
void |
void |
packet_put_raw(const void *buf, u_int len) |
packet_put_raw(const void *buf, u_int len) |
{ |
{ |
buffer_append(&outgoing_packet, buf, len); |
buffer_append(&active_state->outgoing_packet, buf, len); |
} |
} |
|
|
void |
void |
packet_put_bignum(BIGNUM * value) |
packet_put_bignum(BIGNUM * value) |
{ |
{ |
buffer_put_bignum(&outgoing_packet, value); |
buffer_put_bignum(&active_state->outgoing_packet, value); |
} |
} |
|
|
void |
void |
packet_put_bignum2(BIGNUM * value) |
packet_put_bignum2(BIGNUM * value) |
{ |
{ |
buffer_put_bignum2(&outgoing_packet, value); |
buffer_put_bignum2(&active_state->outgoing_packet, value); |
} |
} |
|
|
/* |
/* |
|
|
* If using packet compression, compress the payload of the outgoing |
* If using packet compression, compress the payload of the outgoing |
* packet. |
* packet. |
*/ |
*/ |
if (packet_compression) { |
if (active_state->packet_compression) { |
buffer_clear(&compression_buffer); |
buffer_clear(&active_state->compression_buffer); |
/* Skip padding. */ |
/* Skip padding. */ |
buffer_consume(&outgoing_packet, 8); |
buffer_consume(&active_state->outgoing_packet, 8); |
/* padding */ |
/* padding */ |
buffer_append(&compression_buffer, "\0\0\0\0\0\0\0\0", 8); |
buffer_append(&active_state->compression_buffer, |
buffer_compress(&outgoing_packet, &compression_buffer); |
"\0\0\0\0\0\0\0\0", 8); |
buffer_clear(&outgoing_packet); |
buffer_compress(&active_state->outgoing_packet, |
buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), |
&active_state->compression_buffer); |
buffer_len(&compression_buffer)); |
buffer_clear(&active_state->outgoing_packet); |
|
buffer_append(&active_state->outgoing_packet, |
|
buffer_ptr(&active_state->compression_buffer), |
|
buffer_len(&active_state->compression_buffer)); |
} |
} |
/* Compute packet length without padding (add checksum, remove padding). */ |
/* Compute packet length without padding (add checksum, remove padding). */ |
len = buffer_len(&outgoing_packet) + 4 - 8; |
len = buffer_len(&active_state->outgoing_packet) + 4 - 8; |
|
|
/* Insert padding. Initialized to zero in packet_start1() */ |
/* Insert padding. Initialized to zero in packet_start1() */ |
padding = 8 - len % 8; |
padding = 8 - len % 8; |
if (!send_context.plaintext) { |
if (!active_state->send_context.plaintext) { |
cp = buffer_ptr(&outgoing_packet); |
cp = buffer_ptr(&active_state->outgoing_packet); |
for (i = 0; i < padding; i++) { |
for (i = 0; i < padding; i++) { |
if (i % 4 == 0) |
if (i % 4 == 0) |
rnd = arc4random(); |
rnd = arc4random(); |
|
|
rnd >>= 8; |
rnd >>= 8; |
} |
} |
} |
} |
buffer_consume(&outgoing_packet, 8 - padding); |
buffer_consume(&active_state->outgoing_packet, 8 - padding); |
|
|
/* Add check bytes. */ |
/* Add check bytes. */ |
checksum = ssh_crc32(buffer_ptr(&outgoing_packet), |
checksum = ssh_crc32(buffer_ptr(&active_state->outgoing_packet), |
buffer_len(&outgoing_packet)); |
buffer_len(&active_state->outgoing_packet)); |
put_u32(buf, checksum); |
put_u32(buf, checksum); |
buffer_append(&outgoing_packet, buf, 4); |
buffer_append(&active_state->outgoing_packet, buf, 4); |
|
|
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "packet_send plain: "); |
fprintf(stderr, "packet_send plain: "); |
buffer_dump(&outgoing_packet); |
buffer_dump(&active_state->outgoing_packet); |
#endif |
#endif |
|
|
/* Append to output. */ |
/* Append to output. */ |
put_u32(buf, len); |
put_u32(buf, len); |
buffer_append(&output, buf, 4); |
buffer_append(&active_state->output, buf, 4); |
cp = buffer_append_space(&output, buffer_len(&outgoing_packet)); |
cp = buffer_append_space(&active_state->output, |
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), |
buffer_len(&active_state->outgoing_packet)); |
buffer_len(&outgoing_packet)); |
cipher_crypt(&active_state->send_context, cp, |
|
buffer_ptr(&active_state->outgoing_packet), |
|
buffer_len(&active_state->outgoing_packet)); |
|
|
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "encrypted: "); |
fprintf(stderr, "encrypted: "); |
buffer_dump(&output); |
buffer_dump(&active_state->output); |
#endif |
#endif |
p_send.packets++; |
active_state->p_send.packets++; |
p_send.bytes += len + buffer_len(&outgoing_packet); |
active_state->p_send.bytes += len + |
buffer_clear(&outgoing_packet); |
buffer_len(&active_state->outgoing_packet); |
|
buffer_clear(&active_state->outgoing_packet); |
|
|
/* |
/* |
* Note that the packet is now only buffered in output. It won't be |
* Note that the packet is now only buffered in output. It won't be |
|
|
debug2("set_newkeys: mode %d", mode); |
debug2("set_newkeys: mode %d", mode); |
|
|
if (mode == MODE_OUT) { |
if (mode == MODE_OUT) { |
cc = &send_context; |
cc = &active_state->send_context; |
crypt_type = CIPHER_ENCRYPT; |
crypt_type = CIPHER_ENCRYPT; |
p_send.packets = p_send.blocks = 0; |
active_state->p_send.packets = active_state->p_send.blocks = 0; |
max_blocks = &max_blocks_out; |
max_blocks = &active_state->max_blocks_out; |
} else { |
} else { |
cc = &receive_context; |
cc = &active_state->receive_context; |
crypt_type = CIPHER_DECRYPT; |
crypt_type = CIPHER_DECRYPT; |
p_read.packets = p_read.blocks = 0; |
active_state->p_read.packets = active_state->p_read.blocks = 0; |
max_blocks = &max_blocks_in; |
max_blocks = &active_state->max_blocks_in; |
} |
} |
if (newkeys[mode] != NULL) { |
if (active_state->newkeys[mode] != NULL) { |
debug("set_newkeys: rekeying"); |
debug("set_newkeys: rekeying"); |
cipher_cleanup(cc); |
cipher_cleanup(cc); |
enc = &newkeys[mode]->enc; |
enc = &active_state->newkeys[mode]->enc; |
mac = &newkeys[mode]->mac; |
mac = &active_state->newkeys[mode]->mac; |
comp = &newkeys[mode]->comp; |
comp = &active_state->newkeys[mode]->comp; |
mac_clear(mac); |
mac_clear(mac); |
xfree(enc->name); |
xfree(enc->name); |
xfree(enc->iv); |
xfree(enc->iv); |
|
|
xfree(mac->name); |
xfree(mac->name); |
xfree(mac->key); |
xfree(mac->key); |
xfree(comp->name); |
xfree(comp->name); |
xfree(newkeys[mode]); |
xfree(active_state->newkeys[mode]); |
} |
} |
newkeys[mode] = kex_get_newkeys(mode); |
active_state->newkeys[mode] = kex_get_newkeys(mode); |
if (newkeys[mode] == NULL) |
if (active_state->newkeys[mode] == NULL) |
fatal("newkeys: no keys for mode %d", mode); |
fatal("newkeys: no keys for mode %d", mode); |
enc = &newkeys[mode]->enc; |
enc = &active_state->newkeys[mode]->enc; |
mac = &newkeys[mode]->mac; |
mac = &active_state->newkeys[mode]->mac; |
comp = &newkeys[mode]->comp; |
comp = &active_state->newkeys[mode]->comp; |
if (mac_init(mac) == 0) |
if (mac_init(mac) == 0) |
mac->enabled = 1; |
mac->enabled = 1; |
DBG(debug("cipher_init_context: %d", mode)); |
DBG(debug("cipher_init_context: %d", mode)); |
|
|
memset(enc->key, 0, enc->key_len); |
memset(enc->key, 0, enc->key_len); |
memset(mac->key, 0, mac->key_len); */ |
memset(mac->key, 0, mac->key_len); */ |
if ((comp->type == COMP_ZLIB || |
if ((comp->type == COMP_ZLIB || |
(comp->type == COMP_DELAYED && after_authentication)) && |
(comp->type == COMP_DELAYED && |
comp->enabled == 0) { |
active_state->after_authentication)) && comp->enabled == 0) { |
packet_init_compression(); |
packet_init_compression(); |
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
buffer_compress_init_send(6); |
buffer_compress_init_send(6); |
|
|
*max_blocks = (u_int64_t)1 << (enc->block_size*2); |
*max_blocks = (u_int64_t)1 << (enc->block_size*2); |
else |
else |
*max_blocks = ((u_int64_t)1 << 30) / enc->block_size; |
*max_blocks = ((u_int64_t)1 << 30) / enc->block_size; |
if (rekey_limit) |
if (active_state->rekey_limit) |
*max_blocks = MIN(*max_blocks, rekey_limit / enc->block_size); |
*max_blocks = MIN(*max_blocks, |
|
active_state->rekey_limit / enc->block_size); |
} |
} |
|
|
/* |
/* |
|
|
* Remember that we are past the authentication step, so rekeying |
* Remember that we are past the authentication step, so rekeying |
* with COMP_DELAYED will turn on compression immediately. |
* with COMP_DELAYED will turn on compression immediately. |
*/ |
*/ |
after_authentication = 1; |
active_state->after_authentication = 1; |
for (mode = 0; mode < MODE_MAX; mode++) { |
for (mode = 0; mode < MODE_MAX; mode++) { |
/* protocol error: USERAUTH_SUCCESS received before NEWKEYS */ |
/* protocol error: USERAUTH_SUCCESS received before NEWKEYS */ |
if (newkeys[mode] == NULL) |
if (active_state->newkeys[mode] == NULL) |
continue; |
continue; |
comp = &newkeys[mode]->comp; |
comp = &active_state->newkeys[mode]->comp; |
if (comp && !comp->enabled && comp->type == COMP_DELAYED) { |
if (comp && !comp->enabled && comp->type == COMP_DELAYED) { |
packet_init_compression(); |
packet_init_compression(); |
if (mode == MODE_OUT) |
if (mode == MODE_OUT) |
|
|
Comp *comp = NULL; |
Comp *comp = NULL; |
int block_size; |
int block_size; |
|
|
if (newkeys[MODE_OUT] != NULL) { |
if (active_state->newkeys[MODE_OUT] != NULL) { |
enc = &newkeys[MODE_OUT]->enc; |
enc = &active_state->newkeys[MODE_OUT]->enc; |
mac = &newkeys[MODE_OUT]->mac; |
mac = &active_state->newkeys[MODE_OUT]->mac; |
comp = &newkeys[MODE_OUT]->comp; |
comp = &active_state->newkeys[MODE_OUT]->comp; |
} |
} |
block_size = enc ? enc->block_size : 8; |
block_size = enc ? enc->block_size : 8; |
|
|
cp = buffer_ptr(&outgoing_packet); |
cp = buffer_ptr(&active_state->outgoing_packet); |
type = cp[5]; |
type = cp[5]; |
|
|
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "plain: "); |
fprintf(stderr, "plain: "); |
buffer_dump(&outgoing_packet); |
buffer_dump(&active_state->outgoing_packet); |
#endif |
#endif |
|
|
if (comp && comp->enabled) { |
if (comp && comp->enabled) { |
len = buffer_len(&outgoing_packet); |
len = buffer_len(&active_state->outgoing_packet); |
/* skip header, compress only payload */ |
/* skip header, compress only payload */ |
buffer_consume(&outgoing_packet, 5); |
buffer_consume(&active_state->outgoing_packet, 5); |
buffer_clear(&compression_buffer); |
buffer_clear(&active_state->compression_buffer); |
buffer_compress(&outgoing_packet, &compression_buffer); |
buffer_compress(&active_state->outgoing_packet, |
buffer_clear(&outgoing_packet); |
&active_state->compression_buffer); |
buffer_append(&outgoing_packet, "\0\0\0\0\0", 5); |
buffer_clear(&active_state->outgoing_packet); |
buffer_append(&outgoing_packet, buffer_ptr(&compression_buffer), |
buffer_append(&active_state->outgoing_packet, "\0\0\0\0\0", 5); |
buffer_len(&compression_buffer)); |
buffer_append(&active_state->outgoing_packet, |
|
buffer_ptr(&active_state->compression_buffer), |
|
buffer_len(&active_state->compression_buffer)); |
DBG(debug("compression: raw %d compressed %d", len, |
DBG(debug("compression: raw %d compressed %d", len, |
buffer_len(&outgoing_packet))); |
buffer_len(&active_state->outgoing_packet))); |
} |
} |
|
|
/* sizeof (packet_len + pad_len + payload) */ |
/* sizeof (packet_len + pad_len + payload) */ |
len = buffer_len(&outgoing_packet); |
len = buffer_len(&active_state->outgoing_packet); |
|
|
/* |
/* |
* calc size of padding, alloc space, get random data, |
* calc size of padding, alloc space, get random data, |
|
|
padlen = block_size - (len % block_size); |
padlen = block_size - (len % block_size); |
if (padlen < 4) |
if (padlen < 4) |
padlen += block_size; |
padlen += block_size; |
if (extra_pad) { |
if (active_state->extra_pad) { |
/* will wrap if extra_pad+padlen > 255 */ |
/* will wrap if extra_pad+padlen > 255 */ |
extra_pad = roundup(extra_pad, block_size); |
active_state->extra_pad = |
pad = extra_pad - ((len + padlen) % extra_pad); |
roundup(active_state->extra_pad, block_size); |
|
pad = active_state->extra_pad - |
|
((len + padlen) % active_state->extra_pad); |
debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)", |
debug3("packet_send2: adding %d (len %d padlen %d extra_pad %d)", |
pad, len, padlen, extra_pad); |
pad, len, padlen, active_state->extra_pad); |
padlen += pad; |
padlen += pad; |
extra_pad = 0; |
active_state->extra_pad = 0; |
} |
} |
cp = buffer_append_space(&outgoing_packet, padlen); |
cp = buffer_append_space(&active_state->outgoing_packet, padlen); |
if (enc && !send_context.plaintext) { |
if (enc && !active_state->send_context.plaintext) { |
/* random padding */ |
/* random padding */ |
for (i = 0; i < padlen; i++) { |
for (i = 0; i < padlen; i++) { |
if (i % 4 == 0) |
if (i % 4 == 0) |
|
|
memset(cp, 0, padlen); |
memset(cp, 0, padlen); |
} |
} |
/* packet_length includes payload, padding and padding length field */ |
/* packet_length includes payload, padding and padding length field */ |
packet_length = buffer_len(&outgoing_packet) - 4; |
packet_length = buffer_len(&active_state->outgoing_packet) - 4; |
cp = buffer_ptr(&outgoing_packet); |
cp = buffer_ptr(&active_state->outgoing_packet); |
put_u32(cp, packet_length); |
put_u32(cp, packet_length); |
cp[4] = padlen; |
cp[4] = padlen; |
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); |
DBG(debug("send: len %d (includes padlen %d)", packet_length+4, padlen)); |
|
|
/* 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, active_state->p_send.seqnr, |
buffer_ptr(&outgoing_packet), |
buffer_ptr(&active_state->outgoing_packet), |
buffer_len(&outgoing_packet)); |
buffer_len(&active_state->outgoing_packet)); |
DBG(debug("done calc MAC out #%d", p_send.seqnr)); |
DBG(debug("done calc MAC out #%d", active_state->p_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(&active_state->output, |
cipher_crypt(&send_context, cp, buffer_ptr(&outgoing_packet), |
buffer_len(&active_state->outgoing_packet)); |
buffer_len(&outgoing_packet)); |
cipher_crypt(&active_state->send_context, cp, |
|
buffer_ptr(&active_state->outgoing_packet), |
|
buffer_len(&active_state->outgoing_packet)); |
/* append unencrypted MAC */ |
/* append unencrypted MAC */ |
if (mac && mac->enabled) |
if (mac && mac->enabled) |
buffer_append(&output, macbuf, mac->mac_len); |
buffer_append(&active_state->output, macbuf, mac->mac_len); |
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "encrypted: "); |
fprintf(stderr, "encrypted: "); |
buffer_dump(&output); |
buffer_dump(&active_state->output); |
#endif |
#endif |
/* increment sequence number for outgoing packets */ |
/* increment sequence number for outgoing packets */ |
if (++p_send.seqnr == 0) |
if (++active_state->p_send.seqnr == 0) |
logit("outgoing seqnr wraps around"); |
logit("outgoing seqnr wraps around"); |
if (++p_send.packets == 0) |
if (++active_state->p_send.packets == 0) |
if (!(datafellows & SSH_BUG_NOREKEY)) |
if (!(datafellows & SSH_BUG_NOREKEY)) |
fatal("XXX too many packets with same key"); |
fatal("XXX too many packets with same key"); |
p_send.blocks += (packet_length + 4) / block_size; |
active_state->p_send.blocks += (packet_length + 4) / block_size; |
p_send.bytes += packet_length + 4; |
active_state->p_send.bytes += packet_length + 4; |
buffer_clear(&outgoing_packet); |
buffer_clear(&active_state->outgoing_packet); |
|
|
if (type == SSH2_MSG_NEWKEYS) |
if (type == SSH2_MSG_NEWKEYS) |
set_newkeys(MODE_OUT); |
set_newkeys(MODE_OUT); |
else if (type == SSH2_MSG_USERAUTH_SUCCESS && server_side) |
else if (type == SSH2_MSG_USERAUTH_SUCCESS && active_state->server_side) |
packet_enable_delayed_compress(); |
packet_enable_delayed_compress(); |
} |
} |
|
|
|
|
struct packet *p; |
struct packet *p; |
u_char type, *cp; |
u_char type, *cp; |
|
|
cp = buffer_ptr(&outgoing_packet); |
cp = buffer_ptr(&active_state->outgoing_packet); |
type = cp[5]; |
type = cp[5]; |
|
|
/* during rekeying we can only send key exchange messages */ |
/* during rekeying we can only send key exchange messages */ |
|
|
debug("enqueue packet: %u", type); |
debug("enqueue packet: %u", type); |
p = xmalloc(sizeof(*p)); |
p = xmalloc(sizeof(*p)); |
p->type = type; |
p->type = type; |
memcpy(&p->payload, &outgoing_packet, sizeof(Buffer)); |
memcpy(&p->payload, &active_state->outgoing_packet, |
buffer_init(&outgoing_packet); |
sizeof(Buffer)); |
TAILQ_INSERT_TAIL(&outgoing, p, next); |
buffer_init(&active_state->outgoing_packet); |
|
TAILQ_INSERT_TAIL(&active_state->outgoing, p, next); |
return; |
return; |
} |
} |
} |
} |
|
|
/* after a NEWKEYS message we can send the complete queue */ |
/* after a NEWKEYS message we can send the complete queue */ |
if (type == SSH2_MSG_NEWKEYS) { |
if (type == SSH2_MSG_NEWKEYS) { |
rekeying = 0; |
rekeying = 0; |
while ((p = TAILQ_FIRST(&outgoing))) { |
while ((p = TAILQ_FIRST(&active_state->outgoing))) { |
type = p->type; |
type = p->type; |
debug("dequeue packet: %u", type); |
debug("dequeue packet: %u", type); |
buffer_free(&outgoing_packet); |
buffer_free(&active_state->outgoing_packet); |
memcpy(&outgoing_packet, &p->payload, |
memcpy(&active_state->outgoing_packet, &p->payload, |
sizeof(Buffer)); |
sizeof(Buffer)); |
TAILQ_REMOVE(&outgoing, p, next); |
TAILQ_REMOVE(&active_state->outgoing, p, next); |
xfree(p); |
xfree(p); |
packet_send2_wrapped(); |
packet_send2_wrapped(); |
} |
} |
|
|
|
|
DBG(debug("packet_read()")); |
DBG(debug("packet_read()")); |
|
|
setp = (fd_set *)xcalloc(howmany(connection_in+1, NFDBITS), |
setp = (fd_set *)xcalloc(howmany(active_state->connection_in + 1, |
sizeof(fd_mask)); |
NFDBITS), sizeof(fd_mask)); |
|
|
/* Since we are blocking, ensure that all written packets have been sent. */ |
/* Since we are blocking, ensure that all written packets have been sent. */ |
packet_write_wait(); |
packet_write_wait(); |
|
|
* Otherwise, wait for some data to arrive, add it to the |
* Otherwise, wait for some data to arrive, add it to the |
* buffer, and try again. |
* buffer, and try again. |
*/ |
*/ |
memset(setp, 0, howmany(connection_in + 1, NFDBITS) * |
memset(setp, 0, howmany(active_state->connection_in + 1, |
sizeof(fd_mask)); |
NFDBITS) * sizeof(fd_mask)); |
FD_SET(connection_in, setp); |
FD_SET(active_state->connection_in, setp); |
|
|
if (packet_timeout_ms > 0) { |
if (active_state->packet_timeout_ms > 0) { |
ms_remain = packet_timeout_ms; |
ms_remain = active_state->packet_timeout_ms; |
timeoutp = &timeout; |
timeoutp = &timeout; |
} |
} |
/* Wait for some data to arrive. */ |
/* Wait for some data to arrive. */ |
for (;;) { |
for (;;) { |
if (packet_timeout_ms != -1) { |
if (active_state->packet_timeout_ms != -1) { |
ms_to_timeval(&timeout, ms_remain); |
ms_to_timeval(&timeout, ms_remain); |
gettimeofday(&start, NULL); |
gettimeofday(&start, NULL); |
} |
} |
if ((ret = select(connection_in + 1, setp, NULL, |
if ((ret = select(active_state->connection_in + 1, setp, |
NULL, timeoutp)) >= 0) |
NULL, NULL, timeoutp)) >= 0) |
break; |
break; |
if (errno != EAGAIN && errno != EINTR) |
if (errno != EAGAIN && errno != EINTR) |
break; |
break; |
if (packet_timeout_ms == -1) |
if (active_state->packet_timeout_ms == -1) |
continue; |
continue; |
ms_subtract_diff(&start, &ms_remain); |
ms_subtract_diff(&start, &ms_remain); |
if (ms_remain <= 0) { |
if (ms_remain <= 0) { |
|
|
cleanup_exit(255); |
cleanup_exit(255); |
} |
} |
/* Read data from the socket. */ |
/* Read data from the socket. */ |
len = read(connection_in, buf, sizeof(buf)); |
len = read(active_state->connection_in, buf, sizeof(buf)); |
if (len == 0) { |
if (len == 0) { |
logit("Connection closed by %.200s", get_remote_ipaddr()); |
logit("Connection closed by %.200s", get_remote_ipaddr()); |
cleanup_exit(255); |
cleanup_exit(255); |
|
|
u_int checksum, stored_checksum; |
u_int checksum, stored_checksum; |
|
|
/* Check if input size is less than minimum packet size. */ |
/* Check if input size is less than minimum packet size. */ |
if (buffer_len(&input) < 4 + 8) |
if (buffer_len(&active_state->input) < 4 + 8) |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
/* Get length of incoming packet. */ |
/* Get length of incoming packet. */ |
cp = buffer_ptr(&input); |
cp = buffer_ptr(&active_state->input); |
len = get_u32(cp); |
len = get_u32(cp); |
if (len < 1 + 2 + 2 || len > 256 * 1024) |
if (len < 1 + 2 + 2 || len > 256 * 1024) |
packet_disconnect("Bad packet length %u.", len); |
packet_disconnect("Bad packet length %u.", len); |
padded_len = (len + 8) & ~7; |
padded_len = (len + 8) & ~7; |
|
|
/* Check if the packet has been entirely received. */ |
/* Check if the packet has been entirely received. */ |
if (buffer_len(&input) < 4 + padded_len) |
if (buffer_len(&active_state->input) < 4 + padded_len) |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
|
|
/* The entire packet is in buffer. */ |
/* The entire packet is in buffer. */ |
|
|
/* Consume packet length. */ |
/* Consume packet length. */ |
buffer_consume(&input, 4); |
buffer_consume(&active_state->input, 4); |
|
|
/* |
/* |
* Cryptographic attack detector for ssh |
* Cryptographic attack detector for ssh |
* (C)1998 CORE-SDI, Buenos Aires Argentina |
* (C)1998 CORE-SDI, Buenos Aires Argentina |
* Ariel Futoransky(futo@core-sdi.com) |
* Ariel Futoransky(futo@core-sdi.com) |
*/ |
*/ |
if (!receive_context.plaintext) { |
if (!active_state->receive_context.plaintext) { |
switch (detect_attack(buffer_ptr(&input), padded_len)) { |
switch (detect_attack(buffer_ptr(&active_state->input), |
|
padded_len)) { |
case DEATTACK_DETECTED: |
case DEATTACK_DETECTED: |
packet_disconnect("crc32 compensation attack: " |
packet_disconnect("crc32 compensation attack: " |
"network attack detected"); |
"network attack detected"); |
|
|
} |
} |
|
|
/* Decrypt data to incoming_packet. */ |
/* Decrypt data to incoming_packet. */ |
buffer_clear(&incoming_packet); |
buffer_clear(&active_state->incoming_packet); |
cp = buffer_append_space(&incoming_packet, padded_len); |
cp = buffer_append_space(&active_state->incoming_packet, padded_len); |
cipher_crypt(&receive_context, cp, buffer_ptr(&input), padded_len); |
cipher_crypt(&active_state->receive_context, cp, |
|
buffer_ptr(&active_state->input), padded_len); |
|
|
buffer_consume(&input, padded_len); |
buffer_consume(&active_state->input, padded_len); |
|
|
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "read_poll plain: "); |
fprintf(stderr, "read_poll plain: "); |
buffer_dump(&incoming_packet); |
buffer_dump(&active_state->incoming_packet); |
#endif |
#endif |
|
|
/* Compute packet checksum. */ |
/* Compute packet checksum. */ |
checksum = ssh_crc32(buffer_ptr(&incoming_packet), |
checksum = ssh_crc32(buffer_ptr(&active_state->incoming_packet), |
buffer_len(&incoming_packet) - 4); |
buffer_len(&active_state->incoming_packet) - 4); |
|
|
/* Skip padding. */ |
/* Skip padding. */ |
buffer_consume(&incoming_packet, 8 - len % 8); |
buffer_consume(&active_state->incoming_packet, 8 - len % 8); |
|
|
/* Test check bytes. */ |
/* Test check bytes. */ |
if (len != buffer_len(&incoming_packet)) |
if (len != buffer_len(&active_state->incoming_packet)) |
packet_disconnect("packet_read_poll1: len %d != buffer_len %d.", |
packet_disconnect("packet_read_poll1: len %d != buffer_len %d.", |
len, buffer_len(&incoming_packet)); |
len, buffer_len(&active_state->incoming_packet)); |
|
|
cp = (u_char *)buffer_ptr(&incoming_packet) + len - 4; |
cp = (u_char *)buffer_ptr(&active_state->incoming_packet) + len - 4; |
stored_checksum = get_u32(cp); |
stored_checksum = get_u32(cp); |
if (checksum != stored_checksum) |
if (checksum != stored_checksum) |
packet_disconnect("Corrupted check bytes on input."); |
packet_disconnect("Corrupted check bytes on input."); |
buffer_consume_end(&incoming_packet, 4); |
buffer_consume_end(&active_state->incoming_packet, 4); |
|
|
if (packet_compression) { |
if (active_state->packet_compression) { |
buffer_clear(&compression_buffer); |
buffer_clear(&active_state->compression_buffer); |
buffer_uncompress(&incoming_packet, &compression_buffer); |
buffer_uncompress(&active_state->incoming_packet, |
buffer_clear(&incoming_packet); |
&active_state->compression_buffer); |
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), |
buffer_clear(&active_state->incoming_packet); |
buffer_len(&compression_buffer)); |
buffer_append(&active_state->incoming_packet, |
|
buffer_ptr(&active_state->compression_buffer), |
|
buffer_len(&active_state->compression_buffer)); |
} |
} |
p_read.packets++; |
active_state->p_read.packets++; |
p_read.bytes += padded_len + 4; |
active_state->p_read.bytes += padded_len + 4; |
type = buffer_get_char(&incoming_packet); |
type = buffer_get_char(&active_state->incoming_packet); |
if (type < SSH_MSG_MIN || type > SSH_MSG_MAX) |
if (type < SSH_MSG_MIN || type > SSH_MSG_MAX) |
packet_disconnect("Invalid ssh1 packet type: %d", type); |
packet_disconnect("Invalid ssh1 packet type: %d", type); |
return type; |
return type; |
|
|
static int |
static int |
packet_read_poll2(u_int32_t *seqnr_p) |
packet_read_poll2(u_int32_t *seqnr_p) |
{ |
{ |
static u_int packet_length = 0; |
|
u_int padlen, need; |
u_int padlen, need; |
u_char *macbuf, *cp, type; |
u_char *macbuf, *cp, type; |
u_int maclen, block_size; |
u_int maclen, block_size; |
|
|
Mac *mac = NULL; |
Mac *mac = NULL; |
Comp *comp = NULL; |
Comp *comp = NULL; |
|
|
if (packet_discard) |
if (active_state->packet_discard) |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
|
|
if (newkeys[MODE_IN] != NULL) { |
if (active_state->newkeys[MODE_IN] != NULL) { |
enc = &newkeys[MODE_IN]->enc; |
enc = &active_state->newkeys[MODE_IN]->enc; |
mac = &newkeys[MODE_IN]->mac; |
mac = &active_state->newkeys[MODE_IN]->mac; |
comp = &newkeys[MODE_IN]->comp; |
comp = &active_state->newkeys[MODE_IN]->comp; |
} |
} |
maclen = mac && mac->enabled ? mac->mac_len : 0; |
maclen = mac && mac->enabled ? mac->mac_len : 0; |
block_size = enc ? enc->block_size : 8; |
block_size = enc ? enc->block_size : 8; |
|
|
if (packet_length == 0) { |
if (active_state->packlen == 0) { |
/* |
/* |
* check if input size is less than the cipher block size, |
* check if input size is less than the cipher block size, |
* decrypt first block and extract length of incoming packet |
* decrypt first block and extract length of incoming packet |
*/ |
*/ |
if (buffer_len(&input) < block_size) |
if (buffer_len(&active_state->input) < block_size) |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
buffer_clear(&incoming_packet); |
buffer_clear(&active_state->incoming_packet); |
cp = buffer_append_space(&incoming_packet, block_size); |
cp = buffer_append_space(&active_state->incoming_packet, |
cipher_crypt(&receive_context, cp, buffer_ptr(&input), |
|
block_size); |
block_size); |
cp = buffer_ptr(&incoming_packet); |
cipher_crypt(&active_state->receive_context, cp, |
packet_length = get_u32(cp); |
buffer_ptr(&active_state->input), block_size); |
if (packet_length < 1 + 4 || packet_length > PACKET_MAX_SIZE) { |
cp = buffer_ptr(&active_state->incoming_packet); |
|
active_state->packlen = get_u32(cp); |
|
if (active_state->packlen < 1 + 4 || |
|
active_state->packlen > PACKET_MAX_SIZE) { |
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
buffer_dump(&incoming_packet); |
buffer_dump(&active_state->incoming_packet); |
#endif |
#endif |
logit("Bad packet length %u.", packet_length); |
logit("Bad packet length %u.", active_state->packlen); |
packet_start_discard(enc, mac, packet_length, |
packet_start_discard(enc, mac, active_state->packlen, |
PACKET_MAX_SIZE); |
PACKET_MAX_SIZE); |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
} |
} |
DBG(debug("input: packet len %u", packet_length+4)); |
DBG(debug("input: packet len %u", active_state->packlen+4)); |
buffer_consume(&input, block_size); |
buffer_consume(&active_state->input, block_size); |
} |
} |
/* we have a partial packet of block_size bytes */ |
/* we have a partial packet of block_size bytes */ |
need = 4 + packet_length - block_size; |
need = 4 + active_state->packlen - block_size; |
DBG(debug("partial packet %d, need %d, maclen %d", block_size, |
DBG(debug("partial packet %d, need %d, maclen %d", block_size, |
need, maclen)); |
need, maclen)); |
if (need % block_size != 0) { |
if (need % block_size != 0) { |
logit("padding error: need %d block %d mod %d", |
logit("padding error: need %d block %d mod %d", |
need, block_size, need % block_size); |
need, block_size, need % block_size); |
packet_start_discard(enc, mac, packet_length, |
packet_start_discard(enc, mac, active_state->packlen, |
PACKET_MAX_SIZE - block_size); |
PACKET_MAX_SIZE - block_size); |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
} |
} |
|
|
* check if the entire packet has been received and |
* check if the entire packet has been received and |
* decrypt into incoming_packet |
* decrypt into incoming_packet |
*/ |
*/ |
if (buffer_len(&input) < need + maclen) |
if (buffer_len(&active_state->input) < need + maclen) |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "read_poll enc/full: "); |
fprintf(stderr, "read_poll enc/full: "); |
buffer_dump(&input); |
buffer_dump(&active_state->input); |
#endif |
#endif |
cp = buffer_append_space(&incoming_packet, need); |
cp = buffer_append_space(&active_state->incoming_packet, need); |
cipher_crypt(&receive_context, cp, buffer_ptr(&input), need); |
cipher_crypt(&active_state->receive_context, cp, |
buffer_consume(&input, need); |
buffer_ptr(&active_state->input), need); |
|
buffer_consume(&active_state->input, need); |
/* |
/* |
* compute MAC over seqnr and packet, |
* compute MAC over seqnr and packet, |
* 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, active_state->p_read.seqnr, |
buffer_ptr(&incoming_packet), |
buffer_ptr(&active_state->incoming_packet), |
buffer_len(&incoming_packet)); |
buffer_len(&active_state->incoming_packet)); |
if (memcmp(macbuf, buffer_ptr(&input), mac->mac_len) != 0) { |
if (memcmp(macbuf, buffer_ptr(&active_state->input), |
|
mac->mac_len) != 0) { |
logit("Corrupted MAC on input."); |
logit("Corrupted MAC on input."); |
if (need > PACKET_MAX_SIZE) |
if (need > PACKET_MAX_SIZE) |
fatal("internal error need %d", need); |
fatal("internal error need %d", need); |
packet_start_discard(enc, mac, packet_length, |
packet_start_discard(enc, mac, active_state->packlen, |
PACKET_MAX_SIZE - need); |
PACKET_MAX_SIZE - need); |
return SSH_MSG_NONE; |
return SSH_MSG_NONE; |
} |
} |
|
|
DBG(debug("MAC #%d ok", p_read.seqnr)); |
DBG(debug("MAC #%d ok", active_state->p_read.seqnr)); |
buffer_consume(&input, mac->mac_len); |
buffer_consume(&active_state->input, mac->mac_len); |
} |
} |
/* XXX now it's safe to use fatal/packet_disconnect */ |
/* XXX now it's safe to use fatal/packet_disconnect */ |
if (seqnr_p != NULL) |
if (seqnr_p != NULL) |
*seqnr_p = p_read.seqnr; |
*seqnr_p = active_state->p_read.seqnr; |
if (++p_read.seqnr == 0) |
if (++active_state->p_read.seqnr == 0) |
logit("incoming seqnr wraps around"); |
logit("incoming seqnr wraps around"); |
if (++p_read.packets == 0) |
if (++active_state->p_read.packets == 0) |
if (!(datafellows & SSH_BUG_NOREKEY)) |
if (!(datafellows & SSH_BUG_NOREKEY)) |
fatal("XXX too many packets with same key"); |
fatal("XXX too many packets with same key"); |
p_read.blocks += (packet_length + 4) / block_size; |
active_state->p_read.blocks += (active_state->packlen + 4) / block_size; |
p_read.bytes += packet_length + 4; |
active_state->p_read.bytes += active_state->packlen + 4; |
|
|
/* get padlen */ |
/* get padlen */ |
cp = buffer_ptr(&incoming_packet); |
cp = buffer_ptr(&active_state->incoming_packet); |
padlen = cp[4]; |
padlen = cp[4]; |
DBG(debug("input: padlen %d", padlen)); |
DBG(debug("input: padlen %d", padlen)); |
if (padlen < 4) |
if (padlen < 4) |
packet_disconnect("Corrupted padlen %d on input.", padlen); |
packet_disconnect("Corrupted padlen %d on input.", padlen); |
|
|
/* skip packet size + padlen, discard padding */ |
/* skip packet size + padlen, discard padding */ |
buffer_consume(&incoming_packet, 4 + 1); |
buffer_consume(&active_state->incoming_packet, 4 + 1); |
buffer_consume_end(&incoming_packet, padlen); |
buffer_consume_end(&active_state->incoming_packet, padlen); |
|
|
DBG(debug("input: len before de-compress %d", buffer_len(&incoming_packet))); |
DBG(debug("input: len before de-compress %d", |
|
buffer_len(&active_state->incoming_packet))); |
if (comp && comp->enabled) { |
if (comp && comp->enabled) { |
buffer_clear(&compression_buffer); |
buffer_clear(&active_state->compression_buffer); |
buffer_uncompress(&incoming_packet, &compression_buffer); |
buffer_uncompress(&active_state->incoming_packet, |
buffer_clear(&incoming_packet); |
&active_state->compression_buffer); |
buffer_append(&incoming_packet, buffer_ptr(&compression_buffer), |
buffer_clear(&active_state->incoming_packet); |
buffer_len(&compression_buffer)); |
buffer_append(&active_state->incoming_packet, |
|
buffer_ptr(&active_state->compression_buffer), |
|
buffer_len(&active_state->compression_buffer)); |
DBG(debug("input: len after de-compress %d", |
DBG(debug("input: len after de-compress %d", |
buffer_len(&incoming_packet))); |
buffer_len(&active_state->incoming_packet))); |
} |
} |
/* |
/* |
* get packet type, implies consume. |
* get packet type, implies consume. |
* return length of payload (without type field) |
* return length of payload (without type field) |
*/ |
*/ |
type = buffer_get_char(&incoming_packet); |
type = buffer_get_char(&active_state->incoming_packet); |
if (type < SSH2_MSG_MIN || type >= SSH2_MSG_LOCAL_MIN) |
if (type < SSH2_MSG_MIN || type >= SSH2_MSG_LOCAL_MIN) |
packet_disconnect("Invalid ssh2 packet type: %d", type); |
packet_disconnect("Invalid ssh2 packet type: %d", type); |
if (type == SSH2_MSG_NEWKEYS) |
if (type == SSH2_MSG_NEWKEYS) |
set_newkeys(MODE_IN); |
set_newkeys(MODE_IN); |
else if (type == SSH2_MSG_USERAUTH_SUCCESS && !server_side) |
else if (type == SSH2_MSG_USERAUTH_SUCCESS && |
|
!active_state->server_side) |
packet_enable_delayed_compress(); |
packet_enable_delayed_compress(); |
#ifdef PACKET_DEBUG |
#ifdef PACKET_DEBUG |
fprintf(stderr, "read/plain[%d]:\r\n", type); |
fprintf(stderr, "read/plain[%d]:\r\n", type); |
buffer_dump(&incoming_packet); |
buffer_dump(&active_state->incoming_packet); |
#endif |
#endif |
/* reset for next packet */ |
/* reset for next packet */ |
packet_length = 0; |
active_state->packlen = 0; |
return type; |
return type; |
} |
} |
|
|
|
|
if (compat20) { |
if (compat20) { |
type = packet_read_poll2(seqnr_p); |
type = packet_read_poll2(seqnr_p); |
if (type) { |
if (type) { |
keep_alive_timeouts = 0; |
active_state->keep_alive_timeouts = 0; |
DBG(debug("received packet type %d", type)); |
DBG(debug("received packet type %d", type)); |
} |
} |
switch (type) { |
switch (type) { |
|
|
void |
void |
packet_process_incoming(const char *buf, u_int len) |
packet_process_incoming(const char *buf, u_int len) |
{ |
{ |
if (packet_discard) { |
if (active_state->packet_discard) { |
keep_alive_timeouts = 0; /* ?? */ |
active_state->keep_alive_timeouts = 0; /* ?? */ |
if (len >= packet_discard) |
if (len >= active_state->packet_discard) |
packet_stop_discard(); |
packet_stop_discard(); |
packet_discard -= len; |
active_state->packet_discard -= len; |
return; |
return; |
} |
} |
buffer_append(&input, buf, len); |
buffer_append(&active_state->input, buf, len); |
} |
} |
|
|
/* Returns a character from the packet. */ |
/* Returns a character from the packet. */ |
|
|
{ |
{ |
char ch; |
char ch; |
|
|
buffer_get(&incoming_packet, &ch, 1); |
buffer_get(&active_state->incoming_packet, &ch, 1); |
return (u_char) ch; |
return (u_char) ch; |
} |
} |
|
|
|
|
u_int |
u_int |
packet_get_int(void) |
packet_get_int(void) |
{ |
{ |
return buffer_get_int(&incoming_packet); |
return buffer_get_int(&active_state->incoming_packet); |
} |
} |
|
|
/* |
/* |
|
|
void |
void |
packet_get_bignum(BIGNUM * value) |
packet_get_bignum(BIGNUM * value) |
{ |
{ |
buffer_get_bignum(&incoming_packet, value); |
buffer_get_bignum(&active_state->incoming_packet, value); |
} |
} |
|
|
void |
void |
packet_get_bignum2(BIGNUM * value) |
packet_get_bignum2(BIGNUM * value) |
{ |
{ |
buffer_get_bignum2(&incoming_packet, value); |
buffer_get_bignum2(&active_state->incoming_packet, value); |
} |
} |
|
|
void * |
void * |
packet_get_raw(u_int *length_ptr) |
packet_get_raw(u_int *length_ptr) |
{ |
{ |
u_int bytes = buffer_len(&incoming_packet); |
u_int bytes = buffer_len(&active_state->incoming_packet); |
|
|
if (length_ptr != NULL) |
if (length_ptr != NULL) |
*length_ptr = bytes; |
*length_ptr = bytes; |
return buffer_ptr(&incoming_packet); |
return buffer_ptr(&active_state->incoming_packet); |
} |
} |
|
|
int |
int |
packet_remaining(void) |
packet_remaining(void) |
{ |
{ |
return buffer_len(&incoming_packet); |
return buffer_len(&active_state->incoming_packet); |
} |
} |
|
|
/* |
/* |
|
|
void * |
void * |
packet_get_string(u_int *length_ptr) |
packet_get_string(u_int *length_ptr) |
{ |
{ |
return buffer_get_string(&incoming_packet, length_ptr); |
return buffer_get_string(&active_state->incoming_packet, length_ptr); |
} |
} |
|
|
void * |
void * |
packet_get_string_ptr(u_int *length_ptr) |
packet_get_string_ptr(u_int *length_ptr) |
{ |
{ |
return buffer_get_string_ptr(&incoming_packet, length_ptr); |
return buffer_get_string_ptr(&active_state->incoming_packet, length_ptr); |
} |
} |
|
|
/* |
/* |
|
|
void |
void |
packet_write_poll(void) |
packet_write_poll(void) |
{ |
{ |
int len = buffer_len(&output); |
int len = buffer_len(&active_state->output); |
|
|
if (len > 0) { |
if (len > 0) { |
len = write(connection_out, buffer_ptr(&output), len); |
len = write(active_state->connection_out, |
|
buffer_ptr(&active_state->output), len); |
if (len == -1) { |
if (len == -1) { |
if (errno == EINTR || errno == EAGAIN) |
if (errno == EINTR || errno == EAGAIN) |
return; |
return; |
|
|
} |
} |
if (len == 0) |
if (len == 0) |
fatal("Write connection closed"); |
fatal("Write connection closed"); |
buffer_consume(&output, len); |
buffer_consume(&active_state->output, len); |
} |
} |
} |
} |
|
|
|
|
int ret, ms_remain; |
int ret, ms_remain; |
struct timeval start, timeout, *timeoutp = NULL; |
struct timeval start, timeout, *timeoutp = NULL; |
|
|
setp = (fd_set *)xcalloc(howmany(connection_out + 1, NFDBITS), |
setp = (fd_set *)xcalloc(howmany(active_state->connection_out + 1, |
sizeof(fd_mask)); |
NFDBITS), sizeof(fd_mask)); |
packet_write_poll(); |
packet_write_poll(); |
while (packet_have_data_to_write()) { |
while (packet_have_data_to_write()) { |
memset(setp, 0, howmany(connection_out + 1, NFDBITS) * |
memset(setp, 0, howmany(active_state->connection_out + 1, |
sizeof(fd_mask)); |
NFDBITS) * sizeof(fd_mask)); |
FD_SET(connection_out, setp); |
FD_SET(active_state->connection_out, setp); |
|
|
if (packet_timeout_ms > 0) { |
if (active_state->packet_timeout_ms > 0) { |
ms_remain = packet_timeout_ms; |
ms_remain = active_state->packet_timeout_ms; |
timeoutp = &timeout; |
timeoutp = &timeout; |
} |
} |
for (;;) { |
for (;;) { |
if (packet_timeout_ms != -1) { |
if (active_state->packet_timeout_ms != -1) { |
ms_to_timeval(&timeout, ms_remain); |
ms_to_timeval(&timeout, ms_remain); |
gettimeofday(&start, NULL); |
gettimeofday(&start, NULL); |
} |
} |
if ((ret = select(connection_out + 1, NULL, setp, |
if ((ret = select(active_state->connection_out + 1, |
NULL, timeoutp)) >= 0) |
NULL, setp, NULL, timeoutp)) >= 0) |
break; |
break; |
if (errno != EAGAIN && errno != EINTR) |
if (errno != EAGAIN && errno != EINTR) |
break; |
break; |
if (packet_timeout_ms == -1) |
if (active_state->packet_timeout_ms == -1) |
continue; |
continue; |
ms_subtract_diff(&start, &ms_remain); |
ms_subtract_diff(&start, &ms_remain); |
if (ms_remain <= 0) { |
if (ms_remain <= 0) { |
|
|
int |
int |
packet_have_data_to_write(void) |
packet_have_data_to_write(void) |
{ |
{ |
return buffer_len(&output) != 0; |
return buffer_len(&active_state->output) != 0; |
} |
} |
|
|
/* Returns true if there is not too much data to write to the connection. */ |
/* Returns true if there is not too much data to write to the connection. */ |
|
|
int |
int |
packet_not_very_much_data_to_write(void) |
packet_not_very_much_data_to_write(void) |
{ |
{ |
if (interactive_mode) |
if (active_state->interactive_mode) |
return buffer_len(&output) < 16384; |
return buffer_len(&active_state->output) < 16384; |
else |
else |
return buffer_len(&output) < 128 * 1024; |
return buffer_len(&active_state->output) < 128 * 1024; |
} |
} |
|
|
static void |
static void |
|
|
if (!packet_connection_is_on_socket() || |
if (!packet_connection_is_on_socket() || |
!packet_connection_is_ipv4()) |
!packet_connection_is_ipv4()) |
return; |
return; |
if (setsockopt(connection_in, IPPROTO_IP, IP_TOS, &tos, |
if (setsockopt(active_state->connection_in, IPPROTO_IP, IP_TOS, &tos, |
sizeof(tos)) < 0) |
sizeof(tos)) < 0) |
error("setsockopt IP_TOS %d: %.100s:", |
error("setsockopt IP_TOS %d: %.100s:", |
tos, strerror(errno)); |
tos, strerror(errno)); |
|
|
called = 1; |
called = 1; |
|
|
/* Record that we are in interactive mode. */ |
/* Record that we are in interactive mode. */ |
interactive_mode = interactive; |
active_state->interactive_mode = interactive; |
|
|
/* 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; |
set_nodelay(connection_in); |
set_nodelay(active_state->connection_in); |
packet_set_tos(interactive); |
packet_set_tos(interactive); |
} |
} |
|
|
|
|
int |
int |
packet_is_interactive(void) |
packet_is_interactive(void) |
{ |
{ |
return interactive_mode; |
return active_state->interactive_mode; |
} |
} |
|
|
int |
int |
|
|
|
|
if (called) { |
if (called) { |
logit("packet_set_maxsize: called twice: old %d new %d", |
logit("packet_set_maxsize: called twice: old %d new %d", |
max_packet_size, s); |
active_state->max_packet_size, s); |
return -1; |
return -1; |
} |
} |
if (s < 4 * 1024 || s > 1024 * 1024) { |
if (s < 4 * 1024 || s > 1024 * 1024) { |
|
|
} |
} |
called = 1; |
called = 1; |
debug("packet_set_maxsize: setting to %d", s); |
debug("packet_set_maxsize: setting to %d", s); |
max_packet_size = s; |
active_state->max_packet_size = s; |
return s; |
return s; |
} |
} |
|
|
|
int |
|
packet_inc_alive_timeouts(void) |
|
{ |
|
return ++active_state->keep_alive_timeouts; |
|
} |
|
|
|
void |
|
packet_set_alive_timeouts(int ka) |
|
{ |
|
active_state->keep_alive_timeouts = ka; |
|
} |
|
|
|
u_int |
|
packet_get_maxsize(void) |
|
{ |
|
return active_state->max_packet_size; |
|
} |
|
|
/* roundup current message to pad bytes */ |
/* roundup current message to pad bytes */ |
void |
void |
packet_add_padding(u_char pad) |
packet_add_padding(u_char pad) |
{ |
{ |
extra_pad = pad; |
active_state->extra_pad = pad; |
} |
} |
|
|
/* |
/* |
|
|
if (datafellows & SSH_BUG_NOREKEY) |
if (datafellows & SSH_BUG_NOREKEY) |
return 0; |
return 0; |
return |
return |
(p_send.packets > MAX_PACKETS) || |
(active_state->p_send.packets > MAX_PACKETS) || |
(p_read.packets > MAX_PACKETS) || |
(active_state->p_read.packets > MAX_PACKETS) || |
(max_blocks_out && (p_send.blocks > max_blocks_out)) || |
(active_state->max_blocks_out && |
(max_blocks_in && (p_read.blocks > max_blocks_in)); |
(active_state->p_send.blocks > active_state->max_blocks_out)) || |
|
(active_state->max_blocks_in && |
|
(active_state->p_read.blocks > active_state->max_blocks_in)); |
} |
} |
|
|
void |
void |
packet_set_rekey_limit(u_int32_t bytes) |
packet_set_rekey_limit(u_int32_t bytes) |
{ |
{ |
rekey_limit = bytes; |
active_state->rekey_limit = bytes; |
} |
} |
|
|
void |
void |
packet_set_server(void) |
packet_set_server(void) |
{ |
{ |
server_side = 1; |
active_state->server_side = 1; |
} |
} |
|
|
void |
void |
packet_set_authenticated(void) |
packet_set_authenticated(void) |
{ |
{ |
after_authentication = 1; |
active_state->after_authentication = 1; |
|
} |
|
|
|
void * |
|
packet_get_input(void) |
|
{ |
|
return (void *)&active_state->input; |
|
} |
|
|
|
void * |
|
packet_get_output(void) |
|
{ |
|
return (void *)&active_state->output; |
|
} |
|
|
|
void * |
|
packet_get_newkeys(int mode) |
|
{ |
|
return (void *)active_state->newkeys[mode]; |
} |
} |