[conntrack-tools] filter: CIDR-based filtering support

Pablo Neira netfilter-cvslog-bounces at lists.netfilter.org
Tue Nov 25 23:52:08 CET 2008


Gitweb:		http://git.netfilter.org/cgi-bin/gitweb.cgi?p=conntrack-tools.git;a=commit;h=b2edf895af82914ab09a842641a45b7a806e9b1e
commit b2edf895af82914ab09a842641a45b7a806e9b1e
Author:     Pablo Neira Ayuso <pablo at netfilter.org>
AuthorDate: Tue Nov 25 23:34:48 2008 +0100
Commit:     Pablo Neira Ayuso <pablo at netfilter.org>
CommitDate: Tue Nov 25 23:34:48 2008 +0100

    filter: CIDR-based filtering support
    
    This patch adds CIDR-based filtering support. The current
    implementation is O(n).
    
    This patch also introduces the vector data type which is
    used to store the IP address and the network mask.
    
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>
       via  b2edf895af82914ab09a842641a45b7a806e9b1e (commit)
      from  6262a4a7b7139fb5636228cb0f5a1e72f848d871 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b2edf895af82914ab09a842641a45b7a806e9b1e
Author: Pablo Neira Ayuso <pablo at netfilter.org>
Date:   Tue Nov 25 23:34:48 2008 +0100

    filter: CIDR-based filtering support
    
    This patch adds CIDR-based filtering support. The current
    implementation is O(n).
    
    This patch also introduces the vector data type which is
    used to store the IP address and the network mask.
    
    Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>

-----------------------------------------------------------------------

 doc/sync/alarm/conntrackd.conf   |    3 +
 doc/sync/ftfw/conntrackd.conf    |    3 +
 doc/sync/notrack/conntrackd.conf |    3 +
 include/Makefile.am              |    2 +-
 include/cidr.h                   |    8 +++
 include/filter.h                 |   15 ++++++-
 include/vector.h                 |   13 +++++
 src/Makefile.am                  |    4 +-
 src/cidr.c                       |   59 +++++++++++++++++++++++++
 src/filter.c                     |   90 ++++++++++++++++++++++++++++++++++++++
 src/read_config_lex.l            |    6 ++-
 src/read_config_yy.y             |   86 +++++++++++++++++++++++++++++-------
 src/vector.c                     |   88 +++++++++++++++++++++++++++++++++++++
 13 files changed, 358 insertions(+), 22 deletions(-)
 create mode 100644 include/cidr.h
 create mode 100644 include/vector.h
 create mode 100644 src/cidr.c
 create mode 100644 src/vector.c
This patch adds CIDR-based filtering support. The current
implementation is O(n).

This patch also introduces the vector data type which is
used to store the IP address and the network mask.

Signed-off-by: Pablo Neira Ayuso <pablo at netfilter.org>

diff --git a/doc/sync/alarm/conntrackd.conf b/doc/sync/alarm/conntrackd.conf
index 6995d6c..31a1a4d 100644
--- a/doc/sync/alarm/conntrackd.conf
+++ b/doc/sync/alarm/conntrackd.conf
@@ -191,6 +191,9 @@ General {
 			IPv4_address 192.168.0.1
 			IPv4_address 192.168.1.1
 			IPv4_address 192.168.100.100 # dedicated link ip
+			#
+			# You can also specify networks in format IP/cidr.
+			# IPv4_address 192.168.0.0/24
 		}
 
 		#
diff --git a/doc/sync/ftfw/conntrackd.conf b/doc/sync/ftfw/conntrackd.conf
index 3a2ed0e..ae2fe78 100644
--- a/doc/sync/ftfw/conntrackd.conf
+++ b/doc/sync/ftfw/conntrackd.conf
@@ -195,6 +195,9 @@ General {
 			IPv4_address 192.168.0.1
 			IPv4_address 192.168.1.1
 			IPv4_address 192.168.100.100 # dedicated link ip
+			#
+			# You can also specify networks in format IP/cidr.
+			# IPv4_address 192.168.0.0/24
 		}
 
 		#
