ban2fail/maxoff.c

192 lines
6.1 KiB
C

/***************************************************************************
* Copyright (C) 2019 by John D. Robertson *
* john@rrci.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <assert.h>
#include "ban2fail.h"
#include "cntry.h"
#include "maxoff.h"
static struct {
int is_init;
MAP cntry_map,
addr_map;
} S;
static void
initialize(void)
/********************************************************
* Perform one-time initializations.
*/
{
S.is_init= 1;
MAP_constructor(&S.cntry_map, 10, 10);
MAP_constructor(&S.addr_map, N_ADDRESSES_HINT/BUCKET_DEPTH_HINT, BUCKET_DEPTH_HINT);
}
// Compiler doesn't like that we use integers in place of item pointers */
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wint-conversion"
int
MAXOFF_allowed(const char *addr)
/********************************************************
* Returns the maximum number of allowed offenses.
* -1 means unlimited.
*/
{
if(!S.is_init)
initialize();
/* Default is no offenses allowed */
int rtn= 0;
/* Check for by-address specification */
rtn= MAP_findStrItem(&S.addr_map, addr);
/* by-address spec trumps by-country spec */
if(!rtn) {
const char *cntry;
cntry= COUNTRY_get_code(addr);
/* if the source country of an address is not known,
* then it will be keyed in our map under "unknown".
*/
cntry= cntry ? cntry : "unknown";
rtn= MAP_findStrItem(&S.cntry_map, cntry);
}
return rtn;
}
int
MAXOFF_init(CFGMAP *h_cfgmap, char *pfix)
/**************************************************************
* Initialize objects from configuration map.
*/
{
if(!S.is_init)
initialize();
int rtn= -1;
size_t len= strlen(pfix)+1024;
char symBuf[len];
unsigned arr_sz= CFGMAP_numTuples(h_cfgmap);
struct CFGMAP_tuple rtn_arr[arr_sz];
int nAllowed;
/* Get the allowed number from pfix */
const char *str= strrchr(pfix, '\\');
++str;
if(1 != sscanf(str, "%d", &nAllowed)) {
eprintf("ERROR: \"%s\" is not an integer number.", str);
goto abort;
}
{ /*--- Register IP entries ---*/
snprintf(symBuf, len, "%s\\IP", pfix);
unsigned nFound= CFGMAP_find_tuples(h_cfgmap, rtn_arr, symBuf);
for(unsigned i= 0; i < nFound; ++i) {
const struct CFGMAP_tuple *tpl= rtn_arr + i;
/* Break the address into prefix & subnet bits */
static char addr[43];
unsigned bits;
int rc= sscanf(tpl->value, "%42[0-9a-zA-Z:.]/%u", addr, &bits);
if(1 != rc && 2 != rc) {
eprintf("ERROR: \"%s\" is neither IP address or CIDR.", tpl->value);
goto abort;
}
/* If it's simply an IP address, place in map & keep going */
if(1 == rc) {
/* Place in the map the number allowed as if it were
* a pointer to an object (there is no object in this case).
*/
MAP_addStrKey(&S.addr_map, addr, (void*)nAllowed);
continue;
}
/* Avoid stupidity right off the hop */
if(strchr(addr, ':')) {
eprintf("ERROR: CIDR not implemented for ipv6 \"%s\"", tpl->value);
goto abort;
} else if(16 > bits) {
eprintf("ERROR: Subnet is too large! \"%s\"", tpl->value);
goto abort;
}
/*--- Expand the CIDR notation to addresses ---*/
unsigned q1, q2, q3, q4;
/* Convert quad values from text to binary */
rc= sscanf(addr, "%u.%u.%u.%u", &q1, &q2, &q3, &q4);
/* Convert quads into useful parameters */
uint32_t baddr= (q1 << 24) | (q2 << 16) | (q3 << 8) | q4,
mask= 0xffffffff << (32-bits),
net= baddr & mask,
nAddr= 0xffffffff >> bits;
assert(4 == rc);
/* Generate individual addresses, and place them in the map */
for(unsigned i= 0; i < nAddr; ++i) {
baddr= net | i;
q1= (baddr & 0xff000000) >> 24;
q2= (baddr & 0x00ff0000) >> 16;
q3= (baddr & 0x0000ff00) >> 8;
q4= baddr & 0x000000ff;
/* Convert back to text form */
snprintf(addr, sizeof(addr), "%u.%u.%u.%u", q1, q2, q3, q4);
/* Add to the map */
MAP_addStrKey(&S.addr_map, addr, (void*)nAllowed);
}
}
}
{ /*--- Register COUNTRY entries ---*/
snprintf(symBuf, len, "%s\\COUNTRY", pfix);
unsigned nFound= CFGMAP_find_tuples(h_cfgmap, rtn_arr, symBuf);
for(unsigned i= 0; i < nFound; ++i) {
const struct CFGMAP_tuple *tpl= rtn_arr + i;
/* Place in the map the number allowed as if it were
* a pointer to an object (superflous in this case).
*/
MAP_addStrKey(&S.cntry_map, tpl->value, (void*)nAllowed);
}
}
rtn= 0;
abort:
return rtn;
}
#pragma GCC diagnostic pop
#pragma GCC diagnostic pop