Compare commits

..

16 Commits

  1. 3
      .gitignore
  2. 8
      CMakeLists.txt
  3. 37
      ChangeLog
  4. 6
      configs/conf-available/10-backend-exec-ipfw.conf
  5. 3
      configs/conf-available/20-jail-dovecot.conf.in
  6. 3
      configs/conf-available/20-jail-nginx.conf.in
  7. 3
      configs/conf-available/20-jail-postfix.conf.in
  8. 3
      configs/conf-available/20-jail-ssh.conf.in
  9. 6
      configs/f2b.conf.in
  10. 6
      debian/changelog
  11. 2
      debian/compat
  12. 5
      debian/control
  13. 1
      debian/f2b.dirs
  14. 3
      debian/f2b.install
  15. 2
      filters/README.txt
  16. 4
      filters/asterisk.preg
  17. 2
      filters/coturn.preg
  18. 6
      filters/dovecot.preg
  19. 10
      filters/exim.pcre
  20. 3
      filters/gitea.preg
  21. 6
      filters/named.preg
  22. 32
      filters/nginx-bots.pcre
  23. 11
      filters/postfix.preg
  24. 17
      filters/ssh.preg
  25. 1
      src/backend-test.c
  26. 14
      src/backends/CMakeLists.txt
  27. 0
      src/backends/ipset6.c
  28. 192
      src/backends/ipset7.c
  29. 4
      src/filters/CMakeLists.txt
  30. 4
      src/sources/CMakeLists.txt

3
.gitignore vendored

@ -1,3 +1,6 @@
CMakeCache.txt
CMakeFiles/
*.cmake
# generated configs:
configs/f2b.conf
configs/conf-available/20-jail-*.conf

8
CMakeLists.txt

@ -1,11 +1,13 @@
set(CNAME "f2b")
set(VERSION "0.5")
set(VERSION "0.6")
project(${CNAME} C)
cmake_minimum_required(VERSION 2.6)
include(CTest)
find_package(PkgConfig REQUIRED)
option(WITH_CLIENT "Simple client for configuring daemon" ON)
option(WITH_CSOCKET "Unix control socket support for daemon" ON)
option(WITH_HARDENING "Enable hardening options" ON)
@ -38,6 +40,9 @@ if (WITH_HARDENING)
add_definitions("-D_FORTIFY_SOURCE=2")
endif ()
pkg_check_modules(READLINE "readline" REQUIRED)
message(STATUS "----------------------------------------")
message(STATUS "Compiler : ${CMAKE_C_COMPILER} (${CMAKE_C_COMPILER_ID} ${CMAKE_C_COMPILER_VERSION})")
message(STATUS "- CFLAGS : ${CMAKE_C_FLAGS}")
message(STATUS "Paths:")
@ -63,7 +68,6 @@ add_subdirectory(src)
add_subdirectory(t)
set_property(DIRECTORY "t" PROPERTY COMPILE_FLAGS "-g;-ggdb;-Wall;-Wextra;-pedantic;-O0")
install(DIRECTORY "filters" DESTINATION "${CMAKE_INSTALL_DATAROOTDIR}/${CNAME}")
file(GLOB_RECURSE CONFIGS "*.conf.in")
foreach(CONFIG ${CONFIGS})
string(REPLACE ".conf.in" ".conf" GENERATED ${CONFIG})

37
ChangeLog