diff --git a/doc/sync/notrack/conntrackd.conf b/doc/sync/notrack/conntrackd.conf
index e9835e8..d0e141c 100644
--- a/doc/sync/notrack/conntrackd.conf
+++ b/doc/sync/notrack/conntrackd.conf
@@ -179,6 +179,9 @@ General {
 			IPv4_address 192.168.0.1
 			IPv4_address 192.168.1.1
 			IPv4_address 192.168.100.100 # dedicated link ip
+			#
+			# You can also specify networks in format IP/cidr.
+			# IPv4_address 192.168.0.0/24
 		}
 
 		#
diff --git a/include/Makefile.am b/include/Makefile.am
index 3287a0c..4d22993 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -2,6 +2,6 @@
 noinst_HEADERS = alarm.h jhash.h slist.h cache.h linux_list.h linux_rbtree.h \
 		 sync.h conntrackd.h local.h us-conntrack.h \
 		 debug.h log.h hash.h mcast.h conntrack.h \
-		 network.h filter.h queue.h \
+		 network.h filter.h queue.h vector.h \
 		 traffic_stats.h netlink.h fds.h event.h bitops.h
 
diff --git a/include/cidr.h b/include/cidr.h
new file mode 100644
index 0000000..f8a4e2a
--- /dev/null
+++ b/include/cidr.h
@@ -0,0 +1,8 @@
+#ifndef _CIDR_H_
+
+uint32_t ipv4_cidr2mask_host(uint8_t cidr);
+uint32_t ipv4_cidr2mask_net(uint8_t cidr);
+void ipv6_cidr2mask_host(uint8_t cidr, uint32_t *res);
+void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res);
+
+#endif
diff --git a/include/filter.h b/include/filter.h
index de0754e..567be34 100644
--- a/include/filter.h
+++ b/include/filter.h
@@ -2,11 +2,13 @@
 #define _FILTER_H_
 
 #include <stdint.h>
+#include <string.h>
+#include <netinet/in.h>
 
 enum ct_filter_type {
 	CT_FILTER_L4PROTO,
 	CT_FILTER_STATE,
-	CT_FILTER_ADDRESS,
+	CT_FILTER_ADDRESS,	/* also for netmask */
 	CT_FILTER_MAX
 };
 
@@ -15,12 +17,23 @@ enum ct_filter_logic {
 	CT_FILTER_POSITIVE = 1,
 };
 
+struct ct_filter_netmask_ipv4 {
+	uint32_t ip;
+	uint32_t mask;
+};
+
+struct ct_filter_netmask_ipv6 {
+	uint32_t ip[4];
+	uint32_t mask[4];
+};
+
 struct nf_conntrack;
 struct ct_filter;
 
 struct ct_filter *ct_filter_create(void);
 void ct_filter_destroy(struct ct_filter *filter);
 int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family);
