This commit is contained in:
Daniel Brahneborg 2025-12-04 16:53:41 +01:00
parent 048bf96e51
commit 54c8012836
8 changed files with 604 additions and 4 deletions

View file

@ -3,7 +3,19 @@ cmake_minimum_required(VERSION 3.10)
project(AutoFW)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
add_executable(autofw
autofw.c
matcher.c
pbuf.c
vbuf.c
)
execute_process(
COMMAND pcre2-config --libs8
OUTPUT_VARIABLE LIBPCRE
OUTPUT_STRIP_TRAILING_WHITESPACE)
target_link_libraries(autofw ${LIBPCRE})

View file

@ -2,3 +2,8 @@
Inspired by fail2ban.
## Building
On Ubuntu:
apt-get install -y cmake libpcre2-dev

114
matcher.c Normal file
View file

@ -0,0 +1,114 @@
#include "matcher.h"
#include "vbuf.h"
#include <string.h>
static void
matcher_free_match_data_ptr(pcre2_match_data** p)
{
if (!p)
return;
pcre2_match_data_free(*p);
*p = NULL;
}
static void
matcher_pcre2_code_free_ptr(pcre2_code** p)
{
if (!p)
return;
pcre2_code_free(*p);
*p = NULL;
}
int
matcher_init_regexp(
regexp_matcher_t* matcher,
const char* regexp)
{
if (!matcher || !regexp)
return -1;
int errorcode;
PCRE2_SIZE errorpos;
matcher->regexp = pcre2_compile(
(PCRE2_SPTR8) regexp,
PCRE2_ZERO_TERMINATED,
0, /* options */
&errorcode,
&errorpos,
NULL /* context */);
if (!matcher->regexp) {
PCRE2_UCHAR8 errortext[1024];
pcre2_get_error_message(errorcode, errortext, sizeof(errortext));
fprintf(stderr, "%s: regexp at %p errorpos %ld: `%s'\n",
__FUNCTION__, matcher->regexp, errorpos, errortext);
return -1;
}
pbuf_init(&matcher->results, 10, 0, (pbuf_func_free_t) vbuf_destroy);
return 0;
}
void
matcher_destroy(regexp_matcher_t* matcher)
{
if (!matcher || !matcher->regexp)
return;
pcre2_code_free(matcher->regexp);
pbuf_destroy(&matcher->results);
}
int
matcher_match(regexp_matcher_t* matcher, const char* subject)
{
if (!matcher || !subject)
return -1;
pbuf_clear(&matcher->results);
pcre2_match_data* __attribute__((cleanup(matcher_free_match_data_ptr))) match_data =
pcre2_match_data_create(30, NULL);
int const n = pcre2_match(matcher->regexp,
(PCRE2_SPTR8) subject, strlen(subject),
0, // startoffset
PCRE2_ANCHORED, // options
match_data, // match data
NULL // match context
);
fprintf(stderr, "%s: pcre2_match returned %d for `%s'\n",
__FUNCTION__, n, subject);
if (n < 0)
return n;
#define START_IX(i) ((i) * 2 + 0)
#define END_IX(i) ((i) * 2 + 1)
PCRE2_SIZE* const ovector = pcre2_get_ovector_pointer(match_data);
int i;
for (i = 0; i < n; ++i) {
if (ovector[START_IX(i)] == ovector[END_IX(i)])
continue;
#if 1
fprintf(stderr, "%s: match %d: %ld .. %ld: `%.*s'\n",
__FUNCTION__, i,
ovector[START_IX(i)], ovector[END_IX(i)] - 1,
(int) (ovector[END_IX(i)] - ovector[START_IX(i)]),
subject + ovector[START_IX(i)]);
#endif
pbuf_putat(&matcher->results, i,
vbuf_createbuf2(subject + ovector[START_IX(i)],
ovector[END_IX(i)] - ovector[START_IX(i)]));
}
return n;
}
const char*
matcher_result(regexp_matcher_t* matcher, int index)
{
if (!matcher)
return NULL;
return vbuf_notnull(pbuf_getat(&matcher->results, index));
}

View file