@ -6,6 +6,43 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## Unreleased
## [0.6] - 2023-02-07
### Added
* add 'log level <level>' command
* add 'log events' command
* support for libipset > 7.X
* readline support in f2bc
* add log rotation to debian package
* new options for daemon -- "coredumps" && "nice"
* allow jails without filter
* replace simple "match count" with advanced "scored matches"
* add source/filter match tags in stats
* show daemon uptime in status
### Changed
* filters collection now in separate repository
* change modules naming & location
* change 'rotate' command to 'log rotate' for consistency
* client and control socket fully refactored to use plain tcp
* allow redis source/backend fail on start (no network yet)
* filter-test now uses config instead direct library load
* match count now not limited to last 5
* jail's "maxcount" parameter replaced with "maxscore" (need config fix)
* if missing password for control socket in config it will be set random (and send to logfile)
* build system now relies on pkg-config instead cmake modules
### Removed
* multicast source/backend (replaced with f2bcd)
### Fixed
* don't hard depend on mountall
* fix setting jail 'state' param
* SO_PEERCRED is linux-specific now
## [0.5] - 2017-01-19
### Added

6
configs/conf-available/10-backend-exec-ipfw.conf

@ -1,6 +1,8 @@
# -q option stops a ipfw table add or delete from failing if the entry
# already exists or is not present.
[backend:exec-ipfw]
load = backend_exec.so
ban = /sbin/ipfw table <ID> add <IP>
unban = /sbin/ipfw table <ID> delete <IP>
ban = /sbin/ipfw -q table <ID> add <IP>
unban = /sbin/ipfw -q table <ID> delete <IP>
timeout = 2
shared = yes

3
configs/conf-available/20-jail-dovecot.conf.in

@ -0,0 +1,3 @@
[jail:dovecot]
source = files:/var/log/mail.log
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/dovecot.preg

3
configs/conf-available/20-jail-nginx.conf.in

@ -0,0 +1,3 @@
[jail:nginx]
source = files:/var/log/nginx/*access*.log
filter = pcre:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/nginx-bots.pcre

3
configs/conf-available/20-jail-postfix.conf.in

@ -0,0 +1,3 @@
[jail:postfix]
source = files:/var/log/mail.log
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/postfix.preg

3
configs/conf-available/20-jail-ssh.conf.in

@ -0,0 +1,3 @@
[jail:ssh]
source = files:/var/log/auth.log
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/ssh.preg

6
configs/f2b.conf.in

@ -13,7 +13,7 @@ nice = 0
[defaults]
state = no
enabled = no
enabled = yes
bantime = 3600
findtime = 300
expiretime = 14400
@ -30,7 +30,3 @@ listen = unix:/var/run/f2b.sock
; auth used only for 'inet' connections
; if password not set - it will be generated on each restart, see logs
;password = <something-long-enough>
[jail:ssh]
source = files:/var/log/auth.log
filter = preg:${CMAKE_INSTALL_FULL_DATAROOTDIR}/f2b/filters/ssh.preg

6
debian/changelog vendored

@ -1,3 +1,9 @@
f2b (0.6-1) unstable; urgency=medium
* new version
-- Alex 'AdUser' Z <ad_user@runbox.com> Tue, 07 Feb 2023 14:00:06 +1000
f2b (0.5-1) unstable; urgency=medium
* new version

2
debian/compat vendored

@ -1 +1 @@
9
11

5
debian/control vendored

@ -2,7 +2,7 @@ Source: f2b
Section: net
Priority: optional
Maintainer: Alex 'AdUser' Z <ad_user@runbox.com>
Build-Depends: debhelper (>= 9), cmake, libpcre3-dev, libhiredis-dev, libipset-dev, libreadline-dev
Build-Depends: debhelper (>= 9), cmake, libpcre3-dev, libhiredis-dev, libipset-dev, libreadline-dev, pkg-config
Standards-Version: 3.9.5
Homepage: https://github.com/AdUser/f2b
Vcs-Git: https://github.com/AdUser/f2b.git
@ -10,7 +10,8 @@ Vcs-Browser: https://github.com/AdUser/f2b
Package: f2b
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Depends: ${shlibs:Depends}, ${misc:Depends}, f2b-filters
Recommends: netfilter-persistent
Description: lightweight automatic anti-bot turret for your public serivces
Features:
.

1
debian/f2b.dirs vendored

@ -1 +1,2 @@
usr/share/f2b/filters
var/lib/f2b

3
debian/f2b.install vendored

@ -2,13 +2,12 @@ etc/f2b/conf-available/*-source-files.conf
etc/f2b/conf-available/*-source-portknock.conf
etc/f2b/conf-available/*-filter-preg.conf
etc/f2b/conf-available/*-backend-exec-*.conf
etc/f2b/conf-available/*-jail-global.conf
etc/f2b/conf-available/*-jail-*.conf
etc/f2b/conf-enabled
etc/f2b/f2b.conf
usr/bin/f2b-*-test
usr/bin/f2bc
usr/sbin/f2b
usr/share/f2b
usr/lib/*/f2b/source_files.so
usr/lib/*/f2b/source_portknock.so
usr/lib/*/f2b/filter_preg.so

