Create b2f-grep to facilitate add-addr.sh placing cursor for vim

This commit is contained in:
john 2021-04-18 16:39:37 -04:00
parent 3aa81aac46
commit 20b109af40
4 changed files with 612 additions and 8 deletions

View File

@ -2,7 +2,7 @@ baseDir := ~
libsDir := $(baseDir)/libs
projectName := ban2fail
versions := debug release
cc_exe := ban2fail fsckdns
cc_exe := ban2fail b2f-grep
#install_dir := /usr/local/bin
########################################
@ -36,9 +36,21 @@ src := \
timestamp.c \
util.c \
libs := z crypto GeoIP pthread db
libs += z crypto GeoIP pthread db
endif
ifeq ($(exe), b2f-grep)
src := \
ez_libc.c \
b2f-grep.c \
ptrvec.c \
str.c \
util.c \
libs += gmp
endif
ifeq ($(exe), fsckdns)
src := \
ez_libc.c \

View File

@ -2,7 +2,7 @@ baseDir := ~
libsDir := $(baseDir)/libs
projectName := ban2fail
versions := debug release
cc_exe := ban2fail fsckdns
cc_exe := ban2fail b2f-grep
#install_dir := /usr/local/bin
########################################
@ -36,9 +36,21 @@ src := \
timestamp.c \
util.c \
libs := z crypto GeoIP pthread db
libs += z crypto GeoIP pthread db
endif
ifeq ($(exe), b2f-grep)
src := \
ez_libc.c \
b2f-grep.c \
ptrvec.c \
str.c \
util.c \
libs += gmp
endif
ifeq ($(exe), fsckdns)
src := \
ez_libc.c \
@ -70,15 +82,15 @@ ifndef version
all : debug release
debug :
@$(MAKE) version=debug exe=ban2fail mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
@$(MAKE) version=debug exe=fsckdns mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
@$(MAKE) version=debug exe=b2f-grep mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
release :
@$(MAKE) version=release exe=ban2fail mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
@$(MAKE) version=release exe=fsckdns mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
@$(MAKE) version=release exe=b2f-grep mainType=CC --no-builtin-rules -f $(makefile) --no-print-directory
install : release
@strip release/ban2fail
@[ $(install_dir)_foo = _foo ] || cp release/ban2fail $(install_dir)/
@strip release/fsckdns
@[ $(install_dir)_foo = _foo ] || cp release/fsckdns $(install_dir)/
@strip release/b2f-grep
@[ $(install_dir)_foo = _foo ] || cp release/b2f-grep $(install_dir)/
@[ -e install.sh ] && INSTALLDIR=$(install_dir) INSTALLTYPE=$(install_type) sudo ./install.sh
uninstall :
clean :

63
add-addrs.sh Executable file
View File

@ -0,0 +1,63 @@
#!/bin/bash
#
# Add new addresses to ban2fail
set -efu
WD=~/projects/ban2fail
PROTO_CFG=$WD/real-ban2fail.cfg
ACTUAL_CFG=/etc/ban2fail/ban2fail.cfg
BAN2FAIL=/usr/local/bin/ban2fail
B2F_GREP=/usr/local/bin/b2f-grep
MD5SUM=
NEW_MD5SUM=
JUNK=
SEP=
IP=
PRTL_IP=
LINE=
trap "echo && $BAN2FAIL -s" 0
while true; do
read MD5SUM JUNK < <(md5sum $ACTUAL_CFG)
read -p 'Next address(es) please? ' IP
# Only consider editing PROTO_CFG is IP is not empty.
if [[ -n "$IP" ]]; then
$BAN2FAIL $IP
echo '--------------------------------'
read -p 'Edit config file? '
case ${REPLY:0:1} in
y|Y) true;;
*) continue;;
esac
# Edit all addresses we got from b2f-grep
for LINE in $(2>/dev/null $B2F_GREP $IP <$PROTO_CFG); do
$EDITOR +${LINE} $PROTO_CFG
done
fi
# See if PROTO_CFG was changed.
read NEW_MD5SUM JUNK < <(md5sum $PROTO_CFG)
[[ $NEW_MD5SUM == $MD5SUM ]] && continue
$BAN2FAIL -t $PROTO_CFG
read -p 'Make this permanent? '
case ${REPLY:0:1} in
y|Y) true;;
*) continue;;
esac
sudo /bin/cp $PROTO_CFG $ACTUAL_CFG
$BAN2FAIL -s
done