@ -5,7 +5,21 @@
#include "pbuf.h"
typedef struct {
pcre2_code* regexp;
pbuf_t results;
pcre2_code* regexp;
pbuf_t results;
} regexp_matcher_t;
int
matcher_init_regexp(
regexp_matcher_t* matcher,
const char* regexp);
void
matcher_destroy(regexp_matcher_t* matcher);
int
matcher_match(regexp_matcher_t* matcher, const char* needle);
const char*
matcher_result(regexp_matcher_t* matcher, int index);

168
pbuf.c Normal file
View file

@ -0,0 +1,168 @@
#include "pbuf.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
void
pbuf_init(pbuf_t* pbuf, int size, int chunksize, pbuf_func_free_t func_free)
{
if (!pbuf)
return;
pbuf->used = 0;
if (size <= 0)
size = 1;
pbuf->allocated = size;
if (chunksize <= 0)
chunksize = size / 2;
if (chunksize <= 8)
chunksize = 8;
pbuf->chunksize = chunksize;
pbuf->ptr = calloc(pbuf->allocated, sizeof(pbuf->ptr[0]));
pbuf->func_free = func_free;
}
static void
pbuf_clear_range(pbuf_t* pbuf, int first, int firstNot)
{
if (!pbuf)
return;
for (int i = first; i < firstNot; ++i) {
void* obj = pbuf->ptr[i];
if (!obj)
continue;
if (pbuf->func_free != PBUF_NONE) {
if (pbuf->func_free)
pbuf->func_free(obj);
else
free(obj);
}
pbuf->ptr[i] = NULL;
}
}
void
pbuf_clear(pbuf_t* pbuf)
{
if (!pbuf || (pbuf->used == 0))
return;
pbuf_clear_range(pbuf, 0, pbuf->used);
pbuf->used = 0;
}
void
pbuf_destroy(pbuf_t *pbuf)
{
if (!pbuf)
return;
pbuf_clear(pbuf);
free(pbuf->ptr);
}
int
pbuf_size(const pbuf_t* pbuf)
{
if (!pbuf)
return 0;
return pbuf->used;
}
static void
pbuf_ensure(pbuf_t *pbuf, int amount)
{
int const needed = pbuf->used + amount;
if (needed < pbuf->allocated)
return;
int const blocks = needed / pbuf->chunksize + 1;
int const current = pbuf->allocated;
pbuf->allocated = blocks * pbuf->chunksize;
pbuf->ptr = realloc(pbuf->ptr, pbuf->allocated * sizeof(pbuf->ptr[0]));
memset(pbuf->ptr + current, 0,
(pbuf->allocated - current) * sizeof(pbuf->ptr[0]));
}
void
pbuf_append(pbuf_t* pbuf, void* ptr)
{
if (!pbuf)
return;
pbuf_ensure(pbuf, 1);
pbuf->ptr[pbuf->used++] = ptr;
}
void
pbuf_sort(pbuf_t* pbuf, pbuf_func_sort_t func)
{
if (!pbuf || (pbuf->used < 2))
return;
qsort(pbuf->ptr, pbuf->used, sizeof(pbuf->ptr[0]), func);
}
void*
pbuf_find(const pbuf_t* pbuf, pbuf_func_find_t func_find, const void* arg)
{
if (!pbuf || !func_find)
return NULL;
for (int i = 0; i < pbuf->used; ++i) {
void* const obj = pbuf->ptr[i];
if (!obj)
continue;
if (func_find(obj, arg))
return obj;
}
return NULL;
}
static void
pbuf_trim_end(pbuf_t* pbuf)
{
if (!pbuf)
return;
while (pbuf->used > 0) {
if (pbuf->ptr[pbuf->used - 1])
break;
pbuf->used--;
}
}
static bool
pbuf_clearat(pbuf_t* pbuf, int ix)
{
if (!pbuf || (pbuf->used <= ix))
return false;
void* const obj = pbuf->ptr[ix];
if (!obj)
return false;
pbuf->ptr[ix] = NULL;
if (pbuf->func_free != PBUF_NONE) {
if (pbuf->func_free)
pbuf->func_free(obj);
else
free(obj);
}
pbuf_trim_end(pbuf);
return true;
}
void
pbuf_putat(pbuf_t* pbuf, int ix, void* obj)
{
if (!pbuf)
return;
pbuf_ensure(pbuf, ix + 1 - pbuf->used);
pbuf_clearat(pbuf, ix);
pbuf->ptr[ix] = obj;
if (ix + 1 > pbuf->used)
pbuf->used = ix + 1;
pbuf_trim_end(pbuf);
}
void*
pbuf_getat(const pbuf_t* pbuf, int ix)
{
if (!pbuf || (pbuf->used <= ix) || (ix < 0))
return NULL;
return pbuf->ptr[ix];
}