2
filters/README.txt

@ -0,0 +1,2 @@
- Where have all filters gone?
- Now it located in their own repository, for convinient maintenance

4
filters/asterisk.preg

@ -1,4 +0,0 @@
SECURITY.* SecurityEvent="FailedACL".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9]+"
SECURITY.* SecurityEvent="InvalidAccountID".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9+]+"
SECURITY.* SecurityEvent="ChallengeResponseFailed".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9]+"
SECURITY.* SecurityEvent="InvalidPassword".*RemoteAddress="IPV[46]/[TU][CD]P/<HOST>/[0-9]+"

2
filters/coturn.preg

@ -1,2 +0,0 @@
# set: defscore=5
closed \(2nd stage\), user <> .* remote <HOST>:[0-9]+, reason: allocation watchdog determined stale session state

6
filters/dovecot.preg

@ -1,6 +0,0 @@
pop3-login: Aborted login \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST>
imap-login: Aborted login \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST>
pop3-login: Disconnected \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST>
imap-login: Disconnected \(auth failed, [0-9]+ attempts in [0-9]+ secs\): .* rip=<HOST>
# set: defscore=5
submission-login: Client has quit the connection \(tried to use disallowed plaintext auth\): .* rip=<HOST>

10
filters/exim.pcre

@ -1,10 +0,0 @@
# set: defscore=10
SMTP protocol synchronization error \(input sent without waiting for greeting\): rejected connection from .*\[<HOST>\]
SMTP protocol synchronization error \(next input sent too soon: pipelining was not advertised\): rejected .*\[<HOST>\]
rejected [HE][EH]HLO from \[<HOST>\]: syntactically invalid argument
\[<HOST>\] .* host is listed in .+
\[<HOST>\] .* relay not permitted
\[<HOST>\] .* rejected after DATA: This message was detected as possible malware
# set: defscore=5
\[<HOST>\] .* too many connections from that IP address
\[<HOST>\] .* temporarily rejected RCPT \<\S+\>: lowest numbered MX record points to local host

3
filters/gitea.preg

@ -1,3 +0,0 @@
Failed authentication attempt for [[:print:]]+ from <HOST>
Failed authentication attempt from <HOST>
invalid credentials from <HOST>

6
filters/named.preg

@ -1,6 +0,0 @@
# set: defscore=10
<HOST>#[0-9]+ .* query \(cache\) '[0-9.]+.in-addr.arpa/(PTR|SOA)/IN' denied
# requests to '.' or top-level domains
<HOST>#[0-9]+ .* query \(cache\) '[a-z.]+/ANY/IN' denied
# set: defscore=1
<HOST>#[0-9]+ .* query \(cache\) '[0-9a-z.-]+/RRSIG/IN' denied

32
filters/nginx-bots.pcre