517
b2f-grep.c Normal file
View File

@ -0,0 +1,517 @@
#include <assert.h>
#include <arpa/inet.h>
#include <byteswap.h>
#include <getopt.h>
#include <gmp.h>
#include "ez_libc.h"
#include "ptrvec.h"
#include "util.h"
/*==================================================================*/
/*=================== Support structs ==============================*/
/*==================================================================*/
/****************************************************************
* signed 129 bit integer IP address or IP address difference.
* This covers IPv4 and IPv6 addresses.
*/
typedef struct _MpAddr {
enum {
MPADDR_INIT_FLG= 1<<0
} flags;
// AF_INET or AF_INET6
int domain;
// GNU multi-precision integer
mpz_t addr;
} MpAddr;
/****************************************************************
* Entry class, one for each address passed on command line.
*/
/* Useful class for this app */
typedef struct _Entry {
// 129 bit integer address.
MpAddr mp_addr;
// Line from stdin which has was closest to ours.
unsigned lineno;
// Invalid if 0 == lineno
MpAddr mp_closest_addr, // Address which was closest to ours.
mp_closest_prox; // Proximity to ours.
} Entry;
/*==================================================================*/
/*================= Forward declarations ===========================*/
/*==================================================================*/
static void MpAddr_sinit(MpAddr *self);
static MpAddr* MpAddr_constructor(MpAddr *self);
static void* MpAddr_destructor(MpAddr *self);
static int MpAddr_inetAssign(MpAddr *self, const char *addrStr);
static void MpAddr_assign(MpAddr *self, const MpAddr *src);
static void MpAdd_absDiff(MpAddr *self, const MpAddr *opl, const MpAddr *opr);
static int MpAdd_cmp(const MpAddr *self, const MpAddr *other);
static int MpAddr_isSameFamily(const MpAddr *self, const MpAddr *other);
static int MpAddr_lt(const MpAddr *self, const MpAddr *other);
#define Entry_create(p, addr) \
((p)=(Entry_constructor((p)=malloc(sizeof(Entry)), addr) ? (p) : ( p ? realloc(Entry_destructor(p),0) : 0 )))
static Entry* Entry_constructor(Entry *self, const char *addr);
static void* Entry_destructor(Entry *self);
//static int Entry_isSameFamily(const Entry *self, const MpAddr *mp_addr);
static int Entry_is_closer(const Entry *self, const MpAddr *mp_addr);
static int Entry_lineno_cmp(const void *const*pp1, const void *const* pp2);
static void Entry_print(const Entry *self);
static void Entry_register(Entry *self, unsigned lineno, const MpAddr *mp_addr);
//static MpAddr* Entry_get_prox(const Entry *self, MpAddr *rtn, const MpAddr *other);
/*==================================================================*/
/*========================= static data ============================*/
/*==================================================================*/
static struct {
PTRVEC entry_vec;
unsigned max_off;
struct {
int major,
minor,
patch;
} version;
} S= {
.max_off= 50,
.version= {
.major= 0,
.minor= 0,
.patch= 0
}
};
/*==================================================================*/
/*======================== main() stuff ============================*/
/*==================================================================*/
/* Enums for long options */
enum {
VERSION_OPT_ENUM=128, /* Larger than any printable character */
HELP_OPT_ENUM
};
/*==================================================================*/
/*======================== main() ==================================*/
/*==================================================================*/
int
main(int argc, char **argv)
/***************************************************
* Program execution begins here ...
*/
{
int rtn= EXIT_FAILURE;
extern char *optarg;
extern int optind, optopt;
PTRVEC_constructor(&S.entry_vec, 10);
/* Parse command line arguments */
{ /*==================================================================*/
int c, errflg= 0;
for(;;) {
static const struct option long_options[]= {
{"help", no_argument, 0, HELP_OPT_ENUM},
{"version", no_argument, 0, VERSION_OPT_ENUM},
{}
};
int c, option_ndx= 0;
c= getopt_long(argc, argv, ":m:", long_options, &option_ndx);
if(-1 == c) break;
switch(c) {
/* print usage help */
case HELP_OPT_ENUM:
++errflg;
break;
case VERSION_OPT_ENUM:
ez_fprintf(stdout, "b2f-grep v%d.%d.%d\n", S.version.major, S.version.minor, S.version.patch);
return 0;
case 'm':
{
int rc= sscanf(optarg, "%u", &S.max_off);
if(1 != rc)
++errflg;
} break;
case '?':
ez_fprintf(stderr, "Unrecognized option: -%c\n", optopt);
++errflg;
break;
}
}
if(errflg) {
ez_fprintf(stderr,
"b2f-grep v%d.%d.%d Usage:\n"
"%s [options] addr1 [...] <ban2fail.cfg_file\n"
" -m max\tlargest value to consider in MAX_OFFENSES block\n"
" --help\tprint this usage message.\n"
" --version\tprint the version number and exit.\n"
, S.version.major, S.version.minor, S.version.patch
, argv[0]
);
goto abort;
}
/* Make sure we have at least one address to process */
if(optind == argc) {
eprintf("ERROR: no addresses supplied on command line.");
goto abort;
}
/* Pick up addresses on command line */
for(; optind < argc; ++optind) {
const char *addr= argv[optind];
/* Create an entry, and place it in our vector */
Entry *e;
if(!Entry_create(e, addr))
continue;
PTRVEC_addTail(&S.entry_vec, e);
}
} // command options
{ /*====== Line by line processing ============*/
static char lbuf[1024],
ipbuf[40];
static MpAddr mp_addr,
mp_prox;
MpAddr_sinit(&mp_addr);
MpAddr_sinit(&mp_prox);
char *str;
unsigned lineno, max_off= 0;
for(lineno= 1, str= ez_fgets(lbuf, sizeof(lbuf)-1, stdin);
str;
str= ez_fgets(lbuf, sizeof(lbuf)-1, stdin), ++lineno)
{
str= trim(str);
/* See if this is a MAX_OFFENSES block declaration */
int rc= sscanf(str, "MAX_OFFENSES %u", &max_off);
if(1 == rc || max_off > S.max_off)
continue; // We have what we need for this line
/* Nope, maybe an IP address ... */
rc= sscanf(str, "IP = %39[^ \t]", ipbuf);
if(1 != rc)
continue; // Ignore line
if(MpAddr_inetAssign(&mp_addr, ipbuf)) {
eprintf("ERROR: on line %u", lineno);
continue; // Don't recognize address string
}
{ /* Loop through all entries, assign line numbers if necessary */
unsigned i;
Entry *e;
PTRVEC_loopFwd(&S.entry_vec, i, e) {
Entry_register(e, lineno, &mp_addr);
}
}
}
} // reading stdin
{ /*========= Print results ============*/
unsigned i;
Entry *e;
PTRVEC_sort(&S.entry_vec, Entry_lineno_cmp);
PTRVEC_loopFwd(&S.entry_vec, i, e) {
if(i)
ez_fputc('\t', stdout);
Entry_print(e);
}
ez_fputc('\n', stdout);
}
rtn= EXIT_SUCCESS;
abort:
return rtn;
}
/*==================================================================*/
/*============== Supporting functions ==============================*/
/*==================================================================*/
static void
MpAddr_sinit(MpAddr *self)
/**************************************************************
* Construct if necessary.
*/
{
if(!(self->flags & MPADDR_INIT_FLG))
MpAddr_constructor(self);
}
static MpAddr*
MpAddr_constructor(MpAddr *self)
/**************************************************************
* Initialize for use.
*/
{
mpz_init2(self->addr, 129);
self->flags= MPADDR_INIT_FLG;
return self;
}
static void*
MpAddr_destructor(MpAddr *self)
/**************************************************************
* Free resources.
*/
{
if(self->flags & MPADDR_INIT_FLG)
mpz_clear(self->addr);
return self;
}
static int
MpAddr_inetAssign(MpAddr *self, const char *addrStr)
/**************************************************************
* Assign address from string representation of numeric address
*/
{
int rtn= -1;
char hex_buf[33];
unsigned char buf[sizeof(struct in6_addr)];
self->domain= strchr(addrStr, ':') ? AF_INET6 : AF_INET;
int rc= inet_pton(self->domain, addrStr, buf);
switch(rc) {
case -1:
sys_eprintf("ERROR: inet_pton(\"%s\")", addrStr);
goto abort;
case 0:
eprintf("WARNING: \"%s\" not recognized as an address", addrStr);
goto abort;
}
/* At this point we have the address as an integer in big-endian order in buf */
switch(self->domain) {
case AF_INET:
snprintf(hex_buf, sizeof(hex_buf), "%hhu%hhu%hhu%hhu", buf[0], buf[1], buf[2], buf[3]);
break;
case AF_INET6:
snprintf(hex_buf, sizeof(hex_buf), "%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu%hhu"
, buf[0]
, buf[1]
, buf[2]
, buf[3]
, buf[4]
, buf[5]
, buf[6]
, buf[7]
, buf[8]
, buf[9]
, buf[10]
, buf[11]
, buf[12]
, buf[13]
, buf[14]
, buf[15]
);
break;
default:
assert(0);
}
rc= mpz_set_str(self->addr, hex_buf, 16);
if(-1 == rc) {
eprintf("ERROR: \"%s\" not recognized as hexidecimal integer.", hex_buf);
goto abort;
}
rtn= 0;
abort:
return rtn;
}
static void
MpAdd_absDiff(MpAddr *self, const MpAddr *opl, const MpAddr *opr)
/***************************************************************
* Compute the absolute different between opl and opr
*/
{
MpAddr diff;
MpAddr_sinit(&diff);
mpz_sub(diff.addr, opl->addr, opr->addr);
mpz_abs(self->addr, diff.addr);
}
static int
MpAdd_cmp(const MpAddr *self, const MpAddr *other)
/***************************************************************
* strcmp() style comparision return.
*/
{
return mpz_cmp(self->addr, other->addr);
}
static int
MpAddr_isSameFamily(const MpAddr *self, const MpAddr *other)
/***************************************************************
* Returns non-zero if self and other are in the same address
* family.
*/
{
return self->domain == other->domain;
}
static int
MpAddr_cmp(const MpAddr *self, const MpAddr *other)
/***************************************************************
* strcmp() style return value for comparison of self & other.
*/
{
return mpz_cmp(self->addr, other->addr);
}
static void
MpAddr_assign(MpAddr *self, const MpAddr *src)
/***************************************************************
* Assign the value of src to ourself.
*/
{
mpz_set(self->addr, src->addr);
}
static Entry*
Entry_constructor(Entry *self, const char *addr)
/***************************************************************
* Create an entry object for the supplied IP address string.
*/
{
memset(self, 0, sizeof(*self));
Entry *rtn= NULL;
MpAddr_constructor(&self->mp_addr);
MpAddr_constructor(&self->mp_closest_addr);
MpAddr_constructor(&self->mp_closest_prox);
if(MpAddr_inetAssign(&self->mp_addr, addr))
goto abort;
rtn= self;
abort:
return rtn;
}
static void*
Entry_destructor(Entry *self)
/***************************************************************
* Destructor.
*/
{
MpAddr_destructor(&self->mp_addr);
MpAddr_destructor(&self->mp_closest_addr);
MpAddr_destructor(&self->mp_closest_prox);
return self;
}
static void
Entry_print(const Entry *self)
/***************************************************************
* Print result to stdout.
*/
{
unsigned lineno= MAX(self->lineno, 1);
if(MpAddr_cmp(&self->mp_addr, &self->mp_closest_addr))
--lineno;
ez_fprintf(stdout, "%u", lineno);
}
static int
Entry_lineno_cmp(const void *const*pp1, const void *const* pp2)
/***************************************************************
* Comparison function we can use with PTRVEC_sort().
*/
{
const Entry *e1= *(const Entry *const*)pp1,
*e2= *(const Entry *const*)pp2;
if(e1->lineno < e2->lineno)
return -1;
if(e1->lineno > e2->lineno)
return 1;
return 0;
return -1;
}
static void
Entry_register(Entry *self, unsigned lineno, const MpAddr *mp_addr)
/***************************************************************
* Registers the address found on lineno.
*/
{
/* Ignore address of different family */
if(!MpAddr_isSameFamily(&self->mp_addr, mp_addr))
return;
static MpAddr prox;
MpAddr_sinit(&prox);
MpAdd_absDiff(&prox, &self->mp_addr, mp_addr);
if(!self->lineno || 0 < MpAddr_cmp(&self->mp_closest_prox, &prox)) {
self->lineno= lineno;
MpAddr_assign(&self->mp_closest_addr, mp_addr);
MpAddr_assign(&self->mp_closest_prox, &prox);
}
}
static int
Entry_isSameFamily(const Entry *self, const MpAddr *mp_addr)
/***************************************************************
* Frontend for MpAddr_isSameFamily()
*/
{
return MpAddr_isSameFamily(&self->mp_addr, mp_addr);
}