+int ct_filter_add_netmask(struct ct_filter *filter, void *data, uint8_t family);
 void ct_filter_add_proto(struct ct_filter *filter, int protonum);
 void ct_filter_add_state(struct ct_filter *f, int protonum, int state);
 void ct_filter_set_logic(struct ct_filter *f,
diff --git a/include/vector.h b/include/vector.h
new file mode 100644
index 0000000..5b05cba
--- /dev/null
+++ b/include/vector.h
@@ -0,0 +1,13 @@
+#ifndef _VECTOR_H_
+#define _VECTOR_H_
+
+#include <stdlib.h>
+
+struct vector;
+
+struct vector *vector_create(size_t size);
+void vector_destroy(struct vector *v);
+int vector_add(struct vector *v, void *data);
+int vector_iterate(struct vector *v, const void *data, int (*fcn)(const void *a, const void *b));
+
+#endif
diff --git a/src/Makefile.am b/src/Makefile.am
index 82f7dfe..64ed2b5 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -11,13 +11,13 @@ conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp
 conntrack_LDFLAGS = $(all_libraries) @LIBNETFILTER_CONNTRACK_LIBS@
 
 conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \
-		    local.c log.c mcast.c netlink.c \
+		    local.c log.c mcast.c netlink.c vector.c \
 		    filter.c fds.c event.c \
 		    cache.c cache_iterators.c \
 		    cache_lifetime.c cache_timer.c cache_wt.c \
 		    sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \
 		    traffic_stats.c stats-mode.c \
-		    network.c \
+		    network.c cidr.c \
 		    build.c parse.c \
 		    read_config_yy.y read_config_lex.l
 
diff --git a/src/cidr.c b/src/cidr.c
new file mode 100644
index 0000000..d43dabc
--- /dev/null
+++ b/src/cidr.c
@@ -0,0 +1,59 @@
+/*
+ * (C) 2006-2008 by Pablo Neira Ayuso <pablo at netfilter.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <netinet/in.h>
+#include "cidr.h"
+
+/* returns the netmask in host byte order */
+uint32_t ipv4_cidr2mask_host(uint8_t cidr)
+{
+	return 0xFFFFFFFF << (32 - cidr);
+}
+
+/* returns the netmask in network byte order */
+uint32_t ipv4_cidr2mask_net(uint8_t cidr)
+{
+	return htonl(ipv4_cidr2mask_host(cidr));
+}
+
+void ipv6_cidr2mask_host(uint8_t cidr, uint32_t *res)
+{
+	int i, j;
+
+	memset(res, 0, sizeof(uint32_t)*4);
+	for (i = 0;  i < 4 && cidr > 32; i++) {
+		res[i] = 0xFFFFFFFF;
+		cidr -= 32;
+	}
+	res[i] = 0xFFFFFFFF << (32 - cidr);
+	for (j = i+1; j < 4; j++) {
+		res[j] = 0;
+	}
+}
+
+void ipv6_cidr2mask_net(uint8_t cidr, uint32_t *res)
+{
+	int i;
+
+	ipv6_cidr2mask_host(cidr, res);
+	for (i=0; i<4; i++)
+		res[i] = htonl(res[i]);
+}
+
diff --git a/src/filter.c b/src/filter.c
index f6da8bb..905d10f 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -20,12 +20,14 @@
 #include "bitops.h"
 #include "jhash.h"
 #include "hash.h"
+#include "vector.h"
 #include "conntrackd.h"
 #include "log.h"
 
 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 #include <limits.h>
 
 struct ct_filter {
@@ -34,6 +36,8 @@ struct ct_filter {
 	u_int16_t statemap[IPPROTO_MAX];
 	struct hashtable *h;
 	struct hashtable *h6;
+	struct vector *v;
+	struct vector *v6;
 };
 
 /* XXX: These should be configurable, better use a rb-tree */
@@ -95,6 +99,23 @@ struct ct_filter *ct_filter_create(void)
 		return NULL;
 	}
 
+	filter->v = vector_create(sizeof(struct ct_filter_netmask_ipv4));
+	if (!filter->v) {
+		free(filter->h6);
+		free(filter->h);
+		free(filter);
+		return NULL;
+	}
+
+	filter->v6 = vector_create(sizeof(struct ct_filter_netmask_ipv6));
+	if (!filter->v6) {
+		free(filter->v);
+		free(filter->h6);
+		free(filter->h);
+		free(filter);
+		return NULL;
+	}
+
 	for (i=0; i<CT_FILTER_MAX; i++)
 		filter->logic[i] = -1;
 
@@ -105,6 +126,8 @@ void ct_filter_destroy(struct ct_filter *filter)
 {
 	hashtable_destroy(filter->h);
 	hashtable_destroy(filter->h6);
+	vector_destroy(filter->v);
+	vector_destroy(filter->v6);
 	free(filter);
 }
 
@@ -147,6 +170,39 @@ int ct_filter_add_ip(struct ct_filter *filter, void *data, uint8_t family)
 	return 1;
 }
 
