You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
2.6 KiB
128 lines
2.6 KiB
3 months ago
|
/*
|
||
|
* UCW Library -- IP address access lists
|
||
|
*
|
||
|
* (c) 1997--2007 Martin Mares <mj@ucw.cz>
|
||
|
*
|
||
|
* This software may be freely distributed and used according to the terms
|
||
|
* of the GNU Lesser General Public License.
|
||
|
*/
|
||
|
|
||
|
#include <ucw/lib.h>
|
||
|
#include <ucw/clists.h>
|
||
|
#include <ucw/conf.h>
|
||
|
#include <ucw/getopt.h>
|
||
|
#include <ucw/fastbuf.h>
|
||
|
#include <ucw/ipaccess.h>
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
struct ipaccess_entry {
|
||
|
cnode n;
|
||
|
int allow;
|
||
|
struct ip_addrmask addr;
|
||
|
};
|
||
|
|
||
|
static char *
|
||
|
addrmask_parser(char *c, void *ptr)
|
||
|
{
|
||
|
/*
|
||
|
* This is tricky: addrmasks will be compared by memcmp(), so we must ensure
|
||
|
* that even the padding between structure members is zeroed out.
|
||
|
*/
|
||
|
struct ip_addrmask *am = ptr;
|
||
|
bzero(am, sizeof(*am));
|
||
|
|
||
|
char *p = strchr(c, '/');
|
||
|
if (p)
|
||
|
*p++ = 0;
|
||
|
char *err = cf_parse_ip(c, &am->addr);
|
||
|
if (err)
|
||
|
return err;
|
||
|
if (p)
|
||
|
{
|
||
|
uint len;
|
||
|
if (!cf_parse_int(p, &len) && len <= 32)
|
||
|
am->mask = ~(len == 32 ? 0 : ~0U >> len);
|
||
|
else if (cf_parse_ip(p, &am->mask))
|
||
|
return "Invalid prefix length or netmask";
|
||
|
}
|
||
|
else
|
||
|
am->mask = ~0U;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
addrmask_dumper(struct fastbuf *fb, void *ptr)
|
||
|
{
|
||
|
struct ip_addrmask *am = ptr;
|
||
|
bprintf(fb, "%08x/%08x ", am->addr, am->mask);
|
||
|
}
|
||
|
|
||
|
struct cf_user_type ip_addrmask_type = {
|
||
|
.size = sizeof(struct ip_addrmask),
|
||
|
.name = "ip_addrmask",
|
||
|
.parser = addrmask_parser,
|
||
|
.dumper = addrmask_dumper
|
||
|
};
|
||
|
|
||
|
struct cf_section ipaccess_cf = {
|
||
|
CF_TYPE(struct ipaccess_entry),
|
||
|
CF_ITEMS {
|
||
|
CF_LOOKUP("Mode", PTR_TO(struct ipaccess_entry, allow), ((const char* const []) { "deny", "allow", NULL })),
|
||
|
CF_USER("IP", PTR_TO(struct ipaccess_entry, addr), &ip_addrmask_type),
|
||
|
CF_END
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int ip_addrmask_match(struct ip_addrmask *am, u32 ip)
|
||
|
{
|
||
|
return !((ip ^ am->addr) & am->mask);
|
||
|
}
|
||
|
|
||
|
int
|
||
|
ipaccess_check(clist *l, u32 ip)
|
||
|
{
|
||
|
CLIST_FOR_EACH(struct ipaccess_entry *, a, *l)
|
||
|
if (ip_addrmask_match(&a->addr, ip))
|
||
|
return a->allow;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#ifdef TEST
|
||
|
|
||
|
#include <stdio.h>
|
||
|
|
||
|
static clist t;
|
||
|
|
||
|
static struct cf_section test_cf = {
|
||
|
CF_ITEMS {
|
||
|
CF_LIST("A", &t, &ipaccess_cf),
|
||
|
CF_END
|
||
|
}
|
||
|
};
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
cf_declare_section("T", &test_cf, 0);
|
||
|
if (cf_getopt(argc, argv, CF_SHORT_OPTS, CF_NO_LONG_OPTS, NULL) != -1)
|
||
|
die("Invalid arguments");
|
||
|
|
||
|
byte buf[256];
|
||
|
while (fgets(buf, sizeof(buf), stdin))
|
||
|
{
|
||
|
char *c = strchr(buf, '\n');
|
||
|
if (c)
|
||
|
*c = 0;
|
||
|
u32 ip;
|
||
|
if (cf_parse_ip(buf, &ip))
|
||
|
puts("Invalid IP address");
|
||
|
else if (ipaccess_check(&t, ip))
|
||
|
puts("Allowed");
|
||
|
else
|
||
|
puts("Denied");
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#endif
|