@ -1,32 +0,0 @@
# set: defscore=15
# h4x0rs
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/(shell|cmd|x)\.(php|cgi)
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/w00tw00t
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+Ringing\.at\.your\.dorbell
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/.*(wget|curl)(\\x|%)20https?://
<HOST> .* "(GET|HEAD|POST) .*/bin/(ba|c|z)?sh( |\\x20|%20)-c
<HOST> .* "(\\x[0-9a-z]{2,6})+" 400
# set: defscore=10
# phpmyadmin and variations
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+(php|sqlite)-?(manager)?
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+(php|pg|sql)-?my-?admin
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+pma[0-9]*
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+((my|pg)(sql)?|db|msd?)-?(admin|dumper|dump|manager)
# set: defscore=5
# open proxy search
<HOST> .* "(GET|HEAD|POST) https?://[a-z-\.]+proxyradar\.com
<HOST> .* "CONNECT [a-z-\.]*proxyradar\.com
<HOST> .* "CONNECT [a-z-\.]*proxytest\.zmap\.io
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+testproxy\.php
# set: defscore=2
# search bots
<HOST> .* "(GET|HEAD|POST) .* "python-(requests|urllib)/[0-9\.]+
<HOST> .* "(GET|HEAD|POST) .* "AhrefsBot/[0-9a-z\.]+
<HOST> .* "(GET|HEAD|POST) .* "DotBot/[0-9a-z\.]+
<HOST> .* "(GET|HEAD|POST) .* "MauiBot
<HOST> .* "(GET|HEAD|POST) .* SiteExplorer/[0-9a-z\.]+
<HOST> .* "(GET|HEAD|POST) .* MJ12bot
<HOST> .* "(GET|HEAD|POST) .* WebIndex
# shit-coded php cms
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/.*/wp-login.php
<HOST> .* "(GET|HEAD|POST) (https?://[0-9a-z.-]+)?(:[0-9]*)?/+(joomla|cms)/administrator

11
filters/postfix.preg

@ -1,11 +0,0 @@
# set: defscore=10
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 450 4\.7\.1 Client host rejected
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 454 4\.7\.1 Service unavailable; Client host \[[[:print:]]+\] blocked
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 454 4\.7\.1 <[[:print:]]+>: Relay access denied
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 554 5\.7\.1 <[[:print:]]+>: Relay access denied
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 550 5\.1\.1 <[[:print:]]+>: Recipient address rejected: undeliverable address
warning: [[:print:]]+\[<HOST>\]: SASL [A-Z0-9-]+ authentication failed
# set: defscore=5
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 450 4\.7\.1 <[[:print:]]+>: Helo command rejected: Host not found
NOQUEUE: reject: RCPT from [[:print:]]+\[<HOST>\]: 504 5\.5\.2 <[[:print:]]+>: Helo command rejected: need fully-qualified hostname
lost connection after AUTH from [[:print:]]+\[<HOST>\]

17
filters/ssh.preg

@ -1,17 +0,0 @@
# set: defscore=15
User [[:print:]]+ from <HOST> not allowed because listed in DenyUsers
User [[:print:]]+ from <HOST> not allowed because a group is listed in DenyGroups
# set: defscore=10
User [[:print:]]+ from <HOST> not allowed because not listed in AllowUsers
User [[:print:]]+ from <HOST> not allowed because not in any group
User [[:print:]]+ from <HOST> not allowed because none of user's groups are listed in AllowGroups
[Aa]uthentication failure for .* from <HOST>( via [[:print:]]*)?
[Aa]uthentication error for .* from <HOST>( via [[:print:]]*)?
Failed password for .* from <HOST>
# set: defscore=5
User not known to the underlying authentication module for .* from <HOST>
Invalid user [[:print:]]+ from <HOST>
# set: defscore=3
refused connect from [[:print:]]+ \(<HOST>\)
Did not receive identification string from <HOST>
Connection closed by <HOST>( port [0-9]+)? \[preauth\]

1
src/backend-test.c

