diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 86 | ||||
-rw-r--r-- | src/build.c | 36 | ||||
-rw-r--r-- | src/cache-ct.c | 21 | ||||
-rw-r--r-- | src/cache.c | 4 | ||||
-rw-r--r-- | src/conntrack.c | 741 | ||||
-rw-r--r-- | src/cthelper.c | 4 | ||||
-rw-r--r-- | src/filter.c | 2 | ||||
-rw-r--r-- | src/hash.c | 1 | ||||
-rw-r--r-- | src/helpers.c | 3 | ||||
-rw-r--r-- | src/helpers/Makefile.am | 2 | ||||
-rw-r--r-- | src/helpers/amanda.c | 1 | ||||
-rw-r--r-- | src/helpers/dhcpv6.c | 1 | ||||
-rw-r--r-- | src/helpers/ftp.c | 33 | ||||
-rw-r--r-- | src/helpers/rpc.c | 14 | ||||
-rw-r--r-- | src/helpers/sane.c | 11 | ||||
-rw-r--r-- | src/helpers/slp.c | 1 | ||||
-rw-r--r-- | src/helpers/ssdp.c | 10 | ||||
-rw-r--r-- | src/helpers/tftp.c | 1 | ||||
-rw-r--r-- | src/helpers/tns.c | 8 | ||||
-rw-r--r-- | src/main.c | 7 | ||||
-rw-r--r-- | src/network.c | 2 | ||||
-rw-r--r-- | src/nfct-extensions/helper.c | 184 | ||||
-rw-r--r-- | src/parse.c | 20 | ||||
-rw-r--r-- | src/process.c | 2 | ||||
-rw-r--r-- | src/queue.c | 4 | ||||
-rw-r--r-- | src/read_config_lex.l | 4 | ||||
-rw-r--r-- | src/read_config_yy.y | 303 | ||||
-rw-r--r-- | src/run.c | 2 | ||||
-rw-r--r-- | src/vector.c | 7 |
29 files changed, 923 insertions, 592 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 4771997..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: 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 987a521..0d71352 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -68,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; @@ -92,6 +96,10 @@ struct ct_tmpl { 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; @@ -131,6 +139,8 @@ static int alloc_tmpl_objects(struct ct_tmpl *tmpl) static void free_tmpl_objects(struct ct_tmpl *tmpl) { + if (!tmpl) + return; if (tmpl->ct) nfct_destroy(tmpl->ct); if (tmpl->exptuple) @@ -145,68 +155,6 @@ static void free_tmpl_objects(struct ct_tmpl *tmpl) 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), @@ -345,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'}, @@ -388,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:<:>::(:):"; @@ -405,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,2,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,2,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] = { @@ -438,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[] = { @@ -541,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[] = @@ -585,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" @@ -601,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; @@ -792,12 +745,13 @@ static int ct_save_snprintf(char *buf, size_t len, 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, "-I "); + ret = snprintf(buf + offset, len, "-A "); BUFFER_SIZE(ret, size, len, offset); break; case NFCT_T_UPDATE: @@ -809,7 +763,6 @@ static int ct_save_snprintf(char *buf, size_t len, BUFFER_SIZE(ret, size, len, offset); break; default: - ret = 0; break; } @@ -852,6 +805,7 @@ static int ct_save_snprintf(char *buf, size_t len, 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) @@ -862,9 +816,16 @@ static int ct_save_snprintf(char *buf, size_t len, 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'; @@ -874,6 +835,20 @@ static int ct_save_snprintf(char *buf, size_t len, 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; @@ -893,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) { @@ -1083,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 " @@ -1120,8 +1095,7 @@ enum { _O_ID = (1 << 3), _O_KTMS = (1 << 4), _O_CL = (1 << 5), - _O_US = (1 << 6), - _O_SAVE = (1 << 7), + _O_SAVE = (1 << 6), }; enum { @@ -1141,12 +1115,12 @@ static struct parse_parameter { { {"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", "save"}, 8, - { _O_XML, _O_EXT, _O_TMS, _O_ID, _O_KTMS, _O_CL, _O_US, _O_SAVE }, + { _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; @@ -1171,7 +1145,7 @@ do_parse_parameter(const char *str, size_t str_length, unsigned int *value, ret = 1; break; } - + return ret; } @@ -1193,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; @@ -1674,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); } @@ -1749,7 +1770,7 @@ static char *portid2name(pid_t pid, uint32_t portid, unsigned long inode) continue; rl = readlink(procname, tmp, sizeof(tmp)); - if (rl <= 0 || rl > (ssize_t)sizeof(tmp)) + if (rl <= 0 || rl >= (ssize_t)sizeof(tmp)) continue; tmp[rl] = 0; @@ -1923,7 +1944,7 @@ static int event_cb(const struct nlmsghdr *nlh, void *data) nfct_snprintf_labels(buf, sizeof(buf), ct, type, op_type, op_flags, labelmap); done: - if ((output_mask & _O_US) && nlh->nlmsg_pid) { + if (nlh->nlmsg_pid && !(output_mask & _O_XML)) { char *prog = get_progname(nlh->nlmsg_pid); if (prog) @@ -1941,65 +1962,41 @@ out: return MNL_CB_OK; } -static int dump_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) -{ - unsigned int op_type = NFCT_O_DEFAULT; - unsigned int op_flags = 0; - struct ct_cmd *cmd = data; - char buf[1024]; +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); - if (nfct_filter(cmd, ct, cur_tmpl)) - return NFCT_CB_CONTINUE; - - 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); - - counter++; - - return NFCT_CB_CONTINUE; -} - -static int delete_cb(enum nf_conntrack_msg_type type, - struct nf_conntrack *ct, - void *data) +static int mnl_nfct_delete_cb(const struct nlmsghdr *nlh, void *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; + ct = nfct_new(); + if (ct == NULL) + return MNL_CB_OK; + + nfct_nlmsg_parse(nlh, ct); + if (nfct_filter(cmd, ct, cur_tmpl)) - return NFCT_CB_CONTINUE; + 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); @@ -2019,16 +2016,23 @@ done: 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); @@ -2046,7 +2050,9 @@ static int print_cb(enum nf_conntrack_msg_type type, done: printf("%s\n", buf); - return NFCT_CB_CONTINUE; + nfct_destroy(ct); + + return MNL_CB_OK; } static void copy_mark(const struct ct_cmd *cmd, struct nf_conntrack *tmp, @@ -2139,29 +2145,34 @@ static void copy_label(const struct ct_cmd *cmd, struct nf_conntrack *tmp, } } -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 nf_conntrack *obj = cmd->tmpl.ct, *tmp; + struct nfct_mnl_socket *modifier_sock = &_modifier_sock; + struct nf_conntrack *ct, *obj = cmd->tmpl.ct, *tmp = NULL; int res; + 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)) - return NFCT_CB_CONTINUE; + 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 (cmd->options & CT_OPT_TUPLE_ORIG && !nfct_cmp(obj, ct, NFCT_CMP_ORIG)) - return NFCT_CB_CONTINUE; + goto destroy_ok; if (cmd->options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) - return NFCT_CB_CONTINUE; + goto destroy_ok; tmp = nfct_new(); if (tmp == NULL) @@ -2174,36 +2185,47 @@ static int update_cb(enum nf_conntrack_msg_type type, 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, @@ -2348,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)); @@ -2384,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; - return mnl_cb_run(buf, res, nlh->nlmsg_seq, sock.portid, cb, NULL); + 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; + + 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) { @@ -2452,8 +2526,6 @@ static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) return MNL_CB_OK; } -#define UNKNOWN_STATS_NUM 4 - static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data) { struct nlattr *tb[CTA_STATS_MAX + UNKNOWN_STATS_NUM + 1] = {}; @@ -2473,6 +2545,7 @@ static int nfct_stats_cb(const struct nlmsghdr *nlh, void *data) [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. @@ -2573,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]; @@ -2582,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); @@ -2797,7 +2900,8 @@ 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))) + if (counter == 0 && + !(cmd->command & (CT_LIST | EXP_LIST))) return -1; } @@ -2850,27 +2954,24 @@ static void do_parse(struct ct_cmd *ct_cmd, 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': @@ -2914,8 +3015,15 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[]) break; case 'u': options |= CT_OPT_STATUS; - parse_parameter(optarg, &status, PARSE_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; @@ -2963,6 +3071,8 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[]) nfct_set_nat_details(c, tmpl->ct, &ad, port_str, family); } + free(port_str); + free(nat_address); } break; case 'w': @@ -3117,39 +3227,29 @@ static void do_parse(struct ct_cmd *ct_cmd, int argc, char *argv[]) ct_cmd->socketbuffersize = socketbuffersize; } -static int do_command_ct(const char *progname, struct ct_cmd *cmd) +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 (cmd->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, + res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_DYING, - mnl_nfct_dump_cb, cmd->family); - - nfct_mnl_socket_close(); + mnl_nfct_dump_cb, cmd, NULL); break; } else if (cmd->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, + res = nfct_mnl_dump(sock, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_UNCONFIRMED, - mnl_nfct_dump_cb, cmd->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 (cmd->options & CT_COMPARISON && cmd->options & CT_OPT_ZERO) exit_error(PARAMETER_PROBLEM, "Can't use -z with " @@ -3157,8 +3257,6 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) nfct_filter_init(cmd); - nfct_callback_register(cth, NFCT_T_ALL, dump_cb, cmd); - filter_dump = nfct_filter_dump_create(); if (filter_dump == NULL) exit_error(OTHER_PROBLEM, "OOM"); @@ -3171,12 +3269,20 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) nfct_filter_dump_set_attr_u8(filter_dump, NFCT_FILTER_DUMP_L3NUM, cmd->family); - - if (cmd->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); + 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); @@ -3184,10 +3290,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) printf("</conntrack>\n"); fflush(stdout); } - - nfct_close(cth); break; - case EXP_LIST: cth = nfct_open(EXPECT, 0); if (!cth) @@ -3204,6 +3307,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) break; case CT_CREATE: + 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)) @@ -3216,14 +3320,15 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) nfct_set_attr(cmd->tmpl.ct, ATTR_CONNLABELS, xnfct_bitmask_clone(cmd->tmpl.label_modify)); - cth = nfct_open(CONNTRACK, 0); - if (!cth) - exit_error(OTHER_PROBLEM, "Can't open handler"); + if (cmd->command == CT_CREATE) + nl_flags = NLM_F_EXCL; - res = nfct_query(cth, NFCT_Q_CREATE, cmd->tmpl.ct); - if (res != -1) + 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: @@ -3240,31 +3345,21 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) 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(cmd); - - nfct_callback_register(cth, NFCT_T_ALL, update_cb, cmd); - - res = nfct_query(cth, NFCT_Q_DUMP, &cmd->family); - nfct_close(ith); - nfct_close(cth); + 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(cmd); - nfct_callback_register(cth, NFCT_T_ALL, delete_cb, cmd); - filter_dump = nfct_filter_dump_create(); if (filter_dump == NULL) exit_error(OTHER_PROBLEM, "OOM"); @@ -3278,12 +3373,11 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) NFCT_FILTER_DUMP_L3NUM, 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: @@ -3298,13 +3392,9 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) 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, cmd); - res = nfct_query(cth, NFCT_Q_GET, cmd->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: @@ -3320,11 +3410,9 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) 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_FILTER, &cmd->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; @@ -3350,9 +3438,10 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) 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); } @@ -3365,17 +3454,17 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) 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, 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", @@ -3390,7 +3479,7 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) 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, @@ -3407,9 +3496,9 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) strerror(errno)); break; } - res = mnl_cb_run(buf, res, 0, 0, event_cb, cmd); + 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: @@ -3443,20 +3532,14 @@ static int do_command_ct(const char *progname, struct ct_cmd *cmd) /* 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; @@ -3488,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) @@ -3507,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) @@ -3737,6 +3810,8 @@ static const char *ct_unsupp_cmd_file(const struct ct_cmd *cmd) 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; @@ -3751,18 +3826,22 @@ int main(int argc, char *argv[]) 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_UPDATE | CT_DELETE | CT_FLUSH))) + 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); + res |= do_command_ct(argv[0], cmd, sock); list_del(&cmd->list); free(cmd); } @@ -3772,10 +3851,12 @@ int main(int argc, char *argv[]) exit_error(OTHER_PROBLEM, "OOM"); do_parse(cmd, argc, argv); - do_command_ct(argv[0], cmd); - res = print_stats(cmd); + 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/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 */ @@ -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) { @@ -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 e97a721..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), }, @@ -234,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 f1f4fe3..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" %} @@ -141,6 +142,7 @@ 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_true} { return T_ON; } {is_false} { return T_OFF; } @@ -173,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 b215a72..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) { @@ -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++; |