X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;ds=sidebyside;f=lib%2Fipaccess.c;h=79508ab0eb113e4d72b32562fe4e9725118de058;hb=8c48090e240d68564c79eb29ac9004cc911bb5d0;hp=1bbd085fc2ee69b16384cd4f69d5515f13c629c9;hpb=06e407148505bb6f8fb92592d8484062362256ef;p=libucw.git diff --git a/lib/ipaccess.c b/lib/ipaccess.c index 1bbd085f..79508ab0 100644 --- a/lib/ipaccess.c +++ b/lib/ipaccess.c @@ -1,74 +1,127 @@ /* * UCW Library -- IP address access lists * - * (c) 1997--2001 Martin Mares + * (c) 1997--2006 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. */ #include "lib/lib.h" -#include "lib/lists.h" +#include "lib/clists.h" #include "lib/conf.h" -#include "lib/chartype.h" +#include "lib/getopt.h" +#include "lib/fastbuf.h" #include "lib/ipaccess.h" #include -#include -struct ipaccess_list { - list l; +struct addrmask { + u32 addr; + u32 mask; }; struct ipaccess_entry { - node n; - uns allow; - u32 addr, mask; + cnode n; + int allow; + struct addrmask addr; }; -struct ipaccess_list * -ipaccess_init(void) +static byte * +addrmask_parser(byte *c, void *ptr) { - /* Cannot use cfg_malloc() here as the pool can be uninitialized now */ - struct ipaccess_list *l = xmalloc(sizeof(*l)); + /* + * This is tricky: addrmasks will be compared by memcmp(), so we must ensure + * that even the padding between structure members is zeroed out. + */ + struct addrmask *am = ptr; + bzero(am, sizeof(*am)); - init_list(&l->l); - return l; -} - -byte * -ipaccess_parse(struct ipaccess_list *l, byte *c, int is_allow) -{ byte *p = strchr(c, '/'); - char *q; - struct ipaccess_entry *a = cfg_malloc(sizeof(struct ipaccess_entry)); - unsigned long pxlen; - - a->allow = is_allow; - a->mask = ~0U; + if (p) + *p++ = 0; + byte *err = cf_parse_ip(c, &am->addr); + if (err) + return err; if (p) { - *p++ = 0; - pxlen = strtoul(p, &q, 10); - if ((!q || !*q) && pxlen <= 32) - { - if (pxlen != 32) - a->mask = ~(~0U >> (uns) pxlen); - } - else if (q = cf_parse_ip(&p, &a->mask)) - return q; + uns 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"; } - add_tail(&l->l, &a->n); - return cf_parse_ip(&c, &a->addr); + else + am->mask = ~0U; + return NULL; } -int -ipaccess_check(struct ipaccess_list *l, u32 ip) +static void +addrmask_dumper(struct fastbuf *fb, void *ptr) { - struct ipaccess_entry *a; + struct addrmask *am = ptr; + bprintf(fb, "%08x/%08x ", am->addr, am->mask); +} - DO_FOR_ALL(a, l->l) - if (! ((ip ^ a->addr) & a->mask)) +static struct cf_user_type addrmask_type = { + .size = sizeof(struct addrmask), + .name = "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), ((byte*[]) { "deny", "allow", NULL })), + CF_USER("IP", PTR_TO(struct ipaccess_entry, addr), &addrmask_type), + CF_END + } +}; + +int +ipaccess_check(clist *l, u32 ip) +{ + CLIST_FOR_EACH(struct ipaccess_entry *, a, *l) + if (! ((ip ^ a->addr.addr) & a->addr.mask)) return a->allow; return 0; } + +#ifdef TEST + +#include + +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)) + { + byte *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