]> mj.ucw.cz Git - libucw.git/blobdiff - lib/ipaccess.c
Don't forget to increase run counter.
[libucw.git] / lib / ipaccess.c
index 1bbd085fc2ee69b16384cd4f69d5515f13c629c9..79508ab0eb113e4d72b32562fe4e9725118de058 100644 (file)
 /*
  *     UCW Library -- IP address access lists
  *
 /*
  *     UCW Library -- IP address access lists
  *
- *     (c) 1997--2001 Martin Mares <mj@ucw.cz>
+ *     (c) 1997--2006 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 "lib/lib.h"
  *
  *     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/conf.h"
-#include "lib/chartype.h"
+#include "lib/getopt.h"
+#include "lib/fastbuf.h"
 #include "lib/ipaccess.h"
 
 #include <string.h>
 #include "lib/ipaccess.h"
 
 #include <string.h>
-#include <stdlib.h>
 
 
-struct ipaccess_list {
-  list l;
+struct addrmask {
+  u32 addr;
+  u32 mask;
 };
 
 struct ipaccess_entry {
 };
 
 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, '/');
   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)
     {
   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;
 }
       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))
+    {
+      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