@ -100,6 +100,7 @@ int main(int argc, char *argv[]) {
}
fputs("usage: <cmd> <ipaddr>\n", stdout);
fputs(" available commands: ban, unban, check\n", stdout);
fputs("press Ctrl-D for exit\n", stdout);
while (1) {
fputs("test >> ", stdout);

14
src/backends/CMakeLists.txt

@ -5,16 +5,20 @@ set(BACKENDS "")
add_library("b_exec" MODULE "exec.c" "../strlcpy.c")
list(APPEND BACKENDS "exec")
find_library(REDIS_FOUND "hiredis")
if (WITH_REDIS AND REDIS_FOUND)
if (WITH_REDIS)
pkg_check_modules(REDIS "hiredis" REQUIRED)
add_library("b_redis" MODULE "redis.c" "../strlcpy.c")
target_link_libraries("b_redis" "hiredis")
list(APPEND BACKENDS "redis")
endif ()
find_library(IPSET_FOUND "ipset")
if (WITH_IPSET AND IPSET_FOUND)
add_library("b_ipset" MODULE "ipset.c" "../strlcpy.c")
if (WITH_IPSET)
pkg_check_modules(IPSET "libipset" REQUIRED)
if (IPSET_VERSION VERSION_LESS 7)
add_library("b_ipset" MODULE "ipset6.c" "../strlcpy.c")
else ()
add_library("b_ipset" MODULE "ipset7.c" "../strlcpy.c")
endif ()
target_link_libraries("b_ipset" "ipset")
list(APPEND BACKENDS "ipset")
endif ()

0
src/backends/ipset.c → src/backends/ipset6.c

192
src/backends/ipset7.c

@ -0,0 +1,192 @@
/* Copyright 2017 Alex 'AdUser' Z (ad_user@runbox.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <assert.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libipset/ipset.h>
#include "../strlcpy.h"
#include "backend.h"
#define MODNAME "ipset"
#define IP_LEN_MAX 46 /* ipv6 in mind */
struct _config {
char name[ID_MAX + 1];
void (*logcb)(enum loglevel lvl, const char *msg);
struct ipset *ipset;
enum ipset_cmd last_cmd;
int flags;
bool shared;
};
#include "backend.c"
/**
* @brief Wrapper to get last ipset error and send to log
* @note Called from this module */
inline static bool
my_ipset_error(cfg_t *cfg, const char *func) {
struct ipset_data *data = NULL;
struct ipset_session *sess = ipset_session(cfg->ipset);
if (ipset_session_report_type(sess) != IPSET_NO_ERROR) {
log_msg(cfg, error, "%s: %s", func, ipset_session_report_msg(sess));
ipset_session_report_reset(sess);
}
if ((data = ipset_session_data(sess)) != NULL)
ipset_data_reset(data);
return false;
}
/**
* @note Called from library internals
*/
int
my_ipset_std_error_cb(struct ipset *ipset, void *cfg) {
struct ipset_session *sess = ipset_session(ipset);
switch (ipset_session_report_type(sess)) {
case IPSET_NOTICE :
case IPSET_WARNING :
if (!ipset_envopt_test(sess, IPSET_ENV_QUIET))
log_msg(cfg, error, "warning: %s", ipset_session_report_msg(sess));
break;
case IPSET_ERROR :
default:
if (((cfg_t *) cfg)->last_cmd != IPSET_CMD_TEST) {
log_msg(cfg, error, "error: %s", ipset_session_report_msg(sess));
}
break;
}
ipset_session_report_reset(sess);
return -1;
}
cfg_t *
create(const char *id) {
cfg_t *cfg = NULL;
assert(id != NULL);
if ((cfg = calloc(1, sizeof(cfg_t))) == NULL)
return NULL;
strlcpy(cfg->name, id, sizeof(cfg->name));
cfg->logcb = &logcb_stub;
cfg->flags |= MOD_IS_READY;
cfg->flags |= MOD_TYPE_BACKEND;
cfg->last_cmd = IPSET_CMD_NONE;
return cfg;
}
bool
config(cfg_t *cfg, const char *key, const char *value) {
assert(cfg != NULL);
assert(key != NULL);
assert(value != NULL);
(void)(cfg);
(void)(key);
(void)(value);
return false;
}
bool
start(cfg_t *cfg) {
assert(cfg != NULL);
if (cfg->shared && usage_inc(cfg->name) > 1)
return true;
ipset_load_types();
if ((cfg->ipset = ipset_init()) == NULL) {
log_msg(cfg, error, "can't init ipset library");
return false;
}
if (ipset_session_output(ipset_session(cfg->ipset), IPSET_LIST_NONE) < 0)
return my_ipset_error(cfg, "ipset_session_output()");
if (ipset_envopt_parse(cfg->ipset, IPSET_ENV_EXIST, NULL) < 0)
return my_ipset_error(cfg, "ipset_envopt_parse()");
ipset_custom_printf(cfg->ipset, NULL, &my_ipset_std_error_cb, NULL, (void *) cfg);
ipset_envopt_set(ipset_session(cfg->ipset), IPSET_ENV_QUIET);
return true;
}
bool
stop(cfg_t *cfg) {
assert(cfg != NULL);
if (cfg->shared && usage_dec(cfg->name) > 0)
return true;
if (cfg->ipset) {
ipset_fini(cfg->ipset);
cfg->ipset = NULL;
}
return true;
}
bool
ban(cfg_t *cfg, const char *ip) {
char ipw[IP_LEN_MAX] = "";
char *argv[] = { "ignored", "add", cfg->name, ipw, NULL };
assert(cfg != NULL);
strlcpy(ipw, ip, sizeof(ipw));
cfg->last_cmd = IPSET_CMD_ADD;
return ipset_parse_argv(cfg->ipset, 4, argv) == 0;
}
bool
unban(cfg_t *cfg, const char *ip) {
char ipw[IP_LEN_MAX] = "";
char *argv[] = { "ignored", "del", cfg->name, ipw, NULL };
assert(cfg != NULL);
strlcpy(ipw, ip, sizeof(ipw));
cfg->last_cmd = IPSET_CMD_DEL;
return ipset_parse_argv(cfg->ipset, 4, argv) == 0;
}
bool
check(cfg_t *cfg, const char *ip) {
char ipw[IP_LEN_MAX] = "";
char *argv[] = { "ignored", "test", cfg->name, ipw, NULL };
assert(cfg != NULL);
strlcpy(ipw, ip, sizeof(ipw));
cfg->last_cmd = IPSET_CMD_TEST;
return ipset_parse_argv(cfg->ipset, 4, argv) == 0;
}
bool
ping(cfg_t *cfg) {
assert(cfg != NULL);
(void)(cfg); /* silence warning about unused variable */
return true;
}
void
destroy(cfg_t *cfg) {
assert(cfg != NULL);
free(cfg);
}

4
src/filters/CMakeLists.txt

@ -5,8 +5,8 @@ set(FILTERS "")
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)
if (WITH_PCRE)
pkg_check_modules(PCRE "libpcre" REQUIRED)
add_library("f_pcre" MODULE "pcre.c" "../strlcpy.c" "../fnv32a.c")
target_link_libraries("f_pcre" "pcre")
list(APPEND FILTERS "pcre")

4
src/sources/CMakeLists.txt

@ -8,8 +8,8 @@ list(APPEND SOURCES "files")
add_library("s_portknock" MODULE "portknock.c" "../strlcpy.c" "../fnv32a.c")
list(APPEND SOURCES "portknock")
find_library(REDIS_FOUND "hiredis")
if (WITH_REDIS AND REDIS_FOUND)
if (WITH_REDIS)
pkg_check_modules(REDIS "hiredis" REQUIRED)
add_library("s_redis" MODULE "redis.c" "../strlcpy.c")
target_link_libraries("s_redis" "hiredis")
list(APPEND SOURCES "redis")

Loading…
Cancel
Save