mirror of
https://github.com/clearml/dropbear
synced 2025-03-03 02:31:35 +00:00
Prevent invalid packets being sent during key-exchange, instead queue
them until afterwards. This could sometimes terminate connections after 8 hours if (for example) a new TCP forwarded connection was sent at the KEX timeout. --HG-- extra : convert_revision : 48426bd66b8f5ba50045f7ba190d1672745132e2
This commit is contained in:
parent
993f58900d
commit
57ae0bfedf
@ -80,9 +80,12 @@ void common_session_init(int sock, char* remotehost) {
|
||||
initqueue(&ses.writequeue);
|
||||
|
||||
ses.requirenext = SSH_MSG_KEXINIT;
|
||||
ses.dataallowed = 0; /* don't send data yet, we'll wait until after kex */
|
||||
ses.dataallowed = 1; /* we can send data until we actually
|
||||
send the SSH_MSG_KEXINIT */
|
||||
ses.ignorenext = 0;
|
||||
ses.lastpacket = 0;
|
||||
ses.reply_queue_head = NULL;
|
||||
ses.reply_queue_tail = NULL;
|
||||
|
||||
/* set all the algos to none */
|
||||
ses.keys = (struct key_context*)m_malloc(sizeof(struct key_context));
|
||||
@ -192,6 +195,10 @@ void session_loop(void(*loophandler)()) {
|
||||
process_packet();
|
||||
}
|
||||
}
|
||||
|
||||
/* if required, flush out any queued reply packets that
|
||||
were being held up during a KEX */
|
||||
maybe_flush_reply_queue();
|
||||
|
||||
/* process pipes etc for the channels, ses.dataallowed == 0
|
||||
* during rekeying ) */
|
||||
|
66
packet.c
66
packet.c
@ -403,7 +403,60 @@ static buffer* buf_decompress(buffer* buf, unsigned int len) {
|
||||
#endif
|
||||
|
||||
|
||||
/* returns 1 if the packet is a valid type during kex (see 7.1 of rfc4253) */
|
||||
static int packet_is_okay_kex(unsigned char type) {
|
||||
if (type >= SSH_MSG_USERAUTH_REQUEST) {
|
||||
return 0;
|
||||
}
|
||||
if (type == SSH_MSG_SERVICE_REQUEST || type == SSH_MSG_SERVICE_ACCEPT) {
|
||||
return 0;
|
||||
}
|
||||
if (type == SSH_MSG_KEXINIT) {
|
||||
/* XXX should this die horribly if !dataallowed ?? */
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void enqueue_reply_packet() {
|
||||
struct packetlist * new_item = NULL;
|
||||
new_item = m_malloc(sizeof(struct packetlist));
|
||||
new_item->next = NULL;
|
||||
|
||||
new_item->payload = buf_newcopy(ses.writepayload);
|
||||
buf_setpos(ses.writepayload, 0);
|
||||
buf_setlen(ses.writepayload, 0);
|
||||
|
||||
if (ses.reply_queue_tail) {
|
||||
ses.reply_queue_tail->next = new_item;
|
||||
} else {
|
||||
ses.reply_queue_head = new_item;
|
||||
ses.reply_queue_tail = new_item;
|
||||
}
|
||||
TRACE(("leave enqueue_reply_packet"))
|
||||
}
|
||||
|
||||
void maybe_flush_reply_queue() {
|
||||
struct packetlist *tmp_item = NULL, *curr_item = NULL;
|
||||
if (!ses.dataallowed)
|
||||
{
|
||||
TRACE(("maybe_empty_reply_queue - no data allowed"))
|
||||
return;
|
||||
}
|
||||
|
||||
for (curr_item = ses.reply_queue_head; curr_item; ) {
|
||||
CHECKCLEARTOWRITE();
|
||||
buf_putbytes(ses.writepayload,
|
||||
curr_item->payload->data, curr_item->payload->len);
|
||||
|
||||
buf_free(curr_item->payload);
|
||||
tmp_item = curr_item;
|
||||
curr_item = curr_item->next;
|
||||
m_free(tmp_item);
|
||||
encrypt_packet();
|
||||
}
|
||||
ses.reply_queue_head = ses.reply_queue_tail = NULL;
|
||||
}
|
||||
|
||||
/* encrypt the writepayload, putting into writebuf, ready for write_packet()
|
||||
* to put on the wire */
|
||||
@ -413,9 +466,20 @@ void encrypt_packet() {
|
||||
unsigned char blocksize, macsize;
|
||||
buffer * writebuf; /* the packet which will go on the wire */
|
||||
buffer * clearwritebuf; /* unencrypted, possibly compressed */
|
||||
unsigned char type;
|
||||
|
||||
type = ses.writepayload->data[0];
|
||||
TRACE(("enter encrypt_packet()"))
|
||||
TRACE(("encrypt_packet type is %d", ses.writepayload->data[0]))
|
||||
TRACE(("encrypt_packet type is %d", type))
|
||||
|
||||
if (!ses.dataallowed && !packet_is_okay_kex(type)) {
|
||||
/* During key exchange only particular packets are allowed.
|
||||
Since this type isn't OK we just enqueue it to send
|
||||
after the KEX, see maybe_flush_reply_queue */
|
||||
enqueue_reply_packet();
|
||||
return;
|
||||
}
|
||||
|
||||
blocksize = ses.keys->trans_algo_crypt->blocksize;
|
||||
macsize = ses.keys->trans_algo_mac->hashsize;
|
||||
|
||||
|
1
packet.h
1
packet.h
@ -35,6 +35,7 @@ void encrypt_packet();
|
||||
|
||||
void process_packet();
|
||||
|
||||
void maybe_flush_reply_queue();
|
||||
typedef struct PacketType {
|
||||
unsigned char type; /* SSH_MSG_FOO */
|
||||
void (*handler)();
|
||||
|
10
session.h
10
session.h
@ -81,6 +81,12 @@ struct key_context {
|
||||
|
||||
};
|
||||
|
||||
struct packetlist;
|
||||
struct packetlist {
|
||||
struct packetlist *next;
|
||||
buffer * payload;
|
||||
};
|
||||
|
||||
struct sshsession {
|
||||
|
||||
/* Is it a client or server? */
|
||||
@ -137,6 +143,10 @@ struct sshsession {
|
||||
buffer* kexhashbuf; /* session hash buffer calculated from various packets*/
|
||||
buffer* transkexinit; /* the kexinit packet we send should be kept so we
|
||||
can add it to the hash when generating keys */
|
||||
|
||||
/* a list of queued replies that should be sent after a KEX has
|
||||
concluded (ie, while dataallowed was unset)*/
|
||||
struct packetlist *reply_queue_head, *reply_queue_tail;
|
||||
|
||||
algo_type*(*buf_match_algo)(buffer*buf, algo_type localalgos[],
|
||||
int *goodguess); /* The function to use to choose which algorithm
|
||||
|
Loading…
Reference in New Issue
Block a user