diff --git a/src/filters/CMakeLists.txt b/src/filters/CMakeLists.txt index 120b8be..7321cb9 100644 --- a/src/filters/CMakeLists.txt +++ b/src/filters/CMakeLists.txt @@ -2,12 +2,12 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) unset(CMAKE_SHARED_MODULE_PREFIX) set(FILTERS "") -add_library("f_preg" MODULE "preg.c" "../strlcpy.c") +add_library("f_preg" MODULE "preg.c" "../strlcpy.c" "../fnv32a.c") list(APPEND FILTERS "preg") find_library(PCRE_FOUND "pcre") if (WITH_PCRE AND PCRE_FOUND) - add_library("f_pcre" MODULE "pcre.c" "../strlcpy.c") + add_library("f_pcre" MODULE "pcre.c" "../strlcpy.c" "../fnv32a.c") target_link_libraries("f_pcre" "pcre") list(APPEND FILTERS "pcre") endif () diff --git a/src/filters/filter.c b/src/filters/filter.c index 3f1aa2f..1770f43 100644 --- a/src/filters/filter.c +++ b/src/filters/filter.c @@ -40,7 +40,8 @@ stats(cfg_t *cfg, char *buf, size_t bufsize) { char tmp[PATTERN_MAX + 64]; const char *fmt = "- pattern: %s\n" - " matches: %d\n"; + " matches: %d\n" + " tag: %08x\n"; assert(cfg != NULL); @@ -48,7 +49,7 @@ stats(cfg_t *cfg, char *buf, size_t bufsize) { return false; for (rx_t *rx = cfg->regexps; rx != NULL; rx = rx->next) { - snprintf(tmp, sizeof(tmp), fmt, rx->pattern, rx->matches); + snprintf(tmp, sizeof(tmp), fmt, rx->pattern, rx->matches, rx->ftag); strlcat(buf, tmp, bufsize); } diff --git a/src/filters/filter.h b/src/filters/filter.h index a3d93f5..10f98a6 100644 --- a/src/filters/filter.h +++ b/src/filters/filter.h @@ -10,11 +10,13 @@ #include #include #include +#include #include #include #include #include "../strlcpy.h" +#include "../fnv.h" #include "../mod-defs.h" #include "../mod-api.h" diff --git a/src/filters/pcre.c b/src/filters/pcre.c index 61ec0f0..85fff2e 100644 --- a/src/filters/pcre.c +++ b/src/filters/pcre.c @@ -4,28 +4,32 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include "filter.h" + #include -#include "filter.h" #define MODNAME "pcre" #define HOST_REGEX "(?[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3})" struct _regexp { rx_t *next; - char pattern[PATTERN_MAX]; - int matches; pcre *regex; pcre_extra *data; + int matches; + uint32_t ftag; + short int score; + char pattern[PATTERN_MAX]; }; struct _config { - char id[ID_MAX]; void (*logcb)(enum loglevel lvl, const char *msg); + rx_t *regexps; int flags; + short int defscore; bool icase; bool study; bool usejit; - rx_t *regexps; + char id[ID_MAX]; }; #include "filter.c" @@ -122,6 +126,7 @@ append(cfg_t *cfg, const char *pattern) { } } + regex->ftag = fnv_32a_str(pattern, FNV1_32A_INIT); regex->next = cfg->regexps; cfg->regexps = regex; strlcpy(regex->pattern, pattern, sizeof(regex->pattern)); diff --git a/src/filters/preg.c b/src/filters/preg.c index adcb93c..fb310a4 100644 --- a/src/filters/preg.c +++ b/src/filters/preg.c @@ -15,17 +15,19 @@ struct _regexp { rx_t *next; - char pattern[PATTERN_MAX]; + uint32_t ftag; int matches; regex_t regex; + char pattern[PATTERN_MAX]; }; struct _config { - char id[ID_MAX]; + rx_t *regexps; + void (*logcb)(enum loglevel lvl, const char *msg); + short int defscore; int flags; + char id[ID_MAX]; bool icase; - void (*logcb)(enum loglevel lvl, const char *msg); - rx_t *regexps; }; #include "filter.c" @@ -87,6 +89,7 @@ append(cfg_t *cfg, const char *pattern) { return false; if ((ret = regcomp(®ex->regex, buf, flags)) == 0) { + regex->ftag = fnv_32a_str(pattern, FNV1_32A_INIT); regex->next = cfg->regexps; cfg->regexps = regex; strlcpy(regex->pattern, pattern, sizeof(regex->pattern)); diff --git a/src/fnv.h b/src/fnv.h new file mode 100644 index 0000000..2d3b392 --- /dev/null +++ b/src/fnv.h @@ -0,0 +1,97 @@ +/* + * 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 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 32 bit FNV-1a hash, pass FNV1_32A_INIT as the + * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_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 /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#if !defined(__FNV_H__) +#define __FNV_H__ + +#include + +#define FNV_VERSION "5.0.2" /* @(#) FNV Version */ + +/* + * 32 bit FNV-0 hash type + */ +typedef uint32_t Fnv32_t; + +/* + * 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 /\../\ + * + * 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 + +extern Fnv32_t fnv_32a_buf(const void *buf, size_t len, Fnv32_t hashval); +extern Fnv32_t fnv_32a_str(const char *buf, Fnv32_t hashval); + +#endif /* __FNV_H__ */ diff --git a/src/fnv32a.c b/src/fnv32a.c new file mode 100644 index 0000000..b02c365 --- /dev/null +++ b/src/fnv32a.c @@ -0,0 +1,142 @@ +/* + * hash_32 - 32 bit Fowler/Noll/Vo FNV-1a hash code + * + * @(#) $Revision: 5.1 $ + * @(#) $Id: hash_32a.c,v 5.1 2009/06/30 09:13:32 chongo Exp $ + * @(#) $Source: /usr/local/src/cmd/fnv/RCS/hash_32a.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 32 bit FNV-1a hash, pass FNV1_32A_INIT as the + * Fnv32_t hashval argument to fnv_32a_buf() or fnv_32a_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 /\oo/\ + * http://www.isthe.com/chongo/ + * + * Share and Enjoy! :-) + */ + +#include +#include +#include "fnv.h" + +/* + * 32 bit magic FNV-1a prime + */ +#define FNV_32_PRIME ((Fnv32_t)0x01000193) + +/* + * fnv_32a_buf - perform a 32 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: + * 32 bit hash as a static hash type + * + * NOTE: To use the recommended 32 bit FNV-1a hash, use FNV1_32A_INIT as the + * hval arg on the first call to either fnv_32a_buf() or fnv_32a_str(). + */ +Fnv32_t +fnv_32a_buf(const void *buf, size_t len, Fnv32_t hval) +{ + unsigned char *bp = (unsigned char *)buf; /* start of buffer */ + unsigned char *be = bp + len; /* beyond end of buffer */ + + /* + * FNV-1a hash each octet in the buffer + */ + while (bp < be) { + + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t)*bp++; + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); +#endif + } + + /* return our new hash value */ + return hval; +} + +/* + * fnv_32a_str - perform a 32 bit Fowler/Noll/Vo FNV-1a hash on a string + * + * input: + * str - string to hash + * hval - previous hash value or 0 if first call + * + * returns: + * 32 bit hash as a static hash type + * + * NOTE: To use the recommended 32 bit FNV-1a hash, use FNV1_32A_INIT as the + * hval arg on the first call to either fnv_32a_buf() or fnv_32a_str(). + */ +Fnv32_t +fnv_32a_str(const char *str, Fnv32_t hval) +{ + unsigned char *s = (unsigned char *)str; /* unsigned string */ + + /* + * FNV-1a hash each octet in the buffer + */ + while (*s) { + + /* xor the bottom with the current octet */ + hval ^= (Fnv32_t)*s++; + + /* multiply by the 32 bit FNV magic prime mod 2^32 */ +#if defined(NO_FNV_GCC_OPTIMIZATION) + hval *= FNV_32_PRIME; +#else + hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24); +#endif + } + + /* return our new hash value */ + return hval; +} diff --git a/src/sources/CMakeLists.txt b/src/sources/CMakeLists.txt index ae32ed1..b822373 100644 --- a/src/sources/CMakeLists.txt +++ b/src/sources/CMakeLists.txt @@ -2,10 +2,10 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) unset(CMAKE_SHARED_MODULE_PREFIX) set(SOURCES "") -add_library("s_files" MODULE "files.c" "../strlcpy.c") +add_library("s_files" MODULE "files.c" "../strlcpy.c" "../fnv32a.c") list(APPEND SOURCES "files") -add_library("s_portknock" MODULE "portknock.c" "../strlcpy.c") +add_library("s_portknock" MODULE "portknock.c" "../strlcpy.c" "../fnv32a.c") list(APPEND SOURCES "portknock") find_library(REDIS_FOUND "hiredis") diff --git a/src/sources/files.c b/src/sources/files.c index 882f324..52ccbff 100644 --- a/src/sources/files.c +++ b/src/sources/files.c @@ -4,22 +4,23 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ +#include "source.h" + #include #include #include - #include #include -#include "source.h" #define MODNAME "files" typedef struct f2b_file_t { struct f2b_file_t *next; + uint32_t lines; + uint32_t stag; FILE *fd; char path[PATH_MAX]; struct stat st; - unsigned int lines; } f2b_file_t; struct _config { @@ -167,6 +168,7 @@ start(cfg_t *cfg) { free(file); continue; } + file->stag = fnv_32a_str(globbuf.gl_pathv[i], FNV1_32A_INIT); if (cfg->files == NULL) { cfg->files = file; } else { diff --git a/src/sources/portknock.c b/src/sources/portknock.c index adcf778..25b4065 100644 --- a/src/sources/portknock.c +++ b/src/sources/portknock.c @@ -18,10 +18,11 @@ typedef struct f2b_port_t { struct f2b_port_t *next; - char host[HOST_MAX]; - char port[PORT_MAX]; unsigned int accepts; + uint32_t stag; int sock; + char host[HOST_MAX]; + char port[PORT_MAX]; } f2b_port_t; struct _config { @@ -98,6 +99,7 @@ config(cfg_t *cfg, const char *key, const char *value) { free(port); return false; } + port->stag = fnv_32a_str(port->port, FNV1_32A_INIT); port->next = cfg->ports; cfg->ports = port; cfg->flags |= MOD_IS_READY; diff --git a/src/sources/redis.c b/src/sources/redis.c index f1608b4..49d7215 100644 --- a/src/sources/redis.c +++ b/src/sources/redis.c @@ -15,17 +15,17 @@ #define ID_MAX 32 struct _config { - char name[ID_MAX + 1]; - char hash[ID_MAX * 2]; + redisContext *conn; void (*logcb)(enum loglevel lvl, const char *msg); time_t timeout; + int flags; + uint16_t port; + uint32_t received; uint8_t database; char password[32]; char host[32]; - uint16_t port; - uint32_t received; - int flags; - redisContext *conn; + char name[ID_MAX + 1]; + char hash[ID_MAX * 2]; }; #include "source.c" diff --git a/src/sources/source.h b/src/sources/source.h index fccc70d..806addc 100644 --- a/src/sources/source.h +++ b/src/sources/source.h @@ -9,11 +9,13 @@ #include #include #include +#include #include #include #include #include "../strlcpy.h" +#include "../fnv.h" #include "../mod-defs.h" #include "../mod-api.h" diff --git a/t/CMakeLists.txt b/t/CMakeLists.txt index 826bd8a..8b418b7 100644 --- a/t/CMakeLists.txt +++ b/t/CMakeLists.txt @@ -16,11 +16,11 @@ add_test("tests/f2b_ipaddr_*" "t_ipaddr") add_test("tests/f2b_statefile_*" "t_statefile") add_test("tests/f2b_config_param*" "t_config_param") -add_executable("t_filter_preg" "t_filters.c" "${SRC_DIR}/filters/preg.c" "${SRC_DIR}/strlcpy.c") +add_executable("t_filter_preg" "t_filters.c" "${SRC_DIR}/filters/preg.c" "${SRC_DIR}/strlcpy.c" "${SRC_DIR}/fnv32a.c") add_test("tests/filter/preg" "t_filter_preg") if (WITH_PCRE) add_test("tests/filter/pcre" "t_filter_pcre") -add_executable("t_filter_pcre" "t_filters.c" "${SRC_DIR}/filters/pcre.c" "${SRC_DIR}/strlcpy.c") +add_executable("t_filter_pcre" "t_filters.c" "${SRC_DIR}/filters/pcre.c" "${SRC_DIR}/strlcpy.c" "${SRC_DIR}/fnv32a.c") target_link_libraries("t_filter_pcre" "pcre") endif ()