summaryrefslogtreecommitdiff
path: root/src/rules.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rules.c')
-rw-r--r--src/rules.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/rules.c b/src/rules.c
new file mode 100644
index 0000000..279ffae
--- /dev/null
+++ b/src/rules.c
@@ -0,0 +1,141 @@
+#include "alloc.h"
+#include "stralloc.h"
+#include "open.h"
+#include "cdbread.h"
+#include "byte.h"
+#include "fmt.h"
+#include "getln.h"
+#include "ip.h"
+#include "str.h"
+#include "ip_bit.h"
+#include "rules.h"
+
+stralloc rules_name = {0};
+stralloc ipstring = {0};
+
+static struct cdb c;
+
+static int dorule(void (*callback)(char *,unsigned int)) {
+ char *data;
+ unsigned int datalen;
+
+ switch (cdb_find(&c,rules_name.s,rules_name.len)) {
+ case -1: return -1;
+ case 0: return 0;
+ }
+
+ datalen = cdb_datalen(&c);
+ data = alloc(datalen);
+ if (!data) return -1;
+ if (cdb_read(&c,data,datalen,cdb_datapos(&c)) == -1) {
+ alloc_free(data);
+ return -1;
+ }
+
+ callback(data, datalen);
+ alloc_free(data);
+ return 1;
+}
+
+static int doit(void (*callback)(char *,unsigned int),char *ip,char *host,char *info) {
+ int p;
+ int r;
+ int ipv6 = str_len(ip) - byte_chr(ip,str_len(ip),':');
+
+ if (info) { /* 1. info@ip */
+ if (!stralloc_copys(&rules_name,info)) return -1;
+ if (!stralloc_cats(&rules_name,"@")) return -1;
+ if (ipv6) {
+ if (!ip6_fmt_str(&ipstring,ip))
+ if (!stralloc_catb(&rules_name,ipstring.s,ipstring.len)) return -1;
+ }
+ else
+ if (!stralloc_cats(&rules_name,ip)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+
+ if (host) { /* 2. info@=host */
+ if (!stralloc_copys(&rules_name,info)) return -1;
+ if (!stralloc_cats(&rules_name,"@=")) return -1;
+ if (!stralloc_cats(&rules_name,host)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ }
+
+ if (ipv6) { /* 3. IPv6/IPv4 */
+ if (!ip6_fmt_str(&ipstring,ip)) {
+ if (!stralloc_copyb(&rules_name,ipstring.s,ipstring.len)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ } else {
+ if (!stralloc_copys(&rules_name,ip)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+
+ if (host) { /* 4. =host */
+ if (!stralloc_copys(&rules_name,"=")) return -1;
+ if (!stralloc_cats(&rules_name,host)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+
+ if (!ipv6) { /* 5. IPv4 class-based */
+ if (!stralloc_copys(&rules_name,ip)) return -1;
+ while (rules_name.len > 0) {
+ if (ip[rules_name.len - 1] == '.') {
+ r = dorule(callback);
+ if (r) return r;
+ }
+ --rules_name.len;
+ }
+ }
+
+ if (ipv6) { /* 6. IPv6/IPv4 CIDR */
+ if (!ip6_bitstring(&ipstring,ip,128)) {
+ for (p = 129; p > 1; p--) {
+ if (!stralloc_copys(&rules_name,"^")) return -1;
+ if (!stralloc_catb(&rules_name,ipstring.s,p)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ }
+ } else {
+ if (!ip4_bitstring(&ipstring,ip,32)) {
+ for (p = 33; p > 1; p--) {
+ if (!stralloc_copys(&rules_name,"_")) return -1;
+ if (!stralloc_catb(&rules_name,ipstring.s,p)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ }
+ }
+
+ if (host) { /* 7. =host. */
+ while (*host) {
+ if (*host == '.') {
+ if (!stralloc_copys(&rules_name,"=")) return -1;
+ if (!stralloc_cats(&rules_name,host)) return -1;
+ r = dorule(callback);
+ if (r) return r;
+ }
+ ++host;
+ }
+ if (!stralloc_copys(&rules_name,"=")) return -1; /* 8. = rule */
+ r = dorule(callback);
+ if (r) return r;
+ }
+
+ rules_name.len = 0;
+ return dorule(callback);
+}
+
+int rules(void (*callback)(char *,unsigned int),int fd,char *ip,char *host,char *info) {
+ int r;
+ cdb_init(&c,fd);
+ r = doit(callback,ip,host,info);
+ cdb_free(&c);
+ return r;
+}