ACK An elegant fix.
-Steffan On 07-01-15 20:26, Lev Stipakov wrote: > Existing check didn't take into account the case when floated client is > lame duck (CN for lame duck is NULL), which allowed lame duck to float > to an address taken by another client. > > As a fix we use cert_hash_compare function which, besides fixing > mentioned case, also allows lame duck to float to an address already > taken by the same client. > --- > src/openvpn/multi.c | 13 ++++++++----- > src/openvpn/ssl_verify.c | 2 +- > src/openvpn/ssl_verify.h | 8 ++++++++ > 3 files changed, 17 insertions(+), 6 deletions(-) > > diff --git a/src/openvpn/multi.c b/src/openvpn/multi.c > index 6ddfbb5..4412491 100644 > --- a/src/openvpn/multi.c > +++ b/src/openvpn/multi.c > @@ -2127,17 +2127,20 @@ void multi_process_float (struct multi_context* m, > struct multi_instance* mi) > const uint32_t hv = hash_value (hash, &real); > struct hash_bucket *bucket = hash_bucket (hash, hv); > > + /* make sure that we don't float to an address taken by another client */ > struct hash_element *he = hash_lookup_fast (hash, bucket, &real, hv); > if (he) > { > struct multi_instance *ex_mi = (struct multi_instance *) he->value; > > - const char *cn = tls_common_name (mi->context.c2.tls_multi, true); > - const char *ex_cn = tls_common_name (ex_mi->context.c2.tls_multi, > true); > - if (cn && ex_cn && strcmp (cn, ex_cn)) > + struct tls_multi *m1 = mi->context.c2.tls_multi; > + struct tls_multi *m2 = ex_mi->context.c2.tls_multi; > + > + /* do not float if target address is taken by client with another cert > */ > + if (!cert_hash_compare(m1->locked_cert_hash_set, > m2->locked_cert_hash_set)) > { > - msg (D_MULTI_MEDIUM, "prevent float to %s", > - multi_instance_string (ex_mi, false, &gc)); > + msg (D_MULTI_MEDIUM, "Disallow float to an address taken by another > client %s", > + multi_instance_string (ex_mi, false, &gc)); > > mi->context.c2.buf.len = 0; > > diff --git a/src/openvpn/ssl_verify.c b/src/openvpn/ssl_verify.c > index cec5f02..ad50458 100644 > --- a/src/openvpn/ssl_verify.c > +++ b/src/openvpn/ssl_verify.c > @@ -238,7 +238,7 @@ cert_hash_free (struct cert_hash_set *chs) > } > } > > -static bool > +bool > cert_hash_compare (const struct cert_hash_set *chs1, const struct > cert_hash_set *chs2) > { > if (chs1 && chs2) > diff --git a/src/openvpn/ssl_verify.h b/src/openvpn/ssl_verify.h > index 5f23431..d5bf22e 100644 > --- a/src/openvpn/ssl_verify.h > +++ b/src/openvpn/ssl_verify.h > @@ -137,6 +137,14 @@ const char *tls_common_name (const struct tls_multi* > multi, const bool null); > */ > const char *tls_username (const struct tls_multi *multi, const bool null); > > +/** > + * Compares certificates hashes, returns true if hashes are equal. > + * > + * @param chs1 cert 1 hash set > + * @param chs2 cert 2 hash set > + */ > +bool cert_hash_compare (const struct cert_hash_set *chs1, const struct > cert_hash_set *chs2); > + > #ifdef ENABLE_PF > > /** >