Package: ipsvd
Version: 0.13.0-1
Severity: wishlist
Tags: patch

Hi,

the flat directory configuration scheme for ipsvd doesn't scale well for
large subnets that are not class A, B or C; for example, a /25 network would
need 128 configuration files.

Allied-Visions GmbH developed a patch to support CIDR-based configuration
(attached). This patch also adds support for configfile expiry on
filesystems mounted with "noatime"; a new switch, -T, causes {tcp,udp}svd to
touch (hence the T) the files it accesses, keeping the atime updated.

Configuration now works as follows:

- the configfile for 1.2.3.0/24 would be the file called 24 in the directory
  called 1.2.3.0

- if you want separate configuration for the IP 1.2.3.0, call the file
  1.2.3.0/32

- if we don't have permission to read a dir, then we assume we don't have
  permission to read the files in it either and act accordingly

To further increase scalability in large configurations, hierarchical
processing of domain names is now possible: the configuration in foo/bar
applies to all clients under the domain .bar.foo.

This patch hasn't received thorough testing yet, but it appears to work.

We'll test it further and post new versions of the patch here if necessary;
this submission is in the spirit of 'release early, release often'. :)

Andras

-- 
                 Andras Korn <korn at chardonnay.math.bme.hu>
                 <http://chardonnay.math.bme.hu/~korn/> QOTD:
                Hogy en ambivalens??? Talan igen, talan nem...
Index: CIDR_test/test.c
===================================================================
--- CIDR_test/test.c	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 0)
+++ CIDR_test/test.c	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -0,0 +1,19 @@
+#include <stdio.h>
+#include "../CIDR.h"
+int main()
+{
+	unsigned char ip_num[4];
+	char *ip = "123.4.31.01";
+	char result[32];
+	int n;
+	
+	printf("res=%d\n", ip2num(ip, ip_num));
+	printf("    %u.%u.%u.%u\n", ip_num[0], ip_num[1], ip_num[2], ip_num[3]);
+	
+	*result = '\0';
+	for(n=32; n>0; n--) {
+		num2CIDR(ip_num, result, n);
+		printf("%2d=%s\n", n, result);
+	}
+	return 0;
+}
Index: CIDR_test/Makefile
===================================================================
--- CIDR_test/Makefile	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 0)
+++ CIDR_test/Makefile	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -0,0 +1,9 @@
+CFLAGS = -Wall -g
+test: test.o ../CIDR.o
+
+test.o: test.c
+
+../CIDR.o: ../CIDR.c
+
+clean:
+	rm test.o test
Index: udpsvd.c
===================================================================
--- udpsvd.c	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 73)
+++ udpsvd.c	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -170,8 +170,9 @@
 
   progname =*argv;
 
