/* * UCW Library -- IP address access lists * * (c) 1997--2007 Martin Mares * * This software may be freely distributed and used according to the terms * of the GNU Lesser General Public License. */ #include #include #include #include #include #include #include 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 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