205ad0f585
- Fold in upstream patches since 1.4.2 release up to git 900d7e8 - Fold in upstream patch set of 2015-08-18 for coverity issues
3719 lines
106 KiB
Diff
3719 lines
106 KiB
Diff
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 <laforge@netfilter.org (Jun 2005)
|
|
.\" Maintained by Pablo Neira Ayuso <pablo@netfilter.org (May 2007)
|
|
@@ -86,7 +86,7 @@ Show the in-kernel connection tracking system statistics.
|
|
.TP
|
|
.BI "-z, --zero "
|
|
Atomically zero counters after reading them. This option is only valid in
|
|
-combination with the "-L, --dump" command options.
|
|
+combination with the "\-L, \-\-dump" command options.
|
|
.TP
|
|
.BI "-o, --output [extended,xml,timestamp,id,ktimestamp,labels] "
|
|
Display output in a certain format. With the extended output option, this tool
|
|
@@ -101,7 +101,7 @@ Set the bitmask of events that are to be generated by the in-kernel ctnetlink
|
|
event code. Using this parameter, you can reduce the event messages generated
|
|
by the kernel to those types to those that you are actually interested in.
|
|
.
|
|
-This option can only be used in conjunction with "-E, --event".
|
|
+This option can only be used in conjunction with "\-E, \-\-event".
|
|
.TP
|
|
.BI "-b, --buffer-size " "value (in bytes)"
|
|
Set the Netlink socket buffer size. This option is useful if the command line
|
|
@@ -112,7 +112,7 @@ other words, if the amount of events are big enough to overrun the socket
|
|
buffer. Note that using a big buffer reduces the chances to hit ENOBUFS,
|
|
however, this results in more memory consumption.
|
|
.
|
|
-This option can only be used in conjunction with "-E, --event".
|
|
+This option can only be used in conjunction with "\-E, \-\-event".
|
|
.SS FILTER PARAMETERS
|
|
.TP
|
|
.BI "-s, --orig-src " IP_ADDRESS
|
|
@@ -132,22 +132,31 @@ Specify layer four (TCP, UDP, ...) protocol.
|
|
.TP
|
|
.BI "-f, --family " "PROTO"
|
|
Specify layer three (ipv4, ipv6) protocol
|
|
-This option is only required in conjunction with "-L, --dump". If this option is not passed, the default layer 3 protocol will be IPv4.
|
|
+This option is only required in conjunction with "\-L, \-\-dump". If this option is not passed, the default layer 3 protocol will be IPv4.
|
|
.TP
|
|
.BI "-t, --timeout " "TIMEOUT"
|
|
Specify the timeout.
|
|
.TP
|
|
.BI "-m, --mark " "MARK[/MASK]"
|
|
Specify the conntrack mark. Optionally, a mask value can be specified.
|
|
-In "--update" mode, this mask specifies the bits that should be zeroed before XORing
|
|
+In "\-\-update" mode, this mask specifies the bits that should be zeroed before XORing
|
|
the MARK value into the ctmark.
|
|
Otherwise, the mask is logically ANDed with the existing mark before the comparision.
|
|
-In "--create" mode, the mask is ignored.
|
|
+In "\-\-create" mode, the mask is ignored.
|
|
.TP
|
|
-.BI "-l, --label " "LABEL,..."
|
|
-Specify the conntrack labels.
|
|
-This option is only available in conjunction with "-L, --dump" or "-E, --event".
|
|
+.BI "-l, --label " "LABEL"
|
|
+Specify a conntrack label.
|
|
+This option is only available in conjunction with "\-L, \-\-dump", "\-E, \-\-event", or "\-U \-\-update".
|
|
+Match entries whose labels match at least those specified.
|
|
+Use multiple \-l commands to specify multiple labels that need to be set.
|
|
Match entries whose labels matches at least those specified as arguments.
|
|
+.BI "--label-add " "LABEL"
|
|
+Specify the conntrack label to add to to the selected conntracks.
|
|
+This option is only available in conjunction with "\-I, \-\-create" or "\-U, \-\-update".
|
|
+.BI "--label-del " "[LABEL]"
|
|
+Specify the conntrack label to delete from the selected conntracks.
|
|
+If no label is given, all labels are deleted.
|
|
+This option is only available in conjunction with "\-U, \-\-update".
|
|
.TP
|
|
.BI "-c, --secmark " "SECMARK"
|
|
Specify the conntrack selinux security mark.
|
|
diff --git a/conntrackd.8 b/conntrackd.8
|
|
index 131a7ac..455f6c5 100644
|
|
--- a/conntrackd.8
|
|
+++ b/conntrackd.8
|
|
@@ -1,4 +1,4 @@
|
|
-.TH CONNTRACKD 8 "Oct 21, 2008" "" ""
|
|
+.TH CONNTRACKD 8 "Sep 25, 2014" "" ""
|
|
|
|
.\" Man page written by Pablo Neira Ayuso <pablo@netfilter.org> (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.</para></listitem>
|
|
<listitem><para>Oracle*TNS, to support its special <emphasis>Redirect</emphasis> message.</para></listitem>
|
|
<listitem><para>NFSv3, mind that version 4 does not require this helper.</para></listitem>
|
|
<listitem><para>FTP (this helper is also available in kernel-space).</para></listitem>
|
|
+<listitem><para>SSDP.</para></listitem>
|
|
</itemizedlist>
|
|
|
|
<para>The following steps describe how to enable the RPC portmapper helper for NFSv3 (this is similar for other helpers):</para>
|
|
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 <stdlib.h>
|
|
+#include <stdint.h>
|
|
|
|
-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 <netinet/in.h>
|
|
|
|
#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 <linux/netlink.h>
|
|
-#include <linux/capability.h>
|
|
-#include <net/netlink.h>
|
|
-
|
|
-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 <stdint.h>
|
|
#include <netinet/in.h>
|
|
#include <net/if.h>
|
|
+#include <sys/select.h>
|
|
|
|
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 <stdint.h>
|
|
#include <netinet/in.h>
|
|
+#include <sys/select.h>
|
|
|
|
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 <stdint.h>
|
|
#include <netinet/in.h>
|
|
+#include <sys/select.h>
|
|
|
|
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 <netinet/in.h>
|
|
#include <netinet/ip.h>
|
|
#include <netinet/ip6.h>
|
|
+#define _GNU_SOURCE
|
|
#include <netinet/tcp.h>
|
|
#include <netinet/udp.h>
|
|
#include <net/ethernet.h>
|
|
@@ -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 <pablo@netfilter.org>
|
|
+ *
|
|
+ * Adapted from:
|
|
+ *
|
|
+ * Amanda extension for IP connection tracking
|
|
+ *
|
|
+ * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
|
|
+ * based on HW's ip_conntrack_irc.c as well as other modules
|
|
+ * (C) 2006 Patrick McHardy <kaber@trash.net>
|
|
+ *
|
|
+ * 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 <errno.h>
|
|
+#include <netinet/ip.h>
|
|
+#include <netinet/ip6.h>
|
|
+#include <netinet/udp.h>
|
|
+#include <libmnl/libmnl.h>
|
|
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue_udp.h>
|
|
+#include <libnetfilter_queue/pktbuff.h>
|
|
+#include <linux/netfilter.h>
|
|
+
|
|
+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 <pablo@netfilter.org>
|
|
+ *
|
|
+ * Adapted from:
|
|
+ *
|
|
+ * DHCPv6 multicast connection tracking helper.
|
|
+ *
|
|
+ * (c) 2012 Google Inc.
|
|
+ *
|
|
+ * Original author: Darren Willis <djw@google.com>
|
|
+ *
|
|
+ * 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 <errno.h>
|
|
+#include <netinet/ip.h>
|
|
+#include <netinet/ip6.h>
|
|
+#include <netinet/udp.h>
|
|
+#include <libmnl/libmnl.h>
|
|
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue_udp.h>
|
|
+#include <libnetfilter_queue/pktbuff.h>
|
|
+#include <linux/netfilter.h>
|
|
+
|
|
+#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 <ctype.h> /* for isdigit */
|
|
#include <errno.h>
|
|
|
|
+#define _GNU_SOURCE
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <libmnl/libmnl.h>
|
|
@@ -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 <pablo@netfilter.org>
|
|
+ *
|
|
+ * 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 <mschmidt@redhat.com>
|
|
+ * Based on the FTP conntrack helper (net/netfilter/nf_conntrack_ftp.c):
|
|
+ * (C) 1999-2001 Paul `Rusty' Russell
|
|
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
|
|
+ * (C) 2003,2004 USAGI/WIDE Project <http://www.linux-ipv6.org>
|
|
+ * (C) 2003 Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp>
|
|
+ *
|
|
+ * 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 <errno.h>
|
|
+#include <netinet/ip.h>
|
|
+#define _GNU_SOURCE
|
|
+#include <netinet/tcp.h>
|
|
+#include <libmnl/libmnl.h>
|
|
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
|
|
+#include <libnetfilter_queue/pktbuff.h>
|
|
+#include <linux/netfilter.h>
|
|
+
|
|
+enum sane_state {
|
|
+ SANE_STATE_NORMAL,
|
|
+ SANE_STATE_START_REQUESTED,
|
|
+};
|
|
+
|
|
+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 <ashley.hughes@blueyonder.co.uk>
|
|
+ * Based on the SSDP conntrack helper (nf_conntrack_ssdp.c),
|
|
+ * :http://marc.info/?t=132945775100001&r=1&w=2
|
|
+ * (C) 2012 Ian Pilcher <arequipeno@gmail.com>
|
|
+ *
|
|
+ * 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 <errno.h>
|
|
+#include <arpa/inet.h>
|
|
+#include <netinet/ip.h>
|
|
+#include <netinet/udp.h>
|
|
+#include <libmnl/libmnl.h>
|
|
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue_tcp.h>
|
|
+#include <libnetfilter_queue/pktbuff.h>
|
|
+#include <linux/netfilter.h>
|
|
+
|
|
+#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 <pablo@netfilter.org>
|
|
+ *
|
|
+ * Adapted from:
|
|
+ *
|
|
+ * (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
|
|
+ * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
|
|
+ * 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 <errno.h>
|
|
+#include <netinet/ip.h>
|
|
+#include <netinet/ip6.h>
|
|
+#include <netinet/udp.h>
|
|
+#include <libmnl/libmnl.h>
|
|
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue.h>
|
|
+#include <libnetfilter_queue/libnetfilter_queue_udp.h>
|
|
+#include <libnetfilter_queue/pktbuff.h>
|
|
+#include <linux/netfilter.h>
|
|
+
|
|
+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 <ctype.h> /* for isdigit */
|
|
#include <errno.h>
|
|
|
|
+#define _GNU_SOURCE
|
|
#include <netinet/tcp.h>
|
|
|
|
#include <libmnl/libmnl.h>
|
|
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 <errno.h>
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
-#include <sys/fcntl.h>
|
|
+#include <fcntl.h>
|
|
#include <libnetfilter_conntrack/libnetfilter_conntrack_tcp.h>
|
|
|
|
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 <pablo@netfilter.org>
|
|
+ * (C) 2012-2013 by Pablo Neira Ayuso <pablo@netfilter.org>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published
|
|
@@ -19,6 +19,7 @@
|
|
#include <unistd.h>
|
|
#include <time.h>
|
|
#include <netinet/in.h>
|
|
+#include <netdb.h>
|
|
#include <errno.h>
|
|
|
|
#include <libmnl/libmnl.h>
|
|
@@ -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 <list|add|delete|get|flush|set> "
|
|
+ "[<parameters>, ...]\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; i<argc; i+=2) {
|
|
+ for (; argc>1; argc-=2, argv+=2) {
|
|
int matching = -1;
|
|
|
|
for (j=0; j<nfct_timeout_attr_max[l4proto]; j++) {
|
|
@@ -241,76 +237,78 @@ int nfct_cmd_timeout_add(int argc, char *argv[])
|
|
nfct_perror("state name is NULL");
|
|
return -1;
|
|
}
|
|
- if (strcasecmp(argv[i], state_name) != 0)
|
|
+ if (strcasecmp(*argv, state_name) != 0)
|
|
continue;
|
|
|
|
matching = j;
|
|
break;
|
|
}
|
|
if (matching != -1) {
|
|
- if (i+1 >= 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 <errno.h>
|
|
|
|
#include <libmnl/libmnl.h>
|
|
-#include <linux/netfilter/nfnetlink_cttimeout.h>
|
|
-#include <libnetfilter_cttimeout/libnetfilter_cttimeout.h>
|
|
|
|
+#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;
|