summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
author/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org>2008-02-02 04:35:05 +0000
committer/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org </C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org>2008-02-02 04:35:05 +0000
commit6f7bc84fb819e87a9145394b0e08fd194b1497da (patch)
tree01148959534277e1135231e08676c822f709c3df /src
parentc66ed8fdb8b64fcb8973f6b60a9696b59ba29ee6 (diff)
downloadconntrack-tools-6f7bc84fb819e87a9145394b0e08fd194b1497da.tar.gz
conntrack-tools-6f7bc84fb819e87a9145394b0e08fd194b1497da.zip
add IPv6 support to conntrackd
Diffstat (limited to 'src')
-rw-r--r--src/cache.c107
-rw-r--r--src/ignore_pool.c65
-rw-r--r--src/mcast.c18
-rw-r--r--src/read_config_yy.y99
-rw-r--r--src/stats-mode.c1
-rw-r--r--src/sync-mode.c2
6 files changed, 189 insertions, 103 deletions
diff --git a/src/cache.c b/src/cache.c
index 2f0e57a..73d539a 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -19,6 +19,7 @@
#include "cache.h"
#include "jhash.h"
#include "hash.h"
+#include "log.h"
#include "us-conntrack.h"
#include "conntrackd.h"
@@ -27,11 +28,9 @@
#include <stdlib.h>
#include <string.h>
-static uint32_t hash(const void *data, struct hashtable *table)
+static uint32_t __hash4(const struct nf_conntrack *ct, struct hashtable *table)
{
unsigned int a, b;
- const struct us_conntrack *u = data;
- struct nf_conntrack *ct = u->ct;
a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC), sizeof(uint32_t),
((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
@@ -51,11 +50,9 @@ static uint32_t hash(const void *data, struct hashtable *table)
return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32;
}
-static uint32_t hash6(const void *data, struct hashtable *table)
+static uint32_t __hash6(const struct nf_conntrack *ct, struct hashtable *table)
{
unsigned int a, b;
- const struct us_conntrack *u = data;
- struct nf_conntrack *ct = u->ct;
a = jhash(nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC), sizeof(uint32_t)*4,
((nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) << 16) |
@@ -68,12 +65,30 @@ static uint32_t hash6(const void *data, struct hashtable *table)
return ((uint64_t)jhash_2words(a, b, 0) * table->hashsize) >> 32;
}
+static uint32_t hash(const void *data, struct hashtable *table)
+{
+ int ret = 0;
+ const struct us_conntrack *u = data;
+
+ switch(nfct_get_attr_u8(u->ct, ATTR_L3PROTO)) {
+ case AF_INET:
+ ret = __hash4(u->ct, table);
+ break;
+ case AF_INET6:
+ ret = __hash6(u->ct, table);
+ break;
+ default:
+ dlog(LOG_ERR, "unknown layer 3 proto in hash");
+ break;
+ }
+
+ return ret;
+}
+
static int __compare(const struct nf_conntrack *ct1,
const struct nf_conntrack *ct2)
{
- return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L3PROTO) ==
- nfct_get_attr_u8(ct2, ATTR_ORIG_L3PROTO)) &&
- (nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) ==
+ return ((nfct_get_attr_u8(ct1, ATTR_ORIG_L4PROTO) ==
nfct_get_attr_u8(ct2, ATTR_ORIG_L4PROTO)) &&
(nfct_get_attr_u16(ct1, ATTR_ORIG_PORT_SRC) ==
nfct_get_attr_u16(ct2, ATTR_ORIG_PORT_SRC)) &&
@@ -85,11 +100,9 @@ static int __compare(const struct nf_conntrack *ct1,
nfct_get_attr_u16(ct2, ATTR_REPL_PORT_DST)));
}
-static int compare(const void *data1, const void *data2)
+static int
+__compare4(const struct us_conntrack *u1, const struct us_conntrack *u2)
{
- const struct us_conntrack *u1 = data1;
- const struct us_conntrack *u2 = data2;
-
return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_SRC) ==
nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV4_SRC)) &&
(nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV4_DST) ==
@@ -101,20 +114,46 @@ static int compare(const void *data1, const void *data2)
__compare(u1->ct, u2->ct));
}
-static int compare6(const void *data1, const void *data2)
+static int
+__compare6(const struct us_conntrack *u1, const struct us_conntrack *u2)
{
+ return ((memcmp(nfct_get_attr(u1->ct, ATTR_ORIG_IPV6_SRC),
+ nfct_get_attr(u2->ct, ATTR_ORIG_IPV6_SRC),
+ sizeof(uint32_t)*4) == 0) &&
+ (memcmp(nfct_get_attr(u1->ct, ATTR_ORIG_IPV6_DST),
+ nfct_get_attr(u2->ct, ATTR_ORIG_IPV6_DST),
+ sizeof(uint32_t)*4) == 0) &&
+ (memcmp(nfct_get_attr(u1->ct, ATTR_REPL_IPV6_SRC),
+ nfct_get_attr(u2->ct, ATTR_REPL_IPV6_SRC),
+ sizeof(uint32_t)*4) == 0) &&
+ (memcmp(nfct_get_attr(u1->ct, ATTR_REPL_IPV6_DST),
+ nfct_get_attr(u2->ct, ATTR_REPL_IPV6_DST),
+ sizeof(uint32_t)*4) == 0) &&
+ __compare(u1->ct, u2->ct));
+}
+
+static int compare(const void *data1, const void *data2)
+{
+ int ret = 0;
const struct us_conntrack *u1 = data1;
const struct us_conntrack *u2 = data2;
- return ((nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_SRC) ==
- nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_SRC)) &&
- (nfct_get_attr_u32(u1->ct, ATTR_ORIG_IPV6_DST) ==
- nfct_get_attr_u32(u2->ct, ATTR_ORIG_IPV6_DST)) &&
- (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_SRC) ==
- nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_SRC)) &&
- (nfct_get_attr_u32(u1->ct, ATTR_REPL_IPV6_DST) ==
- nfct_get_attr_u32(u2->ct, ATTR_REPL_IPV6_DST)) &&
- __compare(u1->ct, u2->ct));
+ if (nfct_get_attr_u8(u1->ct, ATTR_L3PROTO) !=
+ nfct_get_attr_u8(u2->ct, ATTR_L3PROTO))
+ return ret;
+
+ switch(nfct_get_attr_u8(u1->ct, ATTR_L3PROTO)) {
+ case AF_INET:
+ ret = __compare4(u1, u2);
+ break;
+ case AF_INET6:
+ ret = __compare6(u1, u2);
+ break;
+ default:
+ dlog(LOG_ERR, "unknown layer 3 in compare");
+ break;
+ }
+ return ret;
}
struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = {
@@ -125,7 +164,6 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = {
struct cache *cache_create(const char *name,
unsigned int features,
- uint8_t proto,
struct cache_extra *extra)
{
size_t size = sizeof(struct us_conntrack);
@@ -175,22 +213,11 @@ struct cache *cache_create(const char *name,
}
memcpy(c->feature_offset, feature_offset, sizeof(unsigned int) * j);
- switch(proto) {
- case AF_INET:
- c->h = hashtable_create(CONFIG(hashsize),
- CONFIG(limit),
- size,
- hash,
- compare);
- break;
- case AF_INET6:
- c->h = hashtable_create(CONFIG(hashsize),
- CONFIG(limit),
- size,
- hash6,
- compare6);
- break;
- }
+ c->h = hashtable_create(CONFIG(hashsize),
+ CONFIG(limit),
+ size,
+ hash,
+ compare);
if (!c->h) {
free(c->features);
diff --git a/src/ignore_pool.c b/src/ignore_pool.c
index 2d898d1..027d628 100644
--- a/src/ignore_pool.c
+++ b/src/ignore_pool.c
@@ -26,7 +26,7 @@
#include <stdlib.h>
#include <string.h>
-/* XXX: These should be configurable */
+/* XXX: These should be configurable, better use a rb-tree */
#define IGNORE_POOL_SIZE 128
#define IGNORE_POOL_LIMIT INT_MAX
@@ -55,7 +55,7 @@ static int compare6(const void *data1, const void *data2)
return memcmp(data1, data2, sizeof(uint32_t)*4) == 0;
}
-struct ignore_pool *ignore_pool_create(uint8_t proto)
+struct ignore_pool *ignore_pool_create(void)
{
struct ignore_pool *ip;
@@ -64,24 +64,23 @@ struct ignore_pool *ignore_pool_create(uint8_t proto)
return NULL;
memset(ip, 0, sizeof(struct ignore_pool));
- switch(proto) {
- case AF_INET:
- ip->h = hashtable_create(IGNORE_POOL_SIZE,
- IGNORE_POOL_LIMIT,
- sizeof(uint32_t),
- hash,
- compare);
- break;
- case AF_INET6:
- ip->h = hashtable_create(IGNORE_POOL_SIZE,
- IGNORE_POOL_LIMIT,
- sizeof(uint32_t)*4,
- hash6,
- compare6);
- break;
+ ip->h = hashtable_create(IGNORE_POOL_SIZE,
+ IGNORE_POOL_LIMIT,
+ sizeof(uint32_t),
+ hash,
+ compare);
+ if (!ip->h) {
+ free(ip);
+ return NULL;
}
- if (!ip->h) {
+ ip->h6 = hashtable_create(IGNORE_POOL_SIZE,
+ IGNORE_POOL_LIMIT,
+ sizeof(uint32_t)*4,
+ hash6,
+ compare6);
+ if (!ip->h6) {
+ free(ip->h);
free(ip);
return NULL;
}
@@ -92,20 +91,31 @@ struct ignore_pool *ignore_pool_create(uint8_t proto)
void ignore_pool_destroy(struct ignore_pool *ip)
{
hashtable_destroy(ip->h);
+ hashtable_destroy(ip->h6);
free(ip);
}
-int ignore_pool_add(struct ignore_pool *ip, void *data)
+int ignore_pool_add(struct ignore_pool *ip, void *data, uint8_t family)
{
- if (!hashtable_add(ip->h, data))
- return 0;
-
+ switch(family) {
+ case AF_INET:
+ if (!hashtable_add(ip->h, data))
+ return 0;
+ break;
+ case AF_INET6:
+ if (!hashtable_add(ip->h6, data))
+ return 0;
+ break;
+ }
return 1;
}
static int
__ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct)
{
+ if (!ip->h)
+ return 0;
+
return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_SRC)) ||
hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV4_DST)) ||
hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV4_SRC)) ||
@@ -115,10 +125,13 @@ __ignore_pool_test_ipv4(struct ignore_pool *ip, struct nf_conntrack *ct)
static int
__ignore_pool_test_ipv6(struct ignore_pool *ip, struct nf_conntrack *ct)
{
- return (hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) ||
- hashtable_test(ip->h, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) ||
- hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) ||
- hashtable_test(ip->h, nfct_get_attr(ct, ATTR_REPL_IPV6_DST)));
+ if (!ip->h6)
+ return 0;
+
+ return (hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_SRC)) ||
+ hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_ORIG_IPV6_DST)) ||
+ hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_SRC)) ||
+ hashtable_test(ip->h6, nfct_get_attr(ct, ATTR_REPL_IPV6_DST)));
}
int ignore_pool_test(struct ignore_pool *ip, struct nf_conntrack *ct)
diff --git a/src/mcast.c b/src/mcast.c
index 8307f26..f945511 100644
--- a/src/mcast.c
+++ b/src/mcast.c
@@ -51,17 +51,20 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf)
m->addr.ipv4.sin_family = AF_INET;
m->addr.ipv4.sin_port = htons(conf->port);
m->addr.ipv4.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ m->sockaddr_len = sizeof(struct sockaddr_in);
break;
case AF_INET6:
memcpy(&mreq.ipv6.ipv6mr_multiaddr, &conf->in.inet_addr6,
sizeof(uint32_t) * 4);
- memcpy(&mreq.ipv6.ipv6mr_interface, &conf->ifa.interface_addr6,
- sizeof(uint32_t) * 4);
+ mreq.ipv6.ipv6mr_interface = conf->ifa.interface_index6;
m->addr.ipv6.sin6_family = AF_INET6;
m->addr.ipv6.sin6_port = htons(conf->port);
m->addr.ipv6.sin6_addr = in6addr_any;
+
+ m->sockaddr_len = sizeof(struct sockaddr_in6);
break;
}
@@ -93,8 +96,7 @@ struct mcast_sock *mcast_server_create(struct mcast_conf *conf)
return NULL;
}
- if (bind(m->fd, (struct sockaddr *) &m->addr,
- sizeof(struct sockaddr)) == -1) {
+ if (bind(m->fd, (struct sockaddr *) &m->addr, m->sockaddr_len) == -1) {
debug("mcast_sock_server_create:bind");
close(m->fd);
free(m);
@@ -139,6 +141,7 @@ __mcast_client_create_ipv4(struct mcast_sock *m, struct mcast_conf *conf)
m->addr.ipv4.sin_family = AF_INET;
m->addr.ipv4.sin_port = htons(conf->port);
m->addr.ipv4.sin_addr = conf->in.inet_addr;
+ m->sockaddr_len = sizeof(struct sockaddr_in);
if (setsockopt(m->fd, IPPROTO_IP, IP_MULTICAST_LOOP, &no,
sizeof(int)) < 0) {
@@ -168,6 +171,7 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf)
memcpy(&m->addr.ipv6.sin6_addr,
&conf->in.inet_addr6,
sizeof(struct in6_addr));
+ m->sockaddr_len = sizeof(struct sockaddr_in6);
if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &no,
sizeof(int)) < 0) {
@@ -177,8 +181,8 @@ __mcast_client_create_ipv6(struct mcast_sock *m, struct mcast_conf *conf)
}
if (setsockopt(m->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
- &conf->ifa.interface_addr,
- sizeof(struct in_addr)) == -1) {
+ &conf->ifa.interface_index6,
+ sizeof(unsigned int)) == -1) {
debug("mcast_sock_client_create:setsockopt3");
close(m->fd);
return -1;
@@ -247,7 +251,7 @@ ssize_t mcast_send(struct mcast_sock *m, void *data, int size)
size,
0,
(struct sockaddr *) &m->addr,
- sizeof(struct sockaddr));
+ m->sockaddr_len);
if (ret == -1) {
debug("mcast_sock_send");
m->stats.error++;
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
index 0ba5331..86fee9b 100644
--- a/src/read_config_yy.y
+++ b/src/read_config_yy.y
@@ -177,37 +177,63 @@ ignore_traffic_options :
ignore_traffic_option : T_IPV4_ADDR T_IP
{
union inet_address ip;
- int family = 0;
memset(&ip, 0, sizeof(union inet_address));
- if (inet_aton($2, &ip.ipv4))
- family = AF_INET;
-#ifdef HAVE_INET_PTON_IPV6
- else if (inet_pton(AF_INET6, $2, &ip.ipv6) > 0)
- family = AF_INET6;
-#endif
+ if (!inet_aton($2, &ip.ipv4)) {
+ fprintf(stderr, "%s is not a valid IPv4, ignoring", $2);
+ break;
+ }
+
+ if (!STATE(ignore_pool)) {
+ STATE(ignore_pool) = ignore_pool_create();
+ if (!STATE(ignore_pool)) {
+ fprintf(stderr, "Can't create ignore pool!\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ if (!ignore_pool_add(STATE(ignore_pool), &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 (!family) {
- fprintf(stderr, "%s is not a valid IP, ignoring", $2);
+ignore_traffic_option : T_IPV6_ADDR T_IP
+{
+ union inet_address ip;
+
+ memset(&ip, 0, sizeof(union inet_address));
+
+#ifdef HAVE_INET_PTON_IPV6
+ if (inet_pton(AF_INET6, $2, &ip.ipv6) <= 0) {
+ fprintf(stderr, "%s is not a valid IPv6, ignoring", $2);
break;
}
+#else
+ fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!");
+ break;
+#endif
if (!STATE(ignore_pool)) {
- STATE(ignore_pool) = ignore_pool_create(family);
+ STATE(ignore_pool) = ignore_pool_create();
if (!STATE(ignore_pool)) {
fprintf(stderr, "Can't create ignore pool!\n");
exit(EXIT_FAILURE);
}
}
- if (!ignore_pool_add(STATE(ignore_pool), &ip)) {
+ if (!ignore_pool_add(STATE(ignore_pool), &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");
}
+
};
multicast_line : T_MULTICAST '{' multicast_options '}';
@@ -235,8 +261,13 @@ multicast_option : T_IPV4_ADDR T_IP
multicast_option : T_IPV6_ADDR T_IP
{
#ifdef HAVE_INET_PTON_IPV6
- if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0)
+ if (inet_pton(AF_INET6, $2, &conf.mcast.in) <= 0) {
fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
+ break;
+ }
+#else
+ fprintf(stderr, "Cannot find inet_pton(), IPv6 unsupported!");
+ break;
#endif
if (conf.mcast.ipproto == AF_INET) {
@@ -247,6 +278,19 @@ multicast_option : T_IPV6_ADDR T_IP
}
conf.mcast.ipproto = AF_INET6;
+
+ if (conf.mcast.iface[0] && !conf.mcast.ifa.interface_index6) {
+ unsigned int idx;
+
+ idx = if_nametoindex($2);
+ if (!idx) {
+ fprintf(stderr, "%s is an invalid interface.\n", $2);
+ break;
+ }
+
+ conf.mcast.ifa.interface_index6 = idx;
+ conf.mcast.ipproto = AF_INET6;
+ }
};
multicast_option : T_IPV4_IFACE T_IP
@@ -268,24 +312,25 @@ multicast_option : T_IPV4_IFACE T_IP
multicast_option : T_IPV6_IFACE T_IP
{
-#ifdef HAVE_INET_PTON_IPV6
- if (inet_pton(AF_INET6, $2, &conf.mcast.ifa) <= 0)
- fprintf(stderr, "%s is not a valid IPv6 address\n", $2);
-#endif
-
- if (conf.mcast.ipproto == AF_INET) {
- fprintf(stderr, "Your multicast interface is IPv6 but "
- "is binded to an IPv4 interface? Surely "
- "this is not what you want\n");
- break;
- }
-
- conf.mcast.ipproto = AF_INET6;
-};
+ fprintf(stderr, "IPv6_interface not required for IPv6, ignoring.\n");
+}
multicast_option : T_IFACE T_STRING
{
strncpy(conf.mcast.iface, $2, IFNAMSIZ);
+
+ if (conf.mcast.ipproto == AF_INET6) {
+ unsigned int idx;
+
+ idx = if_nametoindex($2);
+ if (!idx) {
+ fprintf(stderr, "%s is an invalid interface.\n", $2);
+ break;
+ }
+
+ conf.mcast.ifa.interface_index6 = idx;
+ conf.mcast.ipproto = AF_INET6;
+ }
};
multicast_option : T_BACKLOG T_NUMBER
@@ -690,7 +735,7 @@ init_config(char *filename)
/* create empty pool */
if (!STATE(ignore_pool)) {
- STATE(ignore_pool) = ignore_pool_create(CONFIG(family));
+ STATE(ignore_pool) = ignore_pool_create();
if (!STATE(ignore_pool)) {
fprintf(stderr, "Can't create ignore pool!\n");
exit(EXIT_FAILURE);
diff --git a/src/stats-mode.c b/src/stats-mode.c
index 9e6089c..b6ae2bd 100644
--- a/src/stats-mode.c
+++ b/src/stats-mode.c
@@ -38,7 +38,6 @@ static int init_stats(void)
STATE_STATS(cache) = cache_create("stats",
LIFETIME,
- CONFIG(family),
NULL);
if (!STATE_STATS(cache)) {
dlog(LOG_ERR, "can't allocate memory for the "
diff --git a/src/sync-mode.c b/src/sync-mode.c
index b9fc25c..a81309f 100644
--- a/src/sync-mode.c
+++ b/src/sync-mode.c
@@ -151,7 +151,6 @@ static int init_sync(void)
STATE_SYNC(internal) =
cache_create("internal",
STATE_SYNC(sync)->internal_cache_flags,
- CONFIG(family),
STATE_SYNC(sync)->internal_cache_extra);
if (!STATE_SYNC(internal)) {
@@ -167,7 +166,6 @@ static int init_sync(void)
STATE_SYNC(external) =
cache_create("external",
STATE_SYNC(sync)->external_cache_flags,
- CONFIG(family),
NULL);
if (!STATE_SYNC(external)) {