]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
Added FNV-64 code.
authorKarel Slany <karel.slany@nic.cz>
Fri, 20 May 2016 12:29:03 +0000 (14:29 +0200)
committerOndřej Surý <ondrej@sury.org>
Thu, 11 Aug 2016 12:06:45 +0000 (14:06 +0200)
contrib/fnv/fnv.h [new file with mode: 0644]
contrib/fnv/hash_64a.c [new file with mode: 0644]
contrib/fnv/longlong.h [new file with mode: 0644]
lib/cookies/control.c
lib/cookies/control.h
lib/lib.mk

diff --git a/contrib/fnv/fnv.h b/contrib/fnv/fnv.h
new file mode 100644 (file)
index 0000000..2083a4a
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * fnv - Fowler/Noll/Vo- hash code
+ *
+ * @(#) $Revision: 5.4 $
+ * @(#) $Id: fnv.h,v 5.4 2009/07/30 22:49:13 chongo Exp $
+ * @(#) $Source: /usr/local/src/cmd/fnv/RCS/fnv.h,v $
+ *
+ ***
+ *
+ * Fowler/Noll/Vo- hash
+ *
+ * The basis of this hash algorithm was taken from an idea sent
+ * as reviewer comments to the IEEE POSIX P1003.2 committee by:
+ *
+ *      Phong Vo (http://www.research.att.com/info/kpv/)
+ *      Glenn Fowler (http://www.research.att.com/~gsf/)
+ *
+ * In a subsequent ballot round:
+ *
+ *      Landon Curt Noll (http://www.isthe.com/chongo/)
+ *
+ * improved on their algorithm.  Some people tried this hash
+ * and found that it worked rather well.  In an EMail message
+ * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash.
+ *
+ * FNV hashes are designed to be fast while maintaining a low
+ * collision rate. The FNV speed allows one to quickly hash lots
+ * of data while maintaining a reasonable collision rate.  See:
+ *
+ *      http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ *
+ * for more details as well as other forms of the FNV hash.
+ *
+ ***
+ *
+ * NOTE: The FNV-0 historic hash is not recommended.  One should use
+ *      the FNV-1 hash instead.
+ *
+ * To use the 32 bit FNV-0 historic hash, pass FNV0_32_INIT as the
+ * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str().
+ *
+ * To use the 64 bit FNV-0 historic hash, pass FNV0_64_INIT as the
+ * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str().
+ *
+ * To use the recommended 32 bit FNV-1 hash, pass FNV1_32_INIT as the
+ * Fnv32_t hashval argument to fnv_32_buf() or fnv_32_str().
+ *
+ * To use the recommended 64 bit FNV-1 hash, pass FNV1_64_INIT as the
+ * Fnv64_t hashval argument to fnv_64_buf() or fnv_64_str().
+ *
+ * To use the recommended 32 bit FNV-1a hash, pass FNV1_32A_INIT as the
+ * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_str().
+ *
+ * To use the recommended 64 bit FNV-1a hash, pass FNV1A_64_INIT as the
+ * Fnv64_t hashval argument to fnv_64a_buf() or fnv_64a_str().
+ *
+ ***
+ *
+ * Please do not copyright this code.  This code is in the public domain.
+ *
+ * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * By:
+ *     chongo <Landon Curt Noll> /\oo/\
+ *      http://www.isthe.com/chongo/
+ *
+ * Share and Enjoy!    :-)
+ */
+
+#if !defined(__FNV_H__)
+#define __FNV_H__
+
+#include <sys/types.h>
+
+#define FNV_VERSION "5.0.2"    /* @(#) FNV Version */
+
+
+/*
+ * 32 bit FNV-0 hash type
+ */
+typedef u_int32_t Fnv32_t;
+
+
+/*
+ * 32 bit FNV-0 zero initial basis
+ *
+ * This historic hash is not recommended.  One should use
+ * the FNV-1 hash and initial basis instead.
+ */
+#define FNV0_32_INIT ((Fnv32_t)0)
+
+
+/*
+ * 32 bit FNV-1 and FNV-1a non-zero initial basis
+ *
+ * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets:
+ *
+ *              chongo <Landon Curt Noll> /\../\
+ *
+ * NOTE: The \'s above are not back-slashing escape characters.
+ * They are literal ASCII  backslash 0x5c characters.
+ *
+ * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition.
+ */
+#define FNV1_32_INIT ((Fnv32_t)0x811c9dc5)
+#define FNV1_32A_INIT FNV1_32_INIT
+
+
+/*
+ * determine how 64 bit unsigned values are represented
+ */
+#include "longlong.h"
+
+
+/*
+ * 64 bit FNV-0 hash
+ */
+#if defined(HAVE_64BIT_LONG_LONG)
+typedef u_int64_t Fnv64_t;
+#else /* HAVE_64BIT_LONG_LONG */
+typedef struct {
+    u_int32_t w32[2]; /* w32[0] is low order, w32[1] is high order word */
+} Fnv64_t;
+#endif /* HAVE_64BIT_LONG_LONG */
+
+
+/*
+ * 64 bit FNV-0 zero initial basis
+ *
+ * This historic hash is not recommended.  One should use
+ * the FNV-1 hash and initial basis instead.
+ */
+#if defined(HAVE_64BIT_LONG_LONG)
+#define FNV0_64_INIT ((Fnv64_t)0)
+#else /* HAVE_64BIT_LONG_LONG */
+extern const Fnv64_t fnv0_64_init;
+#define FNV0_64_INIT (fnv0_64_init)
+#endif /* HAVE_64BIT_LONG_LONG */
+
+
+/*
+ * 64 bit FNV-1 non-zero initial basis
+ *
+ * The FNV-1 initial basis is the FNV-0 hash of the following 32 octets:
+ *
+ *              chongo <Landon Curt Noll> /\../\
+ *
+ * NOTE: The \'s above are not back-slashing escape characters.
+ * They are literal ASCII  backslash 0x5c characters.
+ *
+ * NOTE: The FNV-1a initial basis is the same value as FNV-1 by definition.
+ */
+#if defined(HAVE_64BIT_LONG_LONG)
+#define FNV1_64_INIT ((Fnv64_t)0xcbf29ce484222325ULL)
+#define FNV1A_64_INIT FNV1_64_INIT
+#else /* HAVE_64BIT_LONG_LONG */
+extern const fnv1_64_init;
+extern const Fnv64_t fnv1a_64_init;
+#define FNV1_64_INIT (fnv1_64_init)
+#define FNV1A_64_INIT (fnv1a_64_init)
+#endif /* HAVE_64BIT_LONG_LONG */
+
+
+/*
+ * hash types
+ */
+enum fnv_type {
+    FNV_NONE = 0,      /* invalid FNV hash type */
+    FNV0_32 = 1,       /* FNV-0 32 bit hash */
+    FNV1_32 = 2,       /* FNV-1 32 bit hash */
+    FNV1a_32 = 3,      /* FNV-1a 32 bit hash */
+    FNV0_64 = 4,       /* FNV-0 64 bit hash */
+    FNV1_64 = 5,       /* FNV-1 64 bit hash */
+    FNV1a_64 = 6,      /* FNV-1a 64 bit hash */
+};
+
+
+/*
+ * these test vectors are used as part o the FNV test suite
+ */
+struct test_vector {
+    void *buf;         /* start of test vector buffer */
+    int len;           /* length of test vector */
+};
+struct fnv0_32_test_vector {
+    struct test_vector *test;  /* test vector buffer to hash */
+    Fnv32_t fnv0_32;           /* expected FNV-0 32 bit hash value */
+};
+struct fnv1_32_test_vector {
+    struct test_vector *test;  /* test vector buffer to hash */
+    Fnv32_t fnv1_32;           /* expected FNV-1 32 bit hash value */
+};
+struct fnv1a_32_test_vector {
+    struct test_vector *test;  /* test vector buffer to hash */
+    Fnv32_t fnv1a_32;          /* expected FNV-1a 32 bit hash value */
+};
+struct fnv0_64_test_vector {
+    struct test_vector *test;  /* test vector buffer to hash */
+    Fnv64_t fnv0_64;           /* expected FNV-0 64 bit hash value */
+};
+struct fnv1_64_test_vector {
+    struct test_vector *test;  /* test vector buffer to hash */
+    Fnv64_t fnv1_64;           /* expected FNV-1 64 bit hash value */
+};
+struct fnv1a_64_test_vector {
+    struct test_vector *test;  /* test vector buffer to hash */
+    Fnv64_t fnv1a_64;          /* expected FNV-1a 64 bit hash value */
+};
+
+
+/*
+ * external functions
+ */
+/* hash_32.c */
+extern Fnv32_t fnv_32_buf(void *buf, size_t len, Fnv32_t hashval);
+extern Fnv32_t fnv_32_str(char *buf, Fnv32_t hashval);
+
+/* hash_32a.c */
+extern Fnv32_t fnv_32a_buf(void *buf, size_t len, Fnv32_t hashval);
+extern Fnv32_t fnv_32a_str(char *buf, Fnv32_t hashval);
+
+/* hash_64.c */
+extern Fnv64_t fnv_64_buf(void *buf, size_t len, Fnv64_t hashval);
+extern Fnv64_t fnv_64_str(char *buf, Fnv64_t hashval);
+
+/* hash_64a.c */
+extern Fnv64_t fnv_64a_buf(void *buf, size_t len, Fnv64_t hashval);
+extern Fnv64_t fnv_64a_str(char *buf, Fnv64_t hashval);
+
+/* test_fnv.c */
+extern struct test_vector fnv_test_str[];
+extern struct fnv0_32_test_vector fnv0_32_vector[];
+extern struct fnv1_32_test_vector fnv1_32_vector[];
+extern struct fnv1a_32_test_vector fnv1a_32_vector[];
+extern struct fnv0_64_test_vector fnv0_64_vector[];
+extern struct fnv1_64_test_vector fnv1_64_vector[];
+extern struct fnv1a_64_test_vector fnv1a_64_vector[];
+extern void unknown_hash_type(char *prog, enum fnv_type type, int code);
+extern void print_fnv32(Fnv32_t hval, Fnv32_t mask, int verbose, char *arg);
+extern void print_fnv64(Fnv64_t hval, Fnv64_t mask, int verbose, char *arg);
+
+
+#endif /* __FNV_H__ */
diff --git a/contrib/fnv/hash_64a.c b/contrib/fnv/hash_64a.c
new file mode 100644 (file)
index 0000000..6660f92
--- /dev/null
@@ -0,0 +1,291 @@
+/*
+ * hash_64 - 64 bit Fowler/Noll/Vo-0 FNV-1a hash code
+ *
+ * @(#) $Revision: 5.1 $
+ * @(#) $Id: hash_64a.c,v 5.1 2009/06/30 09:01:38 chongo Exp $
+ * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_64a.c,v $
+ *
+ ***
+ *
+ * Fowler/Noll/Vo hash
+ *
+ * The basis of this hash algorithm was taken from an idea sent
+ * as reviewer comments to the IEEE POSIX P1003.2 committee by:
+ *
+ *      Phong Vo (http://www.research.att.com/info/kpv/)
+ *      Glenn Fowler (http://www.research.att.com/~gsf/)
+ *
+ * In a subsequent ballot round:
+ *
+ *      Landon Curt Noll (http://www.isthe.com/chongo/)
+ *
+ * improved on their algorithm.  Some people tried this hash
+ * and found that it worked rather well.  In an EMail message
+ * to Landon, they named it the ``Fowler/Noll/Vo'' or FNV hash.
+ *
+ * FNV hashes are designed to be fast while maintaining a low
+ * collision rate. The FNV speed allows one to quickly hash lots
+ * of data while maintaining a reasonable collision rate.  See:
+ *
+ *      http://www.isthe.com/chongo/tech/comp/fnv/index.html
+ *
+ * for more details as well as other forms of the FNV hash.
+ *
+ ***
+ *
+ * To use the recommended 64 bit FNV-1a hash, pass FNV1A_64_INIT as the
+ * Fnv64_t hashval argument to fnv_64a_buf() or fnv_64a_str().
+ *
+ ***
+ *
+ * Please do not copyright this code.  This code is in the public domain.
+ *
+ * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+ * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
+ * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ *
+ * By:
+ *     chongo <Landon Curt Noll> /\oo/\
+ *      http://www.isthe.com/chongo/
+ *
+ * Share and Enjoy!    :-)
+ */
+
+#include <stdlib.h>
+#include "fnv.h"
+
+
+/*
+ * FNV-1a defines the initial basis to be non-zero
+ */
+#if !defined(HAVE_64BIT_LONG_LONG)
+const Fnv64_t fnv1a_64_init = { 0x84222325, 0xcbf29ce4 };
+#endif /* ! HAVE_64BIT_LONG_LONG */
+
+
+/*
+ * 64 bit magic FNV-1a prime
+ */
+#if defined(HAVE_64BIT_LONG_LONG)
+#define FNV_64_PRIME ((Fnv64_t)0x100000001b3ULL)
+#else /* HAVE_64BIT_LONG_LONG */
+#define FNV_64_PRIME_LOW ((unsigned long)0x1b3)        /* lower bits of FNV prime */
+#define FNV_64_PRIME_SHIFT (8)         /* top FNV prime shift above 2^32 */
+#endif /* HAVE_64BIT_LONG_LONG */
+
+
+/*
+ * fnv_64a_buf - perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer
+ *
+ * input:
+ *     buf     - start of buffer to hash
+ *     len     - length of buffer in octets
+ *     hval    - previous hash value or 0 if first call
+ *
+ * returns:
+ *     64 bit hash as a static hash type
+ *
+ * NOTE: To use the recommended 64 bit FNV-1a hash, use FNV1A_64_INIT as the
+ *      hval arg on the first call to either fnv_64a_buf() or fnv_64a_str().
+ */
+Fnv64_t
+fnv_64a_buf(void *buf, size_t len, Fnv64_t hval)
+{
+    unsigned char *bp = (unsigned char *)buf;  /* start of buffer */
+    unsigned char *be = bp + len;              /* beyond end of buffer */
+
+#if defined(HAVE_64BIT_LONG_LONG)
+    /*
+     * FNV-1a hash each octet of the buffer
+     */
+    while (bp < be) {
+
+       /* xor the bottom with the current octet */
+       hval ^= (Fnv64_t)*bp++;
+
+       /* multiply by the 64 bit FNV magic prime mod 2^64 */
+#if defined(NO_FNV_GCC_OPTIMIZATION)
+       hval *= FNV_64_PRIME;
+#else /* NO_FNV_GCC_OPTIMIZATION */
+       hval += (hval << 1) + (hval << 4) + (hval << 5) +
+               (hval << 7) + (hval << 8) + (hval << 40);
+#endif /* NO_FNV_GCC_OPTIMIZATION */
+    }
+
+#else /* HAVE_64BIT_LONG_LONG */
+
+    unsigned long val[4];                      /* hash value in base 2^16 */
+    unsigned long tmp[4];                      /* tmp 64 bit value */
+
+    /*
+     * Convert Fnv64_t hval into a base 2^16 array
+     */
+    val[0] = hval.w32[0];
+    val[1] = (val[0] >> 16);
+    val[0] &= 0xffff;
+    val[2] = hval.w32[1];
+    val[3] = (val[2] >> 16);
+    val[2] &= 0xffff;
+
+    /*
+     * FNV-1a hash each octet of the buffer
+     */
+    while (bp < be) {
+
+       /* xor the bottom with the current octet */
+       val[0] ^= (unsigned long)*bp++;
+
+       /*
+        * multiply by the 64 bit FNV magic prime mod 2^64
+        *
+        * Using 0x100000001b3 we have the following digits base 2^16:
+        *
+        *      0x0     0x100   0x0     0x1b3
+        *
+        * which is the same as:
+        *
+        *      0x0     1<<FNV_64_PRIME_SHIFT   0x0     FNV_64_PRIME_LOW
+        */
+       /* multiply by the lowest order digit base 2^16 */
+       tmp[0] = val[0] * FNV_64_PRIME_LOW;
+       tmp[1] = val[1] * FNV_64_PRIME_LOW;
+       tmp[2] = val[2] * FNV_64_PRIME_LOW;
+       tmp[3] = val[3] * FNV_64_PRIME_LOW;
+       /* multiply by the other non-zero digit */
+       tmp[2] += val[0] << FNV_64_PRIME_SHIFT; /* tmp[2] += val[0] * 0x100 */
+       tmp[3] += val[1] << FNV_64_PRIME_SHIFT; /* tmp[3] += val[1] * 0x100 */
+       /* propagate carries */
+       tmp[1] += (tmp[0] >> 16);
+       val[0] = tmp[0] & 0xffff;
+       tmp[2] += (tmp[1] >> 16);
+       val[1] = tmp[1] & 0xffff;
+       val[3] = tmp[3] + (tmp[2] >> 16);
+       val[2] = tmp[2] & 0xffff;
+       /*
+        * Doing a val[3] &= 0xffff; is not really needed since it simply
+        * removes multiples of 2^64.  We can discard these excess bits
+        * outside of the loop when we convert to Fnv64_t.
+        */
+    }
+
+    /*
+     * Convert base 2^16 array back into an Fnv64_t
+     */
+    hval.w32[1] = ((val[3]<<16) | val[2]);
+    hval.w32[0] = ((val[1]<<16) | val[0]);
+
+#endif /* HAVE_64BIT_LONG_LONG */
+
+    /* return our new hash value */
+    return hval;
+}
+
+
+/*
+ * fnv_64a_str - perform a 64 bit Fowler/Noll/Vo FNV-1a hash on a buffer
+ *
+ * input:
+ *     buf     - start of buffer to hash
+ *     hval    - previous hash value or 0 if first call
+ *
+ * returns:
+ *     64 bit hash as a static hash type
+ *
+ * NOTE: To use the recommended 64 bit FNV-1a hash, use FNV1A_64_INIT as the
+ *      hval arg on the first call to either fnv_64a_buf() or fnv_64a_str().
+ */
+Fnv64_t
+fnv_64a_str(char *str, Fnv64_t hval)
+{
+    unsigned char *s = (unsigned char *)str;   /* unsigned string */
+
+#if defined(HAVE_64BIT_LONG_LONG)
+
+    /*
+     * FNV-1a hash each octet of the string
+     */
+    while (*s) {
+
+       /* xor the bottom with the current octet */
+       hval ^= (Fnv64_t)*s++;
+
+       /* multiply by the 64 bit FNV magic prime mod 2^64 */
+#if defined(NO_FNV_GCC_OPTIMIZATION)
+       hval *= FNV_64_PRIME;
+#else /* NO_FNV_GCC_OPTIMIZATION */
+       hval += (hval << 1) + (hval << 4) + (hval << 5) +
+               (hval << 7) + (hval << 8) + (hval << 40);
+#endif /* NO_FNV_GCC_OPTIMIZATION */
+    }
+
+#else /* !HAVE_64BIT_LONG_LONG */
+
+    unsigned long val[4];      /* hash value in base 2^16 */
+    unsigned long tmp[4];      /* tmp 64 bit value */
+
+    /*
+     * Convert Fnv64_t hval into a base 2^16 array
+     */
+    val[0] = hval.w32[0];
+    val[1] = (val[0] >> 16);
+    val[0] &= 0xffff;
+    val[2] = hval.w32[1];
+    val[3] = (val[2] >> 16);
+    val[2] &= 0xffff;
+
+    /*
+     * FNV-1a hash each octet of the string
+     */
+    while (*s) {
+
+       /* xor the bottom with the current octet */
+
+       /*
+        * multiply by the 64 bit FNV magic prime mod 2^64
+        *
+        * Using 1099511628211, we have the following digits base 2^16:
+        *
+        *      0x0     0x100   0x0     0x1b3
+        *
+        * which is the same as:
+        *
+        *      0x0     1<<FNV_64_PRIME_SHIFT   0x0     FNV_64_PRIME_LOW
+        */
+       /* multiply by the lowest order digit base 2^16 */
+       tmp[0] = val[0] * FNV_64_PRIME_LOW;
+       tmp[1] = val[1] * FNV_64_PRIME_LOW;
+       tmp[2] = val[2] * FNV_64_PRIME_LOW;
+       tmp[3] = val[3] * FNV_64_PRIME_LOW;
+       /* multiply by the other non-zero digit */
+       tmp[2] += val[0] << FNV_64_PRIME_SHIFT; /* tmp[2] += val[0] * 0x100 */
+       tmp[3] += val[1] << FNV_64_PRIME_SHIFT; /* tmp[3] += val[1] * 0x100 */
+       /* propagate carries */
+       tmp[1] += (tmp[0] >> 16);
+       val[0] = tmp[0] & 0xffff;
+       tmp[2] += (tmp[1] >> 16);
+       val[1] = tmp[1] & 0xffff;
+       val[3] = tmp[3] + (tmp[2] >> 16);
+       val[2] = tmp[2] & 0xffff;
+       /*
+        * Doing a val[3] &= 0xffff; is not really needed since it simply
+        * removes multiples of 2^64.  We can discard these excess bits
+        * outside of the loop when we convert to Fnv64_t.
+        */
+       val[0] ^= (unsigned long)(*s++);
+    }
+
+    /*
+     * Convert base 2^16 array back into an Fnv64_t
+     */
+    hval.w32[1] = ((val[3]<<16) | val[2]);
+    hval.w32[0] = ((val[1]<<16) | val[0]);
+
+#endif /* !HAVE_64BIT_LONG_LONG */
+
+    /* return our new hash value */
+    return hval;
+}
diff --git a/contrib/fnv/longlong.h b/contrib/fnv/longlong.h
new file mode 100644 (file)
index 0000000..c8cfe48
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * DO NOT EDIT -- generated by the Makefile
+ */
+
+#if !defined(__LONGLONG_H__)
+#define __LONGLONG_H__
+
+/* do we have/want to use a long long type? */
+#define HAVE_64BIT_LONG_LONG   /* yes */
+
+/*
+ * NO64BIT_LONG_LONG undef HAVE_64BIT_LONG_LONG
+ */
+#if defined(NO64BIT_LONG_LONG)
+#undef HAVE_64BIT_LONG_LONG
+#endif /* NO64BIT_LONG_LONG */
+
+#endif /* !__LONGLONG_H__ */
index 3e933afd5450ba245cd2307886238514235c3ecd..772217f49a88f4039aa7bcaf41ae8fb069210aa7 100644 (file)
     along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <arpa/inet.h> /* inet_ntop() */
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <assert.h>
 #include <stdint.h>
 #include <libknot/error.h>
-#include <libknot/rrtype/opt_cookie.h>
 
+#include "contrib/fnv/fnv.h"
 #include "lib/cookies/control.h"
 #include "lib/layer.h"
 #include "lib/utils.h"
@@ -31,7 +32,7 @@ static uint8_t cc[KNOT_OPT_COOKIE_CLNT] = { 1, 2, 3, 4, 5, 6, 7, 8};
 
 static struct secret_quantity client = {
        .size = KNOT_OPT_COOKIE_CLNT,
-       .secret = cc
+       .data = cc
 };
 
 struct cookies_control kr_cookies_control = {
@@ -68,63 +69,79 @@ static int opt_rr_add_cookies(knot_rrset_t *opt_rr,
        return KNOT_EOK;
 }
 
-static int prepare_client_cookie(uint8_t cc[KNOT_OPT_COOKIE_CLNT],
-                                 const void *clnt_addr,
-                                 const void *srvr_addr,
-                                 const struct secret_quantity *csq)
+static void obtain_address(void *sockaddr, uint8_t **addr, size_t *len)
 {
-       assert(cc);
-       assert(srvr_addr);
-       assert(csq);
-
-       assert(csq->size >= KNOT_OPT_COOKIE_CLNT);
-
-       /* According to the draft (section A.1) the recommended sequence is
-        * client IP address | server IP address , client secret. */
-
-       if (clnt_addr) {
-               int addr_family = ((struct sockaddr *) clnt_addr)->sa_family;
-               if (addr_family == AF_INET) {
-                       clnt_addr = &((struct sockaddr_in *) clnt_addr)->sin_addr;
-               } else if (addr_family == AF_INET6) {
-                       clnt_addr = &((struct sockaddr_in6 *) clnt_addr)->sin6_addr;
-               } else {
-                       //assert(0);
-                       //return kr_error(EINVAL);
-                       addr_family = AF_UNSPEC;
-                       DEBUG_MSG(NULL, "%s\n", "could not obtain client IP address for client cookie");
-               }
+       assert(sockaddr && addr && len);
+
+       int addr_family = ((struct sockaddr *) sockaddr)->sa_family;
+
+       switch (addr_family) {
+       case AF_INET:
+               *addr = (uint8_t *) &((struct sockaddr_in *) sockaddr)->sin_addr;
+               *len = 4;
+               break;
+       case AF_INET6:
+               *addr = (uint8_t *) &((struct sockaddr_in6 *) sockaddr)->sin6_addr;
+               *len = 16;
+               break;
+       default:
+               *addr = NULL;
+               *len = 0;
+               addr_family = AF_UNSPEC;
+               DEBUG_MSG(NULL, "%s\n", "could obtain IP address");
+               return;
+               break;
+       }
 
-               if (addr_family != AF_UNSPEC) {
-                       WITH_DEBUG {
-                               char ns_str[INET6_ADDRSTRLEN];
-                               inet_ntop(addr_family, clnt_addr, ns_str, sizeof(ns_str));
-                               DEBUG_MSG(NULL, "adding client IP address '%s' into client cookie\n", ns_str);
-                       }
-               }
+       WITH_DEBUG {
+               char ns_str[INET6_ADDRSTRLEN];
+               inet_ntop(addr_family, *addr, ns_str, sizeof(ns_str));
+               DEBUG_MSG(NULL, "obtaned IP address '%s'\n", ns_str);
+       }
+}
+
+int kr_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
+                          void *clnt_sockaddr, void *srvr_sockaddr,
+                          struct secret_quantity *secret)
+{
+       if (!cc_buf) {
+               return kr_error(EINVAL);
+       }
+
+       if (!clnt_sockaddr && !srvr_sockaddr &&
+           !(secret && secret->size && secret->data)) {
+               return kr_error(EINVAL);
        }
 
-       if (srvr_addr) {
-               int addr_family = ((struct sockaddr *) srvr_addr)->sa_family;
-               if (addr_family == AF_INET) {
-                       srvr_addr = &((struct sockaddr_in *) srvr_addr)->sin_addr;
-               } else if (addr_family == AF_INET6) {
-                       srvr_addr = &((struct sockaddr_in6 *) srvr_addr)->sin6_addr;
-               } else {
-                       addr_family = AF_UNSPEC;
-                       DEBUG_MSG(NULL, "%s\n", "could not obtain server IP address for client cookie");
+       uint8_t *addr = NULL;
+       size_t size = 0;
+
+       Fnv64_t hash_val = FNV1A_64_INIT;
+
+       if (clnt_sockaddr) {
+               obtain_address(clnt_sockaddr, &addr, &size);
+               if (addr && size) {
+                       hash_val = fnv_64a_buf(addr, size, hash_val);
                }
+       }
 
-               if (addr_family != AF_UNSPEC) {
-                       WITH_DEBUG {
-                               char ns_str[INET6_ADDRSTRLEN];
-                               inet_ntop(addr_family, srvr_addr, ns_str, sizeof(ns_str));
-                               DEBUG_MSG(NULL, "adding server address '%s' into client cookie\n", ns_str);
-                       }
+       if (srvr_sockaddr) {
+               obtain_address(srvr_sockaddr, &addr, &size);
+               if (addr && size) {
+                       hash_val = fnv_64a_buf(addr, size, hash_val);
                }
        }
 
-       memcpy(cc, csq->secret, KNOT_OPT_COOKIE_CLNT);
+       if (secret && secret->size && secret->data) {
+               DEBUG_MSG(NULL, "%s\n", "adding client secret into cookie");
+               hash_val = fnv_64a_buf(addr, size, hash_val);
+       }
+
+       assert(KNOT_OPT_COOKIE_CLNT == sizeof(hash_val));
+
+       memcpy(cc_buf, &hash_val, KNOT_OPT_COOKIE_CLNT);
+
+       return kr_ok();
 }
 
 int kr_request_put_cookie(struct cookies_control *cntrl, void *clnt_sockaddr,
@@ -143,7 +160,7 @@ int kr_request_put_cookie(struct cookies_control *cntrl, void *clnt_sockaddr,
                return kr_error(EINVAL);
        }
 
-       int ret = prepare_client_cookie(cc, clnt_sockaddr, srvr_sockaddr,
+       int ret = kr_client_cokie_fnv64(cc, clnt_sockaddr, srvr_sockaddr,
                                        cntrl->client);
 
        /* This is a very nasty hack that prevents the packet to be corrupted
index 0124d48fb5ef38e728226784cba271cb3a4954cc..98a16648ef52aff29eed97bec6fffb2a1afab6d0 100644 (file)
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <libknot/packet/pkt.h>
+#include <libknot/rrtype/opt_cookie.h>
 #include <stdbool.h>
 
 #include "lib/cache.h"
@@ -27,7 +28,7 @@
 /** Holds secret quantity. */
 struct secret_quantity {
        size_t size; /*!< Secret quantity size. */
-       const uint8_t *secret;
+       const uint8_t *data; /*!< Secret quantity data. */
 };
 
 /** DNSSEC cookies controlling structure. */
@@ -42,6 +43,19 @@ struct cookies_control {
 KR_EXPORT
 extern struct cookies_control kr_cookies_control;
 
+/**
+ * Compute client cookie.
+ * @not At least one of the arguments must be non-null.
+ * @param cc_buf        Buffer to which to write the cookie into.
+ * @param clnt_sockaddr Client address.
+ * @param srvr_sockaddr Server address.
+ * @param secret        Client secret quantity.
+ */
+KR_EXPORT
+int kr_client_cokie_fnv64(uint8_t cc_buf[KNOT_OPT_COOKIE_CLNT],
+                          void *clnt_sockaddr, void *srvr_sockaddr,
+                          struct secret_quantity *secret);
+
 /**
  * Insert a DNS cookie into query packet.
  * @note The packet must already contain ENDS section.
index b4cb4a99815062acde36cd8f78dca6c5e11d0d54..0408aa71ecf297325077dcca40da9babec1ba11b 100644 (file)
@@ -1,4 +1,5 @@
 libkres_SOURCES := \
+       contrib/fnv/hash_64a.c \
        lib/generic/map.c      \
        lib/layer/iterate.c    \
        lib/layer/validate.c   \