+static int cmp_ipv4_addr(const void *a, const void *b)
+{
+	return memcmp(a, b, sizeof(struct ct_filter_netmask_ipv4)) == 0;
+}
+
+static int cmp_ipv6_addr(const void *a, const void *b)
+{
+	return memcmp(a, b, sizeof(struct ct_filter_netmask_ipv6)) == 0;
+}
+
+int ct_filter_add_netmask(struct ct_filter *filter, void *data, uint8_t family)
+{
+	filter = __filter_alloc(filter);
+
+	switch(family) {
+		case AF_INET:
+			if (vector_iterate(filter->v, data, cmp_ipv4_addr)) {
+				errno = EEXIST;
+				return 0;
+			}
+			vector_add(filter->v, data);
+			break;
+		case AF_INET6:
+			if (vector_iterate(filter->v, data, cmp_ipv6_addr)) {
+				errno = EEXIST;
+				return 0;
+			}
+			vector_add(filter->v6, data);
+			break;
+	}
+	return 1;
+}
+
 void ct_filter_add_proto(struct ct_filter *f, int protonum)
 {
 	f = __filter_alloc(f);
@@ -176,6 +232,34 @@ __ct_filter_test_ipv6(struct ct_filter *f, struct nf_conntrack *ct)
 	        hashtable_test(f->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)));
 }
 
