diff --git a/.conntrack-tools.metadata b/.conntrack-tools.metadata index fc9a1fd..26de907 100644 --- a/.conntrack-tools.metadata +++ b/.conntrack-tools.metadata @@ -1 +1 @@ -50b89305bb689973d42a163c480dc77a5c0f6fe0 SOURCES/conntrack-tools-1.4.2.tar.bz2 +509db30f34b283f4a74a7e638ba0ca713d3fe98c SOURCES/conntrack-tools-1.4.3.tar.bz2 diff --git a/.gitignore b/.gitignore index f2ab79e..b447185 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -SOURCES/conntrack-tools-1.4.2.tar.bz2 +SOURCES/conntrack-tools-1.4.3.tar.bz2 diff --git a/SOURCES/conntrack-tools-20150818.patch b/SOURCES/conntrack-tools-20150818.patch deleted file mode 100644 index 16330d8..0000000 --- a/SOURCES/conntrack-tools-20150818.patch +++ /dev/null @@ -1,3718 +0,0 @@ -diff --git a/Makefile.am b/Makefile.am -index bd366bf..975c538 100644 ---- a/Makefile.am -+++ b/Makefile.am -@@ -10,4 +10,5 @@ DIST_SUBDIRS = include src extensions - LIBS = @LIBNETFILTER_CONNTRACK_LIBS@ - - dist-hook: -- rm -rf `find $(distdir)/doc -name .svn` -+ rm -rf `find $(distdir)/doc -name *.orig` -+ rm -rf `find $(distdir)/doc -name *.rej` -diff --git a/conntrack.8 b/conntrack.8 -index f273434..abc26c5 100644 ---- a/conntrack.8 -+++ b/conntrack.8 -@@ -1,4 +1,4 @@ --.TH CONNTRACK 8 "Jul 5, 2010" "" "" -+.TH CONNTRACK 8 "Sep 25, 2014" "" "" - - .\" Man page written by Harald Welte (Dec 2007) - -@@ -32,7 +32,7 @@ Dump the external cache, i.e. show foreign states - .TP - .BI "-x " - Display output in XML format. This option is only valid in combination --with "-i" and "-e" parameters. -+with "\-i" and "\-e" parameters. - .TP - .BI "-f " "[|internal|external]" - Flush the internal and/or external cache -diff --git a/doc/helper/conntrackd.conf b/doc/helper/conntrackd.conf -index 56f5162..d2d94a9 100644 ---- a/doc/helper/conntrackd.conf -+++ b/doc/helper/conntrackd.conf -@@ -62,6 +62,22 @@ Helper { - ExpectTimeout 300 - } - } -+ Type dhcpv6 inet6 udp { -+ QueueNum 4 -+ QueueLen 10240 -+ Policy dhcpv6 { -+ ExpectMax 1 -+ ExpectTimeout 300 -+ } -+ } -+ Type ssdp inet udp { -+ QueueNum 5 -+ QueueLen 10240 -+ Policy ssdp { -+ ExpectMax 1 -+ ExpectTimeout 300 -+ } -+ } - } - - # -diff --git a/doc/manual/conntrack-tools.tmpl b/doc/manual/conntrack-tools.tmpl -index f21a4ff..d23dec5 100644 ---- a/doc/manual/conntrack-tools.tmpl -+++ b/doc/manual/conntrack-tools.tmpl -@@ -890,6 +890,7 @@ maintainance. - Oracle*TNS, to support its special Redirect message. - NFSv3, mind that version 4 does not require this helper. - FTP (this helper is also available in kernel-space). -+SSDP. - - - The following steps describe how to enable the RPC portmapper helper for NFSv3 (this is similar for other helpers): -diff --git a/extensions/libct_proto_dccp.c b/extensions/libct_proto_dccp.c -index 586c4cc..f6258ad 100644 ---- a/extensions/libct_proto_dccp.c -+++ b/extensions/libct_proto_dccp.c -@@ -78,7 +78,7 @@ static char dccp_commands_v_options[NUMBER_OF_CMD][DCCP_OPT_MAX] = - /*CT_VERSION*/ {0,0,0,0,0,0,0,0,0,0}, - /*CT_HELP*/ {0,0,0,0,0,0,0,0,0,0}, - /*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0}, --/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1,1}, -+/*EXP_CREATE*/ {1,1,0,0,1,1,0,1,1,1}, - /*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0,0}, - /*EXP_GET*/ {1,1,1,1,0,0,0,0,0,0}, - /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0}, -@@ -118,7 +118,7 @@ static int parse_options(char c, - unsigned int *flags) - { - int i; -- u_int16_t port; -+ uint16_t port; - - switch(c) { - case 1: -diff --git a/extensions/libct_proto_gre.c b/extensions/libct_proto_gre.c -index 0274a37..2dc63d1 100644 ---- a/extensions/libct_proto_gre.c -+++ b/extensions/libct_proto_gre.c -@@ -91,7 +91,7 @@ static int parse_options(char c, - unsigned int *flags) - { - switch(c) { -- u_int16_t port; -+ uint16_t port; - case '1': - port = htons(strtoul(optarg, NULL, 0)); - nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); -diff --git a/extensions/libct_proto_icmp.c b/extensions/libct_proto_icmp.c -index d04397f..2ce1c65 100644 ---- a/extensions/libct_proto_icmp.c -+++ b/extensions/libct_proto_icmp.c -@@ -72,8 +72,8 @@ static int parse(char c, - unsigned int *flags) - { - switch(c) { -- u_int8_t tmp; -- u_int16_t id; -+ uint8_t tmp; -+ uint16_t id; - case '1': - tmp = atoi(optarg); - nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, tmp); -diff --git a/extensions/libct_proto_icmpv6.c b/extensions/libct_proto_icmpv6.c -index f8c2c68..18dd3e5 100644 ---- a/extensions/libct_proto_icmpv6.c -+++ b/extensions/libct_proto_icmpv6.c -@@ -75,8 +75,8 @@ static int parse(char c, - unsigned int *flags) - { - switch(c) { -- u_int8_t tmp; -- u_int16_t id; -+ uint8_t tmp; -+ uint16_t id; - case '1': - tmp = atoi(optarg); - nfct_set_attr_u8(ct, ATTR_ICMP_TYPE, tmp); -diff --git a/extensions/libct_proto_sctp.c b/extensions/libct_proto_sctp.c -index f4c94df..04828bf 100644 ---- a/extensions/libct_proto_sctp.c -+++ b/extensions/libct_proto_sctp.c -@@ -81,7 +81,7 @@ static char sctp_commands_v_options[NUMBER_OF_CMD][SCTP_OPT_MAX] = - /*CT_VERSION*/ {0,0,0,0,0,0,0,0,0,0,0}, - /*CT_HELP*/ {0,0,0,0,0,0,0,0,0,0,0}, - /*EXP_LIST*/ {0,0,0,0,0,0,0,0,0,0,0}, --/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1,1,1}, -+/*EXP_CREATE*/ {1,1,0,0,1,1,0,1,1,1,1}, - /*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0,0,0}, - /*EXP_GET*/ {1,1,1,1,0,0,0,0,0,0,0}, - /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0,0,0}, -@@ -120,8 +120,8 @@ parse_options(char c, struct nf_conntrack *ct, - unsigned int *flags) - { - int i; -- u_int16_t port; -- u_int32_t vtag; -+ uint16_t port; -+ uint32_t vtag; - - switch(c) { - case 1: -diff --git a/extensions/libct_proto_tcp.c b/extensions/libct_proto_tcp.c -index 0b43bf5..8a37a55 100644 ---- a/extensions/libct_proto_tcp.c -+++ b/extensions/libct_proto_tcp.c -@@ -65,7 +65,7 @@ static char tcp_commands_v_options[NUMBER_OF_CMD][TCP_NUMBER_OF_OPT] = - /*CT_VERSION*/ {0,0,0,0,0,0,0,0,0}, - /*CT_HELP*/ {0,0,0,0,0,0,0,0,0}, - /*EXP_LIST*/ {0,0,0,0,0,0,0,0,0}, --/*EXP_CREATE*/ {1,1,1,1,1,1,0,1,1}, -+/*EXP_CREATE*/ {1,1,0,0,1,1,0,1,1}, - /*EXP_DELETE*/ {1,1,1,1,0,0,0,0,0}, - /*EXP_GET*/ {1,1,1,1,0,0,0,0,0}, - /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0,0}, -@@ -106,7 +106,7 @@ static int parse_options(char c, - unsigned int *flags) - { - int i; -- u_int16_t port; -+ uint16_t port; - - switch(c) { - case '1': -diff --git a/extensions/libct_proto_udp.c b/extensions/libct_proto_udp.c -index d7c4da1..e30637c 100644 ---- a/extensions/libct_proto_udp.c -+++ b/extensions/libct_proto_udp.c -@@ -73,7 +73,7 @@ static char udp_commands_v_options[NUMBER_OF_CMD][UDP_NUMBER_OF_OPT] = - /*CT_VERSION*/ {0,0,0,0,0,0,0,0}, - /*CT_HELP*/ {0,0,0,0,0,0,0,0}, - /*EXP_LIST*/ {0,0,0,0,0,0,0,0}, --/*EXP_CREATE*/ {1,1,1,1,1,1,1,1}, -+/*EXP_CREATE*/ {1,1,0,0,1,1,1,1}, - /*EXP_DELETE*/ {1,1,1,1,0,0,0,0}, - /*EXP_GET*/ {1,1,1,1,0,0,0,0}, - /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0}, -@@ -87,7 +87,7 @@ static int parse_options(char c, - unsigned int *flags) - { - switch(c) { -- u_int16_t port; -+ uint16_t port; - case '1': - port = htons(atoi(optarg)); - nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); -diff --git a/extensions/libct_proto_udplite.c b/extensions/libct_proto_udplite.c -index bffd5fe..f46cef0 100644 ---- a/extensions/libct_proto_udplite.c -+++ b/extensions/libct_proto_udplite.c -@@ -81,7 +81,7 @@ static char udplite_commands_v_options[NUMBER_OF_CMD][UDP_OPT_MAX] = - /*CT_VERSION*/ {0,0,0,0,0,0,0,0}, - /*CT_HELP*/ {0,0,0,0,0,0,0,0}, - /*EXP_LIST*/ {0,0,0,0,0,0,0,0}, --/*EXP_CREATE*/ {1,1,1,1,1,1,1,1}, -+/*EXP_CREATE*/ {1,1,0,0,1,1,1,1}, - /*EXP_DELETE*/ {1,1,1,1,0,0,0,0}, - /*EXP_GET*/ {1,1,1,1,0,0,0,0}, - /*EXP_FLUSH*/ {0,0,0,0,0,0,0,0}, -@@ -95,7 +95,7 @@ static int parse_options(char c, - unsigned int *flags) - { - switch(c) { -- u_int16_t port; -+ uint16_t port; - case '1': - port = htons(atoi(optarg)); - nfct_set_attr_u16(ct, ATTR_ORIG_PORT_SRC, port); -diff --git a/include/bitops.h b/include/bitops.h -index 51f4289..27fe58d 100644 ---- a/include/bitops.h -+++ b/include/bitops.h -@@ -1,34 +1,34 @@ - #ifndef _BITOPS_H_ - #define _BITOPS_H_ - --#include -+#include - --static inline void set_bit_u32(int nr, u_int32_t *addr) -+static inline void set_bit_u32(int nr, uint32_t *addr) - { - addr[nr >> 5] |= (1UL << (nr & 31)); - } - --static inline void unset_bit_u32(int nr, u_int32_t *addr) -+static inline void unset_bit_u32(int nr, uint32_t *addr) - { - addr[nr >> 5] &= ~(1UL << (nr & 31)); - } - --static inline int test_bit_u32(int nr, const u_int32_t *addr) -+static inline int test_bit_u32(int nr, const uint32_t *addr) - { - return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0; - } - --static inline void set_bit_u16(int nr, u_int16_t *addr) -+static inline void set_bit_u16(int nr, uint16_t *addr) - { - addr[nr >> 4] |= (1UL << (nr & 15)); - } - --static inline void unset_bit_u16(int nr, u_int16_t *addr) -+static inline void unset_bit_u16(int nr, uint16_t *addr) - { - addr[nr >> 4] &= ~(1UL << (nr & 15)); - } - --static inline int test_bit_u16(int nr, const u_int16_t *addr) -+static inline int test_bit_u16(int nr, const uint16_t *addr) - { - return ((1UL << (nr & 15)) & (addr[nr >> 4])) != 0; - } -diff --git a/include/conntrack.h b/include/conntrack.h -index 6cd9962..c2a0c8f 100644 ---- a/include/conntrack.h -+++ b/include/conntrack.h -@@ -10,7 +10,7 @@ - #include - - #define NUMBER_OF_CMD 19 --#define NUMBER_OF_OPT 25 -+#define NUMBER_OF_OPT 27 - - struct ctproto_handler { - struct list_head head; -diff --git a/include/helper.h b/include/helper.h -index 9d96fb7..f412e55 100644 ---- a/include/helper.h -+++ b/include/helper.h -@@ -25,7 +25,7 @@ struct ctd_helper { - int (*cb)(struct pkt_buff *pkt, - uint32_t protoff, - struct myct *ct, -- u_int32_t ctinfo); -+ uint32_t ctinfo); - - struct ctd_helper_policy policy[CTD_HELPER_POLICY_MAX]; - -@@ -49,6 +49,9 @@ extern int cthelper_del_expect(struct nf_expect *exp); - extern void cthelper_get_addr_src(struct nf_conntrack *ct, int dir, union nfct_attr_grp_addr *addr); - extern void cthelper_get_addr_dst(struct nf_conntrack *ct, int dir, union nfct_attr_grp_addr *addr); - -+void cthelper_get_port_src(struct nf_conntrack *ct, int dir, uint16_t *port); -+void cthelper_get_port_dst(struct nf_conntrack *ct, int dir, uint16_t *port); -+ - extern int in4_pton(const char *src, int srclen, uint8_t *dst, int delim, const char **end); - extern int in6_pton(const char *src, int srclen, uint8_t *dst, int delim, const char **end); - -diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h -index b64454c..c755646 100644 ---- a/include/linux/netfilter/nfnetlink.h -+++ b/include/linux/netfilter/nfnetlink.h -@@ -18,6 +18,10 @@ enum nfnetlink_groups { - #define NFNLGRP_CONNTRACK_EXP_UPDATE NFNLGRP_CONNTRACK_EXP_UPDATE - NFNLGRP_CONNTRACK_EXP_DESTROY, - #define NFNLGRP_CONNTRACK_EXP_DESTROY NFNLGRP_CONNTRACK_EXP_DESTROY -+ NFNLGRP_NFTABLES, -+#define NFNLGRP_NFTABLES NFNLGRP_NFTABLES -+ NFNLGRP_ACCT_QUOTA, -+#define NFNLGRP_ACCT_QUOTA NFNLGRP_ACCT_QUOTA - __NFNLGRP_MAX, - }; - #define NFNLGRP_MAX (__NFNLGRP_MAX - 1) -@@ -49,46 +53,14 @@ struct nfgenmsg { - #define NFNL_SUBSYS_OSF 5 - #define NFNL_SUBSYS_IPSET 6 - #define NFNL_SUBSYS_ACCT 7 --#define NFNL_SUBSYS_COUNT 8 -+#define NFNL_SUBSYS_CTNETLINK_TIMEOUT 8 -+#define NFNL_SUBSYS_CTHELPER 9 -+#define NFNL_SUBSYS_NFTABLES 10 -+#define NFNL_SUBSYS_NFT_COMPAT 11 -+#define NFNL_SUBSYS_COUNT 12 - --#ifdef __KERNEL__ -+/* Reserved control nfnetlink messages */ -+#define NFNL_MSG_BATCH_BEGIN NLMSG_MIN_TYPE -+#define NFNL_MSG_BATCH_END NLMSG_MIN_TYPE+1 - --#include --#include --#include -- --struct nfnl_callback { -- int (*call)(struct sock *nl, struct sk_buff *skb, -- const struct nlmsghdr *nlh, -- const struct nlattr * const cda[]); -- int (*call_rcu)(struct sock *nl, struct sk_buff *skb, -- const struct nlmsghdr *nlh, -- const struct nlattr * const cda[]); -- const struct nla_policy *policy; /* netlink attribute policy */ -- const u_int16_t attr_count; /* number of nlattr's */ --}; -- --struct nfnetlink_subsystem { -- const char *name; -- __u8 subsys_id; /* nfnetlink subsystem ID */ -- __u8 cb_count; /* number of callbacks */ -- const struct nfnl_callback *cb; /* callback for individual types */ --}; -- --extern int nfnetlink_subsys_register(const struct nfnetlink_subsystem *n); --extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); -- --extern int nfnetlink_has_listeners(struct net *net, unsigned int group); --extern int nfnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, unsigned group, -- int echo, gfp_t flags); --extern int nfnetlink_set_err(struct net *net, u32 pid, u32 group, int error); --extern int nfnetlink_unicast(struct sk_buff *skb, struct net *net, u_int32_t pid, int flags); -- --extern void nfnl_lock(void); --extern void nfnl_unlock(void); -- --#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \ -- MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys)) -- --#endif /* __KERNEL__ */ --#endif /* _NFNETLINK_H */ -+#endif /* _NFNETLINK_H */ -diff --git a/include/linux/netfilter/nfnetlink_cttimeout.h b/include/linux/netfilter/nfnetlink_cttimeout.h -index a2810a7..1ab0b97 100644 ---- a/include/linux/netfilter/nfnetlink_cttimeout.h -+++ b/include/linux/netfilter/nfnetlink_cttimeout.h -@@ -6,6 +6,8 @@ enum ctnl_timeout_msg_types { - IPCTNL_MSG_TIMEOUT_NEW, - IPCTNL_MSG_TIMEOUT_GET, - IPCTNL_MSG_TIMEOUT_DELETE, -+ IPCTNL_MSG_TIMEOUT_DEFAULT_SET, -+ IPCTNL_MSG_TIMEOUT_DEFAULT_GET, - - IPCTNL_MSG_TIMEOUT_MAX - }; -diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h -index e0d8fd8..8dd819e 100644 ---- a/include/linux/netfilter/nfnetlink_queue.h -+++ b/include/linux/netfilter/nfnetlink_queue.h -@@ -44,6 +44,11 @@ enum nfqnl_attr_type { - NFQA_PAYLOAD, /* opaque data payload */ - NFQA_CT, /* nf_conntrack_netlink.h */ - NFQA_CT_INFO, /* enum ip_conntrack_info */ -+ NFQA_CAP_LEN, /* __u32 length of captured packet */ -+ NFQA_SKB_INFO, /* __u32 skb meta information */ -+ NFQA_EXP, /* nf_conntrack_netlink.h */ -+ NFQA_UID, /* __u32 sk uid */ -+ NFQA_GID, /* __u32 sk gid */ - - __NFQA_MAX - }; -@@ -95,5 +100,16 @@ enum nfqnl_attr_config { - /* Flags for NFQA_CFG_FLAGS */ - #define NFQA_CFG_F_FAIL_OPEN (1 << 0) - #define NFQA_CFG_F_CONNTRACK (1 << 1) -+#define NFQA_CFG_F_GSO (1 << 2) -+#define NFQA_CFG_F_UID_GID (1 << 3) -+#define NFQA_CFG_F_MAX (1 << 4) -+ -+/* flags for NFQA_SKB_INFO */ -+/* packet appears to have wrong checksums, but they are ok */ -+#define NFQA_SKB_CSUMNOTREADY (1 << 0) -+/* packet is GSO (i.e., exceeds device mtu) */ -+#define NFQA_SKB_GSO (1 << 1) -+/* csum not validated (incoming device doesn't support hw checksum, etc.) */ -+#define NFQA_SKB_CSUM_NOTVERIFIED (1 << 2) - - #endif /* _NFNETLINK_QUEUE_H */ -diff --git a/include/mcast.h b/include/mcast.h -index 402a033..f0225aa 100644 ---- a/include/mcast.h -+++ b/include/mcast.h -@@ -4,6 +4,7 @@ - #include - #include - #include -+#include - - struct mcast_conf { - int ipproto; -diff --git a/include/myct.h b/include/myct.h -index 45d9f29..02d695c 100644 ---- a/include/myct.h -+++ b/include/myct.h -@@ -37,6 +37,7 @@ struct myct_tuple { - - struct myct { - struct nf_conntrack *ct; -+ struct nf_expect *exp; - void *priv_data; - }; - -diff --git a/include/nfct.h b/include/nfct.h -index 5548b03..dc103c6 100644 ---- a/include/nfct.h -+++ b/include/nfct.h -@@ -1,6 +1,8 @@ - #ifndef _NFCT_H_ - #define _NFCT_H_ - -+#include "linux_list.h" -+ - enum { - NFCT_SUBSYS_NONE = 0, - NFCT_SUBSYS_TIMEOUT, -@@ -17,23 +19,26 @@ enum { - NFCT_CMD_GET, - NFCT_CMD_FLUSH, - NFCT_CMD_DISABLE, -+ NFCT_CMD_DEFAULT_SET, -+ NFCT_CMD_DEFAULT_GET, - }; - -+#define __init __attribute__((constructor)) -+ - void nfct_perror(const char *msg); - --int nfct_cmd_timeout_parse_params(int argc, char *argv[]); --int nfct_cmd_timeout_list(int argc, char *argv[]); --int nfct_cmd_timeout_add(int argc, char *argv[]); --int nfct_cmd_timeout_delete(int argc, char *argv[]); --int nfct_cmd_timeout_get(int argc, char *argv[]); --int nfct_cmd_timeout_flush(int argc, char *argv[]); -- --int nfct_cmd_helper_parse_params(int argc, char *argv[]); --int nfct_cmd_helper_list(int argc, char *argv[]); --int nfct_cmd_helper_add(int argc, char *argv[]); --int nfct_cmd_helper_delete(int argc, char *argv[]); --int nfct_cmd_helper_get(int argc, char *argv[]); --int nfct_cmd_helper_flush(int argc, char *argv[]); --int nfct_cmd_helper_disable(int argc, char *argv[]); -+struct nfct_extension { -+ struct list_head head; -+ int type; -+ int (*parse_params)(struct mnl_socket *nl, int argc, char *argv[]); -+}; -+ -+void nfct_extension_register(struct nfct_extension *ext); -+ -+struct mnl_socket *nfct_mnl_open(void); -+int nfct_mnl_talk(struct mnl_socket *nl, struct nlmsghdr *nlh, -+ uint32_t seq, uint32_t portid, -+ int (*cb)(const struct nlmsghdr *nlh, void *data), -+ void *data); - - #endif -diff --git a/include/tcp.h b/include/tcp.h -index 2f0fd0a..068d43a 100644 ---- a/include/tcp.h -+++ b/include/tcp.h -@@ -3,6 +3,7 @@ - - #include - #include -+#include - - struct tcp_conf { - int ipproto; -diff --git a/include/udp.h b/include/udp.h -index 9f9c17a..53d713d 100644 ---- a/include/udp.h -+++ b/include/udp.h -@@ -3,6 +3,7 @@ - - #include - #include -+#include - - struct udp_conf { - int ipproto; -diff --git a/src/Makefile.am b/src/Makefile.am -index ec03e46..1bc3622 100644 ---- a/src/Makefile.am -+++ b/src/Makefile.am -@@ -1,6 +1,8 @@ - include $(top_srcdir)/Make_global.am - -+if HAVE_CTHELPER - SUBDIRS = helpers -+endif - - AM_YFLAGS = -d - -@@ -11,17 +13,29 @@ 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} - --nfct_SOURCES = nfct.c \ -- helpers.c \ -- nfct-extensions/timeout.c \ -- nfct-extensions/helper.c -+nfct_SOURCES = nfct.c -+ -+if HAVE_CTHELPER -+nfct_SOURCES += helpers.c \ -+ nfct-extensions/helper.c -+endif -+ -+if HAVE_CTTIMEOUT -+nfct_SOURCES += nfct-extensions/timeout.c -+endif - - nfct_LDADD = ${LIBMNL_LIBS} \ - ${LIBNETFILTER_CONNTRACK_LIBS} \ -- ${LIBNETFILTER_CTTIMEOUT_LIBS} \ -- ${LIBNETFILTER_CTHELPER_LIBS} \ - ${libdl_LIBS} - -+if HAVE_CTTIMEOUT -+nfct_LDADD += ${LIBNETFILTER_CTTIMEOUT_LIBS} -+endif -+ -+if HAVE_CTHELPER -+nfct_LDADD += ${LIBNETFILTER_CTHELPER_LIBS} -+endif -+ - nfct_LDFLAGS = -export-dynamic - - conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ -@@ -29,7 +43,7 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.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 cthelper.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 \ -@@ -39,15 +53,22 @@ conntrackd_SOURCES = alarm.c main.c run.c hash.c queue.c rbtree.c \ - external_cache.c external_inject.c \ - internal_cache.c internal_bypass.c \ - read_config_yy.y read_config_lex.l \ -- stack.c helpers.c utils.c expect.c -+ stack.c -+ -+if HAVE_CTHELPER -+conntrackd_SOURCES += cthelper.c helpers.c utils.c expect.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 - - conntrackd_LDADD = ${LIBMNL_LIBS} ${LIBNETFILTER_CONNTRACK_LIBS} \ -- ${LIBNETFILTER_QUEUE_LIBS} ${LIBNETFILTER_CTHELPER_LIBS} \ - ${libdl_LIBS} ${LIBNFNETLINK_LIBS} - -+if HAVE_CTHELPER -+conntrackd_LDADD += ${LIBNETFILTER_CTHELPER_LIBS} ${LIBNETFILTER_QUEUE_LIBS} -+endif -+ - conntrackd_LDFLAGS = -export-dynamic - - EXTRA_DIST = read_config_yy.h -diff --git a/src/build.c b/src/build.c -index 5799b51..9ba8b57 100644 ---- a/src/build.c -+++ b/src/build.c -@@ -105,14 +105,14 @@ static enum nf_conntrack_attr nat_type[] = - ATTR_ORIG_NAT_SEQ_OFFSET_AFTER, ATTR_REPL_NAT_SEQ_CORRECTION_POS, - ATTR_REPL_NAT_SEQ_OFFSET_BEFORE, ATTR_REPL_NAT_SEQ_OFFSET_AFTER }; - -+/* 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); -@@ -122,12 +122,12 @@ 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); -@@ -135,18 +135,22 @@ 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); - } - - static void build_l4proto_icmp(const struct nf_conntrack *ct, struct nethdr *n) - { -+ /* This is also used by ICMPv6 and nf_conntrack_ipv6 is optional */ -+ if (!nfct_attr_is_set(ct, ATTR_ICMP_TYPE)) -+ return; -+ - ct_build_u8(ct, ATTR_ICMP_TYPE, n, NTA_ICMP_TYPE); - ct_build_u8(ct, ATTR_ICMP_CODE, n, NTA_ICMP_CODE); - ct_build_u16(ct, ATTR_ICMP_ID, n, NTA_ICMP_ID); -diff --git a/src/channel.c b/src/channel.c -index 8b7c319..acbfa7d 100644 ---- a/src/channel.c -+++ b/src/channel.c -@@ -109,6 +109,7 @@ channel_open(struct channel_conf *cfg) - - if (ioctl(fd, SIOCGIFMTU, &ifr) == -1) { - free(c); -+ close(fd); - return NULL; - } - close(fd); -diff --git a/src/conntrack.c b/src/conntrack.c -index 7d2a365..00b09b6 100644 ---- a/src/conntrack.c -+++ b/src/conntrack.c -@@ -82,6 +82,9 @@ static struct { - - /* 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) -@@ -109,6 +112,8 @@ static void free_tmpl_objects(void) - 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 { -@@ -255,6 +260,12 @@ enum ct_options { - - CT_OPT_LABEL_BIT = 24, - CT_OPT_LABEL = (1 << CT_OPT_LABEL_BIT), -+ -+ CT_OPT_ADD_LABEL_BIT = 25, -+ CT_OPT_ADD_LABEL = (1 << CT_OPT_ADD_LABEL_BIT), -+ -+ CT_OPT_DEL_LABEL_BIT = 26, -+ CT_OPT_DEL_LABEL = (1 << CT_OPT_DEL_LABEL_BIT), - }; - /* If you add a new option, you have to update NUMBER_OF_OPT in conntrack.h */ - -@@ -289,6 +300,8 @@ static const char *optflags[NUMBER_OF_OPT] = { - [CT_OPT_ANY_NAT_BIT] = "any-nat", - [CT_OPT_ZONE_BIT] = "zone", - [CT_OPT_LABEL_BIT] = "label", -+ [CT_OPT_ADD_LABEL_BIT] = "label-add", -+ [CT_OPT_DEL_LABEL_BIT] = "label-del", - }; - - static struct option original_opts[] = { -@@ -330,12 +343,14 @@ static struct option original_opts[] = { - {"any-nat", 2, 0, 'j'}, - {"zone", 1, 0, 'w'}, - {"label", 1, 0, 'l'}, -+ {"label-add", 1, 0, '<'}, -+ {"label-del", 2, 0, '>'}, - {0, 0, 0, 0} - }; - - static const char *getopt_str = ":L::I::U::D::G::E::F::hVs:d:r:q:" - "p:t:u:e:a:z[:]:{:}:m:i:f:o:n::" -- "g::c:b:C::Sj::w:l:"; -+ "g::c:b:C::Sj::w:l:<:>::"; - - /* Table of legal combinations of commands and options. If any of the - * given commands make an option legal, that option is legal (applies to -@@ -350,26 +365,26 @@ 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,0,0,0,2,0,2,2,2,2,2,0,2,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}, --/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,0}, --/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,0}, --/*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,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}, --/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, --/*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}, -+ /* 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,0,0,0,2,0,2,2,2,2,2,0,2,2,2,0,0}, -+/*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}, -+/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,2,2,2}, -+/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,2,0,0}, -+/*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}, -+/*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}, -+/*CT_EVENT*/ {2,2,2,2,2,0,0,0,2,0,0,0,0,0,2,0,0,2,2,2,2,2,2,2,2,0,0}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, -+/*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}, - }; - - static const int cmd2type[][2] = { -@@ -402,6 +417,8 @@ static const int opt2type[] = { - ['j'] = CT_OPT_ANY_NAT, - ['w'] = CT_OPT_ZONE, - ['l'] = CT_OPT_LABEL, -+ ['<'] = CT_OPT_ADD_LABEL, -+ ['>'] = CT_OPT_DEL_LABEL, - }; - - static const int opt2family_attr[][2] = { -@@ -420,11 +437,17 @@ static const int opt2attr[] = { - ['d'] = ATTR_ORIG_L3PROTO, - ['r'] = ATTR_REPL_L3PROTO, - ['q'] = ATTR_REPL_L3PROTO, -+ ['{'] = ATTR_ORIG_L3PROTO, -+ ['}'] = ATTR_ORIG_L3PROTO, -+ ['['] = ATTR_ORIG_L3PROTO, -+ [']'] = ATTR_ORIG_L3PROTO, - ['m'] = ATTR_MARK, - ['c'] = ATTR_SECMARK, - ['i'] = ATTR_ID, - ['w'] = ATTR_ZONE, - ['l'] = ATTR_CONNLABELS, -+ ['<'] = ATTR_CONNLABELS, -+ ['>'] = ATTR_CONNLABELS, - }; - - static char exit_msg[NUMBER_OF_CMD][64] = { -@@ -472,6 +495,11 @@ static const char usage_expectation_parameters[] = - " --mask-src ip\t\tSource mask address\n" - " --mask-dst ip\t\tDestination mask address\n"; - -+static const char usage_update_parameters[] = -+ "Updating parameters and options:\n" -+ " --label-add label\tAdd label\n" -+ " --label-del label\tDelete label\n"; -+ - static const char usage_parameters[] = - "Common parameters and options:\n" - " -s, --orig-src ip\t\tSource address from original direction\n" -@@ -523,7 +551,7 @@ static struct ctproto_handler *findproto(char *name, int *pnum) - - /* is it in the list of supported protocol? */ - list_for_each_entry(cur, &proto_list, head) { -- if (strcmp(cur->name, name) == 0) { -+ if (strcasecmp(cur->name, name) == 0) { - *pnum = cur->protonum; - return cur; - } -@@ -890,20 +918,20 @@ add_command(unsigned int *cmd, const int newcmd) - *cmd |= newcmd; - } - --static char *get_table(int argc, char *argv[]) -+static char *get_optional_arg(int argc, char *argv[]) - { -- char *table = NULL; -+ char *arg = NULL; - - /* Nasty bug or feature in getopt_long ? - * It seems that it behaves badly with optional arguments. - * Fortunately, I just stole the fix from iptables ;) */ - if (optarg) -- return 0; -+ return arg; - else if (optind < argc && argv[optind][0] != '-' && - argv[optind][0] != '!') -- table = argv[optind++]; -+ arg = argv[optind++]; - -- return table; -+ return arg; - } - - enum { -@@ -915,7 +943,7 @@ enum { - - static unsigned int check_type(int argc, char *argv[]) - { -- const char *table = get_table(argc, argv); -+ const char *table = get_optional_arg(argc, argv); - - /* default to conntrack subsystem if nothing has been specified. */ - if (table == NULL) -@@ -1045,6 +1073,7 @@ usage(char *prog) - fprintf(stdout, "\n%s", usage_tables); - fprintf(stdout, "\n%s", usage_conntrack_parameters); - fprintf(stdout, "\n%s", usage_expectation_parameters); -+ fprintf(stdout, "\n%s", usage_update_parameters); - fprintf(stdout, "\n%s\n", usage_parameters); - } - -@@ -1349,7 +1378,7 @@ static int print_cb(enum nf_conntrack_msg_type type, - if (output_mask & _O_ID) - op_flags |= NFCT_OF_ID; - -- nfct_snprintf(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags); -+ nfct_snprintf_labels(buf, sizeof(buf), ct, NFCT_T_UNKNOWN, op_type, op_flags, labelmap); - printf("%s\n", buf); - - return NFCT_CB_CONTINUE; -@@ -1376,6 +1405,72 @@ static void copy_status(struct nf_conntrack *tmp, const struct nf_conntrack *ct) - } - } - -+static struct nfct_bitmask *xnfct_bitmask_clone(const struct nfct_bitmask *a) -+{ -+ struct nfct_bitmask *b = nfct_bitmask_clone(a); -+ if (!b) -+ exit_error(OTHER_PROBLEM, "out of memory"); -+ return b; -+} -+ -+static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct) -+{ -+ struct nfct_bitmask *ctb, *newmask; -+ unsigned int i; -+ -+ if ((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 (ctb == NULL) { -+ nfct_set_attr(tmp, ATTR_CONNLABELS, -+ xnfct_bitmask_clone(tmpl.label_modify)); -+ return; -+ } -+ /* If we send a bitmask shorter than the kernel sent to us, the bits we -+ * omit will be cleared (as "padding"). So we always have to send the -+ * same sized bitmask as we received. -+ * -+ * Mask has to have the same size as the labels, otherwise it will not -+ * be encoded by libnetfilter_conntrack, as different sizes are not -+ * accepted by the kernel. -+ */ -+ 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)) { -+ nfct_bitmask_set_bit(ctb, i); -+ nfct_bitmask_set_bit(newmask, i); -+ } else if (nfct_bitmask_test_bit(ctb, i)) { -+ /* Kernel only retains old bit values that are sent as -+ * zeroes in BOTH labels and mask. -+ */ -+ nfct_bitmask_unset_bit(ctb, i); -+ } -+ } -+ nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); -+ } else if (ctb != NULL) { -+ /* CT_OPT_DEL_LABEL */ -+ if (tmpl.label_modify == NULL) { -+ newmask = nfct_bitmask_new(0); -+ if (newmask) -+ nfct_set_attr(tmp, ATTR_CONNLABELS, newmask); -+ return; -+ } -+ -+ for (i = 0; i <= nfct_bitmask_maxbit(ctb); i++) { -+ if (nfct_bitmask_test_bit(tmpl.label_modify, i)) -+ nfct_bitmask_unset_bit(ctb, i); -+ } -+ -+ 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) -@@ -1395,6 +1490,9 @@ static int update_cb(enum nf_conntrack_msg_type type, - if (options & CT_OPT_TUPLE_REPL && !nfct_cmp(obj, ct, NFCT_CMP_REPL)) - return NFCT_CB_CONTINUE; - -+ if (filter_label(ct)) -+ return NFCT_CB_CONTINUE; -+ - tmp = nfct_new(); - if (tmp == NULL) - exit_error(OTHER_PROBLEM, "out of memory"); -@@ -1403,6 +1501,7 @@ static int update_cb(enum nf_conntrack_msg_type type, - nfct_copy(tmp, obj, NFCT_CP_META); - copy_mark(tmp, ct, &tmpl.mark); - copy_status(tmp, ct); -+ copy_label(tmp, ct); - - /* do not send NFCT_Q_UPDATE if ct appears unchanged */ - if (nfct_cmp(tmp, ct, NFCT_CMP_ALL | NFCT_CMP_MASK)) { -@@ -1411,12 +1510,10 @@ static int update_cb(enum nf_conntrack_msg_type type, - } - - res = nfct_query(ith, NFCT_Q_UPDATE, tmp); -- if (res < 0) { -- nfct_destroy(tmp); -- exit_error(OTHER_PROBLEM, -- "Operation failed: %s", -+ if (res < 0) -+ fprintf(stderr, -+ "Operation failed: %s\n", - err2str(errno, CT_UPDATE)); -- } - nfct_callback_register(ith, NFCT_T_ALL, print_cb, NULL); - - res = nfct_query(ith, NFCT_Q_GET, tmp); -@@ -1601,7 +1698,8 @@ static int nfct_mnl_socket_open(void) - } - - static struct nlmsghdr * --nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) -+nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, -+ uint8_t family) - { - struct nlmsghdr *nlh; - struct nfgenmsg *nfh; -@@ -1612,7 +1710,7 @@ nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type) - nlh->nlmsg_seq = time(NULL); - - nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); -- nfh->nfgen_family = AF_INET; -+ nfh->nfgen_family = family; - nfh->version = NFNETLINK_V0; - nfh->res_id = 0; - -@@ -1625,13 +1723,13 @@ static void nfct_mnl_socket_close(void) - } - - static int --nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) -+nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family) - { - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - int res; - -- nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); -+ nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family); - - res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); - if (res < 0) -@@ -1651,13 +1749,13 @@ nfct_mnl_dump(uint16_t subsys, uint16_t type, mnl_cb_t cb) - } - - static int --nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb) -+nfct_mnl_get(uint16_t subsys, uint16_t type, mnl_cb_t cb, uint8_t family) - { - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - int res; - -- nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type); -+ nlh = nfct_mnl_nlmsghdr_put(buf, subsys, type, family); - - res = mnl_socket_sendto(sock.mnl, nlh, nlh->nlmsg_len); - if (res < 0) -@@ -1818,6 +1916,65 @@ static int mnl_nfct_dump_cb(const struct nlmsghdr *nlh, void *data) - - static struct ctproto_handler *h; - -+static void labelmap_init(void) -+{ -+ if (labelmap) -+ return; -+ labelmap = nfct_labelmap_new(NULL); -+ if (!labelmap) -+ perror("nfct_labelmap_new"); -+} -+ -+static void merge_bitmasks(struct nfct_bitmask **current, -+ struct nfct_bitmask *src) -+{ -+ unsigned int i; -+ -+ if (*current == NULL) { -+ *current = src; -+ return; -+ } -+ -+ /* "current" must be the larger bitmask object */ -+ if (nfct_bitmask_maxbit(src) > nfct_bitmask_maxbit(*current)) { -+ struct nfct_bitmask *tmp = *current; -+ *current = src; -+ src = tmp; -+ } -+ -+ for (i = 0; i <= nfct_bitmask_maxbit(src); i++) { -+ if (nfct_bitmask_test_bit(src, i)) -+ nfct_bitmask_set_bit(*current, i); -+ } -+ -+ nfct_bitmask_destroy(src); -+} -+ -+static void -+nfct_set_addr_from_opt(int opt, struct nf_conntrack *ct, union ct_address *ad, -+ int *family) -+{ -+ int l3protonum; -+ -+ options |= opt2type[opt]; -+ l3protonum = parse_addr(optarg, ad); -+ if (l3protonum == AF_UNSPEC) { -+ exit_error(PARAMETER_PROBLEM, -+ "Invalid IP address `%s'", optarg); -+ } -+ set_family(family, l3protonum); -+ if (l3protonum == AF_INET) { -+ nfct_set_attr_u32(ct, -+ opt2family_attr[opt][0], -+ ad->v4); -+ } else if (l3protonum == AF_INET6) { -+ nfct_set_attr(ct, -+ opt2family_attr[opt][1], -+ &ad->v6); -+ } -+ nfct_set_attr_u8(ct, opt2attr[opt], l3protonum); -+} -+ - int main(int argc, char *argv[]) - { - int c, cmd; -@@ -1825,7 +1982,7 @@ int main(int argc, char *argv[]) - int res = 0, partial; - size_t socketbuffersize = 0; - int family = AF_UNSPEC; -- int l3protonum, protonum = 0; -+ int protonum = 0; - union ct_address ad; - unsigned int command = 0; - -@@ -1896,47 +2053,15 @@ int main(int argc, char *argv[]) - case 'd': - case 'r': - case 'q': -- options |= opt2type[c]; -- -- l3protonum = parse_addr(optarg, &ad); -- if (l3protonum == AF_UNSPEC) { -- exit_error(PARAMETER_PROBLEM, -- "Invalid IP address `%s'", optarg); -- } -- set_family(&family, l3protonum); -- if (l3protonum == AF_INET) { -- nfct_set_attr_u32(tmpl.ct, -- opt2family_attr[c][0], -- ad.v4); -- } else if (l3protonum == AF_INET6) { -- nfct_set_attr(tmpl.ct, -- opt2family_attr[c][1], -- &ad.v6); -- } -- nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum); -+ nfct_set_addr_from_opt(c, tmpl.ct, &ad, &family); - break; - case '{': - case '}': -+ nfct_set_addr_from_opt(c, tmpl.exptuple, &ad, &family); -+ break; - case '[': - case ']': -- options |= opt2type[c]; -- l3protonum = parse_addr(optarg, &ad); -- if (l3protonum == AF_UNSPEC) { -- exit_error(PARAMETER_PROBLEM, -- "Invalid IP address `%s'", optarg); -- } -- set_family(&family, l3protonum); -- if (l3protonum == AF_INET) { -- nfct_set_attr_u32(tmpl.mask, -- opt2family_attr[c][0], -- ad.v4); -- } else if (l3protonum == AF_INET6) { -- nfct_set_attr(tmpl.mask, -- opt2family_attr[c][1], -- &ad.v6); -- } -- nfct_set_attr_u8(tmpl.mask, -- ATTR_ORIG_L3PROTO, l3protonum); -+ nfct_set_addr_from_opt(c, tmpl.mask, &ad, &family); - break; - case 'p': - options |= CT_OPT_PROTO; -@@ -1970,12 +2095,8 @@ int main(int argc, char *argv[]) - case 'o': - options |= CT_OPT_OUTPUT; - parse_parameter(optarg, &output_mask, PARSE_OUTPUT); -- if (output_mask & _O_CL) { -- if (!labelmap) -- labelmap = nfct_labelmap_new(NULL); -- if (!labelmap) -- perror("nfct_labelmap_new"); -- } -+ if (output_mask & _O_CL) -+ labelmap_init(); - break; - case 'z': - options |= CT_OPT_ZERO; -@@ -1987,12 +2108,7 @@ int main(int argc, char *argv[]) - - options |= opt2type[c]; - -- if (optarg) -- continue; -- else if (optind < argc && argv[optind][0] != '-' -- && argv[optind][0] != '!') -- tmp = argv[optind++]; -- -+ tmp = get_optional_arg(argc, argv); - if (tmp == NULL) - continue; - -@@ -2020,19 +2136,39 @@ int main(int argc, char *argv[]) - tmpl.filter_mark_kernel.mask = tmpl.mark.mask; - break; - case 'l': -+ case '<': -+ case '>': - options |= opt2type[c]; -- char *optarg2 = strdup(optarg); - -- if (!labelmap) -- labelmap = nfct_labelmap_new(NULL); -- if (!labelmap) -- exit_error(OTHER_PROBLEM, "unable to open labelmap file"); -+ labelmap_init(); - -+ if ((options & (CT_OPT_DEL_LABEL|CT_OPT_ADD_LABEL)) == -+ (CT_OPT_DEL_LABEL|CT_OPT_ADD_LABEL)) -+ exit_error(OTHER_PROBLEM, "cannot use --label-add and " -+ "--label-del at the same time"); -+ -+ if (c == '>') { /* DELETE */ -+ char *tmp = get_optional_arg(argc, argv); -+ if (tmp == NULL) /* delete all labels */ -+ break; -+ optarg = tmp; -+ } -+ -+ char *optarg2 = strdup(optarg); - unsigned int max = parse_label_get_max(optarg); - struct nfct_bitmask * b = nfct_bitmask_new(max); -+ if (!b) -+ exit_error(OTHER_PROBLEM, "out of memory"); - - parse_label(b, optarg2); -- tmpl.label = b; -+ -+ /* join "-l foo -l bar" into single bitmask object */ -+ if (c == 'l') { -+ merge_bitmasks(&tmpl.label, b); -+ } else { -+ merge_bitmasks(&tmpl.label_modify, b); -+ } -+ - free(optarg2); - break; - case 'a': -@@ -2114,7 +2250,7 @@ int main(int argc, char *argv[]) - - res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_CT_GET_DYING, -- mnl_nfct_dump_cb); -+ mnl_nfct_dump_cb, family); - - nfct_mnl_socket_close(); - break; -@@ -2124,7 +2260,7 @@ int main(int argc, char *argv[]) - - res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_CT_GET_UNCONFIRMED, -- mnl_nfct_dump_cb); -+ mnl_nfct_dump_cb, family); - - nfct_mnl_socket_close(); - break; -@@ -2191,6 +2327,10 @@ int main(int argc, char *argv[]) - 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"); -@@ -2389,7 +2529,7 @@ int main(int argc, char *argv[]) - - res = nfct_mnl_get(NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_CT_GET_STATS, -- nfct_global_stats_cb); -+ nfct_global_stats_cb, AF_UNSPEC); - - nfct_mnl_socket_close(); - -@@ -2434,7 +2574,7 @@ try_proc_count: - - res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK, - IPCTNL_MSG_CT_GET_STATS_CPU, -- nfct_stats_cb); -+ nfct_stats_cb, AF_UNSPEC); - - nfct_mnl_socket_close(); - -@@ -2453,7 +2593,7 @@ try_proc_count: - - res = nfct_mnl_dump(NFNL_SUBSYS_CTNETLINK_EXP, - IPCTNL_MSG_EXP_GET_STATS_CPU, -- nfexp_stats_cb); -+ nfexp_stats_cb, AF_UNSPEC); - - nfct_mnl_socket_close(); - -diff --git a/src/cthelper.c b/src/cthelper.c -index 5a8a92a..6537515 100644 ---- a/src/cthelper.c -+++ b/src/cthelper.c -@@ -31,6 +31,7 @@ - #include - #include - #include -+#define _GNU_SOURCE - #include - #include - #include -@@ -182,6 +183,15 @@ pkt_verdict_issue(struct ctd_helper_instance *cur, struct myct *myct, - nfct_nlmsg_build(nlh, myct->ct); - mnl_attr_nest_end(nlh, nest); - -+ if (myct->exp) { -+ nest = mnl_attr_nest_start(nlh, NFQA_EXP); -+ if (nest == NULL) -+ return -1; -+ -+ nfexp_nlmsg_build(nlh, myct->exp); -+ mnl_attr_nest_end(nlh, nest); -+ } -+ - if (mnl_socket_sendto(STATE_CTH(nl), nlh, nlh->nlmsg_len) < 0) { - dlog(LOG_ERR, "failed to send verdict: %s", strerror(errno)); - return -1; -@@ -315,12 +325,12 @@ static int nfq_queue_cb(const struct nlmsghdr *nlh, void *data) - if (pkt_verdict_issue(helper, myct, queue_num, id, verdict, pktb) < 0) - goto err_pktb; - -- if (ct != NULL) -- nfct_destroy(ct); -- if (myct && myct->priv_data != NULL) -+ nfct_destroy(ct); -+ if (myct->exp != NULL) -+ nfexp_destroy(myct->exp); -+ if (myct->priv_data != NULL) - free(myct->priv_data); -- if (myct != NULL) -- free(myct); -+ free(myct); - - return MNL_CB_OK; - err_pktb: -@@ -458,7 +468,10 @@ static int cthelper_nfqueue_setup(struct ctd_helper_instance *cur) - nfq_nlmsg_cfg_put_params(nlh, NFQNL_COPY_PACKET, 0xffff); - mnl_attr_put_u32(nlh, NFQA_CFG_FLAGS, htonl(NFQA_CFG_F_CONNTRACK)); - mnl_attr_put_u32(nlh, NFQA_CFG_MASK, htonl(0xffffffff)); -- mnl_attr_put_u32(nlh, NFQA_CFG_QUEUE_MAXLEN, htonl(cur->queue_len)); -+ if (cur->queue_len > 0) { -+ mnl_attr_put_u32(nlh, NFQA_CFG_QUEUE_MAXLEN, -+ htonl(cur->queue_len)); -+ } - - if (mnl_socket_sendto(STATE_CTH(nl), nlh, nlh->nlmsg_len) < 0) { - dlog(LOG_ERR, "failed to send configuration"); -diff --git a/src/expect.c b/src/expect.c -index 470b9ae..5add7be 100644 ---- a/src/expect.c -+++ b/src/expect.c -@@ -39,8 +39,7 @@ cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master, - - if (saddr) { - switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) { -- int i; -- uint32_t addr[4] = {}; -+ uint32_t addr[4]; - - case AF_INET: - nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET); -@@ -52,10 +51,7 @@ cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master, - case AF_INET6: - nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6); - nfct_set_attr(expected, ATTR_IPV6_SRC, saddr->ip6); -- -- for (i=0; i<4; i++) -- memset(&addr[i], 0xffffffff, sizeof(uint32_t)); -- -+ memset(addr, 0xff, sizeof(addr)); - nfct_set_attr_u8(mask, ATTR_L3PROTO, AF_INET6); - nfct_set_attr(mask, ATTR_IPV6_SRC, addr); - break; -@@ -64,8 +60,7 @@ cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master, - } - } else { - switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) { -- int i; -- uint32_t addr[4] = {}; -+ uint32_t addr[4]; - - case AF_INET: - nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET); -@@ -75,9 +70,7 @@ cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master, - nfct_set_attr_u32(mask, ATTR_IPV4_SRC, 0x00000000); - break; - case AF_INET6: -- for (i=0; i<4; i++) -- memset(&addr[i], 0x00000000, sizeof(uint32_t)); -- -+ memset(addr, 0x00, sizeof(addr)); - nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6); - nfct_set_attr(expected, ATTR_IPV6_SRC, addr); - -@@ -116,8 +109,7 @@ cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master, - } - - switch(nfct_get_attr_u8(master, ATTR_L3PROTO)) { -- uint32_t addr[4] = {}; -- int i; -+ uint32_t addr[4]; - - case AF_INET: - nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET); -@@ -127,10 +119,7 @@ cthelper_expect_init(struct nf_expect *exp, struct nf_conntrack *master, - case AF_INET6: - nfct_set_attr_u8(expected, ATTR_L3PROTO, AF_INET6); - nfct_set_attr(expected, ATTR_IPV6_DST, daddr->ip6); -- -- for (i=0; i<4; i++) -- memset(addr, 0xffffffff, sizeof(uint32_t)); -- -+ memset(addr, 0xff, sizeof(addr)); - nfct_set_attr(mask, ATTR_IPV6_DST, addr); - break; - default: -@@ -212,3 +201,27 @@ cthelper_get_addr_dst(struct nf_conntrack *ct, int dir, - break; - } - } -+ -+void cthelper_get_port_src(struct nf_conntrack *ct, int dir, uint16_t *port) -+{ -+ switch (dir) { -+ case MYCT_DIR_ORIG: -+ *port = nfct_get_attr_u16(ct, ATTR_PORT_SRC); -+ break; -+ case MYCT_DIR_REPL: -+ *port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_SRC); -+ break; -+ } -+} -+ -+void cthelper_get_port_dst(struct nf_conntrack *ct, int dir, uint16_t *port) -+{ -+ switch (dir) { -+ case MYCT_DIR_ORIG: -+ *port = nfct_get_attr_u16(ct, ATTR_PORT_DST); -+ break; -+ case MYCT_DIR_REPL: -+ *port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); -+ break; -+ } -+} -diff --git a/src/filter.c b/src/filter.c -index 8fac71b..1ae2cc5 100644 ---- a/src/filter.c -+++ b/src/filter.c -@@ -33,8 +33,8 @@ - - struct ct_filter { - int logic[CT_FILTER_MAX]; -- u_int32_t l4protomap[IPPROTO_MAX/32]; -- u_int16_t statemap[IPPROTO_MAX]; -+ uint32_t l4protomap[IPPROTO_MAX/32]; -+ uint16_t statemap[IPPROTO_MAX]; - struct hashtable *h; - struct hashtable *h6; - struct vector *v; -diff --git a/src/helpers/Makefile.am b/src/helpers/Makefile.am -index 589b4f3..78ef7aa 100644 ---- a/src/helpers/Makefile.am -+++ b/src/helpers/Makefile.am -@@ -1,8 +1,21 @@ - include $(top_srcdir)/Make_global.am - --pkglib_LTLIBRARIES = ct_helper_ftp.la \ -+pkglib_LTLIBRARIES = ct_helper_amanda.la \ -+ ct_helper_dhcpv6.la \ -+ ct_helper_ftp.la \ - ct_helper_rpc.la \ -- ct_helper_tns.la -+ ct_helper_tftp.la \ -+ ct_helper_tns.la \ -+ ct_helper_sane.la \ -+ ct_helper_ssdp.la -+ -+ct_helper_amanda_la_SOURCES = amanda.c -+ct_helper_amanda_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) -+ct_helper_amanda_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) -+ -+ct_helper_dhcpv6_la_SOURCES = dhcpv6.c -+ct_helper_dhcpv6_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) -+ct_helper_dhcpv6_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) - - ct_helper_ftp_la_SOURCES = ftp.c - ct_helper_ftp_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) -@@ -12,6 +25,18 @@ ct_helper_rpc_la_SOURCES = rpc.c - ct_helper_rpc_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) - ct_helper_rpc_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) - -+ct_helper_tftp_la_SOURCES = tftp.c -+ct_helper_tftp_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) -+ct_helper_tftp_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) -+ - ct_helper_tns_la_SOURCES = tns.c - ct_helper_tns_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) - ct_helper_tns_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) -+ -+ct_helper_sane_la_SOURCES = sane.c -+ct_helper_sane_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) -+ct_helper_sane_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) -+ -+ct_helper_ssdp_la_SOURCES = ssdp.c -+ct_helper_ssdp_la_LDFLAGS = -avoid-version -module $(LIBNETFILTER_CONNTRACK_LIBS) -+ct_helper_ssdp_la_CFLAGS = $(AM_CFLAGS) $(LIBNETFILTER_CONNTRACK_CFLAGS) -diff --git a/src/helpers/amanda.c b/src/helpers/amanda.c -new file mode 100644 -index 0000000..9e6c4e7 ---- /dev/null -+++ b/src/helpers/amanda.c -@@ -0,0 +1,203 @@ -+/* -+ * (C) 2013 by Pablo Neira Ayuso -+ * -+ * Adapted from: -+ * -+ * Amanda extension for IP connection tracking -+ * -+ * (C) 2002 by Brian J. Murrell -+ * based on HW's ip_conntrack_irc.c as well as other modules -+ * (C) 2006 Patrick McHardy -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+#include "conntrackd.h" -+#include "helper.h" -+#include "myct.h" -+#include "log.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static int nat_amanda(struct pkt_buff *pkt, uint32_t ctinfo, -+ unsigned int matchoff, unsigned int matchlen, -+ struct nf_expect *exp) -+{ -+ char buffer[sizeof("65535")]; -+ uint16_t port, initial_port; -+ unsigned int ret; -+ const struct nf_conntrack *expected; -+ struct nf_conntrack *nat_tuple; -+ -+ nat_tuple = nfct_new(); -+ if (nat_tuple == NULL) -+ return NF_ACCEPT; -+ -+ expected = nfexp_get_attr(exp, ATTR_EXP_EXPECTED); -+ -+ /* Connection comes from client. */ -+ initial_port = nfct_get_attr_u16(expected, ATTR_PORT_DST); -+ nfexp_set_attr_u32(exp, ATTR_EXP_NAT_DIR, IP_CT_DIR_ORIGINAL); -+ -+ /* libnetfilter_conntrack needs this */ -+ nfct_set_attr_u8(nat_tuple, ATTR_L3PROTO, AF_INET); -+ nfct_set_attr_u32(nat_tuple, ATTR_IPV4_SRC, 0); -+ nfct_set_attr_u32(nat_tuple, ATTR_IPV4_DST, 0); -+ nfct_set_attr_u8(nat_tuple, ATTR_L4PROTO, IPPROTO_TCP); -+ nfct_set_attr_u16(nat_tuple, ATTR_PORT_DST, 0); -+ -+ /* When you see the packet, we need to NAT it the same as the -+ * this one (ie. same IP: it will be TCP and master is UDP). */ -+ nfexp_set_attr(exp, ATTR_EXP_FN, "nat-follow-master"); -+ -+ /* Try to get same port: if not, try to change it. */ -+ for (port = ntohs(initial_port); port != 0; port++) { -+ int res; -+ -+ nfct_set_attr_u16(nat_tuple, ATTR_PORT_SRC, htons(port)); -+ nfexp_set_attr(exp, ATTR_EXP_NAT_TUPLE, nat_tuple); -+ -+ res = cthelper_add_expect(exp); -+ if (res == 0) -+ break; -+ else if (res != -EBUSY) { -+ port = 0; -+ break; -+ } -+ } -+ -+ if (port == 0) { -+ pr_debug("all ports in use\n"); -+ return NF_DROP; -+ } -+ -+ sprintf(buffer, "%u", port); -+ ret = nfq_udp_mangle_ipv4(pkt, matchoff, matchlen, buffer, -+ strlen(buffer)); -+ if (ret != NF_ACCEPT) { -+ pr_debug("cannot mangle packet\n"); -+ cthelper_del_expect(exp); -+ } -+ return ret; -+} -+ -+static char amanda_buffer[65536]; -+static unsigned int master_timeout = 300; -+ -+enum amanda_strings { -+ SEARCH_CONNECT, -+ SEARCH_NEWLINE, -+ SEARCH_DATA, -+ SEARCH_MESG, -+ SEARCH_INDEX, -+}; -+ -+static const char *conns[] = { "DATA ", "MESG ", "INDEX " }; -+ -+static int -+amanda_helper_cb(struct pkt_buff *pkt, uint32_t protoff, -+ struct myct *myct, uint32_t ctinfo) -+{ -+ struct nf_expect *exp; -+ char *data, *data_limit, *tmp; -+ unsigned int dataoff, i; -+ uint16_t port, len; -+ int ret = NF_ACCEPT; -+ struct iphdr *iph; -+ union nfct_attr_grp_addr saddr, daddr; -+ -+ /* Only look at packets from the Amanda server */ -+ if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) -+ return NF_ACCEPT; -+ -+ /* increase the UDP timeout of the master connection as replies from -+ * Amanda clients to the server can be quite delayed */ -+ nfct_set_attr_u32(myct->ct, ATTR_TIMEOUT, master_timeout); -+ -+ /* No data? */ -+ iph = (struct iphdr *)pktb_network_header(pkt); -+ dataoff = iph->ihl*4 + sizeof(struct udphdr); -+ if (dataoff >= pktb_len(pkt)) { -+ pr_debug("amanda_help: pktlen = %u\n", pktb_len(pkt)); -+ return NF_ACCEPT; -+ } -+ -+ memcpy(amanda_buffer, pktb_network_header(pkt) + dataoff, -+ pktb_len(pkt) - dataoff); -+ data = amanda_buffer; -+ data_limit = amanda_buffer + pktb_len(pkt) - dataoff; -+ *data_limit = '\0'; -+ -+ /* Search for the CONNECT string */ -+ data = strstr(data, "CONNECT "); -+ if (!data) -+ goto out; -+ data += strlen("CONNECT "); -+ -+ /* Only search first line. */ -+ if ((tmp = strchr(data, '\n'))) -+ *tmp = '\0'; -+ -+ for (i = 0; i < ARRAY_SIZE(conns); i++) { -+ char *match = strstr(data, conns[i]); -+ if (!match) -+ continue; -+ tmp = data = match + strlen(conns[i]); -+ port = strtoul(data, &data, 10); -+ len = data - tmp; -+ if (port == 0 || len > 5) -+ break; -+ -+ exp = nfexp_new(); -+ if (exp == NULL) -+ return NF_DROP; -+ -+ cthelper_get_addr_src(myct->ct, MYCT_DIR_ORIG, &saddr); -+ cthelper_get_addr_dst(myct->ct, MYCT_DIR_ORIG, &daddr); -+ cthelper_get_port_src(myct->ct, MYCT_DIR_ORIG, &port); -+ -+ if (cthelper_expect_init(exp, myct->ct, 0, &saddr, &daddr, -+ IPPROTO_TCP, NULL, &port, 0)) { -+ nfexp_destroy(exp); -+ return NF_DROP; -+ } -+ -+ if (nfct_get_attr_u32(myct->ct, ATTR_STATUS) & IPS_NAT_MASK) { -+ ret = nat_amanda(pkt, ctinfo, tmp - amanda_buffer, -+ len, exp); -+ } else -+ myct->exp = exp; -+ } -+out: -+ return ret; -+} -+ -+static struct ctd_helper amanda_helper = { -+ .name = "amanda", -+ .l4proto = IPPROTO_UDP, -+ .cb = amanda_helper_cb, -+ .policy = { -+ [0] = { -+ .name = "amanda", -+ .expect_max = ARRAY_SIZE(conns), -+ .expect_timeout = 180, -+ }, -+ }, -+}; -+ -+void __attribute__ ((constructor)) amanda_init(void); -+ -+void amanda_init(void) -+{ -+ helper_register(&amanda_helper); -+} -diff --git a/src/helpers/dhcpv6.c b/src/helpers/dhcpv6.c -new file mode 100644 -index 0000000..73632ec ---- /dev/null -+++ b/src/helpers/dhcpv6.c -@@ -0,0 +1,123 @@ -+/* -+ * (C) 2013 by Pablo Neira Ayuso -+ * -+ * Adapted from: -+ * -+ * DHCPv6 multicast connection tracking helper. -+ * -+ * (c) 2012 Google Inc. -+ * -+ * Original author: Darren Willis -+ * -+ * This program is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU General Public License -+ * as published by the Free Software Foundation; either version -+ * 2 of the License, or (at your option) any later version. -+ */ -+ -+#include "conntrackd.h" -+#include "helper.h" -+#include "myct.h" -+#include "log.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define DHCPV6_CLIENT_PORT 546 -+ -+static uint16_t dhcpv6_port; -+ -+/* Timeouts for DHCPv6 replies, in seconds, indexed by message type. */ -+static const int dhcpv6_timeouts[] = { -+ 0, /* No message has type 0. */ -+ 120, /* Solicit. */ -+ 0, /* Advertise. */ -+ 30, /* Request. */ -+ 4, /* Confirm. */ -+ 600, /* Renew. */ -+ 600, /* Rebind. */ -+ 0, /* Reply. */ -+ 1, /* Release. */ -+ 1, /* Decline. */ -+ 0, /* Reconfigure. */ -+ 120, /* Information Request. */ -+ 0, /* Relay-forward. */ -+ 0 /* Relay-reply. */ -+}; -+ -+static inline int ipv6_addr_is_multicast(const struct in6_addr *addr) -+{ -+ return (addr->s6_addr32[0] & htonl(0xFF000000)) == htonl(0xFF000000); -+} -+ -+static int -+dhcpv6_helper_cb(struct pkt_buff *pkt, uint32_t protoff, -+ struct myct *myct, uint32_t ctinfo) -+{ -+ struct iphdr *iph = (struct iphdr *)pktb_network_header(pkt); -+ struct ip6_hdr *ip6h = (struct ip6_hdr *)pktb_network_header(pkt); -+ int dir = CTINFO2DIR(ctinfo); -+ union nfct_attr_grp_addr addr; -+ struct nf_expect *exp; -+ uint8_t *dhcpv6_msg_type; -+ -+ if (iph->version != 6 || !ipv6_addr_is_multicast(&ip6h->ip6_dst)) -+ return NF_ACCEPT; -+ -+ dhcpv6_msg_type = pktb_network_header(pkt) + protoff + sizeof(struct udphdr); -+ if (*dhcpv6_msg_type > ARRAY_SIZE(dhcpv6_timeouts)) { -+ printf("Dropping DHCPv6 message with bad type %u\n", -+ *dhcpv6_msg_type); -+ return NF_DROP; -+ } -+ -+ exp = nfexp_new(); -+ if (exp == NULL) -+ return NF_ACCEPT; -+ -+ cthelper_get_addr_src(myct->ct, dir, &addr); -+ -+ if (cthelper_expect_init(exp, myct->ct, 0, NULL, &addr, -+ IPPROTO_UDP, NULL, &dhcpv6_port, -+ NF_CT_EXPECT_PERMANENT)) { -+ nfexp_destroy(exp); -+ return NF_DROP; -+ } -+ -+ myct->exp = exp; -+ -+ if (dhcpv6_timeouts[*dhcpv6_msg_type] > 0) { -+ nfct_set_attr_u32(myct->ct, ATTR_TIMEOUT, -+ dhcpv6_timeouts[*dhcpv6_msg_type]); -+ } -+ -+ return NF_ACCEPT; -+} -+ -+static struct ctd_helper dhcpv6_helper = { -+ .name = "dhcpv6", -+ .l4proto = IPPROTO_UDP, -+ .cb = dhcpv6_helper_cb, -+ .policy = { -+ [0] = { -+ .name = "dhcpv6", -+ .expect_max = 1, -+ .expect_timeout = 300, -+ }, -+ }, -+}; -+ -+void __attribute__ ((constructor)) dhcpv6_init(void); -+ -+void dhcpv6_init(void) -+{ -+ dhcpv6_port = htons(DHCPV6_CLIENT_PORT); -+ helper_register(&dhcpv6_helper); -+} -diff --git a/src/helpers/ftp.c b/src/helpers/ftp.c -index 2c8dcd6..24ee877 100644 ---- a/src/helpers/ftp.c -+++ b/src/helpers/ftp.c -@@ -25,6 +25,7 @@ - #include /* for isdigit */ - #include - -+#define _GNU_SOURCE - #include - - #include -@@ -58,7 +59,7 @@ enum nf_ct_ftp_type { - }; - - static int --get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, u_int8_t term) -+get_ipv6_addr(const char *src, size_t dlen, struct in6_addr *dst, uint8_t term) - { - const char *end; - int ret = in6_pton(src, min_t(size_t, dlen, 0xffff), -diff --git a/src/helpers/sane.c b/src/helpers/sane.c -new file mode 100644 -index 0000000..c30f4ba ---- /dev/null -+++ b/src/helpers/sane.c -@@ -0,0 +1,173 @@ -+/* -+ * (C) 2013 by Pablo Neira Ayuso -+ * -+ * Port this helper to userspace. -+ */ -+ -+/* SANE connection tracking helper -+ * (SANE = Scanner Access Now Easy) -+ * For documentation about the SANE network protocol see -+ * http://www.sane-project.org/html/doc015.html -+ */ -+ -+/* -+ * Copyright (C) 2007 Red Hat, Inc. -+ * Author: Michal Schmidt -+ * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c): -+ * (C) 1999-2001 Paul `Rusty' Russell -+ * (C) 2002-2004 Netfilter Core Team -+ * (C) 2003,2004 USAGI/WIDE Project -+ * (C) 2003 Yasuyuki Kozakai @USAGI -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "conntrackd.h" -+#include "helper.h" -+#include "myct.h" -+#include "log.h" -+#include -+#include -+#define _GNU_SOURCE -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+enum sane_state { -+ SANE_STATE_NORMAL, -+ SANE_STATE_START_REQUESTED, -+}; -+ -+struct sane_request { -+ uint32_t RPC_code; -+#define SANE_NET_START 7 /* RPC code */ -+ -+ uint32_t handle; -+}; -+ -+struct sane_reply_net_start { -+ uint32_t status; -+#define SANE_STATUS_SUCCESS 0 -+ -+ uint16_t zero; -+ uint16_t port; -+ /* 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) -+{ -+ unsigned int dataoff, datalen; -+ const struct tcphdr *th; -+ void *sb_ptr; -+ int ret = NF_ACCEPT; -+ int dir = CTINFO2DIR(ctinfo); -+ struct nf_ct_sane_master *ct_sane_info = myct->priv_data; -+ struct nf_expect *exp; -+ struct sane_request *req; -+ struct sane_reply_net_start *reply; -+ union nfct_attr_grp_addr saddr; -+ union nfct_attr_grp_addr daddr; -+ -+ /* Until there's been traffic both ways, don't look in packets. */ -+ if (ctinfo != IP_CT_ESTABLISHED && -+ ctinfo != IP_CT_ESTABLISHED_REPLY) -+ return NF_ACCEPT; -+ -+ th = (struct tcphdr *)(pktb_network_header(pkt) + protoff); -+ -+ /* No data? */ -+ dataoff = protoff + th->doff * 4; -+ if (dataoff >= pktb_len(pkt)) -+ return NF_ACCEPT; -+ -+ datalen = pktb_len(pkt) - dataoff; -+ -+ sb_ptr = pktb_network_header(pkt) + dataoff; -+ -+ if (dir == MYCT_DIR_ORIG) { -+ if (datalen != sizeof(struct sane_request)) -+ goto out; -+ -+ req = sb_ptr; -+ if (req->RPC_code != htonl(SANE_NET_START)) { -+ /* Not an interesting command */ -+ ct_sane_info->state = SANE_STATE_NORMAL; -+ goto out; -+ } -+ -+ /* We're interested in the next reply */ -+ ct_sane_info->state = SANE_STATE_START_REQUESTED; -+ goto out; -+ } -+ -+ /* Is it a reply to an uninteresting command? */ -+ if (ct_sane_info->state != SANE_STATE_START_REQUESTED) -+ goto out; -+ -+ /* It's a reply to SANE_NET_START. */ -+ ct_sane_info->state = SANE_STATE_NORMAL; -+ -+ if (datalen < sizeof(struct sane_reply_net_start)) { -+ pr_debug("nf_ct_sane: NET_START reply too short\n"); -+ goto out; -+ } -+ -+ reply = sb_ptr; -+ if (reply->status != htonl(SANE_STATUS_SUCCESS)) { -+ /* saned refused the command */ -+ pr_debug("nf_ct_sane: unsuccessful SANE_STATUS = %u\n", -+ ntohl(reply->status)); -+ goto out; -+ } -+ -+ /* Invalid saned reply? Ignore it. */ -+ if (reply->zero != 0) -+ goto out; -+ -+ exp = nfexp_new(); -+ if (exp == NULL) -+ return NF_DROP; -+ -+ cthelper_get_addr_src(myct->ct, MYCT_DIR_ORIG, &saddr); -+ cthelper_get_addr_dst(myct->ct, MYCT_DIR_ORIG, &daddr); -+ -+ if (cthelper_expect_init(exp, myct->ct, 0, &saddr, &daddr, -+ IPPROTO_TCP, NULL, &reply->port, 0)) { -+ nfexp_destroy(exp); -+ return NF_DROP; -+ } -+ myct->exp = exp; -+out: -+ return ret; -+} -+ -+static struct ctd_helper sane_helper = { -+ .name = "sane", -+ .l4proto = IPPROTO_TCP, -+ .priv_data_len = sizeof(struct nf_ct_sane_master), -+ .cb = sane_helper_cb, -+ .policy = { -+ [0] = { -+ .name = "sane", -+ .expect_max = 1, -+ .expect_timeout = 5 * 60, -+ }, -+ }, -+}; -+ -+static void __attribute__ ((constructor)) sane_init(void) -+{ -+ helper_register(&sane_helper); -+} -diff --git a/src/helpers/ssdp.c b/src/helpers/ssdp.c -new file mode 100644 -index 0000000..bc41087 ---- /dev/null -+++ b/src/helpers/ssdp.c -@@ -0,0 +1,134 @@ -+/* -+ * SSDP connection tracking helper -+ * (SSDP = Simple Service Discovery Protocol) -+ * For documentation about SSDP see -+ * http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol -+ * -+ * Copyright (C) 2014 Ashley Hughes -+ * Based on the SSDP conntrack helper (nf_conntrack_ssdp.c), -+ * :http://marc.info/?t=132945775100001&r=1&w=2 -+ * (C) 2012 Ian Pilcher -+ * -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "conntrackd.h" -+#include "helper.h" -+#include "myct.h" -+#include "log.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define SSDP_MCAST_ADDR "239.255.255.250" -+#define UPNP_MCAST_LL_ADDR "FF02::C" /* link-local */ -+#define UPNP_MCAST_SL_ADDR "FF05::C" /* site-local */ -+ -+#define SSDP_M_SEARCH "M-SEARCH" -+#define SSDP_M_SEARCH_SIZE (sizeof SSDP_M_SEARCH - 1) -+ -+static int ssdp_helper_cb(struct pkt_buff *pkt, uint32_t protoff, -+ struct myct *myct, uint32_t ctinfo) -+{ -+ 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); -+ switch (nfct_get_attr_u8(myct->ct, ATTR_L3PROTO)) { -+ case AF_INET: -+ inet_pton(AF_INET, SSDP_MCAST_ADDR, &(taddr.ip)); -+ if (daddr.ip == taddr.ip) -+ good_packet = 1; -+ break; -+ case AF_INET6: -+ inet_pton(AF_INET6, UPNP_MCAST_LL_ADDR, &(taddr.ip6)); -+ if (daddr.ip6[0] == taddr.ip6[0] && -+ daddr.ip6[1] == taddr.ip6[1] && -+ daddr.ip6[2] == taddr.ip6[2] && -+ daddr.ip6[3] == taddr.ip6[3]) { -+ good_packet = 1; -+ break; -+ } -+ inet_pton(AF_INET6, UPNP_MCAST_SL_ADDR, &(taddr.ip6)); -+ if (daddr.ip6[0] == taddr.ip6[0] && -+ daddr.ip6[1] == taddr.ip6[1] && -+ daddr.ip6[2] == taddr.ip6[2] && -+ daddr.ip6[3] == taddr.ip6[3]) { -+ good_packet = 1; -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+ -+ if (!good_packet) { -+ pr_debug("ssdp_help: destination address not multicast; ignoring\n"); -+ return NF_ACCEPT; -+ } -+ -+ /* No data? Ignore */ -+ dataoff = net_hdr->ihl*4 + sizeof(struct udphdr); -+ if (dataoff >= 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; -+ -+ 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"); -+ return NF_ACCEPT; -+ } -+ -+ cthelper_get_addr_src(myct->ct, MYCT_DIR_ORIG, &saddr); -+ cthelper_get_port_src(myct->ct, MYCT_DIR_ORIG, &port); -+ -+ exp = nfexp_new(); -+ if (exp == NULL) -+ return NF_DROP; -+ -+ if (cthelper_expect_init(exp, myct->ct, 0, NULL, &saddr, -+ IPPROTO_UDP, NULL, &port, -+ NF_CT_EXPECT_PERMANENT)) { -+ nfexp_destroy(exp); -+ return NF_DROP; -+ } -+ myct->exp = exp; -+ -+ return ret; -+} -+ -+static struct ctd_helper ssdp_helper = { -+ .name = "ssdp", -+ .l4proto = IPPROTO_UDP, -+ .priv_data_len = 0, -+ .cb = ssdp_helper_cb, -+ .policy = { -+ [0] = { -+ .name = "ssdp", -+ .expect_max = 1, -+ .expect_timeout = 5 * 60, -+ }, -+ }, -+}; -+ -+static void __attribute__ ((constructor)) ssdp_init(void) -+{ -+ helper_register(&ssdp_helper); -+} -diff --git a/src/helpers/tftp.c b/src/helpers/tftp.c -new file mode 100644 -index 0000000..45591c6 ---- /dev/null -+++ b/src/helpers/tftp.c -@@ -0,0 +1,138 @@ -+/* -+ * (C) 2013 by Pablo Neira Ayuso -+ * -+ * Adapted from: -+ * -+ * (C) 2001-2002 Magnus Boden -+ * (C) 2006-2012 Patrick McHardy -+ * This program is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ */ -+ -+#include "conntrackd.h" -+#include "helper.h" -+#include "myct.h" -+#include "log.h" -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+struct tftphdr { -+ uint16_t opcode; -+}; -+ -+#define TFTP_OPCODE_READ 1 -+#define TFTP_OPCODE_WRITE 2 -+#define TFTP_OPCODE_DATA 3 -+#define TFTP_OPCODE_ACK 4 -+#define TFTP_OPCODE_ERROR 5 -+ -+static unsigned int nat_tftp(struct pkt_buff *pkt, uint32_t ctinfo, -+ struct nf_conntrack *ct, struct nf_expect *exp) -+{ -+ struct nf_conntrack *nat_tuple; -+ static uint32_t zero[4] = { 0, 0, 0, 0 }; -+ -+ nat_tuple = nfct_new(); -+ if (nat_tuple == NULL) -+ return NF_ACCEPT; -+ -+ switch (nfct_get_attr_u8(ct, ATTR_L3PROTO)) { -+ case AF_INET: -+ nfct_set_attr_u8(nat_tuple, ATTR_L3PROTO, AF_INET); -+ nfct_set_attr_u32(nat_tuple, ATTR_IPV4_SRC, 0); -+ nfct_set_attr_u32(nat_tuple, ATTR_IPV4_DST, 0); -+ break; -+ case AF_INET6: -+ nfct_set_attr_u8(nat_tuple, ATTR_L3PROTO, AF_INET6); -+ nfct_set_attr(nat_tuple, ATTR_IPV6_SRC, &zero); -+ nfct_set_attr(nat_tuple, ATTR_IPV6_DST, &zero); -+ break; -+ } -+ nfct_set_attr_u8(nat_tuple, ATTR_L4PROTO, IPPROTO_UDP); -+ nfct_set_attr_u16(nat_tuple, ATTR_PORT_SRC, -+ nfct_get_attr_u16(ct, ATTR_PORT_SRC)); -+ nfct_set_attr_u16(nat_tuple, ATTR_PORT_DST, 0); -+ -+ nfexp_set_attr_u32(exp, ATTR_EXP_NAT_DIR, MYCT_DIR_REPL); -+ nfexp_set_attr(exp, ATTR_EXP_FN, "nat-follow-master"); -+ nfexp_set_attr(exp, ATTR_EXP_NAT_TUPLE, nat_tuple); -+ -+ return NF_ACCEPT; -+} -+ -+static int -+tftp_helper_cb(struct pkt_buff *pkt, uint32_t protoff, -+ struct myct *myct, uint32_t ctinfo) -+{ -+ const struct tftphdr *tfh; -+ struct nf_expect *exp; -+ unsigned int ret = NF_ACCEPT; -+ union nfct_attr_grp_addr saddr, daddr; -+ uint16_t dport; -+ -+ tfh = (struct tftphdr *)(pktb_network_header(pkt) + protoff + sizeof(struct udphdr)); -+ -+ switch (ntohs(tfh->opcode)) { -+ case TFTP_OPCODE_READ: -+ case TFTP_OPCODE_WRITE: -+ /* RRQ and WRQ works the same way */ -+ exp = nfexp_new(); -+ if (exp == NULL) { -+ pr_debug("cannot alloc expectation\n"); -+ return NF_DROP; -+ } -+ -+ cthelper_get_addr_src(myct->ct, MYCT_DIR_REPL, &saddr); -+ cthelper_get_addr_dst(myct->ct, MYCT_DIR_REPL, &daddr); -+ cthelper_get_port_dst(myct->ct, MYCT_DIR_REPL, &dport); -+ -+ if (cthelper_expect_init(exp, myct->ct, 0, &saddr, &daddr, -+ IPPROTO_UDP, NULL, &dport, 0)) { -+ nfexp_destroy(exp); -+ return NF_DROP; -+ } -+ -+ if (nfct_get_attr_u32(myct->ct, ATTR_STATUS) & IPS_NAT_MASK) -+ ret = nat_tftp(pkt, ctinfo, myct->ct, exp); -+ -+ myct->exp = exp; -+ break; -+ case TFTP_OPCODE_DATA: -+ case TFTP_OPCODE_ACK: -+ pr_debug("Data/ACK opcode\n"); -+ break; -+ case TFTP_OPCODE_ERROR: -+ pr_debug("Error opcode\n"); -+ break; -+ default: -+ pr_debug("Unknown opcode\n"); -+ } -+ return ret; -+} -+ -+static struct ctd_helper tftp_helper = { -+ .name = "tftp", -+ .l4proto = IPPROTO_UDP, -+ .cb = tftp_helper_cb, -+ .policy = { -+ [0] = { -+ .name = "tftp", -+ .expect_max = 1, -+ .expect_timeout = 5 * 60, -+ }, -+ }, -+}; -+ -+static void __attribute__ ((constructor)) tftp_init(void) -+{ -+ helper_register(&tftp_helper); -+} -diff --git a/src/helpers/tns.c b/src/helpers/tns.c -index 5833fea..2b4fed4 100644 ---- a/src/helpers/tns.c -+++ b/src/helpers/tns.c -@@ -18,6 +18,7 @@ - #include /* for isdigit */ - #include - -+#define _GNU_SOURCE - #include - - #include -diff --git a/src/internal_bypass.c b/src/internal_bypass.c -index ce2ae46..61988c7 100644 ---- a/src/internal_bypass.c -+++ b/src/internal_bypass.c -@@ -49,7 +49,7 @@ internal_bypass_ct_dump_cb(enum nf_conntrack_msg_type type, - static void internal_bypass_ct_dump(int fd, int type) - { - struct nfct_handle *h; -- u_int32_t family = AF_UNSPEC; -+ uint32_t family = AF_UNSPEC; - int ret; - - h = nfct_open(CONFIG(netlink).subsys_id, 0); -@@ -180,7 +180,7 @@ internal_bypass_exp_dump_cb(enum nf_conntrack_msg_type type, - static void internal_bypass_exp_dump(int fd, int type) - { - struct nfct_handle *h; -- u_int32_t family = AF_UNSPEC; -+ uint32_t family = AF_UNSPEC; - int ret; - - h = nfct_open(CONFIG(netlink).subsys_id, 0); -diff --git a/src/local.c b/src/local.c -index feff608..453799a 100644 ---- a/src/local.c -+++ b/src/local.c -@@ -117,11 +117,10 @@ void local_client_destroy(int fd) - - int do_local_client_step(int fd, void (*process)(char *buf)) - { -- int numbytes; - char buf[1024]; - - memset(buf, 0, sizeof(buf)); -- while ((numbytes = recv(fd, buf, sizeof(buf)-1, 0)) > 0) { -+ while (recv(fd, buf, sizeof(buf)-1, 0) > 0) { - buf[sizeof(buf)-1] = '\0'; - if (process) - process(buf); -diff --git a/src/netlink.c b/src/netlink.c -index 5be102e..189f55a 100644 ---- a/src/netlink.c -+++ b/src/netlink.c -@@ -26,7 +26,7 @@ - #include - #include - #include --#include -+#include - #include - - struct nfct_handle *nl_init_event_handler(void) -diff --git a/src/nfct-extensions/helper.c b/src/nfct-extensions/helper.c -index f91fc41..bfb153f 100644 ---- a/src/nfct-extensions/helper.c -+++ b/src/nfct-extensions/helper.c -@@ -37,8 +37,15 @@ nfct_cmd_helper_usage(char *argv[]) - "[parameters...]\n", VERSION, argv[0]); - } - --int --nfct_cmd_helper_parse_params(int argc, char *argv[]) -+static int nfct_cmd_helper_list(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_helper_add(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_helper_delete(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_helper_get(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_helper_flush(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_helper_disable(struct mnl_socket *nl, int argc, char *argv[]); -+ -+static int -+nfct_cmd_helper_parse_params(struct mnl_socket *nl, int argc, char *argv[]) - { - int cmd = NFCT_CMD_NONE, ret = 0; - -@@ -66,24 +73,25 @@ nfct_cmd_helper_parse_params(int argc, char *argv[]) - nfct_cmd_helper_usage(argv); - exit(EXIT_FAILURE); - } -+ - switch(cmd) { - case NFCT_CMD_LIST: -- ret = nfct_cmd_helper_list(argc, argv); -+ ret = nfct_cmd_helper_list(nl, argc, argv); - break; - case NFCT_CMD_ADD: -- ret = nfct_cmd_helper_add(argc, argv); -+ ret = nfct_cmd_helper_add(nl, argc, argv); - break; - case NFCT_CMD_DELETE: -- ret = nfct_cmd_helper_delete(argc, argv); -+ ret = nfct_cmd_helper_delete(nl, argc, argv); - break; - case NFCT_CMD_GET: -- ret = nfct_cmd_helper_get(argc, argv); -+ ret = nfct_cmd_helper_get(nl, argc, argv); - break; - case NFCT_CMD_FLUSH: -- ret = nfct_cmd_helper_flush(argc, argv); -+ ret = nfct_cmd_helper_flush(nl, argc, argv); - break; - case NFCT_CMD_DISABLE: -- ret = nfct_cmd_helper_disable(argc, argv); -+ ret = nfct_cmd_helper_disable(nl, argc, argv); - break; - } - -@@ -115,13 +123,11 @@ err: - return MNL_CB_OK; - } - --int nfct_cmd_helper_list(int argc, char *argv[]) -+static int nfct_cmd_helper_list(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - unsigned int seq, portid; -- int ret; - - if (argc > 3) { - nfct_perror("too many arguments"); -@@ -132,42 +138,17 @@ int nfct_cmd_helper_list(int argc, char *argv[]) - nlh = nfct_helper_nlmsg_build_hdr(buf, NFNL_MSG_CTHELPER_GET, - NLM_F_DUMP, seq); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -- return -1; -- } -- -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, nfct_helper_cb, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, nfct_helper_cb, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } -- mnl_socket_close(nl); - - return 0; - } - --int nfct_cmd_helper_add(int argc, char *argv[]) -+static int nfct_cmd_helper_add(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; -@@ -175,7 +156,7 @@ int nfct_cmd_helper_add(int argc, char *argv[]) - uint16_t l3proto; - uint8_t l4proto; - struct ctd_helper *helper; -- int ret, j; -+ int j; - - if (argc < 6) { - nfct_perror("missing parameters\n" -@@ -248,47 +229,22 @@ int nfct_cmd_helper_add(int argc, char *argv[]) - - nfct_helper_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -- return -1; -- } -- mnl_socket_close(nl); -- - return 0; - } - --int nfct_cmd_helper_delete(int argc, char *argv[]) -+static int -+nfct_cmd_helper_delete(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; - struct nfct_helper *t; -- int ret; - - if (argc < 4) { - nfct_perror("missing helper policy name"); -@@ -341,48 +297,21 @@ int nfct_cmd_helper_delete(int argc, char *argv[]) - - nfct_helper_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -- return -1; -- } -- -- mnl_socket_close(nl); -- - return 0; - } - --int nfct_cmd_helper_get(int argc, char *argv[]) -+static int nfct_cmd_helper_get(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; - struct nfct_helper *t; -- int ret; - - if (argc < 4) { - nfct_perror("missing helper policy name"); -@@ -435,46 +364,21 @@ int nfct_cmd_helper_get(int argc, char *argv[]) - - nfct_helper_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -- return -1; -- } -- -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, nfct_helper_cb, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, nfct_helper_cb, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } -- mnl_socket_close(nl); - - return 0; - } - --int nfct_cmd_helper_flush(int argc, char *argv[]) -+static int -+nfct_cmd_helper_flush(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; -- int ret; - - if (argc > 3) { - nfct_perror("too many arguments"); -@@ -485,43 +389,18 @@ int nfct_cmd_helper_flush(int argc, char *argv[]) - nlh = nfct_helper_nlmsg_build_hdr(buf, NFNL_MSG_CTHELPER_DEL, - NLM_F_ACK, seq); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -- return -1; -- } -- -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- mnl_socket_close(nl); -- - return 0; - } - --int nfct_cmd_helper_disable(int argc, char *argv[]) -+static int -+nfct_cmd_helper_disable(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; -@@ -529,7 +408,6 @@ int nfct_cmd_helper_disable(int argc, char *argv[]) - uint16_t l3proto; - uint8_t l4proto; - struct ctd_helper *helper; -- int ret; - - if (argc < 6) { - nfct_perror("missing parameters\n" -@@ -580,36 +458,21 @@ int nfct_cmd_helper_disable(int argc, char *argv[]) - - nfct_helper_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -- return -1; -- } -- mnl_socket_close(nl); -- - return 0; - } - -+static struct nfct_extension helper = { -+ .type = NFCT_SUBSYS_HELPER, -+ .parse_params = nfct_cmd_helper_parse_params, -+}; -+ -+static void __init helper_init(void) -+{ -+ nfct_extension_register(&helper); -+} -diff --git a/src/nfct-extensions/timeout.c b/src/nfct-extensions/timeout.c -index 5b32023..c9aa386 100644 ---- a/src/nfct-extensions/timeout.c -+++ b/src/nfct-extensions/timeout.c -@@ -1,5 +1,5 @@ - /* -- * (C) 2012 by Pablo Neira Ayuso -+ * (C) 2012-2013 by Pablo Neira Ayuso - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published -@@ -19,6 +19,7 @@ - #include - #include - #include -+#include - #include - - #include -@@ -31,11 +32,20 @@ static void - nfct_cmd_timeout_usage(char *argv[]) - { - fprintf(stderr, "nfct v%s: Missing command\n" -- "%s timeout list|add|delete|get|flush " -- "[parameters...]\n", VERSION, argv[0]); -+ "%s timeout " -+ "[, ...]\n", VERSION, argv[0]); - } - --int nfct_cmd_timeout_parse_params(int argc, char *argv[]) -+static int nfct_cmd_timeout_list(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_timeout_add(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_timeout_delete(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_timeout_get(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_timeout_flush(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_timeout_default_set(struct mnl_socket *nl, int argc, char *argv[]); -+static int nfct_cmd_timeout_default_get(struct mnl_socket *nl, int argc, char *argv[]); -+ -+static int -+nfct_cmd_timeout_parse_params(struct mnl_socket *nl, int argc, char *argv[]) - { - int cmd = NFCT_CMD_NONE, ret; - -@@ -53,6 +63,10 @@ int nfct_cmd_timeout_parse_params(int argc, char *argv[]) - cmd = NFCT_CMD_GET; - else if (strncmp(argv[2], "flush", strlen(argv[2])) == 0) - cmd = NFCT_CMD_FLUSH; -+ else if (strncmp(argv[2], "default-set", strlen(argv[2])) == 0) -+ cmd = NFCT_CMD_DEFAULT_SET; -+ else if (strncmp(argv[2], "default-get", strlen(argv[2])) == 0) -+ cmd = NFCT_CMD_DEFAULT_GET; - else { - fprintf(stderr, "nfct v%s: Unknown command: %s\n", - VERSION, argv[2]); -@@ -61,19 +75,25 @@ int nfct_cmd_timeout_parse_params(int argc, char *argv[]) - } - switch(cmd) { - case NFCT_CMD_LIST: -- ret = nfct_cmd_timeout_list(argc, argv); -+ ret = nfct_cmd_timeout_list(nl, argc, argv); - break; - case NFCT_CMD_ADD: -- ret = nfct_cmd_timeout_add(argc, argv); -+ ret = nfct_cmd_timeout_add(nl, argc, argv); - break; - case NFCT_CMD_DELETE: -- ret = nfct_cmd_timeout_delete(argc, argv); -+ ret = nfct_cmd_timeout_delete(nl, argc, argv); - break; - case NFCT_CMD_GET: -- ret = nfct_cmd_timeout_get(argc, argv); -+ ret = nfct_cmd_timeout_get(nl, argc, argv); - break; - case NFCT_CMD_FLUSH: -- ret = nfct_cmd_timeout_flush(argc, argv); -+ ret = nfct_cmd_timeout_flush(nl, argc, argv); -+ break; -+ case NFCT_CMD_DEFAULT_SET: -+ ret = nfct_cmd_timeout_default_set(nl, argc, argv); -+ break; -+ case NFCT_CMD_DEFAULT_GET: -+ ret = nfct_cmd_timeout_default_get(nl, argc, argv); - break; - } - -@@ -105,13 +125,11 @@ err: - return MNL_CB_OK; - } - --int nfct_cmd_timeout_list(int argc, char *argv[]) -+static int nfct_cmd_timeout_list(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - unsigned int seq, portid; -- int ret; - - if (argc > 3) { - nfct_perror("too many arguments"); -@@ -122,35 +140,11 @@ int nfct_cmd_timeout_list(int argc, char *argv[]) - nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_GET, - NLM_F_DUMP, seq); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -- return -1; -- } -- -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, nfct_timeout_cb, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, nfct_timeout_cb, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } -- mnl_socket_close(nl); - - return 0; - } -@@ -167,69 +161,71 @@ static uint32_t nfct_timeout_attr_max[IPPROTO_MAX] = { - [IPPROTO_RAW] = NFCT_TIMEOUT_ATTR_GENERIC_MAX, - }; - --int nfct_cmd_timeout_add(int argc, char *argv[]) -+static int nfct_cmd_get_l3proto(char *argv[]) - { -- struct mnl_socket *nl; -- char buf[MNL_SOCKET_BUFFER_SIZE]; -- struct nlmsghdr *nlh; -- uint32_t portid, seq; -- struct nfct_timeout *t; -- uint16_t l3proto; -- uint8_t l4proto; -- int ret, i; -- unsigned int j; -- -- if (argc < 6) { -- nfct_perror("missing parameters\n" -- "syntax: nfct timeout add name " -- "family protocol state1 " -- "timeout1 state2 timeout2..."); -- return -1; -- } -- -- t = nfct_timeout_alloc(); -- if (t == NULL) { -- nfct_perror("OOM"); -- return -1; -- } -+ int l3proto; - -- nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); -- -- if (strcmp(argv[4], "inet") == 0) -+ if (strcmp(*argv, "inet") == 0) - l3proto = AF_INET; -- else if (strcmp(argv[4], "inet6") == 0) -+ else if (strcmp(*argv, "inet6") == 0) - l3proto = AF_INET6; - else { - nfct_perror("unknown layer 3 protocol"); - return -1; - } -+ return l3proto; -+} -+ -+static int nfct_cmd_get_l4proto(char *argv[]) -+{ -+ int l4proto; -+ struct protoent *pent; -+ -+ pent = getprotobyname(*argv); -+ if (!pent) { -+ /* In Debian, /etc/protocols says ipv6-icmp. Support icmpv6 -+ * as well not to break backward compatibility. -+ */ -+ if (strcmp(*argv, "icmpv6") == 0) -+ l4proto = IPPROTO_ICMPV6; -+ else if (strcmp(*argv, "generic") == 0) -+ l4proto = IPPROTO_RAW; -+ else { -+ nfct_perror("unknown layer 4 protocol"); -+ return -1; -+ } -+ } else -+ l4proto = pent->p_proto; -+ -+ return l4proto; -+} -+ -+static int -+nfct_cmd_timeout_parse(struct nfct_timeout *t, int argc, char *argv[]) -+{ -+ int l3proto, l4proto; -+ unsigned int j; -+ const char *proto_name; -+ -+ l3proto = nfct_cmd_get_l3proto(argv); -+ if (l3proto < 0) -+ return -1; -+ - nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO, l3proto); - -- if (strcmp(argv[5], "tcp") == 0) -- l4proto = IPPROTO_TCP; -- else if (strcmp(argv[5], "udp") == 0) -- l4proto = IPPROTO_UDP; -- else if (strcmp(argv[5], "udplite") == 0) -- l4proto = IPPROTO_UDPLITE; -- else if (strcmp(argv[5], "sctp") == 0) -- l4proto = IPPROTO_SCTP; -- else if (strcmp(argv[5], "dccp") == 0) -- l4proto = IPPROTO_DCCP; -- else if (strcmp(argv[5], "icmp") == 0) -- l4proto = IPPROTO_ICMP; -- else if (strcmp(argv[5], "icmpv6") == 0) -- l4proto = IPPROTO_ICMPV6; -- else if (strcmp(argv[5], "gre") == 0) -- l4proto = IPPROTO_GRE; -- else if (strcmp(argv[5], "generic") == 0) -- l4proto = IPPROTO_RAW; -- else { -- nfct_perror("unknown layer 4 protocol"); -+ argc--; -+ argv++; -+ proto_name = *argv; -+ -+ l4proto = nfct_cmd_get_l4proto(argv); -+ if (l4proto < 0) - return -1; -- } -+ - nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO, l4proto); -+ argc--; -+ argv++; - -- for (i=6; i1; argc-=2, argv+=2) { - int matching = -1; - - for (j=0; j= argc) { -- nfct_perror("missing value for this timeout"); -- return -1; -- } - nfct_timeout_policy_attr_set_u32(t, matching, -- atoi(argv[i+1])); -- matching = -1; -+ atoi(*(argv+1))); - } else { - fprintf(stderr, "nfct v%s: Wrong state name: `%s' " - "for protocol `%s'\n", -- VERSION, argv[i], argv[5]); -+ VERSION, *argv, proto_name); - return -1; - } - } -+ if (argc > 0) { -+ nfct_perror("missing value for this timeout"); -+ return -1; -+ } - -- seq = time(NULL); -- nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_NEW, -- NLM_F_CREATE | NLM_F_ACK, seq); -- nfct_timeout_nlmsg_build_payload(nlh, t); -+ return 0; -+} - -- nfct_timeout_free(t); -+int nfct_cmd_timeout_add(struct mnl_socket *nl, int argc, char *argv[]) -+{ -+ char buf[MNL_SOCKET_BUFFER_SIZE]; -+ struct nlmsghdr *nlh; -+ uint32_t portid, seq; -+ struct nfct_timeout *t; - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -+ if (argc < 6) { -+ nfct_perror("missing parameters\n" -+ "syntax: nfct timeout add name " -+ "family protocol state1 " -+ "timeout1 state2 timeout2..."); - return -1; - } - -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -+ t = nfct_timeout_alloc(); -+ if (t == NULL) { -+ nfct_perror("OOM"); - return -1; - } -- portid = mnl_socket_get_portid(nl); - -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -+ nfct_timeout_attr_set(t, NFCT_TIMEOUT_ATTR_NAME, argv[3]); -+ -+ if (nfct_cmd_timeout_parse(t, argc-4, &argv[4]) < 0) - return -1; -- } - -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ seq = time(NULL); -+ nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_NEW, -+ NLM_F_CREATE | NLM_F_ACK, seq); -+ nfct_timeout_nlmsg_build_payload(nlh, t); -+ -+ nfct_timeout_free(t); -+ -+ portid = mnl_socket_get_portid(nl); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } -- mnl_socket_close(nl); - - return 0; - } - --int nfct_cmd_timeout_delete(int argc, char *argv[]) -+int nfct_cmd_timeout_delete(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; - struct nfct_timeout *t; -- int ret; - - if (argc < 4) { - nfct_perror("missing timeout policy name"); -@@ -335,48 +333,21 @@ int nfct_cmd_timeout_delete(int argc, char *argv[]) - - nfct_timeout_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -- return -1; -- } -- -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } - portid = mnl_socket_get_portid(nl); -- -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -- return -1; -- } -- -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- mnl_socket_close(nl); -- - return 0; - } - --int nfct_cmd_timeout_get(int argc, char *argv[]) -+int nfct_cmd_timeout_get(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; - struct nfct_timeout *t; -- int ret; - - if (argc < 4) { - nfct_perror("missing timeout policy name"); -@@ -401,86 +372,135 @@ int nfct_cmd_timeout_get(int argc, char *argv[]) - - nfct_timeout_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -+ portid = mnl_socket_get_portid(nl); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, nfct_timeout_cb, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -- return -1; -- } -- portid = mnl_socket_get_portid(nl); -+ return 0; -+} -+ -+int nfct_cmd_timeout_flush(struct mnl_socket *nl, int argc, char *argv[]) -+{ -+ char buf[MNL_SOCKET_BUFFER_SIZE]; -+ struct nlmsghdr *nlh; -+ uint32_t portid, seq; - -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -+ if (argc > 3) { -+ nfct_perror("too many arguments"); - return -1; - } - -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, nfct_timeout_cb, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ seq = time(NULL); -+ nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DELETE, -+ NLM_F_ACK, seq); -+ -+ portid = mnl_socket_get_portid(nl); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, NULL, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } -- mnl_socket_close(nl); - - return 0; - } - --int nfct_cmd_timeout_flush(int argc, char *argv[]) -+static int -+nfct_cmd_timeout_default_set(struct mnl_socket *nl, int argc, char *argv[]) - { -- struct mnl_socket *nl; - char buf[MNL_SOCKET_BUFFER_SIZE]; - struct nlmsghdr *nlh; - uint32_t portid, seq; -- int ret; -+ struct nfct_timeout *t; - -- if (argc > 3) { -- nfct_perror("too many arguments"); -+ if (argc < 6) { -+ nfct_perror("missing parameters\n" -+ "syntax: nfct timeout default-set " -+ "family protocol state1 " -+ "timeout1 state2 timeout2..."); - return -1; - } - -+ t = nfct_timeout_alloc(); -+ if (t == NULL) -+ return -1; -+ -+ if (nfct_cmd_timeout_parse(t, argc-3, &argv[3]) < 0) -+ return -1; -+ - seq = time(NULL); -- nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DELETE, -+ nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DEFAULT_SET, - NLM_F_ACK, seq); -+ nfct_timeout_nlmsg_build_payload(nlh, t); -+ nfct_timeout_free(t); - -- nl = mnl_socket_open(NETLINK_NETFILTER); -- if (nl == NULL) { -- nfct_perror("mnl_socket_open"); -+ portid = mnl_socket_get_portid(nl); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, nfct_timeout_cb, NULL) < 0) { -+ nfct_perror("netlink error"); - return -1; - } - -- if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { -- nfct_perror("mnl_socket_bind"); -+ return 0; -+} -+ -+static int -+nfct_cmd_timeout_default_get(struct mnl_socket *nl, int argc, char *argv[]) -+{ -+ char buf[MNL_SOCKET_BUFFER_SIZE]; -+ struct nlmsghdr *nlh; -+ uint32_t portid, seq; -+ struct nfct_timeout *t; -+ int l3proto, l4proto; -+ -+ if (argc < 5) { -+ nfct_perror("missing parameters\n" -+ "syntax: nfct timeout default-get " -+ "family protocol"); - return -1; - } -- portid = mnl_socket_get_portid(nl); - -- if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) { -- nfct_perror("mnl_socket_send"); -+ t = nfct_timeout_alloc(); -+ if (t == NULL) - return -1; -- } - -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- while (ret > 0) { -- ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL); -- if (ret <= 0) -- break; -- ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -- } -- if (ret == -1) { -- nfct_perror("error"); -+ argc-=3; -+ argv+=3; -+ -+ l3proto = nfct_cmd_get_l3proto(argv); -+ if (l3proto < 0) - return -1; -- } - -- mnl_socket_close(nl); -+ nfct_timeout_attr_set_u16(t, NFCT_TIMEOUT_ATTR_L3PROTO, l3proto); -+ argc--; -+ argv++; -+ -+ l4proto = nfct_cmd_get_l4proto(argv); -+ if (l4proto < 0) -+ return -1; -+ -+ nfct_timeout_attr_set_u8(t, NFCT_TIMEOUT_ATTR_L4PROTO, l4proto); -+ -+ seq = time(NULL); -+ nlh = nfct_timeout_nlmsg_build_hdr(buf, IPCTNL_MSG_TIMEOUT_DEFAULT_GET, -+ NLM_F_ACK, seq); -+ nfct_timeout_nlmsg_build_payload(nlh, t); -+ nfct_timeout_free(t); -+ -+ portid = mnl_socket_get_portid(nl); -+ if (nfct_mnl_talk(nl, nlh, seq, portid, nfct_timeout_cb, NULL) < 0) { -+ nfct_perror("netlink error"); -+ return -1; -+ } - - return 0; - } -+ -+static struct nfct_extension timeout = { -+ .type = NFCT_SUBSYS_TIMEOUT, -+ .parse_params = nfct_cmd_timeout_parse_params, -+}; -+ -+static void __init timeout_init(void) -+{ -+ nfct_extension_register(&timeout); -+} -diff --git a/src/nfct.c b/src/nfct.c -index b5c9654..533d75d 100644 ---- a/src/nfct.c -+++ b/src/nfct.c -@@ -22,9 +22,8 @@ - #include - - #include --#include --#include - -+#include "linux_list.h" - #include "nfct.h" - - static int nfct_cmd_version(int argc, char *argv[]); -@@ -46,9 +45,29 @@ void nfct_perror(const char *msg) - } - } - -+static LIST_HEAD(nfct_extension_list); -+ -+void nfct_extension_register(struct nfct_extension *ext) -+{ -+ list_add(&ext->head, &nfct_extension_list); -+} -+ -+static struct nfct_extension *nfct_extension_lookup(int type) -+{ -+ struct nfct_extension *ext; -+ -+ list_for_each_entry(ext, &nfct_extension_list, head) { -+ if (ext->type == type) -+ return ext; -+ } -+ return NULL; -+} -+ - int main(int argc, char *argv[]) - { - int subsys = NFCT_SUBSYS_NONE, ret = 0; -+ struct nfct_extension *ext; -+ struct mnl_socket *nl; - - if (argc < 2) { - usage(argv); -@@ -70,18 +89,29 @@ int main(int argc, char *argv[]) - } - - switch(subsys) { -- case NFCT_SUBSYS_TIMEOUT: -- ret = nfct_cmd_timeout_parse_params(argc, argv); -- break; -- case NFCT_SUBSYS_HELPER: -- ret = nfct_cmd_helper_parse_params(argc, argv); -- break; - case NFCT_SUBSYS_VERSION: - ret = nfct_cmd_version(argc, argv); - break; - case NFCT_SUBSYS_HELP: - ret = nfct_cmd_help(argc, argv); - break; -+ default: -+ ext = nfct_extension_lookup(subsys); -+ if (ext == NULL) { -+ fprintf(stderr, "nfct v%s: subsystem %s not supported\n", -+ VERSION, argv[1]); -+ return EXIT_FAILURE; -+ } -+ -+ nl = nfct_mnl_open(); -+ if (nl == NULL) { -+ nfct_perror("cannot open netlink"); -+ return -1; -+ } -+ -+ ret = ext->parse_params(nl, argc, argv); -+ mnl_socket_close(nl); -+ break; - } - return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS; - } -@@ -120,3 +150,42 @@ static int nfct_cmd_help(int argc, char *argv[]) - printf(help_msg, VERSION, argv[0]); - return 0; - } -+ -+int nfct_mnl_talk(struct mnl_socket *nl, struct nlmsghdr *nlh, -+ uint32_t seq, uint32_t portid, -+ int (*cb)(const struct nlmsghdr *nlh, void *data), -+ void *data) -+{ -+ int ret; -+ char buf[MNL_SOCKET_BUFFER_SIZE]; -+ -+ if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) -+ return -1; -+ -+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -+ while (ret > 0) { -+ ret = mnl_cb_run(buf, ret, seq, portid, cb, data); -+ if (ret <= 0) -+ break; -+ -+ ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); -+ } -+ if (ret == -1) -+ return -1; -+ -+ return 0; -+} -+ -+struct mnl_socket *nfct_mnl_open(void) -+{ -+ struct mnl_socket *nl; -+ -+ nl = mnl_socket_open(NETLINK_NETFILTER); -+ if (nl == NULL) -+ return NULL; -+ -+ if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) -+ return NULL; -+ -+ return nl; -+} -diff --git a/src/read_config_lex.l b/src/read_config_lex.l -index b4d11d4..8350069 100644 ---- a/src/read_config_lex.l -+++ b/src/read_config_lex.l -@@ -47,7 +47,7 @@ ip6_part {hex_255}":"? - ip6_form1 {ip6_part}{0,7}"::"{ip6_part}{0,7} - ip6_form2 ({hex_255}":"){0,7}{hex_255} - ip6 {ip6_form1}{ip6_cidr}?|{ip6_form2}{ip6_cidr}? --string [a-zA-Z][a-zA-Z0-9\.\-]* -+string [a-zA-Z][a-zA-Z0-9\.\-\_]* - persistent [P|p][E|e][R|r][S|s][I|i][S|s][T|t][E|e][N|n][T|T] - nack [N|n][A|a][C|c][K|k] - alarm [A|a][L|l][A|a][R|r][M|m] -diff --git a/src/read_config_yy.y b/src/read_config_yy.y -index b824150..73fabbf 100644 ---- a/src/read_config_yy.y -+++ b/src/read_config_yy.y -@@ -1612,12 +1612,17 @@ helper_type: T_TYPE T_STRING T_STRING T_STRING '{' helper_type_list '}' - exit(EXIT_FAILURE); - } - -- /* XXX use configure.ac definitions. */ -- helper = helper_find("/usr/lib/conntrack-tools", $2, l4proto, RTLD_NOW); -+#ifdef BUILD_CTHELPER -+ helper = helper_find(CONNTRACKD_LIB_DIR, $2, l4proto, RTLD_NOW); - if (helper == NULL) { - print_err(CTD_CFG_ERROR, "Unknown `%s' helper", $2); - exit(EXIT_FAILURE); - } -+#else -+ print_err(CTD_CFG_ERROR, "Helper support is disabled, recompile " -+ "conntrackd"); -+ exit(EXIT_FAILURE); -+#endif - - helper_inst = calloc(1, sizeof(struct ctd_helper_instance)); - if (helper_inst == NULL) -diff --git a/src/run.c b/src/run.c -index 7fa6889..a9d4862 100644 ---- a/src/run.c -+++ b/src/run.c -@@ -55,9 +55,10 @@ void killer(int signo) - if (CONFIG(flags) & (CTD_SYNC_MODE | CTD_STATS_MODE)) - ctnl_kill(); - -+#ifdef BUILD_CTHELPER - if (CONFIG(flags) & CTD_HELPER) - cthelper_kill(); -- -+#endif - destroy_fds(STATE(fds)); - unlink(CONFIG(lockfile)); - dlog(LOG_NOTICE, "---- shutdown received ----"); -@@ -205,9 +206,10 @@ static int local_handler(int fd, void *data) - if (CONFIG(flags) & (CTD_SYNC_MODE | CTD_STATS_MODE)) - return ctnl_local(fd, type, data); - -+#ifdef BUILD_CTHELPER - if (CONFIG(flags) & CTD_HELPER) - return cthelper_local(fd, type, data); -- -+#endif - return ret; - } - -@@ -259,11 +261,12 @@ init(void) - if (ctnl_init() < 0) - return -1; - -+#ifdef BUILD_CTHELPER - if (CONFIG(flags) & CTD_HELPER) { - if (cthelper_init() < 0) - return -1; - } -- -+#endif - time(&STATE(stats).daemon_start_time); - - dlog(LOG_NOTICE, "initialization completed"); -diff --git a/src/sync-notrack.c b/src/sync-notrack.c -index a7df4e7..c810bbb 100644 ---- a/src/sync-notrack.c -+++ b/src/sync-notrack.c -@@ -99,7 +99,7 @@ static int kernel_resync_cb(enum nf_conntrack_msg_type type, - static void kernel_resync(void) - { - struct nfct_handle *h; -- u_int32_t family = AF_UNSPEC; -+ uint32_t family = AF_UNSPEC; - int ret; - - h = nfct_open(CONFIG(netlink).subsys_id, 0); -diff --git a/src/udp.c b/src/udp.c -index ecaa46e..d0a7f5b 100644 ---- a/src/udp.c -+++ b/src/udp.c -@@ -136,14 +136,18 @@ struct udp_sock *udp_client_create(struct udp_conf *conf) - m->addr.ipv4.sin_family = AF_INET; - m->addr.ipv4.sin_port = htons(conf->port); - m->addr.ipv4.sin_addr = conf->client.inet_addr; -- m->sockaddr_len = sizeof(struct sockaddr_in); -+ m->sockaddr_len = sizeof(struct sockaddr_in); - break; - case AF_INET6: - m->addr.ipv6.sin6_family = AF_INET6; - m->addr.ipv6.sin6_port = htons(conf->port); - memcpy(&m->addr.ipv6.sin6_addr, &conf->client.inet_addr6, - sizeof(struct in6_addr)); -- m->sockaddr_len = sizeof(struct sockaddr_in6); -+ m->sockaddr_len = sizeof(struct sockaddr_in6); -+ /* Bind the sender side to the same interface that we use to -+ * receive sync messages. -+ */ -+ m->addr.ipv6.sin6_scope_id = conf->server.ipv6.scope_id; - break; - default: - ret = -1; diff --git a/SOURCES/conntrack-tools-coverity20150818.patch b/SOURCES/conntrack-tools-coverity20150818.patch deleted file mode 100644 index ad306bb..0000000 --- a/SOURCES/conntrack-tools-coverity20150818.patch +++ /dev/null @@ -1,217 +0,0 @@ -diff --git a/src/cache.c b/src/cache.c -index 7c41e54..79a024f 100644 ---- a/src/cache.c -+++ b/src/cache.c -@@ -34,7 +34,7 @@ struct cache_feature *cache_feature[CACHE_MAX_FEATURE] = { - }; - - struct cache *cache_create(const char *name, enum cache_type type, -- unsigned int features, -+ unsigned int features, - struct cache_extra *extra, - struct cache_ops *ops) - { -@@ -53,7 +53,8 @@ struct cache *cache_create(const char *name, enum cache_type type, - return NULL; - memset(c, 0, sizeof(struct cache)); - -- strcpy(c->name, name); -+ strncpy(c->name, name, CACHE_MAX_NAMELEN); -+ c->name[CACHE_MAX_NAMELEN - 1] = '\0'; - c->type = type; - - for (i = 0; i < CACHE_MAX_FEATURE; i++) { -diff --git a/src/cthelper.c b/src/cthelper.c -index 6537515..54eb830 100644 ---- a/src/cthelper.c -+++ b/src/cthelper.c -@@ -277,11 +277,11 @@ static int nfq_queue_cb(const struct nlmsghdr *nlh, void *data) - - if (!attr[NFQA_PAYLOAD]) { - dlog(LOG_ERR, "packet with no payload"); -- goto err; -+ goto err1; - } - if (!attr[NFQA_CT] || !attr[NFQA_CT_INFO]) { - dlog(LOG_ERR, "no CT attached to this packet"); -- goto err; -+ goto err1; - } - - pkt = mnl_attr_get_payload(attr[NFQA_PAYLOAD]); -@@ -292,22 +292,22 @@ static int nfq_queue_cb(const struct nlmsghdr *nlh, void *data) - queue_num = ntohs(nfg->res_id); - - if (pkt_get(pkt, pktlen, ntohs(ph->hw_protocol), &protoff)) -- goto err; -+ goto err1; - - ct = nfct_new(); - if (ct == NULL) -- goto err; -+ goto err1; - - if (nfct_payload_parse(mnl_attr_get_payload(attr[NFQA_CT]), - mnl_attr_get_payload_len(attr[NFQA_CT]), - l3num, ct) < 0) { - dlog(LOG_ERR, "cannot convert message to CT"); -- goto err; -+ goto err2; - } - - myct = calloc(1, sizeof(struct myct)); - if (myct == NULL) -- goto err; -+ goto err2; - - myct->ct = ct; - ctinfo = ntohl(mnl_attr_get_u32(attr[NFQA_CT_INFO])); -@@ -315,15 +315,15 @@ static int nfq_queue_cb(const struct nlmsghdr *nlh, void *data) - /* XXX: 256 bytes enough for possible NAT mangling in helpers? */ - pktb = pktb_alloc(AF_INET, pkt, pktlen, 256); - if (pktb == NULL) -- goto err; -+ goto err3; - - /* Misconfiguration: if no helper found, accept the packet. */ - helper = helper_run(pktb, protoff, myct, ctinfo, queue_num, &verdict); - if (!helper) -- goto err_pktb; -+ goto err4; - - if (pkt_verdict_issue(helper, myct, queue_num, id, verdict, pktb) < 0) -- goto err_pktb; -+ goto err4; - - nfct_destroy(ct); - if (myct->exp != NULL) -@@ -333,18 +333,19 @@ static int nfq_queue_cb(const struct nlmsghdr *nlh, void *data) - free(myct); - - return MNL_CB_OK; --err_pktb: -+err4: - pktb_free(pktb); --err: -+err3: -+ free(myct); -+err2: -+ nfct_destroy(ct); -+err1: - /* In case of error, we don't want to disrupt traffic. We accept all. - * This is connection tracking after all. The policy is not to drop - * packet unless we enter some inconsistent state. - */ - pkt_verdict_error(queue_num, id); - -- if (ct != NULL) -- nfct_destroy(ct); -- - return MNL_CB_OK; - } - -diff --git a/src/local.c b/src/local.c -index 453799a..3395b4c 100644 ---- a/src/local.c -+++ b/src/local.c -@@ -77,7 +77,7 @@ int do_local_server_step(struct local_server *server, void *data, - int rfd; - struct sockaddr_un local; - socklen_t sin_size = sizeof(struct sockaddr_un); -- -+ - rfd = accept(server->fd, (struct sockaddr *) &local, &sin_size); - if (rfd == -1) - return -1; -@@ -147,11 +147,14 @@ int do_local_request(int request, - - ret = send(fd, &request, sizeof(int), 0); - if (ret == -1) -- return -1; -+ goto err1; - - do_local_client_step(fd, step); - - local_client_destroy(fd); -- -+ - return 0; -+err1: -+ local_client_destroy(fd); -+ return -1; - } -diff --git a/src/parse.c b/src/parse.c -index f3ec6ac..919d36c 100644 ---- a/src/parse.c -+++ b/src/parse.c -@@ -297,7 +297,7 @@ int msg2ct(struct nf_conntrack *ct, struct nethdr *net, size_t remain) - return -1; - if (attr->nta_len < NTA_LENGTH(0)) - return -1; -- if (attr->nta_attr > NTA_MAX) -+ if (attr->nta_attr >= NTA_MAX) - return -1; - if (h[attr->nta_attr].size && - attr->nta_len != h[attr->nta_attr].size) -@@ -510,7 +510,7 @@ int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain) - ATTR_NETWORK2HOST(attr); - if (attr->nta_len > len) - goto err; -- if (attr->nta_attr > NTA_MAX) -+ if (attr->nta_attr >= NTA_EXP_MAX) - goto err; - if (attr->nta_len < NTA_LENGTH(0)) - goto err; -@@ -524,13 +524,15 @@ int msg2exp(struct nf_expect *exp, struct nethdr *net, size_t remain) - attr = NTA_NEXT(attr, len); - continue; - } -- switch(exp_h[attr->nta_attr].exp_attr) { -+ switch (exp_h[attr->nta_attr].exp_attr) { - case ATTR_EXP_MASTER: - exp_h[attr->nta_attr].parse(master, attr->nta_attr, - NTA_DATA(attr)); -+ break; - case ATTR_EXP_EXPECTED: - exp_h[attr->nta_attr].parse(expected, attr->nta_attr, - NTA_DATA(attr)); -+ break; - case ATTR_EXP_MASK: - exp_h[attr->nta_attr].parse(mask, attr->nta_attr, - NTA_DATA(attr)); -diff --git a/src/process.c b/src/process.c -index 7f0a395..3ddad5f 100644 ---- a/src/process.c -+++ b/src/process.c -@@ -48,6 +48,8 @@ int fork_process_new(int type, int flags, void (*cb)(void *data), void *data) - - if (c->pid > 0) - list_add(&c->head, &process_list); -+ else -+ free(c); - - return pid; - } -diff --git a/src/tcp.c b/src/tcp.c -index af27c46..e570880 100644 ---- a/src/tcp.c -+++ b/src/tcp.c -@@ -247,13 +247,11 @@ int tcp_accept(struct tcp_sock *m) - /* the other peer wants to connect ... */ - ret = accept(m->fd, NULL, NULL); - if (ret == -1) { -- if (errno != EAGAIN) { -- /* unexpected error. Give us another try. */ -- m->state = TCP_SERVER_ACCEPTING; -- } else { -- /* waiting for new connections. */ -- m->state = TCP_SERVER_ACCEPTING; -- } -+ /* unexpected error: Give us another try. Or we have hit -+ * -EAGAIN, in that case we remain in the accepting connections -+ * state. -+ */ -+ m->state = TCP_SERVER_ACCEPTING; - } else { - /* the peer finally got connected. */ - if (fcntl(ret, F_SETFL, O_NONBLOCK) == -1) { diff --git a/SPECS/conntrack-tools.spec b/SPECS/conntrack-tools.spec index 9c252c3..766cb15 100644 --- a/SPECS/conntrack-tools.spec +++ b/SPECS/conntrack-tools.spec @@ -1,6 +1,6 @@ Name: conntrack-tools -Version: 1.4.2 -Release: 9%{?dist} +Version: 1.4.3 +Release: 1%{?dist} Summary: Manipulate netfilter connection tracking table and run High Availability Group: System Environment/Base License: GPLv2 @@ -8,8 +8,6 @@ URL: http://netfilter.org Source0: http://netfilter.org/projects/%{name}/files/%{name}-%{version}.tar.bz2 Source1: conntrackd.service Source2: conntrackd.conf -Patch1: conntrack-tools-20150818.patch -Patch2: conntrack-tools-coverity20150818.patch BuildRequires: libnfnetlink-devel >= 1.0.1, libnetfilter_conntrack-devel >= 1.0.4 BuildRequires: libnetfilter_cttimeout-devel >= 1.0.0, libnetfilter_cthelper-devel >= 1.0.0 BuildRequires: libmnl-devel >= 1.0.3, libnetfilter_queue-devel >= 1.0.2 @@ -42,10 +40,9 @@ show an event message (one line) per newly established connection. %prep %setup -q -%patch1 -p1 -%patch2 -p1 %build +# do not use --enable-cthelper --enable-cttimeout, it causes disabling of these features %configure --disable-static %{__make} %{?_smp_mflags} chmod 644 doc/sync/primary-backup.sh @@ -81,6 +78,9 @@ install -m 0644 %{SOURCE2} %{buildroot}%{_sysconfdir}/conntrackd/ %systemd_postun conntrackd.service %changelog +* Fri Aug 12 2016 Paul Wouters - 1.4.3-1 +- Resolves: rhbz#1351701 conntrackd -d throws "ERROR: Helper support is disabled" + * Fri Aug 21 2015 Paul Wouters - 1.4.2-9 - Resolves: rhbz#1255578 conntrackd could neither be started nor be stopped