49
pbuf.h
View file

@ -1,6 +1,8 @@
typedef void (*pbuf_func_free_t)(void*);
#define PBUF_NONE ((void*)-1)
typedef struct {
int used;
int allocated;
@ -9,6 +11,49 @@ typedef struct {
pbuf_func_free_t func_free;
} pbuf_t;
// Add a new item at the end of the pbuf_t.
extern void pbuf_append(pbuf_t* pbuf, void* ptr);
void pbuf_init(
pbuf_t* pbuf,
int size,
int chunksize,
pbuf_func_free_t func_free);
void pbuf_destroy(pbuf_t* pbuf);
void
pbuf_clear(pbuf_t* pbuf);
void
pbuf_append(pbuf_t* pbuf, void* ptr);
void
pbuf_putat(pbuf_t* pbuf, int ix, void* obj);
void*
pbuf_getat(const pbuf_t* pbuf, int ix);
int
pbuf_size(const pbuf_t* pbuf);
typedef int (*pbuf_func_find_t)(void* obj, const void* arg);
void*
pbuf_find(
const pbuf_t* pbuf,
pbuf_func_find_t func,
const void* arg);
typedef int (*pbuf_func_sort_t)(const void* obj1, const void* obj2);
void
pbuf_sort(
pbuf_t* pbuf,
pbuf_func_sort_t func);
#define PBUF_FOREACH(element, list) { \
int pbuf_i; \
if ((void*)list != NULL) for (pbuf_i = 0; pbuf_i < (list)->used; ++pbuf_i) { \
element = (list)->ptr[pbuf_i]; \
if (!element) continue;
#define PBUF_FOREACH_END } }

201
vbuf.c Normal file
View file

@ -0,0 +1,201 @@
#include "vbuf.h"
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
void
vbuf_init3(vbuf_t* vbuf, int size, int chunksize)
{
if (!vbuf)
return;
// There is no idea to use a smaller buffer than the "abuf",
// so we might as well use it all.
// Besides, size may be 0 here, and we have to watch for that.
//
unsigned int sz = size;
if (size < (int)sizeof(vbuf->abuf))
sz = sizeof(vbuf->abuf);
if (chunksize <= 0)
chunksize = sz / 2;
if (chunksize < 32)
chunksize = 32;
*vbuf = (vbuf_t) { .chunksize = chunksize };
if (sz <= sizeof(vbuf->abuf)) {
vbuf->ptr = vbuf->abuf;
vbuf->size = sz;
} else {
vbuf_ensure(vbuf, sz);
vbuf_init(vbuf);
}
}
void
vbuf_init0(vbuf_t* vbuf)
{
if (!vbuf)
return;
vbuf_init3(vbuf, 0, 0);
}
vbuf_t*
vbuf_createbuf2(const char* buf, int len)
{
vbuf_t* const vbuf = malloc(sizeof(vbuf_t));
vbuf_init3(vbuf, len + 1, 0);
vbuf->len = len;
if (buf)
memcpy(vbuf->ptr, buf, vbuf->len);
vbuf->ptr[vbuf->len] = '\0';
return vbuf;
}
void
vbuf_init(vbuf_t* vbuf)
{
if (!vbuf)
return;
vbuf->len = 0;
if (vbuf->ptr)
vbuf->ptr[0] = '\0';
}
void
vbuf_freeptr(vbuf_t* vbuf)
{
if (!vbuf)
return;
if (vbuf->ptr != vbuf->abuf)
free(vbuf->ptr);
}
void
vbuf_destroy(vbuf_t* vbuf)
{
if (!vbuf)
return;
vbuf_freeptr(vbuf);
free(vbuf);
}
static char nullbyte = 0;
const char*
vbuf_notnull(const vbuf_t* vbuf)
{
if (!vbuf || !vbuf->ptr)
return &nullbyte;
return vbuf->ptr;
}
char*
vbuf_tostring(const vbuf_t* vbuf)
{
if (!vbuf)
return NULL;
if (!vbuf->ptr)
return &nullbyte;
return vbuf->ptr;
}
void
vbuf_ensure(vbuf_t* vbuf, unsigned int len)
{
unsigned int const needed = vbuf->len + len + 1;
if (needed < vbuf->size)
return;
unsigned int const blocks = needed / vbuf->chunksize + 1;
unsigned int const oldsize = vbuf->size;
vbuf->size = blocks * vbuf->chunksize;
if ((vbuf->size > sizeof(vbuf->abuf)) || (vbuf->ptr != vbuf->abuf)) {
const char* const oldptr = vbuf->ptr;
if (oldptr == vbuf->abuf) {
vbuf->ptr = malloc(vbuf->size);
memcpy(vbuf->ptr, oldptr, oldsize);
} else {
vbuf->ptr = realloc(vbuf->ptr, vbuf->size);
}
}
}
int
vbuf_append2(vbuf_t* vbuf, const char* const ptr, const int len)
{
if (!vbuf)
return 0;
if (!ptr || (len == 0))
return vbuf->len;
int datalen = len >= 0 ? len : (int) strlen(ptr);
vbuf_ensure(vbuf, datalen);
switch (datalen) {
case 8:
vbuf->ptr[vbuf->len + 7] = ptr[7];
// fall-through
case 7:
vbuf->ptr[vbuf->len + 6] = ptr[6];
// fall-through
case 6:
vbuf->ptr[vbuf->len + 5] = ptr[5];
// fall-through
case 5:
vbuf->ptr[vbuf->len + 4] = ptr[4];
// fall-through
case 4:
vbuf->ptr[vbuf->len + 3] = ptr[3];
// fall-through
case 3:
vbuf->ptr[vbuf->len + 2] = ptr[2];
// fall-through
case 2:
vbuf->ptr[vbuf->len + 1] = ptr[1];
// fall-through
case 1:
vbuf->ptr[vbuf->len + 0] = ptr[0];
break;
default:
if (vbuf && vbuf->ptr)
memcpy(&vbuf->ptr[vbuf->len], ptr, datalen);
}
vbuf->len += datalen;
if (vbuf && vbuf->ptr)
vbuf->ptr[vbuf->len] = '\0';
return vbuf->len;
}
static int
vbuf_gets2(vbuf_t* vbuf, FILE* fp, bool keepnewline)
{
if (!fp)
return -1;
if (!vbuf)
return 0;
vbuf_init(vbuf);
bool done = false;
while (!done) {
char buf[1024];
buf[0] = 0;
const char* const p = fgets(buf, sizeof(buf), fp);
if (!p) {
if (vbuf->len == 0)
return -1;
break;
}
int len = strlen(buf);
if ((len > 0) && (buf[len - 1] == '\n')) {
done = true;
if (!keepnewline)
--len;
}
vbuf_append2(vbuf, buf, len);
}
return vbuf->len;
}
int
vbuf_gets(vbuf_t* vbuf, FILE* fp)
{
return vbuf_gets2(vbuf, fp, false);
}

41
vbuf.h
View file

@ -0,0 +1,41 @@
#include <stdio.h>
#define VBUF_ABUF_SIZE 16
typedef struct {
unsigned int flags;
unsigned int len;
unsigned int size;
unsigned int chunksize;
char* ptr;
char abuf[VBUF_ABUF_SIZE];
} vbuf_t;
void
vbuf_init0(vbuf_t* vbuf);
void
vbuf_destroy(vbuf_t* vbuf);
vbuf_t*
vbuf_createbuf2(const char* buf, int len);
void
vbuf_init(vbuf_t* vbuf);
void
vbuf_freeptr(vbuf_t* vbuf);
int
vbuf_gets(vbuf_t* vbuf, FILE* fp);
void
vbuf_ensure(vbuf_t* vbuf, unsigned int delta);
char*
vbuf_tostring(const vbuf_t* vbuf);
const char*
vbuf_notnull(const vbuf_t* vbuf);