+static int
+__ct_filter_test_mask4(const void *ptr, const void *ct)
+{
+	const struct ct_filter_netmask_ipv4 *elem = ptr;
+	const uint32_t src = nfct_get_attr_u32(ct, ATTR_ORIG_IPV4_SRC);
+	const uint32_t dst = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_SRC);
+
+	return ((elem->ip & elem->mask) == (src & elem->mask) || 
+		(elem->ip & elem->mask) == (dst & elem->mask));
+}
+
+static int
+__ct_filter_test_mask6(const void *ptr, const void *ct)
+{
+	const struct ct_filter_netmask_ipv6 *elem = ptr;
+	const uint32_t *src = nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC);
+	const uint32_t *dst = nfct_get_attr(ct, ATTR_REPL_IPV6_SRC);
+
+	return (((elem->ip[0] & elem->mask[0]) == (src[0] & elem->mask[0]) &&
+		 (elem->ip[1] & elem->mask[1]) == (src[1] & elem->mask[1]) &&
+		 (elem->ip[2] & elem->mask[2]) == (src[2] & elem->mask[2]) &&
+		 (elem->ip[3] & elem->mask[3]) == (src[3] & elem->mask[3])) ||
+		((elem->ip[0] & elem->mask[0]) == (dst[0] & elem->mask[0]) &&
+		 (elem->ip[1] & elem->mask[1]) == (dst[1] & elem->mask[1]) &&
+		 (elem->ip[2] & elem->mask[2]) == (dst[2] & elem->mask[2]) &&
+		 (elem->ip[3] & elem->mask[3]) == (dst[3] & elem->mask[3])));
+}
+
 static int __ct_filter_test_state(struct ct_filter *f, struct nf_conntrack *ct)
 {
 	uint16_t val = 0;
@@ -212,11 +296,17 @@ int ct_filter_check(struct ct_filter *f, struct nf_conntrack *ct)
 	if (f->logic[CT_FILTER_ADDRESS] != -1) {
 		switch(nfct_get_attr_u8(ct, ATTR_L3PROTO)) {
 		case AF_INET:
+			ret = vector_iterate(f->v, ct, __ct_filter_test_mask4);
+			if (ret ^ f->logic[CT_FILTER_ADDRESS])
+				return 0;
 			ret = __ct_filter_test_ipv4(f, ct);
 			if (ret ^ f->logic[CT_FILTER_ADDRESS])
 				return 0;
 			break;
 		case AF_INET6:
+			ret = vector_iterate(f->v6, ct, __ct_filter_test_mask6);
+			if (ret ^ f->logic[CT_FILTER_ADDRESS])
+				return 0;
 			ret = __ct_filter_test_ipv6(f, ct);
 			if (ret ^ f->logic[CT_FILTER_ADDRESS])
 				return 0;
diff --git a/src/read_config_lex.l b/src/read_config_lex.l
index cbb6ca8..67c95d3 100644
--- a/src/read_config_lex.l
+++ b/src/read_config_lex.l
@@ -36,14 +36,16 @@ is_on		[o|O][n|N]
 is_off		[o|O][f|F][f|F]
 integer		[0-9]+
 path		\/[^\"\n ]*
+ip4_cidr	\/[0-2]*[0-9]+
 ip4_end		[0-9]*[0-9]+
 ip4_part	[0-2]*{ip4_end}
-ip4		{ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part}
+ip4		{ip4_part}\.{ip4_part}\.{ip4_part}\.{ip4_part}{ip4_cidr}?
 hex_255		[0-9a-fA-F]{1,4}
+ip6_cidr	\/[0-1]*[0-9]*[0-9]+
 ip6_part	{hex_255}":"?
 ip6_form1	{ip6_part}{0,16}"::"{ip6_part}{0,16}
 ip6_form2	({hex_255}":"){16}{hex_255}
-ip6		{ip6_form1}|{ip6_form2}
+ip6		{ip6_form1}{ip6_cidr}?|{ip6_form2}{ip6_cidr}?
 string		[a-zA-Z][a-zA-Z0-9\.]*
 persistent	[P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T]
 nack		[N|n][A|a][C|c][K|k]
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
index 06ada52..32ddeff 100644
--- a/src/read_config_yy.y
+++ b/src/read_config_yy.y
@@ -26,6 +26,7 @@
 #include <errno.h>
 #include "conntrackd.h"
 #include "bitops.h"
+#include "cidr.h"
 #include <syslog.h>
 #include <libnetfilter_conntrack/libnetfilter_conntrack.h>
 #include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
@@ -780,27 +781,55 @@ filter_address_list :
 filter_address_item : T_IPV4_ADDR T_IP
 {
 	union inet_address ip;
+	char *slash;
+	unsigned int cidr = 32;
 
 	memset(&ip, 0, sizeof(union inet_address));
 
+	slash = strchr($2, '/');
+	if (slash) {
+		*slash = '\0';
+		cidr = atoi(slash+1);
+		if (cidr > 32) {
+			fprintf(stderr, "%s/%d is not a valid network, "
+					"ignoring\n", $2, cidr);
+			break;
+		}
+	}
+
 	if (!inet_aton($2, &ip.ipv4)) {
 		fprintf(stderr, "%s is not a valid IPv4, ignoring", $2);
 		break;
 	}
 
-	if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) {
-		if (errno == EEXIST)
-			fprintf(stderr, "IP %s is repeated "
-					"in the ignore pool\n", $2);
-		if (errno == ENOSPC)
-			fprintf(stderr, "Too many IP in the ignore pool!\n");
+	if (slash && cidr < 32) {
+		/* network byte order */
+		struct ct_filter_netmask_ipv4 tmp = {
+			.ip = ip.ipv4,
+			.mask = ipv4_cidr2mask_net(cidr)
+		};
+
+		if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET)) {
+			if (errno == EEXIST)
+				fprintf(stderr, "Netmask %s is repeated "
+						"in the ignore pool\n", $2);
+		}
+	} else {
+		if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET)) {
+			if (errno == EEXIST)
+				fprintf(stderr, "IP %s is repeated "
+						"in the ignore pool\n", $2);
+			if (errno == ENOSPC)
+				fprintf(stderr, "Too many IP in the "
+						"ignore pool!\n");
+		}
 	}
-
 	__kernel_filter_start();
 
+	/* host byte order */
 	struct nfct_filter_ipv4 filter_ipv4 = {
-		.addr = htonl(ip.ipv4),
-		.mask = 0xffffffff,
+		.addr = ntohl(ip.ipv4),
+		.mask = ipv4_cidr2mask_host(cidr),
 	};
 
 	nfct_filter_add_attr(STATE(filter), NFCT_FILTER_SRC_IPV4, &filter_ipv4);
@@ -810,9 +839,22 @@ filter_address_item : T_IPV4_ADDR T_IP
 filter_address_item : T_IPV6_ADDR T_IP
 {
 	union inet_address ip;
+	char *slash;
+	int cidr;
 
 	memset(&ip, 0, sizeof(union inet_address));
 
+	slash = strchr($2, '/');
+	if (slash) {
+		*slash = '\0';
+		cidr = atoi(slash+1);
+		if (cidr > 128) {
+			fprintf(stderr, "%s/%d is not a valid network, "
+					"ignoring\n", $2, cidr);
+			break;
+		}
+	}
+
 #ifdef HAVE_INET_PTON_IPV6
 	if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) {
 		fprintf(stderr, "%s is not a valid IPv6, ignoring", $2);
@@ -822,13 +864,25 @@ filter_address_item : T_IPV6_ADDR T_IP
 	fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!");
 	break;
 #endif
-
-	if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) {
-		if (errno == EEXIST)
-			fprintf(stderr, "IP %s is repeated "
-					"in the ignore pool\n", $2);
-		if (errno == ENOSPC)
-			fprintf(stderr, "Too many IP in the ignore pool!\n");
+	if (slash && cidr < 128) {
+		struct ct_filter_netmask_ipv6 tmp;
+
+		memcpy(tmp.ip, ip.ipv6, sizeof(uint32_t)*4);
+		ipv6_cidr2mask_net(cidr, tmp.mask);
+		if (!ct_filter_add_netmask(STATE(us_filter), &tmp, AF_INET6)) {
+			if (errno == EEXIST)
+				fprintf(stderr, "Netmask %s is repeated "
+						"in the ignore pool\n", $2);
+		}
+	} else {
+		if (!ct_filter_add_ip(STATE(us_filter), &ip, AF_INET6)) {
+			if (errno == EEXIST)
+				fprintf(stderr, "IP %s is repeated "
+						"in the ignore pool\n", $2);
+			if (errno == ENOSPC)
+				fprintf(stderr, "Too many IP in the "
+						"ignore pool!\n");
+		}
 	}
 };
 
diff --git a/src/vector.c b/src/vector.c
new file mode 100644
index 0000000..c81e7ce
--- /dev/null
+++ b/src/vector.c
@@ -0,0 +1,88 @@
+/*
+ * (C) 2006-2008 by Pablo Neira Ayuso <pablo at netfilter.org>
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "vector.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+struct vector {
+	char *data;
+	unsigned int cur_elems;
+	unsigned int max_elems;
+	size_t size;
+};
+
+#define DEFAULT_VECTOR_MEMBERS	8
+#define DEFAULT_VECTOR_GROWTH	8
+
+struct vector *vector_create(size_t size)
+{
+	struct vector *v;
+
+	v = calloc(sizeof(struct vector), 1);
+	if (v == NULL)
+		return NULL;
+
+	v->size = size;
+	v->cur_elems = 0;
+	v->max_elems = DEFAULT_VECTOR_MEMBERS;
+
+	v->data = calloc(size * DEFAULT_VECTOR_MEMBERS, 1);
+	if (v->data == NULL) {
+		free(v);
+		return NULL;
+	}
+
+	return v;
+}
+
+void vector_destroy(struct vector *v)
+{
+	free(v->data);
+	free(v);
+}
+
+int vector_add(struct vector *v, void *data)
+{
+	if (v->cur_elems >= v->max_elems) {
+		v->max_elems += DEFAULT_VECTOR_GROWTH;
+		v->data = realloc(v->data, v->max_elems * v->size);
+		if (v->data == NULL) {
+			v->max_elems -= DEFAULT_VECTOR_GROWTH;
+			return -1;
+		}
+	}
+	memcpy(v->data + (v->size * v->cur_elems), data, v->size);
+	v->cur_elems++;
+	return 0;
+}
+
+int vector_iterate(struct vector *v,
+		   const void *data,
+		   int (*fcn)(const void *a, const void *b))
+{
+	unsigned int i;
+
+	for (i=0; i<v->cur_elems; i++) {
+		char *ptr = v->data + (v->size * i);
+		if (fcn(ptr, data))
+			return 1;
+	}
+	return 0;
+}



More information about the netfilter-cvslog mailing list