summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am86
-rw-r--r--src/build.c39
-rw-r--r--src/cache-ct.c21
-rw-r--r--src/cache.c4
-rw-r--r--src/conntrack.c1889
-rw-r--r--src/cthelper.c4
-rw-r--r--src/external_inject.c28
-rw-r--r--src/filter.c2
-rw-r--r--src/hash.c1
-rw-r--r--src/helpers.c3
-rw-r--r--src/helpers/Makefile.am2
-rw-r--r--src/helpers/amanda.c1
-rw-r--r--src/helpers/dhcpv6.c1
-rw-r--r--src/helpers/ftp.c33
-rw-r--r--src/helpers/rpc.c14
-rw-r--r--src/helpers/sane.c11
-rw-r--r--src/helpers/slp.c1
-rw-r--r--src/helpers/ssdp.c10
-rw-r--r--src/helpers/tftp.c1
-rw-r--r--src/helpers/tns.c8
-rw-r--r--src/main.c7
-rw-r--r--src/network.c2
-rw-r--r--src/nfct-extensions/helper.c184
-rw-r--r--src/parse.c25
-rw-r--r--src/process.c2
-rw-r--r--src/queue.c4
-rw-r--r--src/read_config_lex.l12
-rw-r--r--src/read_config_yy.y309
-rw-r--r--src/run.c2
-rw-r--r--src/vector.c7
30 files changed, 1912 insertions, 801 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 2e66ee9..352aa37 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -6,12 +6,23 @@ endif
AM_YFLAGS = -d
-CLEANFILES = read_config_yy.c read_config_lex.c
+BUILT_SOURCES = read_config_yy.h
sbin_PROGRAMS = conntrack conntrackd nfct
conntrack_SOURCES = conntrack.c
-conntrack_LDADD = ../extensions/libct_proto_tcp.la ../extensions/libct_proto_udp.la ../extensions/libct_proto_udplite.la ../extensions/libct_proto_icmp.la ../extensions/libct_proto_icmpv6.la ../extensions/libct_proto_sctp.la ../extensions/libct_proto_dccp.la ../extensions/libct_proto_gre.la ../extensions/libct_proto_unknown.la ${LIBNETFILTER_CONNTRACK_LIBS} ${LIBMNL_LIBS} ${LIBNFNETLINK_LIBS}
+conntrack_LDADD = ../extensions/libct_proto_dccp.la \
+ ../extensions/libct_proto_gre.la \
+ ../extensions/libct_proto_icmp.la \
+ ../extensions/libct_proto_icmpv6.la \
+ ../extensions/libct_proto_sctp.la \
+ ../extensions/libct_proto_tcp.la \
+ ../extensions/libct_proto_udp.la \
+ ../extensions/libct_proto_udplite.la \
+ ../extensions/libct_proto_unknown.la \
+ ${LIBMNL_LIBS} \
+ ${LIBNETFILTER_CONNTRACK_LIBS} \
+ ${LIBNFNETLINK_LIBS}
nfct_SOURCES = nfct.c
@@ -35,24 +46,54 @@ if HAVE_CTHELPER
nfct_LDADD += ${LIBNETFILTER_CTHELPER_LIBS}
endif
-nfct_LDFLAGS = -export-dynamic ${LAZY_LDFLAGS}
-
-conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c queue_tx.c rbtree.c \
- local.c log.c mcast.c udp.c netlink.c vector.c \
- filter.c fds.c event.c process.c origin.c date.c \
- cache.c cache-ct.c cache-exp.c \
- cache_timer.c \
- ctnl.c \
- sync-mode.c sync-alarm.c sync-ftfw.c sync-notrack.c \
- traffic_stats.c stats-mode.c \
- network.c cidr.c \
- build.c parse.c \
- channel.c multichannel.c channel_mcast.c channel_udp.c \
- tcp.c channel_tcp.c \
- external_cache.c external_inject.c \
- internal_cache.c internal_bypass.c \
- read_config_yy.y read_config_lex.l \
- stack.c resync.c
+conntrackd_SOURCES = alarm.c \
+ build.c \
+ cache.c \
+ cache-ct.c \
+ cache-exp.c \
+ cache_timer.c \
+ channel.c \
+ channel_mcast.c \
+ channel_tcp.c \
+ channel_udp.c \
+ cidr.c \
+ ctnl.c \
+ date.c \
+ event.c \
+ external_cache.c \
+ external_inject.c \
+ fds.c \
+ filter.c \
+ hash.c \
+ internal_bypass.c \
+ internal_cache.c \
+ local.c \
+ log.c \
+ main.c \
+ mcast.c \
+ multichannel.c \
+ netlink.c \
+ network.c \
+ origin.c \
+ parse.c \
+ process.c \
+ queue.c \
+ queue_tx.c \
+ rbtree.c \
+ read_config_lex.l \
+ read_config_yy.y \
+ resync.c \
+ run.c \
+ stack.c \
+ stats-mode.c \
+ sync-alarm.c \
+ sync-ftfw.c \
+ sync-mode.c \
+ sync-notrack.c \
+ tcp.c \
+ traffic_stats.c \
+ udp.c \
+ vector.c
if HAVE_CTHELPER
conntrackd_SOURCES += cthelper.c helpers.c utils.c expect.c
@@ -62,9 +103,6 @@ if HAVE_SYSTEMD
conntrackd_SOURCES += systemd.c
endif
-# yacc and lex generate dirty code
-read_config_yy.o read_config_lex.o: AM_CFLAGS += -Wno-missing-prototypes -Wno-missing-declarations -Wno-implicit-function-declaration -Wno-nested-externs -Wno-undef -Wno-redundant-decls -Wno-sign-compare
-
conntrackd_LDADD = ${LIBMNL_LIBS} ${LIBNETFILTER_CONNTRACK_LIBS} \
${libdl_LIBS} ${LIBNFNETLINK_LIBS}
@@ -77,5 +115,3 @@ conntrackd_LDADD += ${LIBSYSTEMD_LIBS}
endif
conntrackd_LDFLAGS = -export-dynamic
-
-EXTRA_DIST = read_config_yy.h
diff --git a/src/build.c b/src/build.c
index 99ff230..c07974f 100644
--- a/src/build.c
+++ b/src/build.c
@@ -66,7 +66,14 @@ ct_build_u32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b)
}
static inline void
-ct_build_u128(const struct nf_conntrack *ct, int a, struct nethdr *n, int b)
+ct_build_be32(const struct nf_conntrack *ct, int a, struct nethdr *n, int b)
+{
+ uint32_t data = nfct_get_attr_u32(ct, a);
+ addattr(n, b, &data, sizeof(uint32_t));
+}
+
+static inline void
+ct_build_be128(const struct nf_conntrack *ct, int a, struct nethdr *n, int b)
{
const char *data = nfct_get_attr(ct, a);
addattr(n, b, data, sizeof(uint32_t) * 4);
@@ -126,11 +133,12 @@ static enum nf_conntrack_attr nat_type[] =
/* ICMP, UDP and TCP are always loaded with nf_conntrack_ipv4 */
static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n)
{
+ ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
+ sizeof(struct nfct_attr_grp_port));
+
if (!nfct_attr_is_set(ct, ATTR_TCP_STATE))
return;
- ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
- sizeof(struct nfct_attr_grp_port));
ct_build_u8(ct, ATTR_TCP_STATE, n, NTA_TCP_STATE);
if (CONFIG(sync).tcp_window_tracking) {
ct_build_u8(ct, ATTR_TCP_WSCALE_ORIG, n, NTA_TCP_WSCALE_ORIG);
@@ -140,12 +148,13 @@ static void build_l4proto_tcp(const struct nf_conntrack *ct, struct nethdr *n)
static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n)
{
+ ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
+ sizeof(struct nfct_attr_grp_port));
+
/* SCTP is optional, make sure nf_conntrack_sctp is loaded */
if (!nfct_attr_is_set(ct, ATTR_SCTP_STATE))
return;
- ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
- sizeof(struct nfct_attr_grp_port));
ct_build_u8(ct, ATTR_SCTP_STATE, n, NTA_SCTP_STATE);
ct_build_u32(ct, ATTR_SCTP_VTAG_ORIG, n, NTA_SCTP_VTAG_ORIG);
ct_build_u32(ct, ATTR_SCTP_VTAG_REPL, n, NTA_SCTP_VTAG_REPL);
@@ -153,12 +162,13 @@ static void build_l4proto_sctp(const struct nf_conntrack *ct, struct nethdr *n)
static void build_l4proto_dccp(const struct nf_conntrack *ct, struct nethdr *n)
{
+ ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
+ sizeof(struct nfct_attr_grp_port));
+
/* DCCP is optional, make sure nf_conntrack_dccp is loaded */
if (!nfct_attr_is_set(ct, ATTR_DCCP_STATE))
return;
- ct_build_group(ct, ATTR_GRP_ORIG_PORT, n, NTA_PORT,
- sizeof(struct nfct_attr_grp_port));
ct_build_u8(ct, ATTR_DCCP_STATE, n, NTA_DCCP_STATE);
ct_build_u8(ct, ATTR_DCCP_ROLE, n, NTA_DCCP_ROLE);
}
@@ -279,18 +289,18 @@ void ct2msg(const struct nf_conntrack *ct, struct nethdr *n)
switch (nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO)) {
case AF_INET:
if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT))
- ct_build_u32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4);
+ ct_build_be32(ct, ATTR_REPL_IPV4_DST, n, NTA_SNAT_IPV4);
if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT))
- ct_build_u32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4);
+ ct_build_be32(ct, ATTR_REPL_IPV4_SRC, n, NTA_DNAT_IPV4);
break;
case AF_INET6:
if (nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT)) {
- ct_build_u128(ct, ATTR_REPL_IPV6_DST, n,
- NTA_SNAT_IPV6);
+ ct_build_be128(ct, ATTR_REPL_IPV6_DST, n,
+ NTA_SNAT_IPV6);
}
if (nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT)) {
- ct_build_u128(ct, ATTR_REPL_IPV6_SRC, n,
- NTA_DNAT_IPV6);
+ ct_build_be128(ct, ATTR_REPL_IPV6_SRC, n,
+ NTA_DNAT_IPV6);
}
break;
default:
@@ -315,6 +325,9 @@ void ct2msg(const struct nf_conntrack *ct, struct nethdr *n)
nfct_attr_is_set(ct, ATTR_SYNPROXY_ITS) &&
nfct_attr_is_set(ct, ATTR_SYNPROXY_TSOFF))
ct_build_synproxy(ct, n);
+
+ if (nfct_attr_is_set(ct, ATTR_ZONE))
+ ct_build_u16(ct, ATTR_ZONE, n, NTA_ZONE);
}
static void
diff --git a/src/cache-ct.c b/src/cache-ct.c
index abcfde4..f56e450 100644
--- a/src/cache-ct.c
+++ b/src/cache-ct.c
@@ -34,13 +34,14 @@
static uint32_t
cache_hash4_ct(const struct nf_conntrack *ct, const struct hashtable *table)
{
- uint32_t a[4] = {
+ uint32_t a[5] = {
[0] = nfct_get_attr_u32(ct, ATTR_IPV4_SRC),
[1] = nfct_get_attr_u32(ct, ATTR_IPV4_DST),
[2] = nfct_get_attr_u8(ct, ATTR_L3PROTO) << 16 |
nfct_get_attr_u8(ct, ATTR_L4PROTO),
[3] = nfct_get_attr_u16(ct, ATTR_PORT_SRC) << 16 |
nfct_get_attr_u16(ct, ATTR_PORT_DST),
+ [4] = nfct_get_attr_u16(ct, ATTR_ZONE),
};
/*
@@ -50,13 +51,13 @@ cache_hash4_ct(const struct nf_conntrack *ct, const struct hashtable *table)
* but using a multiply, less expensive than a divide. See:
* http://www.mail-archive.com/netdev@vger.kernel.org/msg56623.html
*/
- return ((uint64_t)jhash2(a, 4, 0) * table->hashsize) >> 32;
+ return ((uint64_t)jhash2(a, 5, 0) * table->hashsize) >> 32;
}
static uint32_t
cache_hash6_ct(const struct nf_conntrack *ct, const struct hashtable *table)
{
- uint32_t a[10];
+ uint32_t a[11];
memcpy(&a[0], nfct_get_attr(ct, ATTR_IPV6_SRC), sizeof(uint32_t)*4);
memcpy(&a[4], nfct_get_attr(ct, ATTR_IPV6_DST), sizeof(uint32_t)*4);
@@ -64,8 +65,9 @@ cache_hash6_ct(const struct nf_conntrack *ct, const struct hashtable *table)
nfct_get_attr_u8(ct, ATTR_ORIG_L4PROTO);
a[9] = nfct_get_attr_u16(ct, ATTR_ORIG_PORT_SRC) << 16 |
nfct_get_attr_u16(ct, ATTR_ORIG_PORT_DST);
+ a[10] = nfct_get_attr_u16(ct, ATTR_ZONE);
- return ((uint64_t)jhash2(a, 10, 0) * table->hashsize) >> 32;
+ return ((uint64_t)jhash2(a, 11, 0) * table->hashsize) >> 32;
}
static uint32_t
@@ -88,21 +90,12 @@ cache_ct_hash(const void *data, const struct hashtable *table)
return ret;
}
-/* master conntrack of expectations have no ID */
-static inline int
-cache_ct_cmp_id(const struct nf_conntrack *ct1, const struct nf_conntrack *ct2)
-{
- return nfct_attr_is_set(ct2, ATTR_ID) ?
- nfct_get_attr_u32(ct1, ATTR_ID) == nfct_get_attr_u32(ct2, ATTR_ID) : 1;
-}
-
static int cache_ct_cmp(const void *data1, const void *data2)
{
const struct cache_object *obj = data1;
const struct nf_conntrack *ct = data2;
- return nfct_cmp(obj->ptr, ct, NFCT_CMP_ORIG) &&
- cache_ct_cmp_id(obj->ptr, ct);
+ return nfct_cmp(obj->ptr, ct, NFCT_CMP_ORIG);
}
static void *cache_ct_alloc(void)
diff --git a/src/cache.c b/src/cache.c
index 79a024f..9bc8d0f 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -69,12 +69,12 @@ struct cache *cache_create(const char *name, enum cache_type type,
memcpy(c->feature_type, feature_type, sizeof(feature_type));
- c->features = malloc(sizeof(struct cache_feature) * j);
+ c->features = malloc(sizeof(struct cache_feature *) * j);
if (!c->features) {
free(c);
return NULL;
}
- memcpy(c->features, feature_array, sizeof(struct cache_feature) * j);
+ memcpy(c->features, feature_array, sizeof(struct cache_feature *) * j);
c->num_features = j;
c->extra_offset = size;
diff --git a/src/conntrack.c b/src/conntrack.c
index fb4e5be..0d71352 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -41,6 +41,7 @@
#include "conntrack.h"
#include <stdio.h>
+#include <assert.h>
#include <getopt.h>
#include <stdlib.h>
#include <ctype.h>
@@ -53,6 +54,8 @@
#include <sys/socket.h>
#include <sys/time.h>
#include <time.h>
+#include <inttypes.h>
+#include <dirent.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
@@ -65,10 +68,14 @@
#include <linux/netfilter/nf_conntrack_common.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
-static struct nfct_mnl_socket {
+struct nfct_mnl_socket {
struct mnl_socket *mnl;
uint32_t portid;
-} sock;
+};
+
+static struct nfct_mnl_socket _sock;
+static struct nfct_mnl_socket _modifier_sock;
+static struct nfct_mnl_socket _event_sock;
struct u32_mask {
uint32_t value;
@@ -76,7 +83,7 @@ struct u32_mask {
};
/* These are the template objects that are used to send commands. */
-static struct {
+struct ct_tmpl {
struct nf_conntrack *ct;
struct nf_expect *exp;
/* Expectations require the expectation tuple and the mask. */
@@ -89,104 +96,65 @@ static struct {
struct nfct_filter_dump_mark filter_mark_kernel;
bool filter_mark_kernel_set;
+ /* Allow to filter by status from kernel-space. */
+ struct nfct_filter_dump_mark filter_status_kernel;
+ bool filter_status_kernel_set;
+
/* Allows filtering by ctlabels */
struct nfct_bitmask *label;
/* Allows setting/removing specific ctlabels */
struct nfct_bitmask *label_modify;
-} tmpl;
+};
-static int alloc_tmpl_objects(void)
+static struct ct_tmpl *cur_tmpl;
+
+struct ct_cmd {
+ struct list_head list;
+ unsigned int command;
+ unsigned int cmd;
+ unsigned int type;
+ unsigned int event_mask;
+ int options;
+ int family;
+ int protonum;
+ size_t socketbuffersize;
+ struct ct_tmpl tmpl;
+};
+
+static int alloc_tmpl_objects(struct ct_tmpl *tmpl)
{
- tmpl.ct = nfct_new();
- tmpl.exptuple = nfct_new();
- tmpl.mask = nfct_new();
- tmpl.exp = nfexp_new();
+ tmpl->ct = nfct_new();
+ tmpl->exptuple = nfct_new();
+ tmpl->mask = nfct_new();
+ tmpl->exp = nfexp_new();
- memset(&tmpl.mark, 0, sizeof(tmpl.mark));
+ memset(&tmpl->mark, 0, sizeof(tmpl->mark));
- return tmpl.ct != NULL && tmpl.exptuple != NULL &&
- tmpl.mask != NULL && tmpl.exp != NULL;
+ cur_tmpl = tmpl;
+
+ return tmpl->ct != NULL && tmpl->exptuple != NULL &&
+ tmpl->mask != NULL && tmpl->exp != NULL;
}
-static void free_tmpl_objects(void)
+static void free_tmpl_objects(struct ct_tmpl *tmpl)
{
- if (tmpl.ct)
- nfct_destroy(tmpl.ct);
- if (tmpl.exptuple)
- nfct_destroy(tmpl.exptuple);
- if (tmpl.mask)
- nfct_destroy(tmpl.mask);
- if (tmpl.exp)
- nfexp_destroy(tmpl.exp);
- if (tmpl.label)
- nfct_bitmask_destroy(tmpl.label);
- if (tmpl.label_modify)
- nfct_bitmask_destroy(tmpl.label_modify);
+ if (!tmpl)
+ return;
+ if (tmpl->ct)
+ nfct_destroy(tmpl->ct);
+ if (tmpl->exptuple)
+ nfct_destroy(tmpl->exptuple);
+ if (tmpl->mask)
+ nfct_destroy(tmpl->mask);
+ if (tmpl->exp)
+ nfexp_destroy(tmpl->exp);
+ if (tmpl->label)
+ nfct_bitmask_destroy(tmpl->label);
+ if (tmpl->label_modify)
+ nfct_bitmask_destroy(tmpl->label_modify);
}
-enum ct_command {
- CT_NONE = 0,
-
- CT_LIST_BIT = 0,
- CT_LIST = (1 << CT_LIST_BIT),
-
- CT_CREATE_BIT = 1,
- CT_CREATE = (1 << CT_CREATE_BIT),
-
- CT_UPDATE_BIT = 2,
- CT_UPDATE = (1 << CT_UPDATE_BIT),
-
- CT_DELETE_BIT = 3,
- CT_DELETE = (1 << CT_DELETE_BIT),
-
- CT_GET_BIT = 4,
- CT_GET = (1 << CT_GET_BIT),
-
- CT_FLUSH_BIT = 5,
- CT_FLUSH = (1 << CT_FLUSH_BIT),
-
- CT_EVENT_BIT = 6,
- CT_EVENT = (1 << CT_EVENT_BIT),
-
- CT_VERSION_BIT = 7,
- CT_VERSION = (1 << CT_VERSION_BIT),
-
- CT_HELP_BIT = 8,
- CT_HELP = (1 << CT_HELP_BIT),
-
- EXP_LIST_BIT = 9,
- EXP_LIST = (1 << EXP_LIST_BIT),
-
- EXP_CREATE_BIT = 10,
- EXP_CREATE = (1 << EXP_CREATE_BIT),
-
- EXP_DELETE_BIT = 11,
- EXP_DELETE = (1 << EXP_DELETE_BIT),
-
- EXP_GET_BIT = 12,
- EXP_GET = (1 << EXP_GET_BIT),
-
- EXP_FLUSH_BIT = 13,
- EXP_FLUSH = (1 << EXP_FLUSH_BIT),
-
- EXP_EVENT_BIT = 14,
- EXP_EVENT = (1 << EXP_EVENT_BIT),
-
- CT_COUNT_BIT = 15,
- CT_COUNT = (1 << CT_COUNT_BIT),
-
- EXP_COUNT_BIT = 16,
- EXP_COUNT = (1 << EXP_COUNT_BIT),
-
- CT_STATS_BIT = 17,
- CT_STATS = (1 << CT_STATS_BIT),
-
- EXP_STATS_BIT = 18,
- EXP_STATS = (1 << EXP_STATS_BIT),
-};
-/* If you add a new command, you have to update NUMBER_OF_CMD in conntrack.h */
-
enum ct_options {
CT_OPT_ORIG_SRC_BIT = 0,
CT_OPT_ORIG_SRC = (1 << CT_OPT_ORIG_SRC_BIT),
@@ -325,6 +293,7 @@ static const char *optflags[NUMBER_OF_OPT] = {
static struct option original_opts[] = {
{"dump", 2, 0, 'L'},
{"create", 2, 0, 'I'},
+ {"add", 2, 0, 'A'},
{"delete", 2, 0, 'D'},
{"update", 2, 0, 'U'},
{"get", 2, 0, 'G'},
@@ -368,7 +337,7 @@ static struct option original_opts[] = {
{0, 0, 0, 0}
};
-static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:"
+static const char *getopt_str = ":L::I::U::D::G::E::F::A::hVs:d:r:q:"
"p:t:u:e:a:z[:]:{:}:m:i:f:o:n::"
"g::c:b:C::Sj::w:l:<:>::(:):";
@@ -385,26 +354,27 @@ static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:"
static char commands_v_options[NUMBER_OF_CMD][NUMBER_OF_OPT] =
/* Well, it's better than "Re: Linux vs FreeBSD" */
{
- /* s d r q p t u z e [ ] { } a m i f n g o c b j w l < > ( ) */
-/*CT_LIST*/ {2,2,2,2,2,0,2,2,0,0,0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,0,0,2,2},
-/*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
-/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0},
-/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,0,2,2},
-/*CT_GET*/ {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0,0,0},
-/*CT_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,2,2,0,2,0,0,2,2,2,2,2,2,2,2,0,0,2,2},
-/*VERSION*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*HELP*/ {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0},
-/*EXP_CREATE*/{1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_DELETE*/{1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_GET*/ {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_EVENT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0},
-/*CT_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_COUNT*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*CT_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
-/*EXP_STATS*/ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ /* s d r q p t u z e [ ] { } a m i f n g o c b j w l < > ( ) */
+ [CT_LIST_BIT] = {2,2,2,2,2,0,2,2,0,0,0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,0,0,2,2},
+ [CT_CREATE_BIT] = {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
+ [CT_UPDATE_BIT] = {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0},
+ [CT_DELETE_BIT] = {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,0,2,2},
+ [CT_GET_BIT] = {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0,0,0},
+ [CT_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_EVENT_BIT] = {2,2,2,2,2,0,0,0,2,0,0,2,2,0,2,0,2,2,2,2,2,2,2,2,2,0,0,2,2},
+ [CT_VERSION_BIT]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_HELP_BIT] = {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_LIST_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0},
+ [EXP_CREATE_BIT]= {1,1,2,2,1,1,2,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_DELETE_BIT]= {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_GET_BIT] = {1,1,2,2,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_FLUSH_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_EVENT_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0},
+ [CT_COUNT_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_COUNT_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_STATS_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [EXP_STATS_BIT] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ [CT_ADD_BIT] = {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
};
static const int cmd2type[][2] = {
@@ -418,6 +388,8 @@ static const int cmd2type[][2] = {
['h'] = { CT_HELP, CT_HELP },
['C'] = { CT_COUNT, EXP_COUNT },
['S'] = { CT_STATS, EXP_STATS },
+ ['U'] = { CT_UPDATE, 0 },
+ ['A'] = { CT_ADD, 0 },
};
static const int opt2type[] = {
@@ -521,6 +493,7 @@ static char exit_msg[NUMBER_OF_CMD][64] = {
[CT_EVENT_BIT] = "%d flow events have been shown.\n",
[EXP_LIST_BIT] = "%d expectations have been shown.\n",
[EXP_DELETE_BIT] = "%d expectations have been shown.\n",
+ [CT_ADD_BIT] = "%d flow entries have been added.\n",
};
static const char usage_commands[] =
@@ -565,7 +538,7 @@ static const char usage_parameters[] =
"Common parameters and options:\n"
" -s, --src, --orig-src ip\t\tSource address from original direction\n"
" -d, --dst, --orig-dst ip\t\tDestination address from original direction\n"
- " -r, --reply-src ip\t\tSource addres from reply direction\n"
+ " -r, --reply-src ip\t\tSource address from reply direction\n"
" -q, --reply-dst ip\t\tDestination address from reply direction\n"
" -p, --protonum proto\t\tLayer 4 Protocol, eg. 'tcp'\n"
" -f, --family proto\t\tLayer 3 Protocol, eg. 'ipv6'\n"
@@ -581,7 +554,7 @@ static const char usage_parameters[] =
#define OPTION_OFFSET 256
-static struct nfct_handle *cth, *ith;
+static struct nfct_handle *cth;
static struct option *opts = original_opts;
static unsigned int global_option_offset = 0;
@@ -593,7 +566,6 @@ static unsigned int addr_valid_flags[ADDR_VALID_FLAGS_MAX] = {
static LIST_HEAD(proto_list);
-static unsigned int options;
static struct nfct_labelmap *labelmap;
static int filter_family;
@@ -607,8 +579,276 @@ void register_proto(struct ctproto_handler *h)
list_add(&h->head, &proto_list);
}
+#define BUFFER_SIZE(ret, size, len, offset) do { \
+ if ((int)ret > (int)len) \
+ ret = len; \
+ size += ret; \
+ offset += ret; \
+ len -= ret; \
+} while(0)
+
+static int ct_snprintf_u32_bitmap(char *buf, size_t size,
+ const struct nf_conntrack *ct,
+ const struct ct_print_opts *attr)
+{
+ unsigned int offset = 0, ret, len = size;
+ bool found = false;
+ uint32_t val;
+ int i;
+
+ val = nfct_get_attr_u32(ct, attr->type);
+
+ for (i = 0; i < attr->val_mapping_count; i++) {
+ if (!(val & (1 << i)))
+ continue;
+ if (!attr->val_mapping[i])
+ continue;
+
+ ret = snprintf(buf + offset, len, "%s,", attr->val_mapping[i]);
+ BUFFER_SIZE(ret, size, len, offset);
+ found = true;
+ }
+
+ if (found) {
+ offset--;
+ ret = snprintf(buf + offset, len, " ");
+ BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ return offset;
+}
+
+static int ct_snprintf_attr(char *buf, size_t size,
+ const struct nf_conntrack *ct,
+ const struct ct_print_opts *attr)
+{
+ char ipstr[INET6_ADDRSTRLEN] = {};
+ unsigned int offset = 0;
+ int type = attr->type;
+ int len = size, ret;
+
+ ret = snprintf(buf, len, "%s ", attr->name);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ switch (attr->datatype) {
+ case CT_ATTR_TYPE_U8:
+ if (attr->val_mapping)
+ ret = snprintf(buf + offset, len, "%s ",
+ attr->val_mapping[nfct_get_attr_u8(ct, type)]);
+ else
+ ret = snprintf(buf + offset, len, "%u ",
+ nfct_get_attr_u8(ct, type));
+ break;
+ case CT_ATTR_TYPE_BE16:
+ ret = snprintf(buf + offset, len, "%u ",
+ ntohs(nfct_get_attr_u16(ct, type)));
+ break;
+ case CT_ATTR_TYPE_U16:
+ ret = snprintf(buf + offset, len, "%u ",
+ nfct_get_attr_u16(ct, type));
+ break;
+ case CT_ATTR_TYPE_BE32:
+ ret = snprintf(buf + offset, len, "%u ",
+ ntohl(nfct_get_attr_u32(ct, type)));
+ break;
+ case CT_ATTR_TYPE_U32:
+ ret = snprintf(buf + offset, len, "%u ",
+ nfct_get_attr_u32(ct, type));
+ break;
+ case CT_ATTR_TYPE_U64:
+ ret = snprintf(buf + offset, len, "%lu ",
+ nfct_get_attr_u64(ct, type));
+ break;
+ case CT_ATTR_TYPE_IPV4:
+ inet_ntop(AF_INET, nfct_get_attr(ct, type),
+ ipstr, sizeof(ipstr));
+ ret = snprintf(buf + offset, len, "%s ", ipstr);
+ break;
+ case CT_ATTR_TYPE_IPV6:
+ inet_ntop(AF_INET6, nfct_get_attr(ct, type),
+ ipstr, sizeof(ipstr));
+ ret = snprintf(buf + offset, len, "%s ", ipstr);
+ break;
+ case CT_ATTR_TYPE_U32_BITMAP:
+ ret = ct_snprintf_u32_bitmap(buf + offset, len, ct, attr);
+ if (ret == 0 && type == ATTR_STATUS)
+ ret = snprintf(buf + offset, len, "UNSET ");
+ break;
+ default:
+ /* Unsupported datatype, should not ever happen */
+ ret = 0;
+ break;
+ }
+ BUFFER_SIZE(ret, size, len, offset);
+
+ return offset;
+}
+
+int ct_snprintf_opts(char *buf, unsigned int len, const struct nf_conntrack *ct,
+ const struct ct_print_opts *attrs)
+{
+ unsigned int size = 0, offset = 0, ret;
+ int i;
+
+ for (i = 0; attrs[i].name; ++i) {
+ if (!nfct_attr_is_set(ct, attrs[i].type))
+ continue;
+
+ ret = ct_snprintf_attr(buf + offset, len, ct, &attrs[i]);
+ BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ return offset;
+}
+
+static const struct ct_print_opts attrs_ip_map[] = {
+ [ATTR_ORIG_IPV4_SRC] = { "-s", ATTR_ORIG_IPV4_SRC, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_ORIG_IPV4_DST] = { "-d", ATTR_ORIG_IPV4_DST, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_DNAT_IPV4] = { "-g", ATTR_REPL_IPV4_SRC, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_SNAT_IPV4] = { "-n", ATTR_REPL_IPV4_DST, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_REPL_IPV4_SRC] = { "-r", ATTR_REPL_IPV4_SRC, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_REPL_IPV4_DST] = { "-q", ATTR_REPL_IPV4_DST, CT_ATTR_TYPE_IPV4, 0, 0 },
+ [ATTR_ORIG_IPV6_SRC] = { "-s", ATTR_ORIG_IPV6_SRC, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_ORIG_IPV6_DST] = { "-d", ATTR_ORIG_IPV6_DST, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_DNAT_IPV6] = { "-g", ATTR_REPL_IPV6_SRC, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_SNAT_IPV6] = { "-n", ATTR_REPL_IPV6_DST, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_REPL_IPV6_SRC] = { "-r", ATTR_REPL_IPV6_SRC, CT_ATTR_TYPE_IPV6, 0, 0 },
+ [ATTR_REPL_IPV6_DST] = { "-q", ATTR_REPL_IPV6_DST, CT_ATTR_TYPE_IPV6, 0, 0 },
+};
+
+static const char *conntrack_status_map[] = {
+ [IPS_SEEN_REPLY_BIT] = "SEEN_REPLY",
+ [IPS_ASSURED_BIT] = "ASSURED",
+ [IPS_FIXED_TIMEOUT_BIT] = "FIXED_TIMEOUT",
+ [IPS_EXPECTED_BIT] = "EXPECTED"
+};
+
+static struct ct_print_opts attrs_generic[] = {
+ { "-t", ATTR_TIMEOUT, CT_ATTR_TYPE_U32, 0, 0 },
+ { "-u", ATTR_STATUS, CT_ATTR_TYPE_U32_BITMAP,
+ sizeof(conntrack_status_map)/sizeof(conntrack_status_map[0]),
+ conntrack_status_map },
+ { "-c", ATTR_SECMARK, CT_ATTR_TYPE_U32, 0, 0 },
+ { "-w", ATTR_ZONE, CT_ATTR_TYPE_U16, 0, 0 },
+ { "--orig-zone", ATTR_ORIG_ZONE, CT_ATTR_TYPE_U16, 0, 0 },
+ { "--reply-zone", ATTR_REPL_ZONE, CT_ATTR_TYPE_U16, 0, 0 },
+ {},
+};
+
+static int ct_save_snprintf(char *buf, size_t len,
+ const struct nf_conntrack *ct,
+ struct nfct_labelmap *map,
+ enum nf_conntrack_msg_type type)
+{
+ struct ct_print_opts tuple_attr_print[5] = {};
+ unsigned int size = 0, offset = 0;
+ struct ctproto_handler *cur;
+ uint8_t l3proto, l4proto;
+ int tuple_attrs[4] = {};
+ bool l4proto_set;
+ unsigned i;
+ int ret;
+
+ switch (type) {
+ case NFCT_T_NEW:
+ ret = snprintf(buf + offset, len, "-A ");
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ case NFCT_T_UPDATE:
+ ret = snprintf(buf + offset, len, "-U ");
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ case NFCT_T_DESTROY:
+ ret = snprintf(buf + offset, len, "-D ");
+ BUFFER_SIZE(ret, size, len, offset);
+ break;
+ default:
+ break;
+ }
+
+ ret = ct_snprintf_opts(buf + offset, len, ct, attrs_generic);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ l3proto = nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO);
+ if (!l3proto)
+ l3proto = nfct_get_attr_u8(ct, ATTR_REPL_L3PROTO);
+ switch (l3proto) {
+ case AF_INET:
+ tuple_attrs[0] = ATTR_ORIG_IPV4_SRC;
+ tuple_attrs[1] = ATTR_ORIG_IPV4_DST;
+ tuple_attrs[2] = nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) ?
+ ATTR_DNAT_IPV4 : ATTR_REPL_IPV4_SRC;
+ tuple_attrs[3] = nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) ?
+ ATTR_SNAT_IPV4 : ATTR_REPL_IPV4_DST;
+ break;
+ case AF_INET6:
+ tuple_attrs[0] = ATTR_ORIG_IPV6_SRC;
+ tuple_attrs[1] = ATTR_ORIG_IPV6_DST;
+ tuple_attrs[2] = nfct_getobjopt(ct, NFCT_GOPT_IS_DNAT) ?
+ ATTR_DNAT_IPV6 : ATTR_REPL_IPV6_SRC;
+ tuple_attrs[3] = nfct_getobjopt(ct, NFCT_GOPT_IS_SNAT) ?
+ ATTR_SNAT_IPV6 : ATTR_REPL_IPV6_DST;
+ break;
+ default:
+ fprintf(stderr, "WARNING: unsupported l3proto %d, skipping.\n",
+ l3proto);
+ return 0;
+ }
+
+ for (i = 0; i < sizeof(tuple_attrs) / sizeof(tuple_attrs[0]); i++) {
+ memcpy(&tuple_attr_print[i], &attrs_ip_map[tuple_attrs[i]],
+ sizeof(tuple_attr_print[0]));
+ }
+
+ ret = ct_snprintf_opts(buf + offset, len, ct, tuple_attr_print);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ l4proto = nfct_get_attr_u8(ct, ATTR_L4PROTO);
+
+ l4proto_set = false;
+ /* is it in the list of supported protocol? */
+ list_for_each_entry(cur, &proto_list, head) {
+ if (cur->protonum != l4proto)
+ continue;
+
+ ret = snprintf(buf + offset, len, "-p %s ", cur->name);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ ret = ct_snprintf_opts(buf + offset, len, ct, cur->print_opts);
+ BUFFER_SIZE(ret, size, len, offset);
+
+ l4proto_set = true;
+ break;
+ }
+
+ if (!l4proto_set) {
+ ret = snprintf(buf + offset, len, "-p %d ", l4proto);
+ BUFFER_SIZE(ret, size, len, offset);
+ }
+
+ /* skip trailing space, if any */
+ for (; size && buf[size-1] == ' '; --size)
+ buf[size-1] = '\0';
+
+ return size;
+}
+
extern struct ctproto_handler ct_proto_unknown;
+static int parse_proto_num(const char *str)
+{
+ unsigned long val;
+ char *endptr;
+
+ val = strtoul(str, &endptr, 0);
+ if (val > IPPROTO_RAW ||
+ endptr == str ||
+ *endptr != '\0')
+ return -1;
+
+ return val;
+}
+
static struct ctproto_handler *findproto(char *name, int *pnum)
{
struct ctproto_handler *cur;
@@ -628,8 +868,8 @@ static struct ctproto_handler *findproto(char *name, int *pnum)
return &ct_proto_unknown;
}
/* using a protocol number? */
- protonum = atoi(name);
- if (protonum >= 0 && protonum <= IPPROTO_MAX) {
+ protonum = parse_proto_num(name);
+ if (protonum >= 0) {
/* try lookup by number, perhaps this protocol is supported */
list_for_each_entry(cur, &proto_list, head) {
if (cur->protonum == protonum) {
@@ -696,7 +936,7 @@ exit_error(enum exittype status, const char *msg, ...)
if (status == PARAMETER_PROBLEM)
exit_tryhelp(status);
/* release template objects that were allocated in the setup stage. */
- free_tmpl_objects();
+ free_tmpl_objects(cur_tmpl);
exit(status);
}
@@ -818,11 +1058,11 @@ err2str(int err, enum ct_command command)
{ { CT_LIST, ENOTSUPP, "function not implemented" },
{ 0xFFFF, EINVAL, "invalid parameters" },
{ CT_CREATE, EEXIST, "Such conntrack exists, try -U to update" },
- { CT_CREATE|CT_GET|CT_DELETE, ENOENT,
+ { CT_CREATE|CT_GET|CT_DELETE|CT_ADD, ENOENT,
"such conntrack doesn't exist" },
- { CT_CREATE|CT_GET, ENOMEM, "not enough memory" },
+ { CT_CREATE|CT_GET|CT_ADD, ENOMEM, "not enough memory" },
{ CT_GET, EAFNOSUPPORT, "protocol not supported" },
- { CT_CREATE, ETIME, "conntrack has expired" },
+ { CT_CREATE|CT_ADD, ETIME, "conntrack has expired" },
{ EXP_CREATE, ENOENT, "master conntrack not found" },
{ EXP_CREATE, EINVAL, "invalid parameters" },
{ ~0U, EPERM, "sorry, you must be root or get "
@@ -855,7 +1095,7 @@ enum {
_O_ID = (1 << 3),
_O_KTMS = (1 << 4),
_O_CL = (1 << 5),
- _O_US = (1 << 6),
+ _O_SAVE = (1 << 6),
};
enum {
@@ -866,7 +1106,7 @@ enum {
};
static struct parse_parameter {
- const char *parameter[7];
+ const char *parameter[8];
size_t size;
unsigned int value[8];
} parse_array[PARSE_MAX] = {
@@ -874,13 +1114,13 @@ static struct parse_parameter {
{ IPS_ASSURED, IPS_SEEN_REPLY, 0, IPS_FIXED_TIMEOUT, IPS_EXPECTED, IPS_OFFLOAD, IPS_HW_OFFLOAD} },
{ {"ALL", "NEW", "UPDATES", "DESTROY"}, 4,
{ CT_EVENT_F_ALL, CT_EVENT_F_NEW, CT_EVENT_F_UPD, CT_EVENT_F_DEL } },
- { {"xml", "extended", "timestamp", "id", "ktimestamp", "labels", "userspace" }, 7,
- { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, _O_US },
+ { {"xml", "extended", "timestamp", "id", "ktimestamp", "labels", "userspace", "save"}, 8,
+ { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, 0, _O_SAVE },
},
};
static int
-do_parse_parameter(const char *str, size_t str_length, unsigned int *value,
+do_parse_parameter(const char *str, size_t str_length, unsigned int *value,
int parse_type)
{
size_t i;
@@ -905,7 +1145,7 @@ do_parse_parameter(const char *str, size_t str_length, unsigned int *value,
ret = 1;
break;
}
-
+
return ret;
}
@@ -927,6 +1167,53 @@ parse_parameter(const char *arg, unsigned int *status, int parse_type)
}
static void
+parse_parameter_mask(const char *arg, unsigned int *status, unsigned int *mask, int parse_type)
+{
+ static const char unreplied[] = "UNREPLIED";
+ unsigned int *value;
+ const char *comma;
+ bool negated;
+
+ while ((comma = strchr(arg, ',')) != NULL) {
+ if (comma == arg)
+ exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+
+ negated = *arg == '!';
+ if (negated)
+ arg++;
+ if (comma == arg)
+ exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+
+ value = negated ? mask : status;
+
+ if (!negated && strncmp(arg, unreplied, strlen(unreplied)) == 0) {
+ *mask |= IPS_SEEN_REPLY;
+ arg = comma+1;
+ continue;
+ }
+
+ if (!do_parse_parameter(arg, comma-arg, value, parse_type))
+ exit_error(PARAMETER_PROBLEM,"Bad parameter `%s'", arg);
+ arg = comma+1;
+ }
+
+ negated = *arg == '!';
+ if (negated)
+ arg++;
+ value = negated ? mask : status;
+
+ if (!negated && strncmp(arg, unreplied, strlen(unreplied)) == 0) {
+ *mask |= IPS_SEEN_REPLY;
+ return;
+ }
+
+ if (strlen(arg) == 0
+ || !do_parse_parameter(arg, strlen(arg),
+ value, parse_type))
+ exit_error(PARAMETER_PROBLEM, "Bad parameter `%s'", arg);
+}
+
+static void
parse_u32_mask(const char *arg, struct u32_mask *m)
{
char *end;
@@ -1190,8 +1477,7 @@ split_address_and_port(const char *arg, char **address, char **port_str)
}
}
-static void
-usage(char *prog)
+static void usage(const char *prog)
{
fprintf(stdout, "Command line interface for the connection "
"tracking system. Version %s\n", VERSION);
@@ -1208,17 +1494,17 @@ usage(char *prog)
static unsigned int output_mask;
static int
-filter_label(const struct nf_conntrack *ct)
+filter_label(const struct nf_conntrack *ct, const struct ct_tmpl *tmpl)
{
- if (tmpl.label == NULL)
+ if (tmpl->label == NULL)
return 0;
const struct nfct_bitmask *ctb = nfct_get_attr(ct, ATTR_CONNLABELS);
if (ctb == NULL)
return 1;
- for (unsigned int i = 0; i <= nfct_bitmask_maxbit(tmpl.label); i++) {
- if (nfct_bitmask_test_bit(tmpl.label, i) &&
+ for (unsigned int i = 0; i <= nfct_bitmask_maxbit(tmpl->label); i++) {
+ if (nfct_bitmask_test_bit(tmpl->label, i) &&
!nfct_bitmask_test_bit(ctb, i))
return 1;
}
@@ -1226,25 +1512,26 @@ filter_label(const struct nf_conntrack *ct)
return 0;
}
-static int
-filter_mark(const struct nf_conntrack *ct)
+static int filter_mark(const struct ct_cmd *cmd, const struct nf_conntrack *ct)
{
- if ((options & CT_OPT_MARK) &&
- !mark_cmp(&tmpl.mark, ct))
+ const struct ct_tmpl *tmpl = &cmd->tmpl;
+
+ if ((cmd->options & CT_OPT_MARK) &&
+ !mark_cmp(&tmpl->mark, ct))
return 1;
return 0;
}
-static int
-filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct)
+static int filter_nat(const struct ct_cmd *cmd, const struct nf_conntrack *ct)
{
- int check_srcnat = options & CT_OPT_SRC_NAT ? 1 : 0;
- int check_dstnat = options & CT_OPT_DST_NAT ? 1 : 0;
+ int check_srcnat = cmd->options & CT_OPT_SRC_NAT ? 1 : 0;
+ int check_dstnat = cmd->options & CT_OPT_DST_NAT ? 1 : 0;
+ struct nf_conntrack *obj = cmd->tmpl.ct;
int has_srcnat = 0, has_dstnat = 0;
uint32_t ip;
uint16_t port;
- if (options & CT_OPT_ANY_NAT)
+ if (cmd->options & CT_OPT_ANY_NAT)
check_srcnat = check_dstnat = 1;
if (check_srcnat) {
@@ -1307,13 +1594,14 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct)
nfct_getobjopt(ct, NFCT_GOPT_IS_DPAT)))
has_dstnat = 1;
}
- if (options & CT_OPT_ANY_NAT)
+ if (cmd->options & CT_OPT_ANY_NAT)
return !(has_srcnat || has_dstnat);
- else if ((options & CT_OPT_SRC_NAT) && (options & CT_OPT_DST_NAT))
+ else if ((cmd->options & CT_OPT_SRC_NAT) &&
+ (cmd->options & CT_OPT_DST_NAT))
return !(has_srcnat && has_dstnat);
- else if (options & CT_OPT_SRC_NAT)
+ else if (cmd->options & CT_OPT_SRC_NAT)
return !has_srcnat;
- else if (options & CT_OPT_DST_NAT)
+ else if (cmd->options & CT_OPT_DST_NAT)
return !has_dstnat;
return 0;
@@ -1361,14 +1649,14 @@ nfct_filter_network_direction(const struct nf_conntrack *ct, enum ct_direction d
}
static int
-filter_network(const struct nf_conntrack *ct)
+filter_network(const struct ct_cmd *cmd, const struct nf_conntrack *ct)
{
- if (options & CT_OPT_MASK_SRC) {
+ if (cmd->options & CT_OPT_MASK_SRC) {
if (nfct_filter_network_direction(ct, DIR_SRC))
return 1;
}
- if (options & CT_OPT_MASK_DST) {
+ if (cmd->options & CT_OPT_MASK_DST) {
if (nfct_filter_network_direction(ct, DIR_DST))
return 1;
}
@@ -1376,15 +1664,18 @@ filter_network(const struct nf_conntrack *ct)
}
static int
-nfct_filter(struct nf_conntrack *obj, struct nf_conntrack *ct)
+nfct_filter(struct ct_cmd *cmd, struct nf_conntrack *ct,
+ const struct ct_tmpl *tmpl)
{
- if (filter_nat(obj, ct) ||
- filter_mark(ct) ||
- filter_label(ct) ||
- filter_network(ct))
+ struct nf_conntrack *obj = cmd->tmpl.ct;
+
+ if (filter_nat(cmd, ct) ||
+ filter_mark(cmd, ct) ||
+ filter_label(ct, tmpl) ||
+ filter_network(cmd, ct))
return 1;
- if (options & CT_COMPARISON &&
+ if (cmd->options & CT_COMPARISON &&
!nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK))
return 1;
@@ -1404,7 +1695,7 @@ event_sighandler(int s)
fprintf(stderr, "%s v%s (conntrack-tools): ", PROGNAME, VERSION);
fprintf(stderr, "%d flow events have been shown.\n", counter);
- mnl_socket_close(sock.mnl);
+ mnl_socket_close(_sock.mnl);
exit(0);
}
@@ -1422,14 +1713,177 @@ exp_event_sighandler(int s)
exit(0);
}
+static char *pid2name(pid_t pid)
+{
+ char procname[256], *prog;
+ FILE *fp;
+ int ret;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%lu/stat", (unsigned long)pid);
+ if (ret < 0 || ret > (int)sizeof(procname))
+ return NULL;
+
+ fp = fopen(procname, "r");
+ if (!fp)
+ return NULL;
+
+ ret = fscanf(fp, "%*u (%m[^)]", &prog);
+
+ fclose(fp);
+
+ if (ret == 1)
+ return prog;
+
+ return NULL;
+}
+
+static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode)
+{
+ const struct dirent *ent;
+ char procname[256];
+ DIR *dir;
+ int ret;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%lu/fd/", (unsigned long)pid);
+ if (ret < 0 || ret >= (int)sizeof(procname))
+ return NULL;
+
+ dir = opendir(procname);
+ if (!dir)
+ return NULL;
+
+ for (;;) {
+ unsigned long ino;
+ char tmp[128];
+ ssize_t rl;
+
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ if (ent->d_type != DT_LNK)
+ continue;
+
+ ret = snprintf(procname, sizeof(procname), "/proc/%d/fd/%s",
+ pid, ent->d_name);
+ if (ret < 0 || ret >= (int)sizeof(procname))
+ continue;
+
+ rl = readlink(procname, tmp, sizeof(tmp));
+ if (rl <= 0 || rl >= (ssize_t)sizeof(tmp))
+ continue;
+
+ tmp[rl] = 0;
+
+ ret = sscanf(tmp, "socket:[%lu]", &ino);
+ if (ret == 1 && ino == inode) {
+ closedir(dir);
+ return pid2name(pid);
+ }
+ }
+
+ closedir(dir);
+ return NULL;
+}
+
+static char *name_by_portid(uint32_t portid, unsigned long inode)
+{
+ const struct dirent *ent;
+ char *prog;
+ DIR *dir;
+
+ /* Many netlink users use their process ID to allocate the first port id. */
+ prog = portid2name(portid, portid, inode);
+ if (prog)
+ return prog;
+
+ /* no luck, search harder. */
+ dir = opendir("/proc");
+ if (!dir)
+ return NULL;
+
+ for (;;) {
+ unsigned long pid;
+ char *end;
+
+ ent = readdir(dir);
+ if (!ent)
+ break;
+
+ if (ent->d_type != DT_DIR)
+ continue;
+
+ pid = strtoul(ent->d_name, &end, 10);
+ if (pid <= 1 || *end)
+ continue;
+
+ if (pid == portid) /* already tried */
+ continue;
+
+ prog = portid2name(pid, portid, inode);
+ if (prog)
+ break;
+ }
+
+ closedir(dir);
+ return prog;
+}
+
+static char *get_progname(uint32_t portid)
+{
+ FILE *fp = fopen("/proc/net/netlink", "r");
+ uint32_t portid_check;
+ unsigned long inode;
+ int ret, prot;
+
+ if (!fp)
+ return NULL;
+
+ for (;;) {
+ char line[256];
+
+ if (!fgets(line, sizeof(line), fp))
+ break;
+
+ ret = sscanf(line, "%*x %d %u %*x %*d %*d %*x %*d %*u %lu\n",
+ &prot, &portid_check, &inode);
+
+ if (ret == EOF)
+ break;
+
+ if (ret == 3 && portid_check == portid && prot == NETLINK_NETFILTER) {
+ static uint32_t last_portid;
+ static uint32_t last_inode;
+ static char *last_program;
+ char *prog;
+
+ fclose(fp);
+
+ if (last_portid == portid && last_inode == inode)
+ return last_program;
+
+ prog = name_by_portid(portid, inode);
+
+ free(last_program);
+ last_program = prog;
+ last_portid = portid;
+ last_inode = inode;
+ return prog;
+ }
+ }
+
+ fclose(fp);
+ return NULL;
+}
+
static int event_cb(const struct nlmsghdr *nlh, void *data)
{
+ struct nfgenmsg *nfh = mnl_nlmsg_get_payload(nlh);
unsigned int op_type = NFCT_O_DEFAULT;
- struct nf_conntrack *obj = data;
enum nf_conntrack_msg_type type;
+ struct ct_cmd *cmd = data;
unsigned int op_flags = 0;
struct nf_conntrack *ct;
- bool userspace = false;
char buf[1024];
switch(nlh->nlmsg_type & 0xff) {
@@ -1455,9 +1909,16 @@ static int event_cb(const struct nlmsghdr *nlh, void *data)
if (nfct_nlmsg_parse(nlh, ct) < 0)
goto out;
- if (nfct_filter(obj, ct))
+ if ((filter_family != AF_UNSPEC &&
+ filter_family != nfh->nfgen_family) ||
+ nfct_filter(cmd, ct, cur_tmpl))
goto out;
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, type);
+ goto done;
+ }
+
if (output_mask & _O_XML) {
op_type = NFCT_O_XML;
if (dump_xml_header_done) {
@@ -1482,15 +1943,17 @@ static int event_cb(const struct nlmsghdr *nlh, void *data)
op_flags |= NFCT_OF_ID;
nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap);
+done:
+ if (nlh->nlmsg_pid && !(output_mask & _O_XML)) {
+ char *prog = get_progname(nlh->nlmsg_pid);
- if (output_mask & _O_US) {
- if (nlh->nlmsg_pid)
- userspace = true;
+ if (prog)
+ printf("%s [USERSPACE] portid=%u progname=%s\n", buf, nlh->nlmsg_pid, prog);
else
- userspace = false;
+ printf("%s [USERSPACE] portid=%u\n", buf, nlh->nlmsg_pid);
+ } else {
+ puts(buf);
}
-
- printf("%s%s\n", buf, userspace ? " [USERSPACE]" : "");
fflush(stdout);
counter++;
@@ -1499,59 +1962,46 @@ out:
return MNL_CB_OK;
}
-static int dump_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int nfct_mnl_request(struct nfct_mnl_socket *sock, uint16_t subsys,
+ int family, uint16_t type, uint16_t flags,
+ mnl_cb_t cb, const struct nf_conntrack *ct,
+ const struct ct_cmd *cmd);
+
+static int mnl_nfct_delete_cb(const struct nlmsghdr *nlh, void *data)
{
- char buf[1024];
- struct nf_conntrack *obj = data;
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
unsigned int op_type = NFCT_O_DEFAULT;
unsigned int op_flags = 0;
+ struct ct_cmd *cmd = data;
+ struct nf_conntrack *ct;
+ char buf[1024];
+ int res;
- if (nfct_filter(obj, ct))
- return NFCT_CB_CONTINUE;
-
- if (output_mask & _O_XML) {
- op_type = NFCT_O_XML;
- if (dump_xml_header_done) {
- dump_xml_header_done = 0;
- printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
- "<conntrack>\n");
- }
- }
- if (output_mask & _O_EXT)
- op_flags = NFCT_OF_SHOW_LAYER3;
- if (output_mask & _O_KTMS)
- op_flags |= NFCT_OF_TIMESTAMP;
- if (output_mask & _O_ID)
- op_flags |= NFCT_OF_ID;
-
- nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap);
- printf("%s\n", buf);
-
- counter++;
-
- return NFCT_CB_CONTINUE;
-}
+ ct = nfct_new();
+ if (ct == NULL)
+ return MNL_CB_OK;
-static int delete_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
-{
- int res;
- char buf[1024];
- struct nf_conntrack *obj = data;
- unsigned int op_type = NFCT_O_DEFAULT;
- unsigned int op_flags = 0;
+ nfct_nlmsg_parse(nlh, ct);
- if (nfct_filter(obj, ct))
- return NFCT_CB_CONTINUE;
+ if (nfct_filter(cmd, ct, cur_tmpl))
+ goto destroy_ok;
- res = nfct_query(ith, NFCT_Q_DESTROY, ct);
- if (res < 0)
+ res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK,
+ nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+ IPCTNL_MSG_CT_DELETE, NLM_F_ACK, NULL, ct, NULL);
+ if (res < 0) {
+ /* the entry has vanish in middle of the delete */
+ if (errno == ENOENT)
+ goto done;
exit_error(OTHER_PROBLEM,
"Operation failed: %s",
err2str(errno, CT_DELETE));
+ }
+
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_DESTROY);
+ goto done;
+ }
if (output_mask & _O_XML)
op_type = NFCT_O_XML;
@@ -1561,20 +2011,33 @@ static int delete_cb(enum nf_conntrack_msg_type type,
op_flags |= NFCT_OF_ID;
nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags);
+done:
printf("%s\n", buf);
counter++;
- return NFCT_CB_CONTINUE;
+destroy_ok:
+ nfct_destroy(ct);
+ return MNL_CB_OK;
}
-static int print_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int mnl_nfct_print_cb(const struct nlmsghdr *nlh, void *data)
{
- char buf[1024];
unsigned int op_type = NFCT_O_DEFAULT;
unsigned int op_flags = 0;
+ struct nf_conntrack *ct;
+ char buf[1024];
+
+ ct = nfct_new();
+ if (ct == NULL)
+ return MNL_CB_OK;
+
+ nfct_nlmsg_parse(nlh, ct);
+
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
+ goto done;
+ }
if (output_mask & _O_XML)
op_type = NFCT_O_XML;
@@ -1584,25 +2047,29 @@ static int print_cb(enum nf_conntrack_msg_type type,
op_flags |= NFCT_OF_ID;
nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap);
+done:
printf("%s\n", buf);
- return NFCT_CB_CONTINUE;
+ nfct_destroy(ct);
+
+ return MNL_CB_OK;
}
-static void copy_mark(struct nf_conntrack *tmp,
+static void copy_mark(const struct ct_cmd *cmd, struct nf_conntrack *tmp,
const struct nf_conntrack *ct,
const struct u32_mask *m)
{
- if (options & CT_OPT_MARK) {
+ if (cmd->options & CT_OPT_MARK) {
uint32_t mark = nfct_get_attr_u32(ct, ATTR_MARK);
mark = (mark & ~m->mask) ^ m->value;
nfct_set_attr_u32(tmp, ATTR_MARK, mark);
}
}
-static void copy_status(struct nf_conntrack *tmp, const struct nf_conntrack *ct)
+static void copy_status(const struct ct_cmd *cmd, struct nf_conntrack *tmp,
+ const struct nf_conntrack *ct)
{
- if (options & CT_OPT_STATUS) {
+ if (cmd->options & CT_OPT_STATUS) {
/* copy existing flags, we only allow setting them. */
uint32_t status = nfct_get_attr_u32(ct, ATTR_STATUS);
status |= nfct_get_attr_u32(tmp, ATTR_STATUS);
@@ -1618,21 +2085,23 @@ static struct nfct_bitmask *xnfct_bitmask_clone(const struct nfct_bitmask *a)
return b;
}
-static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct)
+static void copy_label(const struct ct_cmd *cmd, struct nf_conntrack *tmp,
+ const struct nf_conntrack *ct,
+ const struct ct_tmpl *tmpl)
{
struct nfct_bitmask *ctb, *newmask;
unsigned int i;
- if ((options & (CT_OPT_ADD_LABEL|CT_OPT_DEL_LABEL)) == 0)
+ if ((cmd->options & (CT_OPT_ADD_LABEL|CT_OPT_DEL_LABEL)) == 0)
return;
nfct_copy_attr(tmp, ct, ATTR_CONNLABELS);
ctb = (void *) nfct_get_attr(tmp, ATTR_CONNLABELS);
- if (options & CT_OPT_ADD_LABEL) {
+ if (cmd->options & CT_OPT_ADD_LABEL) {
if (ctb == NULL) {
nfct_set_attr(tmp, ATTR_CONNLABELS,
- xnfct_bitmask_clone(tmpl.label_modify));
+ xnfct_bitmask_clone(tmpl->label_modify));
return;
}
/* If we send a bitmask shorter than the kernel sent to us, the bits we
@@ -1646,7 +2115,7 @@ static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct)
newmask = nfct_bitmask_new(nfct_bitmask_maxbit(ctb));
for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) {
- if (nfct_bitmask_test_bit(tmpl.label_modify, i)) {
+ if (nfct_bitmask_test_bit(tmpl->label_modify, i)) {
nfct_bitmask_set_bit(ctb, i);
nfct_bitmask_set_bit(newmask, i);
} else if (nfct_bitmask_test_bit(ctb, i)) {
@@ -1659,7 +2128,7 @@ static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct)
nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask);
} else if (ctb != NULL) {
/* CT_OPT_DEL_LABEL */
- if (tmpl.label_modify == NULL) {
+ if (tmpl->label_modify == NULL) {
newmask = nfct_bitmask_new(0);
if (newmask)
nfct_set_attr(tmp, ATTR_CONNLABELS, newmask);
@@ -1667,35 +2136,43 @@ static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct)
}
for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) {
- if (nfct_bitmask_test_bit(tmpl.label_modify, i))
+ if (nfct_bitmask_test_bit(tmpl->label_modify, i))
nfct_bitmask_unset_bit(ctb, i);
}
- newmask = xnfct_bitmask_clone(tmpl.label_modify);
+ newmask = xnfct_bitmask_clone(tmpl->label_modify);
nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask);
}
}
-static int update_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int mnl_nfct_update_cb(const struct nlmsghdr *nlh, void *data)
{
+ struct ct_cmd *cmd = data;
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
+ struct nf_conntrack *ct, *obj = cmd->tmpl.ct, *tmp = NULL;
int res;
- struct nf_conntrack *obj = data, *tmp;
- if (filter_nat(obj, ct) ||
- filter_label(ct) ||
- filter_network(ct))
- return NFCT_CB_CONTINUE;
+ ct = nfct_new();
+ if (ct == NULL)
+ return MNL_CB_OK;
+
+ nfct_nlmsg_parse(nlh, ct);
+
+ if (filter_nat(cmd, ct) ||
+ filter_label(ct, cur_tmpl) ||
+ filter_network(cmd, ct))
+ goto destroy_ok;
if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) &&
nfct_get_attr_u32(obj, ATTR_ID) != nfct_get_attr_u32(ct, ATTR_ID))
- return NFCT_CB_CONTINUE;
+ goto destroy_ok;
- if (options & CT_OPT_TUPLE_ORIG && !nfct_cmp(obj, ct, NFCT_CMP_ORIG))
- return NFCT_CB_CONTINUE;
- if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL))
- return NFCT_CB_CONTINUE;
+ if (cmd->options & CT_OPT_TUPLE_ORIG &&
+ !nfct_cmp(obj, ct, NFCT_CMP_ORIG))
+ goto destroy_ok;
+ if (cmd->options & CT_OPT_TUPLE_REPL &&
+ !nfct_cmp(obj, ct, NFCT_CMP_REPL))
+ goto destroy_ok;
tmp = nfct_new();
if (tmp == NULL)
@@ -1703,41 +2180,52 @@ static int update_cb(enum nf_conntrack_msg_type type,
nfct_copy(tmp, ct, NFCT_CP_ORIG);
nfct_copy(tmp, obj, NFCT_CP_META);
- copy_mark(tmp, ct, &tmpl.mark);
- copy_status(tmp, ct);
- copy_label(tmp, ct);
+ copy_mark(cmd, tmp, ct, &cur_tmpl->mark);
+ copy_status(cmd, tmp, ct);
+ copy_label(cmd, tmp, ct, cur_tmpl);
/* do not send NFCT_Q_UPDATE if ct appears unchanged */
- if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) {
- nfct_destroy(tmp);
- return NFCT_CB_CONTINUE;
- }
+ if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK))
+ goto destroy_ok;
- res = nfct_query(ith, NFCT_Q_UPDATE, tmp);
- if (res < 0)
- fprintf(stderr,
- "Operation failed: %s\n",
+ res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK,
+ nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+ IPCTNL_MSG_CT_NEW, NLM_F_ACK, NULL, tmp, NULL);
+ if (res < 0) {
+ /* the entry has vanish in middle of the update */
+ if (errno == ENOENT)
+ goto destroy_ok;
+ else if (cmd->options & (CT_OPT_ADD_LABEL | CT_OPT_DEL_LABEL) &&
+ !nfct_attr_is_set(ct, ATTR_CONNLABELS) &&
+ errno == ENOSPC)
+ goto destroy_ok;
+
+ exit_error(OTHER_PROBLEM,
+ "Operation failed: %s",
err2str(errno, CT_UPDATE));
- nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL);
+ }
- res = nfct_query(ith, NFCT_Q_GET, tmp);
+ res = nfct_mnl_request(modifier_sock, NFNL_SUBSYS_CTNETLINK,
+ nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO),
+ IPCTNL_MSG_CT_GET, 0,
+ mnl_nfct_print_cb, tmp, NULL);
if (res < 0) {
- nfct_destroy(tmp);
/* the entry has vanish in middle of the update */
- if (errno == ENOENT) {
- nfct_callback_unregister(ith);
- return NFCT_CB_CONTINUE;
- }
+ if (errno == ENOENT)
+ goto destroy_ok;
exit_error(OTHER_PROBLEM,
"Operation failed: %s",
err2str(errno, CT_UPDATE));
}
- nfct_destroy(tmp);
- nfct_callback_unregister(ith);
counter++;
- return NFCT_CB_CONTINUE;
+destroy_ok:
+ if (tmp)
+ nfct_destroy(tmp);
+ nfct_destroy(ct);
+
+ return MNL_CB_OK;
}
static int dump_exp_cb(enum nf_conntrack_msg_type type,
@@ -1882,32 +2370,33 @@ out_err:
return ret;
}
-static int nfct_mnl_socket_open(unsigned int events)
+static int nfct_mnl_socket_open(struct nfct_mnl_socket *socket,
+ unsigned int events)
{
- sock.mnl = mnl_socket_open(NETLINK_NETFILTER);
- if (sock.mnl == NULL) {
+ socket->mnl = mnl_socket_open(NETLINK_NETFILTER);
+ if (socket->mnl == NULL) {
perror("mnl_socket_open");
return -1;
}
- if (mnl_socket_bind(sock.mnl, events, MNL_SOCKET_AUTOPID) < 0) {
+ if (mnl_socket_bind(socket->mnl, events, MNL_SOCKET_AUTOPID) < 0) {
perror("mnl_socket_bind");
return -1;
}
- sock.portid = mnl_socket_get_portid(sock.mnl);
+ socket->portid = mnl_socket_get_portid(socket->mnl);
return 0;
}
static struct nlmsghdr *
nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type,
- uint8_t family)
+ uint16_t flags, uint8_t family)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfh;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = (subsys << 8) | type;
- nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+ nlh->nlmsg_flags = NLM_F_REQUEST | flags;
nlh->nlmsg_seq = time(NULL);
nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
@@ -1918,63 +2407,114 @@ nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type,
return nlh;
}
-static void nfct_mnl_socket_close(void)
+static void nfct_mnl_socket_close(const struct nfct_mnl_socket *sock)
{
- mnl_socket_close(sock.mnl);
+ mnl_socket_close(sock->mnl);
}
-static int
-nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
+static int nfct_mnl_socket_check_open(struct nfct_mnl_socket *socket,
+ unsigned int events)
+{
+ if (socket->mnl != NULL)
+ return 0;
+
+ return nfct_mnl_socket_open(socket, events);
+}
+
+static void nfct_mnl_socket_check_close(struct nfct_mnl_socket *sock)
+{
+ if (sock->mnl) {
+ nfct_mnl_socket_close(sock);
+ memset(sock, 0, sizeof(*sock));
+ }
+}
+
+static int __nfct_mnl_dump(struct nfct_mnl_socket *sock,
+ const struct nlmsghdr *nlh, mnl_cb_t cb, void *data)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
- struct nlmsghdr *nlh;
int res;
- nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family);
-
- res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len);
+ res = mnl_socket_sendto(sock->mnl, nlh, nlh->nlmsg_len);
if (res < 0)
return res;
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
+ res = mnl_socket_recvfrom(sock->mnl, buf, sizeof(buf));
while (res > 0) {
- res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid,
- cb, NULL);
+ res = mnl_cb_run(buf, res, nlh->nlmsg_seq, sock->portid,
+ cb, data);
if (res <= MNL_CB_STOP)
break;
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
+ res = mnl_socket_recvfrom(sock->mnl, buf, sizeof(buf));
}
return res;
}
static int
-nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family)
+nfct_mnl_dump(struct nfct_mnl_socket *sock, uint16_t subsys, uint16_t type,
+ mnl_cb_t cb, struct ct_cmd *cmd,
+ const struct nfct_filter_dump *filter_dump)
{
+ uint8_t family = cmd ? cmd->family : AF_UNSPEC;
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
- int res;
- nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family);
+ nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, NLM_F_DUMP, family);
- res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len);
- if (res < 0)
- return res;
+ if (filter_dump)
+ nfct_nlmsg_build_filter(nlh, filter_dump);
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
- if (res < 0)
- return res;
+ return __nfct_mnl_dump(sock, nlh, cb, cmd);
+}
+
+static int nfct_mnl_talk(struct nfct_mnl_socket *sock,
+ const struct nlmsghdr *nlh, mnl_cb_t cb,
+ const struct ct_cmd *cmd)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret;
+
+ ret = mnl_socket_sendto(sock->mnl, nlh, nlh->nlmsg_len);
+ if (ret < 0)
+ return ret;
+
+ ret = mnl_socket_recvfrom(sock->mnl, buf, sizeof(buf));
+ if (ret < 0)
+ return ret;
+
+ return mnl_cb_run(buf, ret, nlh->nlmsg_seq, sock->portid, cb, (void *)cmd);
+}
+
+static int nfct_mnl_request(struct nfct_mnl_socket *sock, uint16_t subsys,
+ int family, uint16_t type, uint16_t flags,
+ mnl_cb_t cb, const struct nf_conntrack *ct,
+ const struct ct_cmd *cmd)
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ int err;
- return mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, cb, NULL);
+ nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, flags, family);
+
+ if (ct) {
+ err = nfct_nlmsg_build(nlh, ct);
+ if (err < 0)
+ return err;
+ }
+
+ return nfct_mnl_talk(sock, nlh, cb, cmd);
}
+#define UNKNOWN_STATS_NUM 4
+
static int nfct_stats_attr_cb(const struct nlattr *attr, void *data)
{
const struct nlattr **tb = data;
int type = mnl_attr_get_type(attr);
- if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
+ if (mnl_attr_type_valid(attr, CTA_STATS_MAX + UNKNOWN_STATS_NUM) < 0)
return MNL_CB_OK;
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
@@ -1988,9 +2528,9 @@ static int nfct_stats_attr_cb(const struct nlattr *attr, void *data)
static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data)
{
- struct nlattr *tb[CTA_STATS_MAX+1] = {};
+ struct nlattr *tb[CTA_STATS_MAX + UNKNOWN_STATS_NUM + 1] = {};
struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
- const char *attr2name[CTA_STATS_MAX+1] = {
+ const char *attr2name[CTA_STATS_MAX + UNKNOWN_STATS_NUM + 1] = {
[CTA_STATS_SEARCHED] = "searched",
[CTA_STATS_FOUND] = "found",
[CTA_STATS_NEW] = "new",
@@ -2004,6 +2544,16 @@ static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data)
[CTA_STATS_EARLY_DROP] = "early_drop",
[CTA_STATS_ERROR] = "error",
[CTA_STATS_SEARCH_RESTART] = "search_restart",
+ [CTA_STATS_CLASH_RESOLVE] = "clash_resolve",
+ [CTA_STATS_CHAIN_TOOLONG] = "chaintoolong",
+
+ /* leave at end. Allows to show counters supported
+ * by newer kernel with older conntrack-tools release.
+ */
+ [CTA_STATS_MAX + 1] = "unknown1",
+ [CTA_STATS_MAX + 2] = "unknown2",
+ [CTA_STATS_MAX + 3] = "unknown3",
+ [CTA_STATS_MAX + 4] = "unknown4",
};
int i;
@@ -2011,7 +2561,7 @@ static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data)
printf("cpu=%-4u\t", ntohs(nfg->res_id));
- for (i=0; i<CTA_STATS_MAX+1; i++) {
+ for (i=0; i <= CTA_STATS_MAX + UNKNOWN_STATS_NUM; i++) {
if (tb[i]) {
printf("%s=%u ",
attr2name[i], ntohl(mnl_attr_get_u32(tb[i])));
@@ -2096,6 +2646,9 @@ static int nfct_global_stats_cb(const struct nlmsghdr *nlh, void *data)
static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data)
{
+ unsigned int op_type = NFCT_O_DEFAULT;
+ unsigned int op_flags = 0;
+ struct ct_cmd *cmd = data;
struct nf_conntrack *ct;
char buf[4096];
@@ -2105,7 +2658,34 @@ static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data)
nfct_nlmsg_parse(nlh, ct);
- nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, NFCT_O_DEFAULT, 0);
+ if (nfct_filter(cmd, ct, cur_tmpl)) {
+ nfct_destroy(ct);
+ return MNL_CB_OK;
+ }
+
+ if (output_mask & _O_SAVE) {
+ ct_save_snprintf(buf, sizeof(buf), ct, labelmap, NFCT_T_NEW);
+ goto done;
+ }
+
+ if (output_mask & _O_XML) {
+ op_type = NFCT_O_XML;
+ if (dump_xml_header_done) {
+ dump_xml_header_done = 0;
+ printf("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<conntrack>\n");
+ }
+ }
+ if (output_mask & _O_EXT)
+ op_flags = NFCT_OF_SHOW_LAYER3;
+ if (output_mask & _O_KTMS)
+ op_flags |= NFCT_OF_TIMESTAMP;
+ if (output_mask & _O_ID)
+ op_flags |= NFCT_OF_ID;
+
+ nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type,
+ op_flags, labelmap);
+done:
printf("%s\n", buf);
nfct_destroy(ct);
@@ -2127,7 +2707,8 @@ static void labelmap_init(void)
}
static void
-nfct_network_attr_prepare(const int family, enum ct_direction dir)
+nfct_network_attr_prepare(const int family, enum ct_direction dir,
+ const struct ct_tmpl *tmpl)
{
const union ct_address *address, *netmask;
enum nf_conntrack_attr attr;
@@ -2136,8 +2717,8 @@ nfct_network_attr_prepare(const int family, enum ct_direction dir)
attr = famdir2attr[family == AF_INET6][dir];
- address = nfct_get_attr(tmpl.ct, attr);
- netmask = nfct_get_attr(tmpl.mask, attr);
+ address = nfct_get_attr(tmpl->ct, attr);
+ netmask = nfct_get_attr(tmpl->mask, attr);
switch(family) {
case AF_INET:
@@ -2152,25 +2733,29 @@ nfct_network_attr_prepare(const int family, enum ct_direction dir)
memcpy(&net->netmask, netmask, sizeof(union ct_address));
/* avoid exact source matching */
- nfct_attr_unset(tmpl.ct, attr);
+ nfct_attr_unset(tmpl->ct, attr);
}
-static void
-nfct_filter_init(const int family)
+static void nfct_filter_init(const struct ct_cmd *cmd)
{
+ const struct ct_tmpl *tmpl = &cmd->tmpl;
+ int family = cmd->family;
+
filter_family = family;
- if (options & CT_OPT_MASK_SRC) {
- if (!(options & CT_OPT_ORIG_SRC))
+ if (cmd->options & CT_OPT_MASK_SRC) {
+ assert(family != AF_UNSPEC);
+ if (!(cmd->options & CT_OPT_ORIG_SRC))
exit_error(PARAMETER_PROBLEM,
"Can't use --mask-src without --src");
- nfct_network_attr_prepare(family, DIR_SRC);
+ nfct_network_attr_prepare(family, DIR_SRC, tmpl);
}
- if (options & CT_OPT_MASK_DST) {
- if (!(options & CT_OPT_ORIG_DST))
+ if (cmd->options & CT_OPT_MASK_DST) {
+ assert(family != AF_UNSPEC);
+ if (!(cmd->options & CT_OPT_ORIG_DST))
exit_error(PARAMETER_PROBLEM,
"Can't use --mask-dst without --dst");
- nfct_network_attr_prepare(family, DIR_DST);
+ nfct_network_attr_prepare(family, DIR_DST, tmpl);
}
}
@@ -2238,9 +2823,9 @@ nfct_set_addr_only(const int opt, struct nf_conntrack *ct, union ct_address *ad,
static void
nfct_set_addr_opt(const int opt, struct nf_conntrack *ct, union ct_address *ad,
- const int l3protonum)
+ const int l3protonum, unsigned int *options)
{
- options |= opt2type[opt];
+ *options |= opt2type[opt];
nfct_set_addr_only(opt, ct, ad, l3protonum);
nfct_set_attr_u8(ct, opt2attr[opt], l3protonum);
}
@@ -2249,7 +2834,8 @@ static void
nfct_parse_addr_from_opt(const int opt, const char *arg,
struct nf_conntrack *ct,
struct nf_conntrack *ctmask,
- union ct_address *ad, int *family)
+ union ct_address *ad, int *family,
+ unsigned int *options)
{
int mask, maskopt;
@@ -2269,7 +2855,7 @@ nfct_parse_addr_from_opt(const int opt, const char *arg,
"Invalid netmask");
}
- nfct_set_addr_opt(opt, ct, ad, l3protonum);
+ nfct_set_addr_opt(opt, ct, ad, l3protonum, options);
/* bail if we don't have a netmask to set*/
if (mask == -1 || !maskopt || ctmask == NULL)
@@ -2288,7 +2874,7 @@ nfct_parse_addr_from_opt(const int opt, const char *arg,
break;
}
- nfct_set_addr_opt(maskopt, ctmask, ad, l3protonum);
+ nfct_set_addr_opt(maskopt, ctmask, ad, l3protonum, options);
}
static void
@@ -2309,33 +2895,41 @@ nfct_set_nat_details(const int opt, struct nf_conntrack *ct,
}
-int main(int argc, char *argv[])
+static int print_stats(const struct ct_cmd *cmd)
+{
+ if (cmd->command && exit_msg[cmd->cmd][0]) {
+ fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
+ fprintf(stderr, exit_msg[cmd->cmd], counter);
+ if (counter == 0 &&
+ !(cmd->command & (CT_LIST | EXP_LIST)))
+ return -1;
+ }
+
+ return 0;
+}
+
+static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[])
{
- int c, cmd;
unsigned int type = 0, event_mask = 0, l4flags = 0, status = 0;
- int res = 0, partial;
+ int protonum = 0, family = AF_UNSPEC;
size_t socketbuffersize = 0;
- int family = AF_UNSPEC;
- int protonum = 0;
- union ct_address ad;
unsigned int command = 0;
+ unsigned int options = 0;
+ struct ct_tmpl *tmpl;
+ int res = 0, partial;
+ union ct_address ad;
+ int c, cmd;
/* we release these objects in the exit_error() path. */
- if (!alloc_tmpl_objects())
+ if (!alloc_tmpl_objects(&ct_cmd->tmpl))
exit_error(OTHER_PROBLEM, "out of memory");
- register_tcp();
- register_udp();
- register_udplite();
- register_sctp();
- register_dccp();
- register_icmp();
- register_icmpv6();
- register_gre();
- register_unknown();
+ tmpl = &ct_cmd->tmpl;
/* disable explicit missing arguments error output from getopt_long */
opterr = 0;
+ /* reset optind, for the case do_parse is called multiple times */
+ optind = 0;
while ((c = getopt_long(argc, argv, getopt_str, opts, NULL)) != -1) {
switch(c) {
@@ -2360,45 +2954,44 @@ int main(int argc, char *argv[])
case 'h':
case 'C':
case 'S':
- type = check_type(argc, argv);
- if (type == CT_TABLE_DYING ||
- type == CT_TABLE_UNCONFIRMED) {
- exit_error(PARAMETER_PROBLEM,
- "Can't do that command with "
- "tables `dying' and `unconfirmed'");
- }
- add_command(&command, cmd2type[c][type]);
- break;
case 'U':
+ case 'A':
type = check_type(argc, argv);
if (type == CT_TABLE_DYING ||
type == CT_TABLE_UNCONFIRMED) {
exit_error(PARAMETER_PROBLEM,
"Can't do that command with "
"tables `dying' and `unconfirmed'");
- } else if (type == CT_TABLE_CONNTRACK)
- add_command(&command, CT_UPDATE);
- else
+ }
+ if (cmd2type[c][type])
+ add_command(&command, cmd2type[c][type]);
+ else {
exit_error(PARAMETER_PROBLEM,
- "Can't update expectations");
+ "Can't do --%s on %s",
+ get_long_opt(c),
+ type == CT_TABLE_CONNTRACK ?
+ "conntrack" : "expectations");
+ }
break;
/* options */
case 's':
case 'd':
case 'r':
case 'q':
- nfct_parse_addr_from_opt(c, optarg, tmpl.ct,
- tmpl.mask, &ad, &family);
+ nfct_parse_addr_from_opt(c, optarg, tmpl->ct,
+ tmpl->mask, &ad, &family,
+ &options);
break;
case '[':
case ']':
- nfct_parse_addr_from_opt(c, optarg, tmpl.exptuple,
- tmpl.mask, &ad, &family);
+ nfct_parse_addr_from_opt(c, optarg, tmpl->exptuple,
+ tmpl->mask, &ad, &family,
+ &options);
break;
case '{':
case '}':
- nfct_parse_addr_from_opt(c, optarg, tmpl.mask,
- NULL, &ad, &family);
+ nfct_parse_addr_from_opt(c, optarg, tmpl->mask,
+ NULL, &ad, &family, &options);
break;
case 'p':
options |= CT_OPT_PROTO;
@@ -2412,18 +3005,25 @@ int main(int argc, char *argv[])
if (opts == NULL)
exit_error(OTHER_PROBLEM, "out of memory");
- nfct_set_attr_u8(tmpl.ct, ATTR_L4PROTO, protonum);
+ nfct_set_attr_u8(tmpl->ct, ATTR_L4PROTO, protonum);
break;
case 't':
options |= CT_OPT_TIMEOUT;
- nfct_set_attr_u32(tmpl.ct, ATTR_TIMEOUT, atol(optarg));
- nfexp_set_attr_u32(tmpl.exp,
+ nfct_set_attr_u32(tmpl->ct, ATTR_TIMEOUT, atol(optarg));
+ nfexp_set_attr_u32(tmpl->exp,
ATTR_EXP_TIMEOUT, atol(optarg));
break;
case 'u':
options |= CT_OPT_STATUS;
- parse_parameter(optarg, &status, PARSE_STATUS);
- nfct_set_attr_u32(tmpl.ct, ATTR_STATUS, status);
+ parse_parameter_mask(optarg, &status,
+ &tmpl->filter_status_kernel.mask,
+ PARSE_STATUS);
+ nfct_set_attr_u32(tmpl->ct, ATTR_STATUS, status);
+ if (tmpl->filter_status_kernel.mask == 0)
+ tmpl->filter_status_kernel.mask = status;
+
+ tmpl->filter_status_kernel.val = status;
+ tmpl->filter_status_kernel_set = true;
break;
case 'e':
options |= CT_OPT_EVENT_MASK;
@@ -2434,6 +3034,10 @@ int main(int argc, char *argv[])
parse_parameter(optarg, &output_mask, PARSE_OUTPUT);
if (output_mask & _O_CL)
labelmap_init();
+ if ((output_mask & _O_SAVE) &&
+ (output_mask & (_O_EXT |_O_TMS |_O_ID | _O_KTMS | _O_CL | _O_XML)))
+ exit_error(OTHER_PROBLEM,
+ "cannot combine save output with any other output type, use -o save only");
break;
case 'z':
options |= CT_OPT_ZERO;
@@ -2452,43 +3056,46 @@ int main(int argc, char *argv[])
&nat_address,
&port_str);
nfct_parse_addr_from_opt(c, nat_address,
- tmpl.ct, NULL,
- &ad, &family);
+ tmpl->ct, NULL,
+ &ad, &family,
+ &options);
if (c == 'j') {
/* Set details on both src and dst
* with any-nat
*/
- nfct_set_nat_details('g', tmpl.ct, &ad,
+ nfct_set_nat_details('g', tmpl->ct, &ad,
port_str, family);
- nfct_set_nat_details('n', tmpl.ct, &ad,
+ nfct_set_nat_details('n', tmpl->ct, &ad,
port_str, family);
} else {
- nfct_set_nat_details(c, tmpl.ct, &ad,
+ nfct_set_nat_details(c, tmpl->ct, &ad,
port_str, family);
}
+ free(port_str);
+ free(nat_address);
}
break;
case 'w':
case '(':
case ')':
options |= opt2type[c];
- nfct_set_attr_u16(tmpl.ct,
+ nfct_set_attr_u16(tmpl->ct,
opt2attr[c],
strtoul(optarg, NULL, 0));
break;
case 'i':
case 'c':
options |= opt2type[c];
- nfct_set_attr_u32(tmpl.ct,
+ nfct_set_attr_u32(tmpl->ct,
opt2attr[c],
strtoul(optarg, NULL, 0));
break;
case 'm':
options |= opt2type[c];
- parse_u32_mask(optarg, &tmpl.mark);
- tmpl.filter_mark_kernel.val = tmpl.mark.value;
- tmpl.filter_mark_kernel.mask = tmpl.mark.mask;
- tmpl.filter_mark_kernel_set = true;
+ parse_u32_mask(optarg, &tmpl->mark);
+ tmpl->filter_mark_kernel.val = tmpl->mark.value;
+ tmpl->filter_mark_kernel.mask = tmpl->mark.mask;
+ tmpl->filter_mark_kernel_set = true;
break;
case 'l':
case '<':
@@ -2519,9 +3126,9 @@ int main(int argc, char *argv[])
/* join "-l foo -l bar" into single bitmask object */
if (c == 'l') {
- merge_bitmasks(&tmpl.label, b);
+ merge_bitmasks(&tmpl->label, b);
} else {
- merge_bitmasks(&tmpl.label_modify, b);
+ merge_bitmasks(&tmpl->label_modify, b);
}
free(optarg2);
@@ -2554,18 +3161,31 @@ int main(int argc, char *argv[])
"unknown option `%s'", argv[optind-1]);
break;
default:
- if (h && h->parse_opts
- &&!h->parse_opts(c - h->option_offset, tmpl.ct,
- tmpl.exptuple, tmpl.mask,
- &l4flags))
+ if (h && h->parse_opts &&
+ !h->parse_opts(c - h->option_offset, tmpl->ct,
+ tmpl->exptuple, tmpl->mask,
+ &l4flags))
exit_error(PARAMETER_PROBLEM, "parse error");
break;
}
}
- /* default family */
- if (family == AF_UNSPEC)
- family = AF_INET;
+ /* default family only for the following commands */
+ if (family == AF_UNSPEC) {
+ switch (command) {
+ case CT_LIST:
+ case CT_UPDATE:
+ case CT_DELETE:
+ case CT_GET:
+ case CT_FLUSH:
+ case CT_EVENT:
+ break;
+ default:
+ family = AF_INET;
+ break;
+ }
+ }
+
/* we cannot check this combination with generic_opt_check. */
if (options & CT_OPT_ANY_NAT &&
@@ -2593,65 +3213,76 @@ int main(int argc, char *argv[])
}
}
if (!(command & CT_HELP) && h && h->final_check)
- h->final_check(l4flags, cmd, tmpl.ct);
+ h->final_check(l4flags, cmd, tmpl->ct);
- switch(command) {
+ free_options();
+
+ ct_cmd->command = command;
+ ct_cmd->cmd = cmd;
+ ct_cmd->options = options;
+ ct_cmd->family = family;
+ ct_cmd->type = type;
+ ct_cmd->protonum = protonum;
+ ct_cmd->event_mask = event_mask;
+ ct_cmd->socketbuffersize = socketbuffersize;
+}
+
+static int do_command_ct(const char *progname, struct ct_cmd *cmd,
+ struct nfct_mnl_socket *sock)
+{
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
+ struct nfct_mnl_socket *event_sock = &_event_sock;
struct nfct_filter_dump *filter_dump;
+ uint16_t nl_flags = 0;
+ int res = 0;
+ switch(cmd->command) {
case CT_LIST:
- if (type == CT_TABLE_DYING) {
- if (nfct_mnl_socket_open(0) < 0)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
+ if (cmd->type == CT_TABLE_DYING) {
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
IPCTNL_MSG_CT_GET_DYING,
- mnl_nfct_dump_cb, family);
-
- nfct_mnl_socket_close();
+ mnl_nfct_dump_cb, cmd, NULL);
break;
- } else if (type == CT_TABLE_UNCONFIRMED) {
- if (nfct_mnl_socket_open(0) < 0)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
+ } else if (cmd->type == CT_TABLE_UNCONFIRMED) {
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
IPCTNL_MSG_CT_GET_UNCONFIRMED,
- mnl_nfct_dump_cb, family);
-
- nfct_mnl_socket_close();
+ mnl_nfct_dump_cb, cmd, NULL);
break;
}
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- if (options & CT_COMPARISON &&
- options & CT_OPT_ZERO)
+ if (cmd->options & CT_COMPARISON &&
+ cmd->options & CT_OPT_ZERO)
exit_error(PARAMETER_PROBLEM, "Can't use -z with "
"filtering parameters");
- nfct_filter_init(family);
-
- nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct);
+ nfct_filter_init(cmd);
filter_dump = nfct_filter_dump_create();
if (filter_dump == NULL)
exit_error(OTHER_PROBLEM, "OOM");
- if (tmpl.filter_mark_kernel_set) {
+ if (cmd->tmpl.filter_mark_kernel_set) {
nfct_filter_dump_set_attr(filter_dump,
NFCT_FILTER_DUMP_MARK,
- &tmpl.filter_mark_kernel);
+ &cmd->tmpl.filter_mark_kernel);
}
nfct_filter_dump_set_attr_u8(filter_dump,
NFCT_FILTER_DUMP_L3NUM,
- family);
-
- if (options & CT_OPT_ZERO)
- res = nfct_query(cth, NFCT_Q_DUMP_FILTER_RESET,
- filter_dump);
- else
- res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump);
+ cmd->family);
+ if (cmd->tmpl.filter_status_kernel_set) {
+ nfct_filter_dump_set_attr(filter_dump,
+ NFCT_FILTER_DUMP_STATUS,
+ &cmd->tmpl.filter_status_kernel);
+ }
+ if (cmd->options & CT_OPT_ZERO) {
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET_CTRZERO,
+ mnl_nfct_dump_cb, cmd, filter_dump);
+ } else {
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET,
+ mnl_nfct_dump_cb, cmd, filter_dump);
+ }
nfct_filter_dump_destroy(filter_dump);
@@ -2659,17 +3290,14 @@ int main(int argc, char *argv[])
printf("</conntrack>\n");
fflush(stdout);
}
-
- nfct_close(cth);
break;
-
case EXP_LIST:
cth = nfct_open(EXPECT, 0);
if (!cth)
exit_error(OTHER_PROBLEM, "Can't open handler");
nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);
- res = nfexp_query(cth, NFCT_Q_DUMP, &family);
+ res = nfexp_query(cth, NFCT_Q_DUMP, &cmd->family);
nfct_close(cth);
if (dump_xml_header_done == 0) {
@@ -2679,127 +3307,112 @@ int main(int argc, char *argv[])
break;
case CT_CREATE:
- if ((options & CT_OPT_ORIG) && !(options & CT_OPT_REPL))
- nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_REPLY);
- else if (!(options & CT_OPT_ORIG) && (options & CT_OPT_REPL))
- nfct_setobjopt(tmpl.ct, NFCT_SOPT_SETUP_ORIGINAL);
-
- if (options & CT_OPT_MARK)
- nfct_set_attr_u32(tmpl.ct, ATTR_MARK, tmpl.mark.value);
-
- if (options & CT_OPT_ADD_LABEL)
- nfct_set_attr(tmpl.ct, ATTR_CONNLABELS,
- xnfct_bitmask_clone(tmpl.label_modify));
-
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- res = nfct_query(cth, NFCT_Q_CREATE, tmpl.ct);
- if (res != -1)
+ case CT_ADD:
+ if ((cmd->options & CT_OPT_ORIG) && !(cmd->options & CT_OPT_REPL))
+ nfct_setobjopt(cmd->tmpl.ct, NFCT_SOPT_SETUP_REPLY);
+ else if (!(cmd->options & CT_OPT_ORIG) && (cmd->options & CT_OPT_REPL))
+ nfct_setobjopt(cmd->tmpl.ct, NFCT_SOPT_SETUP_ORIGINAL);
+
+ if (cmd->options & CT_OPT_MARK)
+ nfct_set_attr_u32(cmd->tmpl.ct, ATTR_MARK, cmd->tmpl.mark.value);
+
+ if (cmd->options & CT_OPT_ADD_LABEL)
+ nfct_set_attr(cmd->tmpl.ct, ATTR_CONNLABELS,
+ xnfct_bitmask_clone(cmd->tmpl.label_modify));
+
+ if (cmd->command == CT_CREATE)
+ nl_flags = NLM_F_EXCL;
+
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family,
+ IPCTNL_MSG_CT_NEW,
+ NLM_F_CREATE | NLM_F_ACK | nl_flags,
+ NULL, cmd->tmpl.ct, NULL);
+ if (res >= 0)
counter++;
- nfct_close(cth);
break;
case EXP_CREATE:
- nfexp_set_attr(tmpl.exp, ATTR_EXP_MASTER, tmpl.ct);
- nfexp_set_attr(tmpl.exp, ATTR_EXP_EXPECTED, tmpl.exptuple);
- nfexp_set_attr(tmpl.exp, ATTR_EXP_MASK, tmpl.mask);
+ nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_MASTER, cmd->tmpl.ct);
+ nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_EXPECTED, cmd->tmpl.exptuple);
+ nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_MASK, cmd->tmpl.mask);
cth = nfct_open(EXPECT, 0);
if (!cth)
exit_error(OTHER_PROBLEM, "Can't open handler");
- res = nfexp_query(cth, NFCT_Q_CREATE, tmpl.exp);
+ res = nfexp_query(cth, NFCT_Q_CREATE, cmd->tmpl.exp);
nfct_close(cth);
break;
case CT_UPDATE:
- cth = nfct_open(CONNTRACK, 0);
- /* internal handler for delete_cb, otherwise we hit EILSEQ */
- ith = nfct_open(CONNTRACK, 0);
- if (!cth || !ith)
+ if (nfct_mnl_socket_check_open(modifier_sock, 0) < 0)
exit_error(OTHER_PROBLEM, "Can't open handler");
- nfct_filter_init(family);
-
- nfct_callback_register(cth, NFCT_T_ALL, update_cb, tmpl.ct);
-
- res = nfct_query(cth, NFCT_Q_DUMP, &family);
- nfct_close(ith);
- nfct_close(cth);
+ nfct_filter_init(cmd);
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET, mnl_nfct_update_cb,
+ cmd, NULL);
break;
-
+
case CT_DELETE:
- cth = nfct_open(CONNTRACK, 0);
- ith = nfct_open(CONNTRACK, 0);
- if (!cth || !ith)
+ if (nfct_mnl_socket_check_open(modifier_sock, 0) < 0)
exit_error(OTHER_PROBLEM, "Can't open handler");
- nfct_filter_init(family);
-
- nfct_callback_register(cth, NFCT_T_ALL, delete_cb, tmpl.ct);
+ nfct_filter_init(cmd);
filter_dump = nfct_filter_dump_create();
if (filter_dump == NULL)
exit_error(OTHER_PROBLEM, "OOM");
- if (tmpl.filter_mark_kernel_set) {
+ if (cmd->tmpl.filter_mark_kernel_set) {
nfct_filter_dump_set_attr(filter_dump,
NFCT_FILTER_DUMP_MARK,
- &tmpl.filter_mark_kernel);
+ &cmd->tmpl.filter_mark_kernel);
}
nfct_filter_dump_set_attr_u8(filter_dump,
NFCT_FILTER_DUMP_L3NUM,
- family);
+ cmd->family);
- res = nfct_query(cth, NFCT_Q_DUMP_FILTER, filter_dump);
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
+ IPCTNL_MSG_CT_GET, mnl_nfct_delete_cb,
+ cmd, filter_dump);
nfct_filter_dump_destroy(filter_dump);
-
- nfct_close(ith);
- nfct_close(cth);
break;
case EXP_DELETE:
- nfexp_set_attr(tmpl.exp, ATTR_EXP_EXPECTED, tmpl.ct);
+ nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_EXPECTED, cmd->tmpl.ct);
cth = nfct_open(EXPECT, 0);
if (!cth)
exit_error(OTHER_PROBLEM, "Can't open handler");
- res = nfexp_query(cth, NFCT_Q_DESTROY, tmpl.exp);
+ res = nfexp_query(cth, NFCT_Q_DESTROY, cmd->tmpl.exp);
nfct_close(cth);
break;
case CT_GET:
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
-
- nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct);
- res = nfct_query(cth, NFCT_Q_GET, tmpl.ct);
- nfct_close(cth);
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family,
+ IPCTNL_MSG_CT_GET, 0,
+ mnl_nfct_dump_cb, cmd->tmpl.ct, cmd);
break;
case EXP_GET:
- nfexp_set_attr(tmpl.exp, ATTR_EXP_MASTER, tmpl.ct);
+ nfexp_set_attr(cmd->tmpl.exp, ATTR_EXP_MASTER, cmd->tmpl.ct);
cth = nfct_open(EXPECT, 0);
if (!cth)
exit_error(OTHER_PROBLEM, "Can't open handler");
nfexp_callback_register(cth, NFCT_T_ALL, dump_exp_cb, NULL);
- res = nfexp_query(cth, NFCT_Q_GET, tmpl.exp);
+ res = nfexp_query(cth, NFCT_Q_GET, cmd->tmpl.exp);
nfct_close(cth);
break;
case CT_FLUSH:
- cth = nfct_open(CONNTRACK, 0);
- if (!cth)
- exit_error(OTHER_PROBLEM, "Can't open handler");
- res = nfct_query(cth, NFCT_Q_FLUSH, &family);
- nfct_close(cth);
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, cmd->family,
+ IPCTNL_MSG_CT_DELETE, NLM_F_ACK, NULL, NULL, NULL);
+
fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
fprintf(stderr,"connection tracking table has been emptied.\n");
break;
@@ -2808,26 +3421,27 @@ int main(int argc, char *argv[])
cth = nfct_open(EXPECT, 0);
if (!cth)
exit_error(OTHER_PROBLEM, "Can't open handler");
- res = nfexp_query(cth, NFCT_Q_FLUSH, &family);
+ res = nfexp_query(cth, NFCT_Q_FLUSH, &cmd->family);
nfct_close(cth);
fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
fprintf(stderr,"expectation table has been emptied.\n");
break;
case CT_EVENT:
- if (options & CT_OPT_EVENT_MASK) {
+ if (cmd->options & CT_OPT_EVENT_MASK) {
unsigned int nl_events = 0;
- if (event_mask & CT_EVENT_F_NEW)
+ if (cmd->event_mask & CT_EVENT_F_NEW)
nl_events |= NF_NETLINK_CONNTRACK_NEW;
- if (event_mask & CT_EVENT_F_UPD)
+ if (cmd->event_mask & CT_EVENT_F_UPD)
nl_events |= NF_NETLINK_CONNTRACK_UPDATE;
- if (event_mask & CT_EVENT_F_DEL)
+ if (cmd->event_mask & CT_EVENT_F_DEL)
nl_events |= NF_NETLINK_CONNTRACK_DESTROY;
- res = nfct_mnl_socket_open(nl_events);
+ res = nfct_mnl_socket_open(event_sock, nl_events);
} else {
- res = nfct_mnl_socket_open(NF_NETLINK_CONNTRACK_NEW |
+ res = nfct_mnl_socket_open(event_sock,
+ NF_NETLINK_CONNTRACK_NEW |
NF_NETLINK_CONNTRACK_UPDATE |
NF_NETLINK_CONNTRACK_DESTROY);
}
@@ -2835,27 +3449,29 @@ int main(int argc, char *argv[])
if (res < 0)
exit_error(OTHER_PROBLEM, "Can't open netlink socket");
- if (options & CT_OPT_BUFFERSIZE) {
+ if (cmd->options & CT_OPT_BUFFERSIZE) {
+ size_t socketbuffersize = cmd->socketbuffersize;
+
socklen_t socklen = sizeof(socketbuffersize);
- res = setsockopt(mnl_socket_get_fd(sock.mnl),
+ res = setsockopt(mnl_socket_get_fd(sock->mnl),
SOL_SOCKET, SO_RCVBUFFORCE,
&socketbuffersize,
sizeof(socketbuffersize));
if (res < 0) {
- setsockopt(mnl_socket_get_fd(sock.mnl),
+ setsockopt(mnl_socket_get_fd(sock->mnl),
SOL_SOCKET, SO_RCVBUF,
&socketbuffersize,
- socketbuffersize);
+ sizeof(socketbuffersize));
}
- getsockopt(mnl_socket_get_fd(sock.mnl), SOL_SOCKET,
+ getsockopt(mnl_socket_get_fd(sock->mnl), SOL_SOCKET,
SO_RCVBUF, &socketbuffersize, &socklen);
fprintf(stderr, "NOTICE: Netlink socket buffer size "
"has been set to %zu bytes.\n",
socketbuffersize);
}
- nfct_filter_init(family);
+ nfct_filter_init(cmd);
signal(SIGINT, event_sighandler);
signal(SIGTERM, event_sighandler);
@@ -2863,7 +3479,7 @@ int main(int argc, char *argv[])
while (1) {
char buf[MNL_SOCKET_BUFFER_SIZE];
- res = mnl_socket_recvfrom(sock.mnl, buf, sizeof(buf));
+ res = mnl_socket_recvfrom(event_sock->mnl, buf, sizeof(buf));
if (res < 0) {
if (errno == ENOBUFS) {
fprintf(stderr,
@@ -2880,20 +3496,20 @@ int main(int argc, char *argv[])
strerror(errno));
break;
}
- res = mnl_cb_run(buf, res, 0, 0, event_cb, tmpl.ct);
+ mnl_cb_run(buf, res, 0, 0, event_cb, cmd);
}
- mnl_socket_close(sock.mnl);
+ mnl_socket_close(event_sock->mnl);
break;
case EXP_EVENT:
- if (options & CT_OPT_EVENT_MASK) {
+ if (cmd->options & CT_OPT_EVENT_MASK) {
unsigned int nl_events = 0;
- if (event_mask & CT_EVENT_F_NEW)
+ if (cmd->event_mask & CT_EVENT_F_NEW)
nl_events |= NF_NETLINK_CONNTRACK_EXP_NEW;
- if (event_mask & CT_EVENT_F_UPD)
+ if (cmd->event_mask & CT_EVENT_F_UPD)
nl_events |= NF_NETLINK_CONNTRACK_EXP_UPDATE;
- if (event_mask & CT_EVENT_F_DEL)
+ if (cmd->event_mask & CT_EVENT_F_DEL)
nl_events |= NF_NETLINK_CONNTRACK_EXP_DESTROY;
cth = nfct_open(CONNTRACK, nl_events);
@@ -2916,20 +3532,14 @@ int main(int argc, char *argv[])
/* If we fail with netlink, fall back to /proc to ensure
* backward compatibility.
*/
- if (nfct_mnl_socket_open(0) < 0)
- goto try_proc_count;
-
- res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK,
- IPCTNL_MSG_CT_GET_STATS,
- nfct_global_stats_cb, AF_UNSPEC);
-
- nfct_mnl_socket_close();
+ res = nfct_mnl_request(sock, NFNL_SUBSYS_CTNETLINK, AF_UNSPEC,
+ IPCTNL_MSG_CT_GET_STATS, 0,
+ nfct_global_stats_cb, NULL, NULL);
/* don't look at /proc, we got the information via ctnetlink */
if (res >= 0)
break;
-try_proc_count:
{
#define NF_CONNTRACK_COUNT_PROC "/proc/sys/net/netfilter/nf_conntrack_count"
FILE *fd;
@@ -2953,7 +3563,7 @@ try_proc_count:
exit_error(OTHER_PROBLEM, "Can't open handler");
nfexp_callback_register(cth, NFCT_T_ALL, count_exp_cb, NULL);
- res = nfexp_query(cth, NFCT_Q_DUMP, &family);
+ res = nfexp_query(cth, NFCT_Q_DUMP, &cmd->family);
nfct_close(cth);
printf("%d\n", counter);
break;
@@ -2961,14 +3571,9 @@ try_proc_count:
/* If we fail with netlink, fall back to /proc to ensure
* backward compatibility.
*/
- if (nfct_mnl_socket_open(0) < 0)
- goto try_proc;
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK,
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK,
IPCTNL_MSG_CT_GET_STATS_CPU,
- nfct_stats_cb, AF_UNSPEC);
-
- nfct_mnl_socket_close();
+ nfct_stats_cb, NULL, NULL);
/* don't look at /proc, we got the information via ctnetlink */
if (res >= 0)
@@ -2980,14 +3585,9 @@ try_proc_count:
/* If we fail with netlink, fall back to /proc to ensure
* backward compatibility.
*/
- if (nfct_mnl_socket_open(0) < 0)
- goto try_proc;
-
- res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP,
+ res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK_EXP,
IPCTNL_MSG_EXP_GET_STATS_CPU,
- nfexp_stats_cb, AF_UNSPEC);
-
- nfct_mnl_socket_close();
+ nfexp_stats_cb, NULL, NULL);
/* don't look at /proc, we got the information via ctnetlink */
if (res >= 0)
@@ -3000,30 +3600,263 @@ try_proc:
printf("%s v%s (conntrack-tools)\n", PROGNAME, VERSION);
break;
case CT_HELP:
- usage(argv[0]);
- if (options & CT_OPT_PROTO)
- extension_help(h, protonum);
+ usage(progname);
+ if (cmd->options & CT_OPT_PROTO)
+ extension_help(h, cmd->protonum);
break;
default:
- usage(argv[0]);
+ usage(progname);
break;
}
if (res < 0)
exit_error(OTHER_PROBLEM, "Operation failed: %s",
- err2str(errno, command));
+ err2str(errno, cmd->command));
- free_tmpl_objects();
- free_options();
+ free_tmpl_objects(&cmd->tmpl);
if (labelmap)
nfct_labelmap_destroy(labelmap);
- if (command && exit_msg[cmd][0]) {
- fprintf(stderr, "%s v%s (conntrack-tools): ",PROGNAME,VERSION);
- fprintf(stderr, exit_msg[cmd], counter);
- if (counter == 0 && !(command & (CT_LIST | EXP_LIST)))
- return EXIT_FAILURE;
+ return EXIT_SUCCESS;
+}
+
+/* Taken from iptables/xshared.c:
+ * - add_argv()
+ * - add_param_to_argv()
+ * - free_argv()
+ */
+#define MAX_ARGC 255
+struct argv_store {
+ int argc;
+ char *argv[MAX_ARGC];
+ int argvattr[MAX_ARGC];
+};
+
+/* function adding one argument to store, updating argc
+ * returns if argument added, does not return otherwise */
+static void add_argv(struct argv_store *store, const char *what, int quoted)
+{
+ if (store->argc + 1 >= MAX_ARGC)
+ exit_error(PARAMETER_PROBLEM, "too many arguments");
+ if (!what)
+ exit_error(PARAMETER_PROBLEM, "invalid NULL argument");
+
+ store->argv[store->argc] = strdup(what);
+ store->argvattr[store->argc] = quoted;
+ store->argv[++store->argc] = NULL;
+}
+
+static void free_argv(struct argv_store *store)
+{
+ while (store->argc) {
+ store->argc--;
+ free(store->argv[store->argc]);
+ store->argvattr[store->argc] = 0;
}
+}
- return EXIT_SUCCESS;
+struct ct_param_buf {
+ char buffer[1024];
+ int len;
+};
+
+static void add_param(struct ct_param_buf *param, const char *curchar)
+{
+ param->buffer[param->len++] = *curchar;
+ if (param->len >= (int)sizeof(param->buffer))
+ exit_error(PARAMETER_PROBLEM, "Parameter too long!");
+}
+
+static void add_param_to_argv(struct argv_store *store, char *parsestart)
+{
+ int quote_open = 0, escaped = 0, quoted = 0;
+ struct ct_param_buf param = {};
+ char *curchar;
+
+ /* After fighting with strtok enough, here's now
+ * a 'real' parser. According to Rusty I'm now no
+ * longer a real hacker, but I can live with that */
+
+ for (curchar = parsestart; *curchar; curchar++) {
+ if (quote_open) {
+ if (escaped) {
+ add_param(&param, curchar);
+ escaped = 0;
+ continue;
+ } else if (*curchar == '\\') {
+ escaped = 1;
+ continue;
+ } else if (*curchar == '"') {
+ quote_open = 0;
+ } else {
+ add_param(&param, curchar);
+ continue;
+ }
+ } else {
+ if (*curchar == '"') {
+ quote_open = 1;
+ quoted = 1;
+ continue;
+ }
+ }
+
+ switch (*curchar) {
+ case '"':
+ break;
+ case ' ':
+ case '\t':
+ case '\n':
+ if (!param.len) {
+ /* two spaces? */
+ continue;
+ }
+ break;
+ default:
+ /* regular character, copy to buffer */
+ add_param(&param, curchar);
+ continue;
+ }
+
+ param.buffer[param.len] = '\0';
+ add_argv(store, param.buffer, quoted);
+ param.len = 0;
+ quoted = 0;
+ }
+ if (param.len) {
+ param.buffer[param.len] = '\0';
+ add_argv(store, param.buffer, 0);
+ }
+}
+
+static void ct_file_parse_line(struct list_head *cmd_list,
+ const char *progname, char *buffer)
+{
+ struct argv_store store = {};
+ struct ct_cmd *ct_cmd;
+
+ /* skip prepended tabs and spaces */
+ for (; *buffer == ' ' || *buffer == '\t'; buffer++);
+
+ if (buffer[0] == '\n' ||
+ buffer[0] == '#')
+ return;
+
+ add_argv(&store, progname, false);
+ add_param_to_argv(&store, buffer);
+
+ ct_cmd = calloc(1, sizeof(*ct_cmd));
+ if (!ct_cmd)
+ exit_error(OTHER_PROBLEM, "OOM");
+
+ do_parse(ct_cmd, store.argc, store.argv);
+ free_argv(&store);
+
+ list_add_tail(&ct_cmd->list, cmd_list);
+}
+
+static void ct_parse_file(struct list_head *cmd_list, const char *progname,
+ const char *file_name)
+{
+ char buffer[10240] = {};
+ FILE *file;
+
+ if (!strcmp(file_name, "-"))
+ file_name = "/dev/stdin";
+
+ file = fopen(file_name, "r");
+ if (!file)
+ exit_error(PARAMETER_PROBLEM,
+ "Failed to open file %s for reading", file_name);
+
+ while (fgets(buffer, sizeof(buffer), file))
+ ct_file_parse_line(cmd_list, progname, buffer);
+
+ fclose(file);
+}
+
+static struct {
+ uint32_t command;
+ const char *text;
+} ct_unsupp_cmd_parse_file[] = {
+ { CT_LIST, "-L" },
+ { CT_GET, "-G" },
+ { CT_EVENT, "-E" },
+ { CT_VERSION, "-V" },
+ { CT_HELP, "-h" },
+ { EXP_LIST, "-L expect" },
+ { EXP_CREATE, "-C expect" },
+ { EXP_DELETE, "-D expect" },
+ { EXP_GET, "-G expect" },
+ { EXP_FLUSH, "-F expect" },
+ { EXP_EVENT, "-E expect" },
+ { CT_COUNT, "-C" },
+ { EXP_COUNT, "-C expect" },
+ { CT_STATS, "-S" },
+ { EXP_STATS, "-S expect" },
+ { 0, NULL },
+};
+
+static const char *ct_unsupp_cmd_file(const struct ct_cmd *cmd)
+{
+ int i;
+
+ for (i = 0; ct_unsupp_cmd_parse_file[i].text; i++) {
+ if (cmd->command == ct_unsupp_cmd_parse_file[i].command)
+ return ct_unsupp_cmd_parse_file[i].text;
+ }
+
+ return "unknown";
+}
+
+int main(int argc, char *argv[])
+{
+ struct nfct_mnl_socket *modifier_sock = &_modifier_sock;
+ struct nfct_mnl_socket *sock = &_sock;
+ struct ct_cmd *cmd, *next;
+ LIST_HEAD(cmd_list);
+ int res = 0;
+
+ register_tcp();
+ register_udp();
+ register_udplite();
+ register_sctp();
+ register_dccp();
+ register_icmp();
+ register_icmpv6();
+ register_gre();
+ register_unknown();
+
+ if (nfct_mnl_socket_open(sock, 0) < 0)
+ exit_error(OTHER_PROBLEM, "Can't open handler");
+
+ if (argc > 2 &&
+ (!strcmp(argv[1], "-R") || !strcmp(argv[1], "--load-file"))) {
+ ct_parse_file(&cmd_list, argv[0], argv[2]);
+
+ list_for_each_entry(cmd, &cmd_list, list) {
+ if (!(cmd->command &
+ (CT_CREATE | CT_ADD | CT_UPDATE | CT_DELETE | CT_FLUSH)))
+ exit_error(PARAMETER_PROBLEM,
+ "Cannot use command `%s' with --load-file",
+ ct_unsupp_cmd_file(cmd));
+ }
+ list_for_each_entry_safe(cmd, next, &cmd_list, list) {
+ res |= do_command_ct(argv[0], cmd, sock);
+ list_del(&cmd->list);
+ free(cmd);
+ }
+ } else {
+ cmd = calloc(1, sizeof(*cmd));
+ if (!cmd)
+ exit_error(OTHER_PROBLEM, "OOM");
+
+ do_parse(cmd, argc, argv);
+ res = do_command_ct(argv[0], cmd, sock);
+ res |= print_stats(cmd);
+ free(cmd);
+ }
+ nfct_mnl_socket_close(sock);
+ nfct_mnl_socket_check_close(modifier_sock);
+
+ return res < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/cthelper.c b/src/cthelper.c
index f01c509..f133e4b 100644
--- a/src/cthelper.c
+++ b/src/cthelper.c
@@ -386,6 +386,10 @@ static int cthelper_setup(struct ctd_helper_instance *cur)
nfct_helper_attr_set_u32(t, NFCTH_ATTR_QUEUE_NUM, cur->queue_num);
nfct_helper_attr_set_u16(t, NFCTH_ATTR_PROTO_L3NUM, cur->l3proto);
nfct_helper_attr_set_u8(t, NFCTH_ATTR_PROTO_L4NUM, cur->l4proto);
+ if (CONFIG(cthelper).setup) {
+ nfct_helper_attr_set_u32(t, NFCTH_ATTR_PRIV_DATA_LEN,
+ cur->helper->priv_data_len);
+ }
nfct_helper_attr_set_u32(t, NFCTH_ATTR_STATUS,
NFCT_HELPER_STATUS_ENABLED);
diff --git a/src/external_inject.c b/src/external_inject.c
index 0ad3478..920d7c4 100644
--- a/src/external_inject.c
+++ b/src/external_inject.c
@@ -76,12 +76,14 @@ retry:
}
}
external_inject_stat.add_fail++;
- dlog(LOG_ERR, "inject-add1: %s", strerror(errno));
+ dlog(LOG_WARNING,
+ "could not add new ct entry, even when deleting it first: %s",
+ strerror(errno));
dlog_ct(STATE(log), ct, NFCT_O_PLAIN);
return;
}
external_inject_stat.add_fail++;
- dlog(LOG_ERR, "inject-add2: %s", strerror(errno));
+ dlog(LOG_WARNING, "could not add new ct entry: %s", strerror(errno));
dlog_ct(STATE(log), ct, NFCT_O_PLAIN);
} else {
external_inject_stat.add_ok++;
@@ -102,7 +104,9 @@ static void external_inject_ct_upd(struct nf_conntrack *ct)
if (errno == ENOENT) {
if (nl_create_conntrack(inject, ct, 0) == -1) {
external_inject_stat.upd_fail++;
- dlog(LOG_ERR, "inject-upd1: %s", strerror(errno));
+ dlog(LOG_WARNING,
+ "could not update ct entry, even if creating it instead: %s",
+ strerror(errno));
dlog_ct(STATE(log), ct, NFCT_O_PLAIN);
} else {
external_inject_stat.upd_ok++;
@@ -117,7 +121,9 @@ static void external_inject_ct_upd(struct nf_conntrack *ct)
if (ret == 0 || (ret == -1 && errno == ENOENT)) {
if (nl_create_conntrack(inject, ct, 0) == -1) {
external_inject_stat.upd_fail++;
- dlog(LOG_ERR, "inject-upd2: %s", strerror(errno));
+ dlog(LOG_WARNING,
+ "could not update ct entry, even when deleting it first: %s",
+ strerror(errno));
dlog_ct(STATE(log), ct, NFCT_O_PLAIN);
} else {
external_inject_stat.upd_ok++;
@@ -125,7 +131,7 @@ static void external_inject_ct_upd(struct nf_conntrack *ct)
return;
}
external_inject_stat.upd_fail++;
- dlog(LOG_ERR, "inject-upd3: %s", strerror(errno));
+ dlog(LOG_WARNING, "could not update ct entry: %s", strerror(errno));
dlog_ct(STATE(log), ct, NFCT_O_PLAIN);
}
@@ -134,7 +140,7 @@ static void external_inject_ct_del(struct nf_conntrack *ct)
if (nl_destroy_conntrack(inject, ct) == -1) {
if (errno != ENOENT) {
external_inject_stat.del_fail++;
- dlog(LOG_ERR, "inject-del: %s", strerror(errno));
+ dlog(LOG_WARNING, "could not destroy ct entry: %s", strerror(errno));
dlog_ct(STATE(log), ct, NFCT_O_PLAIN);
}
} else {
@@ -200,12 +206,15 @@ retry:
}
}
exp_external_inject_stat.add_fail++;
- dlog(LOG_ERR, "inject-add1: %s", strerror(errno));
+ dlog(LOG_WARNING,
+ "could not add new exp entry, even when deleting it first: %s",
+ strerror(errno));
dlog_exp(STATE(log), exp, NFCT_O_PLAIN);
return;
}
exp_external_inject_stat.add_fail++;
- dlog(LOG_ERR, "inject-add2: %s", strerror(errno));
+ dlog(LOG_WARNING,
+ "could not add new exp entry: %s", strerror(errno));
dlog_exp(STATE(log), exp, NFCT_O_PLAIN);
} else {
exp_external_inject_stat.add_ok++;
@@ -217,7 +226,8 @@ static void external_inject_exp_del(struct nf_expect *exp)
if (nl_destroy_expect(inject, exp) == -1) {
if (errno != ENOENT) {
exp_external_inject_stat.del_fail++;
- dlog(LOG_ERR, "inject-del: %s", strerror(errno));
+ dlog(LOG_WARNING,
+ "could not delete exp entry: %s", strerror(errno));
dlog_exp(STATE(log), exp, NFCT_O_PLAIN);
}
} else {
diff --git a/src/filter.c b/src/filter.c
index 6577102..ee316e7 100644
--- a/src/filter.c
+++ b/src/filter.c
@@ -476,7 +476,7 @@ struct exp_filter *exp_filter_create(void)
struct exp_filter_item {
struct list_head head;
- char helper_name[NFCT_HELPER_NAME_MAX];
+ char helper_name[NFCT_HELPER_NAME_MAX + 1];
};
/* this is ugly, but it simplifies read_config_yy.y */
diff --git a/src/hash.c b/src/hash.c
index fe6a047..a0f240c 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -55,6 +55,7 @@ hashtable_create(int hashsize, int limit,
void hashtable_destroy(struct hashtable *h)
{
+ hashtable_flush(h);
free(h);
}
diff --git a/src/helpers.c b/src/helpers.c
index 3e4e6c8..8ca78dc 100644
--- a/src/helpers.c
+++ b/src/helpers.c
@@ -26,8 +26,7 @@ void helper_register(struct ctd_helper *helper)
list_add(&helper->head, &helper_list);
}
-static struct ctd_helper *
-__helper_find(const char *helper_name, uint8_t l4proto)
+struct ctd_helper *__helper_find(const char *helper_name, uint8_t l4proto)
{
struct ctd_helper *cur, *helper = NULL;
diff --git a/src/helpers/Makefile.am b/src/helpers/Makefile.am
index e4f10c9..e458ab4 100644
--- a/src/helpers/Makefile.am
+++ b/src/helpers/Makefile.am
@@ -11,7 +11,7 @@ pkglib_LTLIBRARIES = ct_helper_amanda.la \
ct_helper_slp.la \
ct_helper_ssdp.la
-HELPER_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) $(LAZY_LDFLAGS)
+HELPER_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS)
HELPER_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS)
ct_helper_amanda_la_SOURCES = amanda.c
diff --git a/src/helpers/amanda.c b/src/helpers/amanda.c
index faee1cd..234d511 100644
--- a/src/helpers/amanda.c
+++ b/src/helpers/amanda.c
@@ -24,6 +24,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/dhcpv6.c b/src/helpers/dhcpv6.c
index f87b6ce..4c5676d 100644
--- a/src/helpers/dhcpv6.c
+++ b/src/helpers/dhcpv6.c
@@ -25,6 +25,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/ftp.c b/src/helpers/ftp.c
index c3aa284..2b34534 100644
--- a/src/helpers/ftp.c
+++ b/src/helpers/ftp.c
@@ -30,22 +30,15 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
-static bool loose; /* XXX: export this as config option. */
-
-#define NUM_SEQ_TO_REMEMBER 2
+#include "helpers/ftp.h"
-/* This structure exists only once per master */
-struct ftp_info {
- /* Valid seq positions for cmd matching after newline */
- uint32_t seq_aft_nl[MYCT_DIR_MAX][NUM_SEQ_TO_REMEMBER];
- /* 0 means seq_match_aft_nl not set */
- int seq_aft_nl_num[MYCT_DIR_MAX];
-};
+static bool loose; /* XXX: export this as config option. */
enum nf_ct_ftp_type {
/* PORT command from client */
@@ -339,23 +332,21 @@ static int nf_nat_ftp_fmt_cmd(enum nf_ct_ftp_type type,
char *buffer, size_t buflen,
uint32_t addr, uint16_t port)
{
+ union {
+ unsigned char c[4];
+ uint32_t d;
+ } tmp;
+
+ tmp.d = addr;
switch (type) {
case NF_CT_FTP_PORT:
case NF_CT_FTP_PASV:
return snprintf(buffer, buflen, "%u,%u,%u,%u,%u,%u",
- ((unsigned char *)&addr)[0],
- ((unsigned char *)&addr)[1],
- ((unsigned char *)&addr)[2],
- ((unsigned char *)&addr)[3],
- port >> 8,
- port & 0xFF);
+ tmp.c[0], tmp.c[1], tmp.c[2], tmp.c[3],
+ port >> 8, port & 0xFF);
case NF_CT_FTP_EPRT:
return snprintf(buffer, buflen, "|1|%u.%u.%u.%u|%u|",
- ((unsigned char *)&addr)[0],
- ((unsigned char *)&addr)[1],
- ((unsigned char *)&addr)[2],
- ((unsigned char *)&addr)[3],
- port);
+ tmp.c[0], tmp.c[1], tmp.c[2], tmp.c[3], port);
case NF_CT_FTP_EPSV:
return snprintf(buffer, buflen, "|||%u|", port);
}
diff --git a/src/helpers/rpc.c b/src/helpers/rpc.c
index bd24dd3..732e9ba 100644
--- a/src/helpers/rpc.c
+++ b/src/helpers/rpc.c
@@ -35,26 +35,18 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
+#include "helpers/rpc.h"
+
/* RFC 1050: RPC: Remote Procedure Call Protocol Specification Version 2 */
/* RFC 1014: XDR: External Data Representation Standard */
#define SUPPORTED_RPC_VERSION 2
-struct rpc_info {
- /* XID */
- uint32_t xid;
- /* program */
- uint32_t pm_prog;
- /* program version */
- uint32_t pm_vers;
- /* transport protocol: TCP|UDP */
- uint32_t pm_prot;
-};
-
/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int
diff --git a/src/helpers/sane.c b/src/helpers/sane.c
index c30f4ba..ebcb24c 100644
--- a/src/helpers/sane.c
+++ b/src/helpers/sane.c
@@ -34,15 +34,12 @@
#include <netinet/tcp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
-
-enum sane_state {
- SANE_STATE_NORMAL,
- SANE_STATE_START_REQUESTED,
-};
+#include "helpers/sane.h"
struct sane_request {
uint32_t RPC_code;
@@ -60,10 +57,6 @@ struct sane_reply_net_start {
/* other fields aren't interesting for conntrack */
};
-struct nf_ct_sane_master {
- enum sane_state state;
-};
-
static int
sane_helper_cb(struct pkt_buff *pkt, uint32_t protoff,
struct myct *myct, uint32_t ctinfo)
diff --git a/src/helpers/slp.c b/src/helpers/slp.c
index b8339d6..a53485a 100644
--- a/src/helpers/slp.c
+++ b/src/helpers/slp.c
@@ -28,6 +28,7 @@
#include "myct.h"
#include "log.h"
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <linux/netfilter.h>
diff --git a/src/helpers/ssdp.c b/src/helpers/ssdp.c
index 58658e3..527892c 100644
--- a/src/helpers/ssdp.c
+++ b/src/helpers/ssdp.c
@@ -48,12 +48,12 @@
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>
-#include <netinet/ip.h>
#define _GNU_SOURCE
#include <netinet/tcp.h>
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
@@ -158,11 +158,9 @@ static int handle_ssdp_new(struct pkt_buff *pkt, uint32_t protoff,
{
int ret = NF_ACCEPT;
union nfct_attr_grp_addr daddr, saddr, taddr;
- struct iphdr *net_hdr = (struct iphdr *)pktb_network_header(pkt);
int good_packet = 0;
struct nf_expect *exp;
uint16_t port;
- unsigned int dataoff;
void *sb_ptr;
cthelper_get_addr_dst(myct->ct, MYCT_DIR_ORIG, &daddr);
@@ -200,13 +198,12 @@ static int handle_ssdp_new(struct pkt_buff *pkt, uint32_t protoff,
}
/* No data? Ignore */
- dataoff = net_hdr->ihl*4 + sizeof(struct udphdr);
- if (dataoff >= pktb_len(pkt)) {
+ if (protoff + sizeof(struct udphdr) >= pktb_len(pkt)) {
pr_debug("ssdp_help: UDP payload too small for M-SEARCH; ignoring\n");
return NF_ACCEPT;
}
- sb_ptr = pktb_network_header(pkt) + dataoff;
+ sb_ptr = pktb_network_header(pkt) + protoff + sizeof(struct udphdr);
if (memcmp(sb_ptr, SSDP_M_SEARCH, SSDP_M_SEARCH_SIZE) != 0) {
pr_debug("ssdp_help: UDP payload does not begin with 'M-SEARCH'; ignoring\n");
@@ -259,7 +256,6 @@ static int find_hdr(const char *name, const uint8_t *data, int data_len,
data += i+2;
}
- data_len -= name_len;
data += name_len;
if (pos)
*pos = data;
diff --git a/src/helpers/tftp.c b/src/helpers/tftp.c
index 70dd28a..e61195f 100644
--- a/src/helpers/tftp.c
+++ b/src/helpers/tftp.c
@@ -20,6 +20,7 @@
#include <netinet/udp.h>
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_udp.h>
#include <libnetfilter_queue/pktbuff.h>
diff --git a/src/helpers/tns.c b/src/helpers/tns.c
index 2b4fed4..5692f29 100644
--- a/src/helpers/tns.c
+++ b/src/helpers/tns.c
@@ -23,11 +23,14 @@
#include <libmnl/libmnl.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
+#include <linux/netfilter/nfnetlink_queue.h>
#include <libnetfilter_queue/libnetfilter_queue.h>
#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
#include <libnetfilter_queue/pktbuff.h>
#include <linux/netfilter.h>
+#include "helpers/tns.h"
+
/* TNS SQL*Net Version 2 */
enum tns_types {
TNS_TYPE_CONNECT = 1,
@@ -57,11 +60,6 @@ struct tns_redirect {
uint16_t data_len;
};
-struct tns_info {
- /* Scan next DATA|REDIRECT packet */
- bool parse;
-};
-
static int try_number(const char *data, size_t dlen, uint32_t array[],
int array_size, char sep, char term)
{
diff --git a/src/main.c b/src/main.c
index 31e0eed..c6b2600 100644
--- a/src/main.c
+++ b/src/main.c
@@ -175,7 +175,7 @@ int main(int argc, char *argv[])
}
show_usage(argv[0]);
dlog(LOG_ERR, "Missing config filename");
- break;
+ exit(EXIT_FAILURE);
case 'F':
set_operation_mode(&type, REQUEST, argv);
i = set_action_by_table(i, argc, argv,
@@ -309,8 +309,7 @@ int main(int argc, char *argv[])
default:
show_usage(argv[0]);
dlog(LOG_ERR, "Unknown option: %s", argv[i]);
- return 0;
- break;
+ exit(EXIT_FAILURE);
}
}
@@ -319,7 +318,7 @@ int main(int argc, char *argv[])
umask(0177);
- if ((ret = init_config(config_file)) == -1) {
+ if (init_config(config_file) == -1) {
dlog(LOG_ERR, "can't open config file `%s'", config_file);
exit(EXIT_FAILURE);
}
diff --git a/src/network.c b/src/network.c
index 13db37c..2560d97 100644
--- a/src/network.c
+++ b/src/network.c
@@ -113,7 +113,7 @@ void nethdr_track_update_seq(uint32_t seq)
STATE_SYNC(last_seq_recv) = seq;
}
-int nethdr_track_is_seq_set()
+int nethdr_track_is_seq_set(void)
{
return local_seq_set;
}
diff --git a/src/nfct-extensions/helper.c b/src/nfct-extensions/helper.c
index e5d8d0a..894bf26 100644
--- a/src/nfct-extensions/helper.c
+++ b/src/nfct-extensions/helper.c
@@ -180,7 +180,7 @@ static int nfct_cmd_helper_add(struct mnl_socket *nl, int argc, char *argv[])
return -1;
}
- helper = helper_find(CONNTRACKD_LIB_DIR, argv[3], l4proto, RTLD_LAZY);
+ helper = __helper_find(argv[3], l4proto);
if (helper == NULL) {
nfct_perror("that helper is not supported");
return -1;
@@ -430,7 +430,7 @@ nfct_cmd_helper_disable(struct mnl_socket *nl, int argc, char *argv[])
return -1;
}
- helper = helper_find(CONNTRACKD_LIB_DIR, argv[3], l4proto, RTLD_LAZY);
+ helper = __helper_find(argv[3], l4proto);
if (helper == NULL) {
nfct_perror("that helper is not supported");
return -1;
@@ -468,7 +468,187 @@ static struct nfct_extension helper = {
.parse_params = nfct_helper_parse_params,
};
+/*
+ * supported helpers: to set up helpers via nfct, the following definitions are
+ * provided for backward compatibility reasons since conntrackd does not depend
+ * on nfct anymore to set up the userspace helpers.
+ */
+
+static struct ctd_helper amanda_helper = {
+ .name = "amanda",
+ .l4proto = IPPROTO_UDP,
+ .policy = {
+ [0] = {
+ .name = "amanda",
+ .expect_max = 3,
+ .expect_timeout = 180,
+ },
+ },
+};
+
+static struct ctd_helper dhcpv6_helper = {
+ .name = "dhcpv6",
+ .l4proto = IPPROTO_UDP,
+ .policy = {
+ [0] = {
+ .name = "dhcpv6",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+#include "helpers/ftp.h"
+
+static struct ctd_helper ftp_helper = {
+ .name = "ftp",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct ftp_info),
+ .policy = {
+ [0] = {
+ .name = "ftp",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+static struct ctd_helper mdns_helper = {
+ .name = "mdns",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "mdns",
+ .expect_max = 8,
+ .expect_timeout = 30,
+ },
+ },
+};
+
+#include "helpers/rpc.h"
+
+static struct ctd_helper rpc_helper_tcp = {
+ .name = "rpc",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct rpc_info),
+ .policy = {
+ {
+ .name = "rpc",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+static struct ctd_helper rpc_helper_udp = {
+ .name = "rpc",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = sizeof(struct rpc_info),
+ .policy = {
+ {
+ .name = "rpc",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
+#include "helpers/sane.h"
+
+static struct ctd_helper sane_helper = {
+ .name = "sane",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct nf_ct_sane_master),
+ .policy = {
+ [0] = {
+ .name = "sane",
+ .expect_max = 1,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+static struct ctd_helper slp_helper = {
+ .name = "slp",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "slp",
+ .expect_max = 8,
+ .expect_timeout = 16, /* default CONFIG_MC_MAX + 1 */
+ },
+ },
+};
+
+static struct ctd_helper ssdp_helper_udp = {
+ .name = "ssdp",
+ .l4proto = IPPROTO_UDP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "ssdp",
+ .expect_max = 8,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+static struct ctd_helper ssdp_helper_tcp = {
+ .name = "ssdp",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = 0,
+ .policy = {
+ [0] = {
+ .name = "ssdp",
+ .expect_max = 8,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+static struct ctd_helper tftp_helper = {
+ .name = "tftp",
+ .l4proto = IPPROTO_UDP,
+ .policy = {
+ [0] = {
+ .name = "tftp",
+ .expect_max = 1,
+ .expect_timeout = 5 * 60,
+ },
+ },
+};
+
+#include "helpers/tns.h"
+
+static struct ctd_helper tns_helper = {
+ .name = "tns",
+ .l4proto = IPPROTO_TCP,
+ .priv_data_len = sizeof(struct tns_info),
+ .policy = {
+ [0] = {
+ .name = "tns",
+ .expect_max = 1,
+ .expect_timeout = 300,
+ },
+ },
+};
+
static void __init helper_init(void)
{
+ helper_register(&amanda_helper);
+ helper_register(&dhcpv6_helper);
+ helper_register(&ftp_helper);
+ helper_register(&mdns_helper);
+ helper_register(&rpc_helper_tcp);
+ helper_register(&rpc_helper_udp);
+ helper_register(&sane_helper);
+ helper_register(&slp_helper);
+ helper_register(&ssdp_helper_udp);
+ helper_register(&ssdp_helper_tcp);
+ helper_register(&tftp_helper);
+ helper_register(&tns_helper);
+
nfct_extension_register(&helper);
}
diff --git a/src/parse.c b/src/parse.c
index 7e524ed..eedba66 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -29,7 +29,8 @@
static void ct_parse_u8(struct nf_conntrack *ct, int attr, void *data);
static void ct_parse_u16(struct nf_conntrack *ct, int attr, void *data);
static void ct_parse_u32(struct nf_conntrack *ct, int attr, void *data);
-static void ct_parse_u128(struct nf_conntrack *ct, int attr, void *data);
+static void ct_parse_be32(struct nf_conntrack *ct, int attr, void *data);
+static void ct_parse_be128(struct nf_conntrack *ct, int attr, void *data);
static void ct_parse_str(struct nf_conntrack *ct,
const struct netattr *, void *data);
static void ct_parse_group(struct nf_conntrack *ct, int attr, void *data);
@@ -108,12 +109,12 @@ static struct ct_parser h[NTA_MAX] = {
.size = NTA_SIZE(sizeof(struct nfct_attr_grp_port)),
},
[NTA_SNAT_IPV4] = {
- .parse = ct_parse_u32,
+ .parse = ct_parse_be32,
.attr = ATTR_SNAT_IPV4,
.size = NTA_SIZE(sizeof(uint32_t)),
},
[NTA_DNAT_IPV4] = {
- .parse = ct_parse_u32,
+ .parse = ct_parse_be32,
.attr = ATTR_DNAT_IPV4,
.size = NTA_SIZE(sizeof(uint32_t)),
},
@@ -192,12 +193,12 @@ static struct ct_parser h[NTA_MAX] = {
.max_size = NTA_SIZE(NTA_LABELS_MAX_SIZE),
},
[NTA_SNAT_IPV6] = {
- .parse = ct_parse_u128,
+ .parse = ct_parse_be128,
.attr = ATTR_SNAT_IPV6,
.size = NTA_SIZE(sizeof(uint32_t) * 4),
},
[NTA_DNAT_IPV6] = {
- .parse = ct_parse_u128,
+ .parse = ct_parse_be128,
.attr = ATTR_DNAT_IPV6,
.size = NTA_SIZE(sizeof(uint32_t) * 4),
},
@@ -205,6 +206,11 @@ static struct ct_parser h[NTA_MAX] = {
.parse = ct_parse_synproxy,
.size = NTA_SIZE(sizeof(struct nta_attr_synproxy)),
},
+ [NTA_ZONE] = {
+ .parse = ct_parse_u16,
+ .attr = ATTR_ZONE,
+ .size = NTA_SIZE(sizeof(uint16_t)),
+ },
};
static void
@@ -229,7 +235,14 @@ ct_parse_u32(struct nf_conntrack *ct, int attr, void *data)
}
static void
-ct_parse_u128(struct nf_conntrack *ct, int attr, void *data)
+ct_parse_be32(struct nf_conntrack *ct, int attr, void *data)
+{
+ uint32_t *value = (uint32_t *) data;
+ nfct_set_attr_u32(ct, h[attr].attr, *value);
+}
+
+static void
+ct_parse_be128(struct nf_conntrack *ct, int attr, void *data)
{
nfct_set_attr(ct, h[attr].attr, data);
}
diff --git a/src/process.c b/src/process.c
index 3ddad5f..08598ee 100644
--- a/src/process.c
+++ b/src/process.c
@@ -84,7 +84,7 @@ void fork_process_dump(int fd)
int size = 0;
list_for_each_entry(this, &process_list, head) {
- size += snprintf(buf+size, sizeof(buf),
+ size += snprintf(buf + size, sizeof(buf) - size,
"PID=%u type=%s\n",
this->pid,
this->type < CTD_PROC_MAX ?
diff --git a/src/queue.c b/src/queue.c
index 76425b1..e94dc7c 100644
--- a/src/queue.c
+++ b/src/queue.c
@@ -69,12 +69,12 @@ void queue_stats_show(int fd)
int size = 0;
char buf[512];
- size += snprintf(buf+size, sizeof(buf),
+ size += snprintf(buf + size, sizeof(buf) - size,
"allocated queue nodes:\t\t%12u\n\n",
qobjects_num);
list_for_each_entry(this, &queue_list, list) {
- size += snprintf(buf+size, sizeof(buf),
+ size += snprintf(buf + size, sizeof(buf) - size,
"queue %s:\n"
"current elements:\t\t%12u\n"
"maximum elements:\t\t%12u\n"
diff --git a/src/read_config_lex.l b/src/read_config_lex.l
index b0d9e61..2708432 100644
--- a/src/read_config_lex.l
+++ b/src/read_config_lex.l
@@ -21,6 +21,7 @@
#include <string.h>
+#include "log.h"
#include "conntrackd.h"
#include "read_config_yy.h"
%}
@@ -35,6 +36,10 @@ nl [\n\r]
is_on [o|O][n|N]
is_off [o|O][f|F][f|F]
+is_yes [y|Y][e|E][s|S]
+is_no [n|N][o|O]
+is_true {is_on}|{is_yes}
+is_false {is_off}|{is_no}
integer [0-9]+
signed_integer [\-\+][0-9]+
path \/[^\"\n ]*
@@ -137,9 +142,10 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k]
"ExpectTimeout" { return T_HELPER_EXPECT_TIMEOUT; }
"Systemd" { return T_SYSTEMD; }
"StartupResync" { return T_STARTUP_RESYNC; }
+"Setup" { return T_SETUP; }
-{is_on} { return T_ON; }
-{is_off} { return T_OFF; }
+{is_true} { return T_ON; }
+{is_false} { return T_OFF; }
{integer} { yylval.val = atoi(yytext); return T_NUMBER; }
{signed_integer} { yylval.val = atoi(yytext); return T_SIGNED_NUMBER; }
{ip4} { yylval.string = strdup(yytext); return T_IP; }
@@ -169,7 +175,7 @@ notrack [N|n][O|o][T|t][R|r][A|a][C|c][K|k]
%%
int
-yywrap()
+yywrap(void)
{
return 1;
}
diff --git a/src/read_config_yy.y b/src/read_config_yy.y
index 31109c4..a116b0b 100644
--- a/src/read_config_yy.y
+++ b/src/read_config_yy.y
@@ -31,19 +31,40 @@
#include "cidr.h"
#include "helper.h"
#include "stack.h"
+#include "log.h"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
#include <sched.h>
#include <dlfcn.h>
+
#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
extern char *yytext;
extern int yylineno;
+int yylex (void);
+int yyerror (const char *msg);
+void yyrestart (FILE *input_file);
+
struct ct_conf conf;
static void __kernel_filter_start(void);
static void __kernel_filter_add_state(int value);
-static void __max_dedicated_links_reached(void);
+
+static struct channel_conf *conf_get_channel(void)
+{
+ if (conf.channel_num >= MULTICHANNEL_MAX) {
+ dlog(LOG_ERR, "too many dedicated links in the configuration "
+ "file (Maximum: %d)", MULTICHANNEL_MAX);
+ exit(EXIT_FAILURE);
+ }
+
+ return &conf.channel[conf.channel_num];
+}
struct stack symbol_stack;
@@ -63,7 +84,7 @@ enum {
%token T_IPV4_ADDR T_IPV4_IFACE T_PORT T_HASHSIZE T_HASHLIMIT T_MULTICAST
%token T_PATH T_UNIX T_REFRESH T_IPV6_ADDR T_IPV6_IFACE
-%token T_BACKLOG T_GROUP T_IGNORE
+%token T_BACKLOG T_GROUP T_IGNORE T_SETUP
%token T_LOG T_UDP T_ICMP T_IGMP T_VRRP T_TCP
%token T_LOCK T_BUFFER_SIZE_MAX_GROWN T_EXPIRE T_TIMEOUT
%token T_GENERAL T_SYNC T_STATS T_BUFFER_SIZE
@@ -121,7 +142,7 @@ logfile_path : T_LOG T_PATH_VAL
FILENAME_MAXLEN);
exit(EXIT_FAILURE);
}
- snprintf(conf.logfile, FILENAME_MAXLEN, "%s", $2);
+ snprintf(conf.logfile, sizeof(conf.logfile), "%s", $2);
free($2);
};
@@ -176,7 +197,7 @@ lock : T_LOCK T_PATH_VAL
FILENAME_MAXLEN);
exit(EXIT_FAILURE);
}
- snprintf(conf.lockfile, FILENAME_MAXLEN, "%s", $2);
+ snprintf(conf.lockfile, sizeof(conf.lockfile), "%s", $2);
free($2);
};
@@ -202,6 +223,8 @@ purge: T_PURGE T_NUMBER
multicast_line : T_MULTICAST '{' multicast_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_MCAST) {
dlog(LOG_ERR, "cannot use `Multicast' with other "
@@ -209,13 +232,15 @@ multicast_line : T_MULTICAST '{' multicast_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_MCAST;
+ channel_conf->channel_flags = CHANNEL_F_BUFFERED;
conf.channel_num++;
};
multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_MCAST) {
dlog(LOG_ERR, "cannot use `Multicast' with other "
@@ -223,9 +248,8 @@ multicast_line : T_MULTICAST T_DEFAULT '{' multicast_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_type = CHANNEL_MCAST;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
- CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_MCAST;
+ channel_conf->channel_flags = CHANNEL_F_DEFAULT | CHANNEL_F_BUFFERED;
conf.channel_default = conf.channel_num;
conf.channel_num++;
};
@@ -235,15 +259,15 @@ multicast_options :
multicast_option : T_IPV4_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.in)) {
+ if (!inet_aton($2, &channel_conf->u.mcast.in.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
+ if (channel_conf->u.mcast.ipproto == AF_INET6) {
dlog(LOG_WARNING, "your multicast address is IPv4 but "
"is binded to an IPv6 interface? "
"Surely, this is not what you want");
@@ -251,16 +275,15 @@ multicast_option : T_IPV4_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET;
+ channel_conf->u.mcast.ipproto = AF_INET;
};
multicast_option : T_IPV6_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.mcast.in);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.mcast.in);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -270,7 +293,7 @@ multicast_option : T_IPV6_ADDR T_IP
exit(EXIT_FAILURE);
}
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET) {
+ if (channel_conf->u.mcast.ipproto == AF_INET) {
dlog(LOG_WARNING, "your multicast address is IPv6 but "
"is binded to an IPv4 interface? "
"Surely this is not what you want");
@@ -278,10 +301,10 @@ multicast_option : T_IPV6_ADDR T_IP
break;
}
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
+ channel_conf->u.mcast.ipproto = AF_INET6;
- if (conf.channel[conf.channel_num].channel_ifname[0] &&
- !conf.channel[conf.channel_num].u.mcast.ifa.interface_index6) {
+ if (channel_conf->channel_ifname[0] &&
+ !channel_conf->u.mcast.ifa.interface_index6) {
unsigned int idx;
idx = if_nametoindex($2);
@@ -291,31 +314,31 @@ multicast_option : T_IPV6_ADDR T_IP
break;
}
- conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx;
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
+ channel_conf->u.mcast.ifa.interface_index6 = idx;
+ channel_conf->u.mcast.ipproto = AF_INET6;
}
free($2);
};
multicast_option : T_IPV4_IFACE T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.mcast.ifa)) {
+ if (!inet_aton($2, &channel_conf->u.mcast.ifa.interface_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
+ if (channel_conf->u.mcast.ipproto == AF_INET6) {
dlog(LOG_WARNING, "your multicast interface is IPv4 but "
"is binded to an IPv6 interface? "
"Surely, this is not what you want");
break;
}
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET;
+ channel_conf->u.mcast.ipproto = AF_INET;
};
multicast_option : T_IPV6_IFACE T_IP
@@ -326,11 +349,10 @@ multicast_option : T_IPV6_IFACE T_IP
multicast_option : T_IFACE T_STRING
{
+ struct channel_conf *channel_conf = conf_get_channel();
unsigned int idx;
- __max_dedicated_links_reached();
-
- strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+ strncpy(channel_conf->channel_ifname, $2, IFNAMSIZ);
idx = if_nametoindex($2);
if (!idx) {
@@ -339,9 +361,9 @@ multicast_option : T_IFACE T_STRING
break;
}
- if (conf.channel[conf.channel_num].u.mcast.ipproto == AF_INET6) {
- conf.channel[conf.channel_num].u.mcast.ifa.interface_index6 = idx;
- conf.channel[conf.channel_num].u.mcast.ipproto = AF_INET6;
+ if (channel_conf->u.mcast.ipproto == AF_INET6) {
+ channel_conf->u.mcast.ifa.interface_index6 = idx;
+ channel_conf->u.mcast.ipproto = AF_INET6;
}
free($2);
@@ -349,36 +371,43 @@ multicast_option : T_IFACE T_STRING
multicast_option : T_GROUP T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.port = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.port = $2;
};
multicast_option: T_SNDBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.sndbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.sndbuf = $2;
};
multicast_option: T_RCVBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.rcvbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.rcvbuf = $2;
};
-multicast_option: T_CHECKSUM T_ON
+multicast_option: T_CHECKSUM T_ON
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.checksum = 0;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.checksum = 0;
};
multicast_option: T_CHECKSUM T_OFF
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.mcast.checksum = 1;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.mcast.checksum = 1;
};
udp_line : T_UDP '{' udp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_UDP) {
dlog(LOG_ERR, "cannot use `UDP' with other "
@@ -386,13 +415,15 @@ udp_line : T_UDP '{' udp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_UDP;
+ channel_conf->channel_flags = CHANNEL_F_BUFFERED;
conf.channel_num++;
};
udp_line : T_UDP T_DEFAULT '{' udp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_UDP) {
dlog(LOG_ERR, "cannot use `UDP' with other "
@@ -400,9 +431,8 @@ udp_line : T_UDP T_DEFAULT '{' udp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_UDP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
- CHANNEL_F_BUFFERED;
+ channel_conf->channel_type = CHANNEL_UDP;
+ channel_conf->channel_flags = CHANNEL_F_DEFAULT | CHANNEL_F_BUFFERED;
conf.channel_default = conf.channel_num;
conf.channel_num++;
};
@@ -412,24 +442,23 @@ udp_options :
udp_option : T_IPV4_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.server.ipv4)) {
+ if (!inet_aton($2, &channel_conf->u.udp.server.ipv4.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
+ channel_conf->u.udp.ipproto = AF_INET;
};
udp_option : T_IPV6_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.udp.server.ipv6);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.udp.server.ipv6);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -440,29 +469,28 @@ udp_option : T_IPV6_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
+ channel_conf->u.udp.ipproto = AF_INET6;
};
udp_option : T_IPV4_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.udp.client)) {
+ if (!inet_aton($2, &channel_conf->u.udp.client.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET;
+ channel_conf->u.udp.ipproto = AF_INET;
};
udp_option : T_IPV6_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.udp.client);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.udp.client);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -473,15 +501,15 @@ udp_option : T_IPV6_DEST_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.udp.ipproto = AF_INET6;
+ channel_conf->u.udp.ipproto = AF_INET6;
};
udp_option : T_IFACE T_STRING
{
+ struct channel_conf *channel_conf = conf_get_channel();
int idx;
- __max_dedicated_links_reached();
- strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+ strncpy(channel_conf->channel_ifname, $2, IFNAMSIZ);
idx = if_nametoindex($2);
if (!idx) {
@@ -489,43 +517,50 @@ udp_option : T_IFACE T_STRING
free($2);
break;
}
- conf.channel[conf.channel_num].u.udp.server.ipv6.scope_id = idx;
+ channel_conf->u.udp.server.ipv6.scope_id = idx;
free($2);
};
udp_option : T_PORT T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.port = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.port = $2;
};
udp_option: T_SNDBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.sndbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.sndbuf = $2;
};
udp_option: T_RCVBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.rcvbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.rcvbuf = $2;
};
-udp_option: T_CHECKSUM T_ON
+udp_option: T_CHECKSUM T_ON
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.checksum = 0;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.checksum = 0;
};
udp_option: T_CHECKSUM T_OFF
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.udp.checksum = 1;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.udp.checksum = 1;
};
tcp_line : T_TCP '{' tcp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_TCP) {
dlog(LOG_ERR, "cannot use `TCP' with other "
@@ -533,15 +568,17 @@ tcp_line : T_TCP '{' tcp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_BUFFERED |
- CHANNEL_F_STREAM |
- CHANNEL_F_ERRORS;
+ channel_conf->channel_type = CHANNEL_TCP;
+ channel_conf->channel_flags = CHANNEL_F_BUFFERED |
+ CHANNEL_F_STREAM |
+ CHANNEL_F_ERRORS;
conf.channel_num++;
};
tcp_line : T_TCP T_DEFAULT '{' tcp_options '}'
{
+ struct channel_conf *channel_conf = conf_get_channel();
+
if (conf.channel_type_global != CHANNEL_NONE &&
conf.channel_type_global != CHANNEL_TCP) {
dlog(LOG_ERR, "cannot use `TCP' with other "
@@ -549,11 +586,11 @@ tcp_line : T_TCP T_DEFAULT '{' tcp_options '}'
exit(EXIT_FAILURE);
}
conf.channel_type_global = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_type = CHANNEL_TCP;
- conf.channel[conf.channel_num].channel_flags = CHANNEL_F_DEFAULT |
- CHANNEL_F_BUFFERED |
- CHANNEL_F_STREAM |
- CHANNEL_F_ERRORS;
+ channel_conf->channel_type = CHANNEL_TCP;
+ channel_conf->channel_flags = CHANNEL_F_DEFAULT |
+ CHANNEL_F_BUFFERED |
+ CHANNEL_F_STREAM |
+ CHANNEL_F_ERRORS;
conf.channel_default = conf.channel_num;
conf.channel_num++;
};
@@ -563,24 +600,23 @@ tcp_options :
tcp_option : T_IPV4_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.server.ipv4)) {
+ if (!inet_aton($2, &channel_conf->u.tcp.server.ipv4.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET;
+ channel_conf->u.tcp.ipproto = AF_INET;
};
tcp_option : T_IPV6_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.tcp.server.ipv6);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.tcp.server.ipv6);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -591,29 +627,28 @@ tcp_option : T_IPV6_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6;
+ channel_conf->u.tcp.ipproto = AF_INET6;
};
tcp_option : T_IPV4_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
- if (!inet_aton($2, &conf.channel[conf.channel_num].u.tcp.client)) {
+ if (!inet_aton($2, &channel_conf->u.tcp.client.inet_addr)) {
dlog(LOG_WARNING, "%s is not a valid IPv4 address", $2);
free($2);
break;
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET;
+ channel_conf->u.tcp.ipproto = AF_INET;
};
tcp_option : T_IPV6_DEST_ADDR T_IP
{
- __max_dedicated_links_reached();
+ struct channel_conf *channel_conf = conf_get_channel();
int err;
- err = inet_pton(AF_INET6, $2,
- &conf.channel[conf.channel_num].u.tcp.client);
+ err = inet_pton(AF_INET6, $2, &channel_conf->u.tcp.client);
if (err == 0) {
dlog(LOG_WARNING, "%s is not a valid IPv6 address", $2);
free($2);
@@ -624,15 +659,15 @@ tcp_option : T_IPV6_DEST_ADDR T_IP
}
free($2);
- conf.channel[conf.channel_num].u.tcp.ipproto = AF_INET6;
+ channel_conf->u.tcp.ipproto = AF_INET6;
};
tcp_option : T_IFACE T_STRING
{
+ struct channel_conf *channel_conf = conf_get_channel();
int idx;
- __max_dedicated_links_reached();
- strncpy(conf.channel[conf.channel_num].channel_ifname, $2, IFNAMSIZ);
+ strncpy(channel_conf->channel_ifname, $2, IFNAMSIZ);
idx = if_nametoindex($2);
if (!idx) {
@@ -640,44 +675,48 @@ tcp_option : T_IFACE T_STRING
free($2);
break;
}
- conf.channel[conf.channel_num].u.tcp.server.ipv6.scope_id = idx;
+ channel_conf->u.tcp.server.ipv6.scope_id = idx;
free($2);
};
tcp_option : T_PORT T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.port = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.port = $2;
};
tcp_option: T_SNDBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.sndbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.sndbuf = $2;
};
tcp_option: T_RCVBUFF T_NUMBER
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.rcvbuf = $2;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.rcvbuf = $2;
};
-tcp_option: T_CHECKSUM T_ON
+tcp_option: T_CHECKSUM T_ON
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.checksum = 0;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.checksum = 0;
};
tcp_option: T_CHECKSUM T_OFF
{
- __max_dedicated_links_reached();
- conf.channel[conf.channel_num].u.tcp.checksum = 1;
+ struct channel_conf *channel_conf = conf_get_channel();
+
+ channel_conf->u.tcp.checksum = 1;
};
tcp_option: T_ERROR_QUEUE_LENGTH T_NUMBER
{
- __max_dedicated_links_reached();
CONFIG(channelc).error_queue_length = $2;
};
@@ -699,12 +738,12 @@ unix_options:
unix_option : T_PATH T_PATH_VAL
{
- if (strlen($2) > UNIX_PATH_MAX) {
+ if (strlen($2) >= UNIX_PATH_MAX) {
dlog(LOG_ERR, "Path is longer than %u characters",
- UNIX_PATH_MAX);
+ UNIX_PATH_MAX - 1);
exit(EXIT_FAILURE);
}
- snprintf(conf.local.path, UNIX_PATH_MAX, "%s", $2);
+ strcpy(conf.local.path, $2);
free($2);
};
@@ -1052,7 +1091,7 @@ scheduler_line : T_PRIO T_NUMBER
{
conf.sched.prio = $2;
if (conf.sched.prio < 0 || conf.sched.prio > 99) {
- dlog(LOG_ERR, "`Priority' must be [0, 99]\n", $2);
+ dlog(LOG_ERR, "`Priority' must be [0, 99]\n");
exit(EXIT_FAILURE);
}
};
@@ -1228,7 +1267,7 @@ filter_address_item : T_IPV4_ADDR T_IP
}
}
- if (!inet_aton($2, &ip.ipv4)) {
+ if (!inet_aton($2, (struct in_addr *) &ip.ipv4)) {
dlog(LOG_WARNING, "%s is not a valid IPv4, ignoring", $2);
free($2);
break;
@@ -1396,7 +1435,7 @@ stat_logfile_path : T_LOG T_PATH_VAL
FILENAME_MAXLEN);
exit(EXIT_FAILURE);
}
- snprintf(conf.stats.logfile, FILENAME_MAXLEN, "%s", $2);
+ snprintf(conf.stats.logfile, sizeof(conf.stats.logfile), "%s", $2);
free($2);
};
@@ -1454,6 +1493,7 @@ helper_list:
;
helper_line: helper_type
+ | helper_setup
;
helper_type: T_TYPE T_STRING T_STRING T_STRING '{' helper_type_list '}'
@@ -1562,6 +1602,16 @@ helper_type: T_TYPE T_STRING T_STRING T_STRING '{' helper_type_list '}'
list_add(&helper_inst->head, &CONFIG(cthelper).list);
};
+helper_setup : T_SETUP T_ON
+{
+ CONFIG(cthelper).setup = true;
+};
+
+helper_setup : T_SETUP T_OFF
+{
+ CONFIG(cthelper).setup = false;
+};
+
helper_type_list:
| helper_type_list helper_type_line
;
@@ -1611,7 +1661,7 @@ helper_type: T_HELPER_POLICY T_STRING '{' helper_policy_list '}'
}
policy = (struct ctd_helper_policy *) &e->data;
- snprintf(policy->name, CTD_HELPER_NAME_LEN, "%s", $2);
+ snprintf(policy->name, sizeof(policy->name), "%s", $2);
free($2);
/* Now object is complete. */
e->type = SYMBOL_HELPER_POLICY_EXPECT_ROOT;
@@ -1659,7 +1709,7 @@ helper_policy_expect_timeout: T_HELPER_EXPECT_TIMEOUT T_NUMBER
%%
int __attribute__((noreturn))
-yyerror(char *msg)
+yyerror(const char *msg)
{
dlog(LOG_ERR, "parsing config file in line (%d), symbol '%s': %s",
yylineno, yytext, msg);
@@ -1690,15 +1740,6 @@ static void __kernel_filter_add_state(int value)
&filter_proto);
}
-static void __max_dedicated_links_reached(void)
-{
- if (conf.channel_num >= MULTICHANNEL_MAX) {
- dlog(LOG_ERR, "too many dedicated links in the configuration "
- "file (Maximum: %d)", MULTICHANNEL_MAX);
- exit(EXIT_FAILURE);
- }
-}
-
int
init_config(char *filename)
{
@@ -1780,5 +1821,11 @@ init_config(char *filename)
NF_NETLINK_CONNTRACK_DESTROY;
}
+ /* default hashtable buckets and maximum number of entries */
+ if (!CONFIG(hashsize))
+ CONFIG(hashsize) = 65536;
+ if (!CONFIG(limit))
+ CONFIG(limit) = 262144;
+
return 0;
}
diff --git a/src/run.c b/src/run.c
index f11a532..37a0eb1 100644
--- a/src/run.c
+++ b/src/run.c
@@ -67,7 +67,7 @@ void killer(int signo)
close_log();
sd_ct_stop();
- exit(0);
+ _exit(0);
}
static void child(int foo)
diff --git a/src/vector.c b/src/vector.c
index c81e7ce..92a5436 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -60,13 +60,16 @@ void vector_destroy(struct vector *v)
int vector_add(struct vector *v, void *data)
{
+ void *ptr;
+
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) {
+ ptr = realloc(v->data, v->max_elems * v->size);
+ if (!ptr) {
v->max_elems -= DEFAULT_VECTOR_GROWTH;
return -1;
}
+ v->data = ptr;
}
memcpy(v->data + (v->size * v->cur_elems), data, v->size);
v->cur_elems++;