[PATCH 1/3] conntrack: add support for netmask filtering

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch extends --mask-src and --mask-dst to also work
with the conntrack table, with commands -L, -D and -E.

Signed-off-by: Asbjørn Sloth Tønnesen <ast@xxxxxxxxxx>
---
 conntrack.8     |   7 ++-
 src/conntrack.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 142 insertions(+), 13 deletions(-)

diff --git a/conntrack.8 b/conntrack.8
index abc26c5..4bb8bfe 100644
--- a/conntrack.8
+++ b/conntrack.8
@@ -183,10 +183,13 @@ Specify the tuple source address of an expectation.
 Specify the tuple destination address of an expectation.
 .TP
 .BI "--mask-src " IP_ADDRESS
-Specify the source address mask of an expectation.
+Specify the source address mask.
+For conntrack this option is only available in conjunction with "\-L, \-\-dump", "\-E, \-\-event", or "\-D \-\-delete".
+For expectations this option is only available in conjunction with "\-I, \-\-create".
 .TP
 .BI "--mask-dst " IP_ADDRESS
-Specify the destination address mask of an expectation.
+Specify the destination address mask.
+Same limitations as for "--mask-src".
 .SS PROTOCOL FILTER PARAMETERS
 .TP
 TCP-specific fields:
diff --git a/src/conntrack.c b/src/conntrack.c
index 1e45ca8..ceafb0c 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -366,13 +366,13 @@ 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,0,0},
+/*CT_LIST*/   {2,2,2,2,2,0,2,2,0,0,0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,0,0},
 /*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_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,0},
 /*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},
+/*CT_EVENT*/  {2,2,2,2,2,0,0,0,2,0,0,2,2,0,2,0,0,2,2,2,2,2,2,2,2,0,0},
 /*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},
@@ -446,6 +446,27 @@ static const int opt2attr[] = {
 	['>']	= ATTR_CONNLABELS,
 };
 
+enum direction {
+	DIR_SRC = 0,
+	DIR_DST = 1,
+};
+
+union ct_address {
+	uint32_t v4;
+	uint32_t v6[4];
+};
+
+static struct network {
+	union ct_address netmask;
+	union ct_address network;
+} dir2network[2];
+
+
+static const int famdir2attr[2][2] = {
+	{ ATTR_ORIG_IPV4_SRC, ATTR_ORIG_IPV4_DST },
+	{ ATTR_ORIG_IPV6_SRC, ATTR_ORIG_IPV6_DST }
+};
+
 static char exit_msg[NUMBER_OF_CMD][64] = {
 	[CT_LIST_BIT] 		= "%d flow entries have been shown.\n",
 	[CT_CREATE_BIT]		= "%d flow entries have been created.\n",
@@ -487,9 +508,7 @@ static const char usage_conntrack_parameters[] =
 static const char usage_expectation_parameters[] =
 	"Expectation parameters and options:\n"
 	"  --tuple-src ip\tSource address in expect tuple\n"
-	"  --tuple-dst ip\tDestination address in expect tuple\n"
-	"  --mask-src ip\t\tSource mask address\n"
-	"  --mask-dst ip\t\tDestination mask address\n";
+	"  --tuple-dst ip\tDestination address in expect tuple\n";
 
 static const char usage_update_parameters[] =
 	"Updating parameters and options:\n"
@@ -508,6 +527,8 @@ static const char usage_parameters[] =
 	"  -u, --status status\t\tSet status, eg. ASSURED\n"
 	"  -w, --zone value\t\tSet conntrack zone\n"
 	"  -b, --buffer-size\t\tNetlink socket buffer size\n"
+	"  --mask-src ip\t\t\tSource mask address\n"
+	"  --mask-dst ip\t\t\tDestination mask address\n"
 	;
 
 #define OPTION_OFFSET 256
@@ -515,6 +536,7 @@ static const char usage_parameters[] =
 static struct nfct_handle *cth, *ith;
 static struct option *opts = original_opts;
 static unsigned int global_option_offset = 0;
+static int global_family;
 
 #define ADDR_VALID_FLAGS_MAX   2
 static unsigned int addr_valid_flags[ADDR_VALID_FLAGS_MAX] = {
@@ -985,11 +1007,6 @@ parse_inetaddr(const char *cp, struct addr_parse *parse)
 	return AF_UNSPEC;
 }
 
-union ct_address {
-	uint32_t v4;
-	uint32_t v6[4];
-};
-
 static int
 parse_addr(const char *cp, union ct_address *address)
 {
@@ -1187,6 +1204,50 @@ filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct)
 	return 0;
 }
 
+static int
+filter_network_direction(const struct nf_conntrack *ct, enum direction dir)
+{
+	const int family = global_family;
+	const union ct_address *address;
+	enum nf_conntrack_attr attr;
+	int i;
+	struct network *net = &dir2network[dir];
+
+	if (nfct_get_attr_u8(ct, ATTR_ORIG_L3PROTO) != family)
+		return 1;
+
+	attr = famdir2attr[family == AF_INET6][dir];
+
+	address = nfct_get_attr(ct, attr);
+
+	if (family == AF_INET) {
+		if ((address->v4 & net->netmask.v4) != net->network.v4)
+			return 1;
+	} else if (family == AF_INET6) {
+		for (i=0;i<4;i++)
+			if ((address->v6[i] & net->netmask.v6[i])
+			     != net->network.v6[i])
+				return 1;
+	}
+
+	return 0;
+}
+
+static int
+filter_network(const struct nf_conntrack *ct)
+{
+	if (options & CT_OPT_MASK_SRC) {
+		if (filter_network_direction(ct, DIR_SRC))
+			return 1;
+	}
+
+	if (options & CT_OPT_MASK_DST) {
+		if (filter_network_direction(ct, DIR_DST))
+			return 1;
+	}
+	return 0;
+}
+
 static int counter;
 static int dump_xml_header_done = 1;
 
@@ -1236,6 +1297,9 @@ static int event_cb(enum nf_conntrack_msg_type type,
 	if (filter_label(ct))
 		return NFCT_CB_CONTINUE;
 
+	if (filter_network(ct))
+		return NFCT_CB_CONTINUE;
+
 	if (options & CT_COMPARISON &&
 	    !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK))
 		return NFCT_CB_CONTINUE;
@@ -1291,6 +1355,9 @@ static int dump_cb(enum nf_conntrack_msg_type type,
 	if (filter_label(ct))
 		return NFCT_CB_CONTINUE;
 
+	if (filter_network(ct))
+		return NFCT_CB_CONTINUE;
+
 	if (options & CT_COMPARISON &&
 	    !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK))
 		return NFCT_CB_CONTINUE;
@@ -1334,6 +1401,9 @@ static int delete_cb(enum nf_conntrack_msg_type type,
 	if (filter_mark(ct))
 		return NFCT_CB_CONTINUE;
 
+	if (filter_network(ct))
+		return NFCT_CB_CONTINUE;
+
 	if (options & CT_COMPARISON &&
 	    !nfct_cmp(obj, ct, NFCT_CMP_ALL | NFCT_CMP_MASK))
 		return NFCT_CB_CONTINUE;
@@ -1907,6 +1977,52 @@ static void labelmap_init(void)
 		perror("nfct_labelmap_new");
 }
 
+static void
+network_attr_prepare(enum direction dir)
+{
+	const int family = global_family;
+	const union ct_address *address, *netmask;
+	enum nf_conntrack_attr attr;
+	int i;
+	struct network *net = &dir2network[dir];
+
+	attr = famdir2attr[family == AF_INET6][dir];
+
+	address = nfct_get_attr(tmpl.ct, attr);
+	netmask = nfct_get_attr(tmpl.mask, attr);
+
+	if (family == AF_INET) {
+		net->network.v4 = address->v4 & netmask->v4;
+	} else if (family == AF_INET6) {
+		for (i=0;i<4;i++)
+			net->network.v6[i] = address->v6[i] & netmask->v6[i];
+	}
+
+	memcpy(&net->netmask, netmask, sizeof(union ct_address));
+
+	/* avoid exact source matching */
+	if (nfct_attr_unset(tmpl.ct, attr) == -1)
+		perror("nfct_attr_unset");
+}
+
+static void
+network_prepare(void)
+{
+	if (options & CT_OPT_MASK_SRC) {
+		if (!(options & CT_OPT_ORIG_SRC))
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't use --mask-src without --src");
+		network_attr_prepare(DIR_SRC);
+	}
+
+	if (options & CT_OPT_MASK_DST) {
+		if (!(options & CT_OPT_ORIG_DST))
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't use --mask-dst without --dst");
+		network_attr_prepare(DIR_DST);
+	}
+}
+
 static void merge_bitmasks(struct nfct_bitmask **current,
 			  struct nfct_bitmask *src)
 {
@@ -2201,6 +2317,9 @@ int main(int argc, char *argv[])
 	if (family == AF_UNSPEC)
 		family = AF_INET;
 
+	/* store family */
+	global_family = family;
+
 	/* we cannot check this combination with generic_opt_check. */
 	if (options & CT_OPT_ANY_NAT &&
 	   ((options & CT_OPT_SRC_NAT) || (options & CT_OPT_DST_NAT))) {
@@ -2264,6 +2383,8 @@ int main(int argc, char *argv[])
 			exit_error(PARAMETER_PROBLEM, "Can't use -z with "
 						      "filtering parameters");
 
+		network_prepare();
+
 		nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct);
 
 		filter_dump = nfct_filter_dump_create();
@@ -2363,6 +2484,8 @@ int main(int argc, char *argv[])
 		if (!cth || !ith)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 
+		network_prepare();
+
 		nfct_callback_register(cth, NFCT_T_ALL, delete_cb, tmpl.ct);
 
 		filter_dump = nfct_filter_dump_create();
@@ -2464,6 +2587,9 @@ int main(int argc, char *argv[])
 			fprintf(stderr, "NOTICE: Netlink socket buffer size "
 					"has been set to %zu bytes.\n", ret);
 		}
+
+		network_prepare();
+
 		signal(SIGINT, event_sighandler);
 		signal(SIGTERM, event_sighandler);
 		nfct_callback_register(cth, NFCT_T_ALL, event_cb, tmpl.ct);
-- 
2.1.4

--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux