/*- * Copyright 2016 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "config.h" #include "bloom.h" #include "cryptobox.h" /* 4 bits are used for counting (implementing delete operation) */ #define SIZE_BIT 4 /* These macroes are for 4 bits for counting element */ #define INCBIT(a, n, acc) do { \ acc = \ a[n * SIZE_BIT / CHAR_BIT] & (0xF << \ (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT)); \ acc ++; \ acc &= 0xF; \ \ a[n * SIZE_BIT / \ CHAR_BIT] &= (0xF << (4 - (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT))); \ a[n * SIZE_BIT / \ CHAR_BIT] |= (acc << (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT)); \ } while (0); #define DECBIT(a, n, acc) do { \ acc = \ a[n * SIZE_BIT / CHAR_BIT] & (0xF << \ (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT)); \ acc --; \ acc &= 0xF; \ \ a[n * SIZE_BIT / \ CHAR_BIT] &= (0xF << (4 - (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT))); \ a[n * SIZE_BIT / \ CHAR_BIT] |= (acc << (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT)); \ } while (0); #define GETBIT(a, \ n) (a[n * SIZE_BIT / CHAR_BIT] & (0xF << \ (n % (CHAR_BIT / SIZE_BIT) * SIZE_BIT))) /* Common hash functions */ rspamd_bloom_filter_t * rspamd_bloom_create (size_t size, size_t nfuncs, ...) { rspamd_bloom_filter_t *bloom; va_list l; gsize n; if (!(bloom = g_malloc (sizeof (rspamd_bloom_filter_t)))) { return NULL; } if (!(bloom->a = g_new0 (gchar, (size + CHAR_BIT - 1) / CHAR_BIT * SIZE_BIT))) { g_free (bloom); return NULL; } if (!(bloom->seeds = g_new0 (guint32, nfuncs))) { g_free (bloom->a); g_free (bloom); return NULL; } va_start (l, nfuncs); for (n = 0; n < nfuncs; ++n) { bloom->seeds[n] = va_arg (l, guint32); } va_end (l); bloom->nfuncs = nfuncs; bloom->asize = size; return bloom; } void rspamd_bloom_destroy (rspamd_bloom_filter_t * bloom) { g_free (bloom->a); g_free (bloom->seeds); g_free (bloom); } gboolean rspamd_bloom_add (rspamd_bloom_filter_t * bloom, const gchar *s) { size_t n, len; u_char t; guint v; if (s == NULL) { return FALSE; } len = strlen (s); for (n = 0; n < bloom->nfuncs; ++n) { v = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, s, len, bloom->seeds[n]) % bloom->asize; INCBIT (bloom->a, v, t); } return TRUE; } gboolean rspamd_bloom_del (rspamd_bloom_filter_t * bloom, const gchar *s) { size_t n, len; u_char t; guint v; if (s == NULL) { return FALSE; } len = strlen (s); for (n = 0; n < bloom->nfuncs; ++n) { v = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, s, len, bloom->seeds[n]) % bloom->asize; DECBIT (bloom->a, v, t); } return TRUE; } gboolean rspamd_bloom_check (rspamd_bloom_filter_t * bloom, const gchar *s) { size_t n, len; guint v; if (s == NULL) { return FALSE; } len = strlen (s); for (n = 0; n < bloom->nfuncs; ++n) { v = rspamd_cryptobox_fast_hash_specific (RSPAMD_CRYPTOBOX_XXHASH64, s, len, bloom->seeds[n]) % bloom->asize; if (!(GETBIT (bloom->a, v))) { return FALSE; } } return TRUE; }