-  while ((opt =getopt(argc, argv, "vu:l:hpi:x:t:V")) != opteof) {
+  while ((opt =getopt(argc, argv, "Tvu:l:hpi:x:t:V")) != opteof) {
     switch(opt) {
+		case 'T': check_touch_configs = 1; break;
     case 'v':
       ++verbose;
       break;
Index: tcpsvd.c
===================================================================
--- tcpsvd.c	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 73)
+++ tcpsvd.c	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -271,12 +271,13 @@
 
 #ifdef SSLSVD
   while ((opt =getopt(argc, (const char **)argv,
-                      "c:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
+                      "Tc:C:i:x:u:l:Eb:hpt:vVU:/:Z:K:")) != opteof) {
 #else
   while ((opt =getopt(argc, (const char **)argv,
-                      "c:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
+                      "Tc:C:i:x:u:l:Eb:hpt:vV")) != opteof) {
 #endif
     switch(opt) {
+		case 'T': check_touch_configs = 1; break;
     case 'c': scan_ulong(optarg, &cmax); if (cmax < 1) usage(); break;
     case 'C':
       delim =scan_ulong(optarg, &phccmax);
Index: ipsvd_check.c
===================================================================
--- ipsvd_check.c	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 73)
+++ ipsvd_check.c	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -2,6 +2,7 @@
 #include <sys/stat.h>
 #include <unistd.h>
 #include <time.h>
+#include <utime.h>
 #include "ipsvd_check.h"
 #include "ipsvd_log.h"
 #include "ipsvd_fmt.h"
@@ -17,7 +18,11 @@
 #include "pathexec.h"
 #include "dns.h"
 #include "ip4.h"
+#include "alloc.h"
+#include "CIDR.h"
 
+int check_touch_configs = 0;
+
 extern const char *progname;
 static stralloc sa ={0};
 static stralloc ips ={0};
@@ -118,12 +123,28 @@
   return(rc);
 }
 
+void touch(const char *file_name, time_t atime)
+{
+	struct utimbuf ut;
+
+	if (atime == 0)
+		atime = time(NULL);
+
+	ut.actime  = atime;
+	ut.modtime = atime;
+
+	utime(file_name, &ut);
+}
+
 int ipsvd_check_direntry(stralloc *d, stralloc *m, char *ip,
                          time_t now, unsigned long t, int *rc) {
   int i;
   struct stat s;
 
   if (stat(m->s, &s) != -1) {
+		/* Do not consider directories */
+		if (S_ISDIR(s.st_mode))
+			return -1;
     if (t && (s.st_mode & S_IWUSR) && (now >= s.st_atime))
       if ((now -s.st_atime) >= t) {
         if (unlink(m->s) == -1)
@@ -135,6 +156,8 @@
       *rc =IPSVD_DENY; return(1);
     }
     if (s.st_mode & S_IXUSR) {
+			if (check_touch_configs)
+				touch(m->s, now);
       if (openreadclose(m->s, d, 256) <= 0) return(-1);
       if (d->len && (d->s[d->len -1] == '\n')) d->len--;
       if (! stralloc_0(d)) return(-1);
@@ -142,6 +165,8 @@
       return(1);
     }
     if (s.st_mode & S_IRUSR) {
+			if (check_touch_configs)
+					touch(m->s, now);
       if (openreadclose(m->s, d, 256) <= 0) return(-1);
       if (d->len && (d->s[d->len -1] == '\n')) d->len--;
       for (i =0; i < d->len; i++) if (d->s[i] == '\n') d->s[i] =0;
@@ -161,11 +186,15 @@
 int ipsvd_check_dir(stralloc *data, stralloc *match, char *dir,
                     char *ip, char *name, unsigned long timeout) {
   struct stat s;
-  int i;
+  int i, n, len;
   int rc;
   int ok;
   int base;
   time_t now =0;
+	stralloc host_path ={0};
+	stralloc cidr_path ={0};
+	char *last, *to, *str;
+	char ip_num[4];
 
   if (stat(dir, &s) == -1) return(IPSVD_ERR);
   if (timeout) now =time((time_t*)0);
@@ -174,6 +203,32 @@
   base =match->len;
   /* ip */
   if (ip) {
+		/* CIDR check */
+		ip2num(ip, ip_num);
+		len = str_len(dir);
+
+		if (! stralloc_ready(&cidr_path, 20 + len))
+			return -1;
+
+		for(to = cidr_path.s, str = dir; *str != '\0'; to++, str++)
+			*to = *str;
+		*to = '/';
+		to++;		
+
+		for(n = 32; n>0; n--) {
+			num2CIDR(ip_num, to, n);
+	    ok = ipsvd_check_direntry(data, &cidr_path, NULL, now, timeout, &rc);
+	    if (ok == -1) return(-1);
+  	  if (ok) {
+				if (!stralloc_0(&cidr_path))
+					return -1;
+    	  if (rc == IPSVD_FORWARD) goto forwarded;
+	      return(rc);
+	    }
+		}
+    if (! stralloc_0(&cidr_path)) return(-1);
+		
+		/* original IP check */
     if (! stralloc_cats(match, ip)) return(-1);
     if (! stralloc_0(match)) return(-1);
     data->len =0;
@@ -181,7 +236,9 @@
       ok =ipsvd_check_direntry(data, match, ip, now, timeout, &rc);
       if (ok == -1) return(-1);
       if (ok) {
-        if (rc == IPSVD_FORWARD) goto forwarded;
+        if (rc == IPSVD_FORWARD) {
+					goto forwarded;
+				}
         return(rc);
       }
       if ((i =byte_rchr(match->s, match->len, '.')) == match->len) break;
@@ -190,7 +247,70 @@
     }
   }
   /* host */
-  if (name) {
+  if ((name) && (*name)) {
+
+		/* Check host as a path - first assamble host_path, reverse order, dots replaced with slashes */
+		len = str_len(name);
+		if (! stralloc_ready(&host_path, len + str_len(dir) + 2))
+			return -1;
+		for(to = host_path.s, str = dir; *str != '\0'; to++, str++)
+			*to = *str;
+		*to = '/';
+		to++;		
+		for(str = name + len - 1, last = str + 1; str >= name; str--) {
+			if (*str == '.') {
+				n = last - str;
+				byte_copy(to, n, str + 1);
+				to += n - 1;
+				*to = '/';
+				to++;
+				last = str;
+			}
+		}
+		if (last != str) {
+			n = last - str;
+			byte_copy(to, n, str + 1);
+			to += n - 1;
+		}
+		*to = '\0';
+
+		/* start removing trailing segments and check for the file */
+    ok =ipsvd_check_direntry(data, &host_path, NULL, now, timeout, &rc);
+    if (ok == -1) return(-1);
+    if (ok) {
+			if (!stralloc_0(&host_path))
+				return -1;
+      if (rc == IPSVD_FORWARD) goto forwarded;
+      return(rc);
+    }
+
+		for(str = host_path.s + len; str >= host_path.s; str--) {
+			if (*str == '/') {
+				str[1] = '0';
+				str[2] = '\0';
+	      ok =ipsvd_check_direntry(data, &host_path, NULL, now, timeout, &rc);
+  	    if (ok == -1) return(-1);
+    	  if (ok) {
+					if (!stralloc_0(&host_path))
+						return -1;
+	        if (rc == IPSVD_FORWARD) goto forwarded;
+  	      return(rc);
+    	  }
+				*str = '\0';
+	      ok =ipsvd_check_direntry(data, &host_path, NULL, now, timeout, &rc);
+  	    if (ok == -1) return(-1);
+    	  if (ok) {
+					if (!stralloc_0(&host_path))
+						return -1;
+	        if (rc == IPSVD_FORWARD) goto forwarded;
+  	      return(rc);
+    	  }
+			}
+		}
+		if (!stralloc_0(&host_path))
+			return -1;
+
+		/* Original check: the whole hostname is a regular file */
     for (;;) {
       if (! *name || (*name == '.')) break;
       match->len =base;
@@ -220,6 +340,7 @@
   }
   if (! stralloc_copys(match, "")) return(-1);
   if (! stralloc_0(match)) return(-1);
+
   return(IPSVD_DEFAULT);
 
  forwarded:
Index: ipsvd_check.h
===================================================================
--- ipsvd_check.h	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 73)
+++ ipsvd_check.h	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -5,6 +5,7 @@
 
 extern unsigned long phccmax;
 extern char *phccmsg;
+extern int check_touch_configs; /* Set this to 1 to enable touching config files before read */
 
 #define IPSVD_ERR 0
 #define IPSVD_DENY 1
Index: Makefile
===================================================================
--- Makefile	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 73)
+++ Makefile	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -7,28 +7,28 @@
 	./check-local $(IT) `grep -v nossl <command.ssl || :`
 
 tcpsvd: load tcpsvd.o ipsvd_log.o ipsvd_fmt.o ipsvd_check.o ipsvd_hostname.o \
-	  ipsvd_phcc.o ipsvd_scan.o uidgid.o cdb.a dns.a unix.a byte.a \
+	  ipsvd_phcc.o ipsvd_scan.o uidgid.o CIDR.o cdb.a dns.a unix.a byte.a \
 	  time.a socket.lib
-	./load tcpsvd ipsvd_log.o ipsvd_fmt.o ipsvd_check.o ipsvd_hostname.o \
+	./load tcpsvd ipsvd_log.o ipsvd_fmt.o ipsvd_check.o CIDR.o ipsvd_hostname.o \
 	  ipsvd_phcc.o ipsvd_scan.o uidgid.o cdb.a dns.a unix.a byte.a \
 	  time.a `cat socket.lib`
 
 sslsvd: load sslsvd.o ssl_io.o sslerror_str.o ipsvd_log.o ipsvd_fmt.o \
-	  ipsvd_check.o ipsvd_hostname.o ipsvd_phcc.o ipsvd_scan.o uidgid.o \
+	  CIDR.o ipsvd_check.o ipsvd_hostname.o ipsvd_phcc.o ipsvd_scan.o uidgid.o \
 	  cdb.a dns.a unix.a byte.a time.a socket.lib matrixssl.a
 	./load sslsvd ssl_io.o sslerror_str.o ipsvd_log.o ipsvd_fmt.o \
-	  ipsvd_check.o ipsvd_hostname.o ipsvd_phcc.o ipsvd_scan.o uidgid.o \
+	  CIDR.o ipsvd_check.o ipsvd_hostname.o ipsvd_phcc.o ipsvd_scan.o uidgid.o \
 	  cdb.a dns.a unix.a byte.a time.a `cat socket.lib` matrixssl.a
 
-udpsvd: load udpsvd.o ipsvd_log.o ipsvd_fmt.o ipsvd_check.o ipsvd_hostname.o \
+udpsvd: load udpsvd.o ipsvd_log.o ipsvd_fmt.o CIDR.o ipsvd_check.o ipsvd_hostname.o \
 	  ipsvd_scan.o uidgid.o cdb.a dns.a unix.a byte.a time.a socket.lib
-	./load udpsvd ipsvd_log.o ipsvd_fmt.o ipsvd_check.o ipsvd_hostname.o \
+	./load udpsvd ipsvd_log.o ipsvd_fmt.o CIDR.o ipsvd_check.o ipsvd_hostname.o \
 	  ipsvd_scan.o uidgid.o cdb.a dns.a unix.a byte.a time.a \
 	  `cat socket.lib`
 
-ipsvd-cdb: load ipsvd-cdb.o ipsvd_fmt.o ipsvd_check.o cdb.a dns.a unix.a \
+ipsvd-cdb: load ipsvd-cdb.o ipsvd_fmt.o CIDR.o ipsvd_check.o cdb.a dns.a unix.a \
 	  byte.a time.a
-	./load ipsvd-cdb ipsvd_fmt.o ipsvd_check.o cdb.a dns.a unix.a byte.a \
+	./load ipsvd-cdb ipsvd_fmt.o CIDR.o ipsvd_check.o cdb.a dns.a unix.a byte.a \
 	  time.a `cat socket.lib`
 
 sslio: load sslio.o ssl_io.o uidgid.o sslerror_str.o unix.a byte.a time.a \
@@ -97,6 +97,9 @@
 ipsvd_check.o: compile ipsvd_check.c uint64.h
 	./compile ipsvd_check.c
 
+CIDR.o: compile CIDR.h CIDR.c
+	./compile CIDR.c
+
 ipsvd_hostname.o: compile ipsvd_hostname.c uint64.h
 	./compile ipsvd_hostname.c
 
Index: CIDR.c
===================================================================
--- CIDR.c	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 0)
+++ CIDR.c	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -0,0 +1,71 @@
+int ip2num(const char *ip, unsigned char *ip_num)
+{
+	const char *s;
+	int accumulator = 0, token = 0;
+	for(s = ip; ; s++) {
+		if ((*s == '.') || (*s == '\0')) {
+			if (accumulator > 255)
+				return 1;
+			if (token > 3)
+				return 2;
+			ip_num[token] = accumulator;
+			token++;
+			accumulator = 0;
+		}
+		else {
+			accumulator *= 10;
+			accumulator += *s - '0';
+		}
+		if (*s == '\0')
+			break;
+	}
+	if (token == 4)
+		return 0;
+	return 3;
+}
+
+static char *bin2dec(char *result, unsigned char num)
+{
+	/* This is probably faster than a for cycle */
+	if ((num / 100) > 0) {
+		*result = num / 100 + '0';
+		num = num % 100;
+		result++;
+	}
+	if ((num / 10) > 0) {
+		*result = num / 10 + '0';
+		num = num % 10;
+		result++;
+	}
+
+	*result = num + '0';
+	result++;		
+
+	return result;
+}
+
+int num2CIDR(const unsigned char *ip_num, char *result, int suffix)
+{
+	int mask = 0xFFFFFFFF << (32 - suffix);
+	int n;
+	unsigned char final[4];
+	char *s;
+
+	for(n = 3; n >= 0; n--) {
+		final[n] = ip_num[n] & (mask & 0xFF);
+		mask = mask >> 8;
+	}
+
+	s = result;
+	for(n = 0; n < 4; n++) {
+		s = bin2dec(s, final[n]);
+		*s = '.';
+		s++;
+	}
+	s--;
+	*s = '/';
+	s++;
+	s = bin2dec(s, suffix);
+	*s = '\0';
+	return s - result;
+}
Index: CIDR.h
===================================================================
--- CIDR.h	(.../ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 0)
+++ CIDR.h	(.../floss/ipsvd/ipsvd-0.13.0/net/ipsvd-0.13.0/src)	(revision 147)
@@ -0,0 +1,2 @@
+int ip2num(const char *ip, unsigned char *ip_num);
+int num2CIDR(const unsigned char *ip_num, char *result, int suffix);

Reply via email to