more files
This commit is contained in:
parent
b62e2706f6
commit
048bf96e51
6 changed files with 377 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -2,3 +2,4 @@ CMakeCache.txt
|
|||
CMakeFiles
|
||||
cmake_install.cmake
|
||||
.DS_Store
|
||||
Makefile
|
||||
|
|
|
|||
9
CMakeLists.txt
Normal file
9
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
cmake_minimum_required(VERSION 3.10)
|
||||
|
||||
project(AutoFW)
|
||||
|
||||
add_executable(autofw
|
||||
autofw.c
|
||||
)
|
||||
|
||||
342
autofw.c
Normal file
342
autofw.c
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
|
||||
#include "matcher.h"
|
||||
#include "vbuf.h"
|
||||
|
||||
static void
|
||||
fclose_ptr(FILE** p)
|
||||
{
|
||||
if (!p || !*p)
|
||||
return;
|
||||
fclose(*p);
|
||||
*p = NULL;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
bool obsolete;
|
||||
uint32_t ip;
|
||||
uint8_t width;
|
||||
} iprange_t;
|
||||
|
||||
static pbuf_t black_ranges;
|
||||
static pbuf_t white_ranges;
|
||||
static pbuf_t new_ranges;
|
||||
static pbuf_t new_b_ranges;
|
||||
|
||||
static iprange_t*
|
||||
iprange_create(uint32_t ip, uint8_t width)
|
||||
{
|
||||
iprange_t* const range = malloc(sizeof(*range));
|
||||
*range = (iprange_t) {
|
||||
.ip = ip & ~0U << (32 - width),
|
||||
.width = width,
|
||||
};
|
||||
return range;
|
||||
}
|
||||
|
||||
static void
|
||||
iprange_add(const char* ipstr, uint8_t width, bool white)
|
||||
{
|
||||
struct in_addr addr;
|
||||
int const rc = inet_pton(AF_INET, ipstr, &addr);
|
||||
if (!rc) return;
|
||||
#if 0
|
||||
printf("%s: inet_pton `%s' => %d.%d.%d.%d\n",
|
||||
__FUNCTION__,
|
||||
ipstr,
|
||||
addr.s_addr >> 24,
|
||||
(addr.s_addr >> 16) & 0xff,
|
||||
(addr.s_addr >> 8) & 0xff,
|
||||
(addr.s_addr >> 0) & 0xff);
|
||||
#endif
|
||||
iprange_t* const range = iprange_create(ntohl(addr.s_addr), width);
|
||||
pbuf_append(white ? &white_ranges : &black_ranges, range);
|
||||
}
|
||||
|
||||
static void
|
||||
iprange_load(const char* filename, bool white)
|
||||
{
|
||||
FILE* __attribute__((cleanup(fclose_ptr))) fp = fopen(filename, "r");
|
||||
if (!fp)
|
||||
return;
|
||||
|
||||
regexp_matcher_t __attribute__((cleanup(matcher_destroy))) matcher;
|
||||
matcher_init_regexp(&matcher,
|
||||
"([0-9\\.]+)" // ipv4
|
||||
"("
|
||||
"/([0-9]+)" // optional width
|
||||
")?");
|
||||
|
||||
vbuf_t __attribute__((cleanup(vbuf_freeptr))) vbuf;
|
||||
vbuf_init0(&vbuf);
|
||||
|
||||
int len;
|
||||
while ((len = vbuf_gets(&vbuf, fp)) > -1) {
|
||||
char* const line = vbuf_tostring(&vbuf);
|
||||
int rc = matcher_match(&matcher, line);
|
||||
// printf("matcher on `%s' returned %d\n", line, rc);
|
||||
if (rc < 2)
|
||||
continue;
|
||||
switch (rc) {
|
||||
case 2:
|
||||
iprange_add(matcher_result(&matcher, 1), 32, white);
|
||||
break;
|
||||
case 4:
|
||||
iprange_add(
|
||||
matcher_result(&matcher, 1),
|
||||
atoi(matcher_result(&matcher, 3)),
|
||||
white);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
iprange_cmp(const void* a, const void* b)
|
||||
{
|
||||
const iprange_t* const r_a = *((iprange_t**)a);
|
||||
const iprange_t* const r_b = *((iprange_t**)b);
|
||||
|
||||
if (r_a->ip < r_b->ip)
|
||||
return -1;
|
||||
if (r_a->ip > r_b->ip)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
iprange_join(iprange_t* prev, iprange_t* curr)
|
||||
{
|
||||
uint32_t const prev_mask = ~0U << (32 - prev->width);
|
||||
#if 0
|
||||
uint32_t const curr_mask = ~0U << (32 - curr->width);
|
||||
printf("masks: prev 0x%08x curr 0x%08x\n", prev_mask, curr_mask);
|
||||
printf("masked: prev 0x%08x curr 0x%08x\n", prev->ip & prev_mask, curr->ip & curr_mask);
|
||||
#endif
|
||||
if ((prev->ip & prev_mask) == (curr->ip & prev_mask)) {
|
||||
curr->obsolete = true;
|
||||
return;
|
||||
}
|
||||
int min_width = prev->width < curr->width ? prev->width : curr->width;
|
||||
if (min_width < 8)
|
||||
min_width = 8;
|
||||
int const max_width = prev->width > curr->width ? prev->width : curr->width;
|
||||
// printf("widths: min %d max %d\n", min_width, max_width);
|
||||
if (max_width - min_width > 8) {
|
||||
// printf("width difference %d, too much\n", max_width - min_width);
|
||||
return;
|
||||
}
|
||||
int new_width = max_width;
|
||||
uint32_t new_mask = 0;
|
||||
for (;;) {
|
||||
if ((new_width <= 8) || (max_width - new_width > 8)) {
|
||||
// printf("nothing in common with at least 8 bits\n");
|
||||
return;
|
||||
}
|
||||
new_width = new_width - 1;
|
||||
new_mask = ~0U << (32 - new_width);
|
||||
uint32_t const prev_masked = prev->ip & new_mask;
|
||||
uint32_t const curr_masked = curr->ip & new_mask;
|
||||
#if 0
|
||||
printf("new masked with width %d: prev 0x%08x curr 0x%08x\n",
|
||||
new_width, prev_masked, curr_masked);
|
||||
#endif
|
||||
if (prev_masked == curr_masked)
|
||||
break;
|
||||
if (!(new_width & 7)) {
|
||||
// printf("too far apart, giving up\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
uint32_t const new_ip = prev->ip & new_mask;
|
||||
iprange_t* const range = iprange_create(new_ip, new_width);
|
||||
pbuf_append(&new_ranges, range);
|
||||
prev->obsolete = true;
|
||||
curr->obsolete = true;
|
||||
}
|
||||
|
||||
static void
|
||||
ipranges_merge(void)
|
||||
{
|
||||
iprange_t* prev = NULL;
|
||||
iprange_t* curr;
|
||||
PBUF_FOREACH(curr, &black_ranges)
|
||||
if (!prev) {
|
||||
prev = curr;
|
||||
continue;
|
||||
}
|
||||
#if 0
|
||||
printf("comparing %d.%d.%d.%d/%d and %d.%d.%d.%d/%d\n",
|
||||
prev->ip >> 24,
|
||||
(prev->ip >> 16) & 0xff,
|
||||
(prev->ip >> 8) & 0xff,
|
||||
(prev->ip >> 0) & 0xff,
|
||||
prev->width,
|
||||
curr->ip >> 24,
|
||||
(curr->ip >> 16) & 0xff,
|
||||
(curr->ip >> 8) & 0xff,
|
||||
(curr->ip >> 0) & 0xff,
|
||||
curr->width);
|
||||
#endif
|
||||
iprange_join(prev, curr);
|
||||
if (!curr->obsolete)
|
||||
prev = curr;
|
||||
PBUF_FOREACH_END
|
||||
}
|
||||
|
||||
static void
|
||||
iprange_maybe_add_b_block(uint32_t counter, uint32_t last_block)
|
||||
{
|
||||
if (counter < 4)
|
||||
return;
|
||||
#if 0
|
||||
printf("found %d ips in block %d.%d.0.0/16\n",
|
||||
counter,
|
||||
last_block >> 24,
|
||||
(last_block >> 16) & 0xff);
|
||||
#endif
|
||||
iprange_t* const range = iprange_create(last_block, 16);
|
||||
pbuf_append(&new_b_ranges, range);
|
||||
}
|
||||
|
||||
static int
|
||||
iprange_match_block(void* obj, const void* arg)
|
||||
{
|
||||
iprange_t* const block = obj;
|
||||
const iprange_t* const curr = arg;
|
||||
|
||||
if (curr->width < block->width)
|
||||
return 0;
|
||||
uint32_t const block_mask = ~0U << (32 - block->width);
|
||||
if ((block->ip & block_mask) != (curr->ip & block_mask))
|
||||
return 0;
|
||||
#if 0
|
||||
printf("ip %d.%d.%d.%d/%d is within block %d.%d.%d.%d/%d\n",
|
||||
curr->ip >> 24,
|
||||
(curr->ip >> 16) & 0xff,
|
||||
(curr->ip >> 8) & 0xff,
|
||||
(curr->ip >> 0) & 0xff,
|
||||
curr->width,
|
||||
block->ip >> 24,
|
||||
(block->ip >> 16) & 0xff,
|
||||
(block->ip >> 8) & 0xff,
|
||||
(block->ip >> 0) & 0xff,
|
||||
block->width);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
ipranges_find_b_blocks(void)
|
||||
{
|
||||
uint32_t last_block = 0;
|
||||
uint32_t counter = 0;
|
||||
uint32_t b_mask = 0xffff0000;
|
||||
iprange_t* curr;
|
||||
PBUF_FOREACH(curr, &black_ranges)
|
||||
if (curr->obsolete)
|
||||
continue;
|
||||
uint32_t const curr_block = curr->ip & b_mask;
|
||||
if (curr_block == last_block) {
|
||||
counter++;
|
||||
continue;
|
||||
}
|
||||
iprange_maybe_add_b_block(counter, last_block);
|
||||
last_block = curr_block;
|
||||
counter = 1;
|
||||
PBUF_FOREACH_END
|
||||
iprange_maybe_add_b_block(counter, last_block);
|
||||
if (pbuf_size(&new_b_ranges) == 0)
|
||||
return;
|
||||
|
||||
// cleanup
|
||||
PBUF_FOREACH(curr, &black_ranges)
|
||||
if (curr->obsolete)
|
||||
continue;
|
||||
iprange_t* const b_block = pbuf_find(&new_b_ranges, iprange_match_block, curr);
|
||||
if (b_block)
|
||||
curr->obsolete = true;
|
||||
PBUF_FOREACH_END
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, const char* argv[])
|
||||
{
|
||||
pbuf_init(&black_ranges, 4, 0, NULL);
|
||||
pbuf_init(&white_ranges, 4, 0, NULL);
|
||||
pbuf_init(&new_ranges, 4, 0, NULL);
|
||||
pbuf_init(&new_b_ranges, 4, 0, NULL);
|
||||
|
||||
iprange_load("autofw.whitelist", true);
|
||||
iprange_load("autofw.blacklist", false);
|
||||
|
||||
(void) argc;
|
||||
(void) argv;
|
||||
|
||||
pbuf_sort(&black_ranges, iprange_cmp);
|
||||
ipranges_merge();
|
||||
ipranges_find_b_blocks();
|
||||
|
||||
pbuf_sort(&new_ranges, iprange_cmp);
|
||||
iprange_t* range;
|
||||
|
||||
PBUF_FOREACH(range, &black_ranges)
|
||||
if (!range->obsolete)
|
||||
continue;
|
||||
printf("yes | ufw delete deny from %d.%d.%d.%d/%d\n",
|
||||
range->ip >> 24,
|
||||
(range->ip >> 16) & 0xff,
|
||||
(range->ip >> 8) & 0xff,
|
||||
(range->ip >> 0) & 0xff,
|
||||
range->width);
|
||||
PBUF_FOREACH_END
|
||||
|
||||
PBUF_FOREACH(range, &new_ranges)
|
||||
printf("ufw insert 1 deny from %d.%d.%d.%d/%d\n",
|
||||
range->ip >> 24,
|
||||
(range->ip >> 16) & 0xff,
|
||||
(range->ip >> 8) & 0xff,
|
||||
(range->ip >> 0) & 0xff,
|
||||
range->width);
|
||||
PBUF_FOREACH_END
|
||||
|
||||
PBUF_FOREACH(range, &new_b_ranges)
|
||||
printf("ufw insert 1 deny from %d.%d.%d.%d/%d\n",
|
||||
range->ip >> 24,
|
||||
(range->ip >> 16) & 0xff,
|
||||
(range->ip >> 8) & 0xff,
|
||||
(range->ip >> 0) & 0xff,
|
||||
range->width);
|
||||
PBUF_FOREACH_END
|
||||
|
||||
if (pbuf_size(&new_ranges) > 0) {
|
||||
PBUF_FOREACH(range, &white_ranges)
|
||||
printf("yes | ufw delete allow from %d.%d.%d.%d/%d\n",
|
||||
range->ip >> 24,
|
||||
(range->ip >> 16) & 0xff,
|
||||
(range->ip >> 8) & 0xff,
|
||||
(range->ip >> 0) & 0xff,
|
||||
range->width);
|
||||
printf("yes | ufw insert 1 allow from %d.%d.%d.%d/%d\n",
|
||||
range->ip >> 24,
|
||||
(range->ip >> 16) & 0xff,
|
||||
(range->ip >> 8) & 0xff,
|
||||
(range->ip >> 0) & 0xff,
|
||||
range->width);
|
||||
PBUF_FOREACH_END
|
||||
}
|
||||
|
||||
pbuf_destroy(&black_ranges);
|
||||
pbuf_destroy(&white_ranges);
|
||||
pbuf_destroy(&new_ranges);
|
||||
pbuf_destroy(&new_b_ranges);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
11
matcher.h
Normal file
11
matcher.h
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
|
||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
||||
#include "pcre2.h"
|
||||
|
||||
#include "pbuf.h"
|
||||
|
||||
typedef struct {
|
||||
pcre2_code* regexp;
|
||||
pbuf_t results;
|
||||
} regexp_matcher_t;
|
||||
|
||||
14
pbuf.h
Normal file
14
pbuf.h
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
typedef void (*pbuf_func_free_t)(void*);
|
||||
|
||||
typedef struct {
|
||||
int used;
|
||||
int allocated;
|
||||
int chunksize;
|
||||
void** ptr;
|
||||
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);
|
||||
|
||||
0
vbuf.h
Normal file
0
vbuf.h
Normal file
Loading…
Add table
Reference in a new issue