Correctly estimate the initial MTU for legacy packets.
authorGuus Sliepen <guus@tinc-vpn.org>
Sat, 10 Jan 2015 22:00:51 +0000 (23:00 +0100)
committerGuus Sliepen <guus@tinc-vpn.org>
Sat, 10 Jan 2015 22:00:51 +0000 (23:00 +0100)
src/cipher.h
src/net_packet.c
src/openssl/cipher.c

index f194c0d..3f98c18 100644 (file)
@@ -33,6 +33,7 @@ extern cipher_t *cipher_open_by_nid(int) __attribute__ ((__malloc__));
 extern cipher_t *cipher_open_blowfish_ofb(void) __attribute__ ((__malloc__));
 extern void cipher_close(cipher_t *);
 extern size_t cipher_keylength(const cipher_t *);
+extern size_t cipher_blocksize(const cipher_t *);
 extern void cipher_get_key(const cipher_t *, void *);
 extern bool cipher_set_key(cipher_t *, void *, bool) __attribute__ ((__warn_unused_result__));
 extern bool cipher_set_key_from_rsa(cipher_t *, void *, size_t, bool) __attribute__ ((__warn_unused_result__));
index 37535c1..8bf399f 100644 (file)
@@ -929,6 +929,25 @@ static length_t choose_initial_maxmtu(node_t *n) {
                mtu -= SPTPS_DATAGRAM_OVERHEAD;
                if((n->options >> 24) >= 4)
                        mtu -= sizeof(node_id_t) + sizeof(node_id_t);
+       } else {
+               mtu -= digest_length(n->outdigest);
+
+               /* Now it's tricky. We use CBC mode, so the length of the
+                  encrypted payload must be a multiple of the blocksize. The
+                  sequence number is also part of the encrypted payload, so we
+                  must account for it after correcting for the blocksize.
+                  Furthermore, the padding in the last block must be at least
+                  1 byte. */
+
+               length_t blocksize = cipher_blocksize(n->outcipher);
+
+               if(blocksize > 1) {
+                       mtu /= blocksize;
+                       mtu *= blocksize;
+                       mtu--;
+               }
+
+               mtu -= 4; // seqno
        }
 
        if (mtu < 512) {
index 9b39a28..04aee27 100644 (file)
@@ -79,6 +79,13 @@ size_t cipher_keylength(const cipher_t *cipher) {
        return cipher->cipher->key_len + cipher->cipher->iv_len;
 }
 
+size_t cipher_blocksize(const cipher_t *cipher) {
+       if(!cipher || !cipher->cipher)
+               return 1;
+
+       return cipher->cipher->block_size;
+}
+
 bool cipher_set_key(cipher_t *cipher, void *key, bool encrypt) {
        bool result;