netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* conntrack: netmask filtering support
@ 2015-01-13 11:55 Asbjørn Sloth Tønnesen
  2015-01-13 11:55 ` [PATCH 1/3] conntrack: add support for netmask filtering Asbjørn Sloth Tønnesen
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Asbjørn Sloth Tønnesen @ 2015-01-13 11:55 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Hi Pablo,

These patches adds support for network filtering, using the
pre-existing netmask options and adds CIDR notation as well.

 conntrack.8          |   9 +-
 include/linux_list.h |   8 +-
 src/conntrack.c      | 234 +++++++++++++++++++++++++++++++++++++++----
 3 files changed, 228 insertions(+), 23 deletions(-)

-- 
Best regards
Asbjørn Sloth Tønnesen
Network Engineer
Fiberby ApS - AS42541

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

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/3] conntrack: add support for netmask filtering
  2015-01-13 11:55 conntrack: netmask filtering support Asbjørn Sloth Tønnesen
@ 2015-01-13 11:55 ` Asbjørn Sloth Tønnesen
  2015-01-15 13:13   ` Pablo Neira Ayuso
  2015-01-13 11:55 ` [PATCH 2/3] conntrack: add support for CIDR notation Asbjørn Sloth Tønnesen
  2015-01-13 11:55 ` [PATCH 3/3] fix unused value warning Asbjørn Sloth Tønnesen
  2 siblings, 1 reply; 5+ messages in thread
From: Asbjørn Sloth Tønnesen @ 2015-01-13 11:55 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

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@fiberby.dk>
---
 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@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/3] conntrack: add support for CIDR notation
  2015-01-13 11:55 conntrack: netmask filtering support Asbjørn Sloth Tønnesen
  2015-01-13 11:55 ` [PATCH 1/3] conntrack: add support for netmask filtering Asbjørn Sloth Tønnesen
@ 2015-01-13 11:55 ` Asbjørn Sloth Tønnesen
  2015-01-13 11:55 ` [PATCH 3/3] fix unused value warning Asbjørn Sloth Tønnesen
  2 siblings, 0 replies; 5+ messages in thread
From: Asbjørn Sloth Tønnesen @ 2015-01-13 11:55 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

Add support for using CIDR notation in -s and -d arguments,
instead of free-form formatting IPv6 netmask in --mask-src
and --mask-dst.

Example:
  conntrack -L -s 2001:db8::/56

Instead of:
  conntrack -L -s 2001:db8:: --mask-src ffff:ffff:ffff:ff00::

Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
---
 conntrack.8     |  2 ++
 src/conntrack.c | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 82 insertions(+), 6 deletions(-)

diff --git a/conntrack.8 b/conntrack.8
index 4bb8bfe..5072839 100644
--- a/conntrack.8
+++ b/conntrack.8
@@ -117,9 +117,11 @@ This option can only be used in conjunction with "\-E, \-\-event".
 .TP
 .BI "-s, --orig-src " IP_ADDRESS
 Match only entries whose source address in the original direction equals the one specified as argument.
+Implies "--mask-src" when CIDR notation is used.
 .TP
 .BI "-d, --orig-dst " IP_ADDRESS
 Match only entries whose destination address in the original direction equals the one specified as argument.
+Implies "--mask-dst" when CIDR notation is used.
 .TP
 .BI "-r, --reply-src " IP_ADDRESS
 Match only entries whose source address in the reply direction equals the one specified as argument.
diff --git a/src/conntrack.c b/src/conntrack.c
index ceafb0c..87903b9 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -421,6 +421,13 @@ static const int opt2type[] = {
 	['>']	= CT_OPT_DEL_LABEL,
 };
 
+static const char opt2mask[] = {
+	['s']	= '{',
+	['d']	= '}',
+	['r']	= 0, /* no netmask */
+	['q']	= 0, /* support yet */
+};
+
 static const int opt2family_attr[][2] = {
 	['s']	= { ATTR_ORIG_IPV4_SRC,	ATTR_ORIG_IPV6_SRC },
 	['d']	= { ATTR_ORIG_IPV4_DST,	ATTR_ORIG_IPV6_DST },
@@ -1008,15 +1015,37 @@ parse_inetaddr(const char *cp, struct addr_parse *parse)
 }
 
 static int
-parse_addr(const char *cp, union ct_address *address)
+parse_addr(const char *cp, union ct_address *address, int *mask)
 {
 	struct addr_parse parse;
 	int ret;
+	char buf[INET6_ADDRSTRLEN];
+	char *slash, *end;
+
+	strncpy((char *) &buf, cp, INET6_ADDRSTRLEN);
+	buf[INET6_ADDRSTRLEN-1] = '\0';
+
+	if (mask != NULL) {
+		slash = strchr(buf, '/');
+		if (slash != NULL) {
+			*mask = strtol(slash+1, &end, 10);
+			if (*mask < 0 || end != slash+strlen(slash))
+				*mask = -2;
+			slash[0] = '\0';
+		} else {
+			*mask = -1;
+		}
+	}
 
-	if ((ret = parse_inetaddr(cp, &parse)) == AF_INET)
+	if ((ret = parse_inetaddr(buf, &parse)) == AF_INET) {
 		address->v4 = parse.addr.s_addr;
-	else if (ret == AF_INET6)
+		if (mask != NULL && *mask > 32)
+			*mask = -2;
+	} else if (ret == AF_INET6) {
 		memcpy(address->v6, &parse.addr6, sizeof(parse.addr6));
+		if (mask != NULL && *mask > 128)
+			*mask = -2;
+	}
 
 	return ret;
 }
@@ -1060,7 +1089,7 @@ nat_parse(char *arg, struct nf_conntrack *obj, int type)
 		}
 	}
 
-	if (parse_addr(arg, &parse) == AF_UNSPEC) {
+	if (parse_addr(arg, &parse, NULL) == AF_UNSPEC) {
 		if (strlen(arg) == 0) {
 			exit_error(PARAMETER_PROBLEM, "No IP specified");
 		} else {
@@ -2048,6 +2077,24 @@ static void merge_bitmasks(struct nfct_bitmask **current,
 	nfct_bitmask_destroy(src);
 }
 
+static void
+buildnetmask(uint32_t *dst, int b, int n)
+{
+	int i;
+
+	for (i=0;i<n;i++) {
+		if (b >= 32) {
+			dst[i] = 0xffffffff;
+			b -= 32;
+		} else if (b > 0) {
+			dst[i] = (1<<b)-1;
+			b = 0;
+		} else {
+			dst[i] = 0;
+		}
+	}
+}
+
 int main(int argc, char *argv[])
 {
 	int c, cmd;
@@ -2058,6 +2105,7 @@ int main(int argc, char *argv[])
 	int l3protonum, protonum = 0;
 	union ct_address ad;
 	unsigned int command = 0;
+	int mask, mc;
 
 	/* we release these objects in the exit_error() path. */
 	if (!alloc_tmpl_objects())
@@ -2128,29 +2176,55 @@ int main(int argc, char *argv[])
 		case 'q':
 			options |= opt2type[c];
 
-			l3protonum = parse_addr(optarg, &ad);
+			l3protonum = parse_addr(optarg, &ad, &mask);
 			if (l3protonum == AF_UNSPEC) {
 				exit_error(PARAMETER_PROBLEM,
 					   "Invalid IP address `%s'", optarg);
 			}
 			set_family(&family, l3protonum);
+			mc = opt2mask[c];
+			if (mask != -1 && !mc) {
+				exit_error(PARAMETER_PROBLEM,
+					   "CIDR notation unavailable"
+					   " for `%c'", c);
+			} else if (mask == -2) {
+				exit_error(PARAMETER_PROBLEM,
+					   "Invalid netmask");
+			}
 			if (l3protonum == AF_INET) {
 				nfct_set_attr_u32(tmpl.ct,
 						  opt2family_attr[c][0],
 						  ad.v4);
+				if (mc) {
+					if (mask >= 0 && mask < 32)
+						buildnetmask(&ad.v4, mask, 1);
+					else
+						mc = 0;
+				}
 			} else if (l3protonum == AF_INET6) {
 				nfct_set_attr(tmpl.ct,
 					      opt2family_attr[c][1],
 					      &ad.v6);
+				if (mc) {
+					if (mask >= 0 && mask < 128)
+						buildnetmask((uint32_t *) &ad.v6, mask, 4);
+					else
+						mc = 0;
+				}
 			}
 			nfct_set_attr_u8(tmpl.ct, opt2attr[c], l3protonum);
+			if (mc) {
+				c = mc;
+				goto set_netmask;
+			}
 			break;
 		case '{':
 		case '}':
 		case '[':
 		case ']':
+			l3protonum = parse_addr(optarg, &ad, NULL);
+set_netmask:
 			options |= opt2type[c];
-			l3protonum = parse_addr(optarg, &ad);
 			if (l3protonum == AF_UNSPEC) {
 				exit_error(PARAMETER_PROBLEM,
 					   "Invalid IP address `%s'", optarg);
-- 
2.1.4

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

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 3/3] fix unused value warning
  2015-01-13 11:55 conntrack: netmask filtering support Asbjørn Sloth Tønnesen
  2015-01-13 11:55 ` [PATCH 1/3] conntrack: add support for netmask filtering Asbjørn Sloth Tønnesen
  2015-01-13 11:55 ` [PATCH 2/3] conntrack: add support for CIDR notation Asbjørn Sloth Tønnesen
@ 2015-01-13 11:55 ` Asbjørn Sloth Tønnesen
  2 siblings, 0 replies; 5+ messages in thread
From: Asbjørn Sloth Tønnesen @ 2015-01-13 11:55 UTC (permalink / raw)
  To: Pablo Neira Ayuso; +Cc: netfilter-devel

This patch silences this warning:
warning: right-hand operand of comma expression has no effect[-Wunused-value]

The prefetch macro doesn't seam to be doing anything, but I will
leave it to Pablo to decide if it should be removed entirely.

Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
---
 include/linux_list.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/include/linux_list.h b/include/linux_list.h
index de182a4..91d9c6a 100644
--- a/include/linux_list.h
+++ b/include/linux_list.h
@@ -340,8 +340,8 @@ static inline void list_splice_init(struct list_head *list,
  * @head:	the head for your list.
  */
 #define list_for_each(pos, head) \
-	for (pos = (head)->next, prefetch(pos->next); pos != (head); \
-        	pos = pos->next, prefetch(pos->next))
+	for (pos = (head)->next, (void) prefetch(pos->next); pos != (head); \
+		pos = pos->next, (void) prefetch(pos->next))
 
 /**
  * __list_for_each	-	iterate over a list
@@ -383,10 +383,10 @@ static inline void list_splice_init(struct list_head *list,
  */
 #define list_for_each_entry(pos, head, member)				\
 	for (pos = list_entry((head)->next, typeof(*pos), member),	\
-		     prefetch(pos->member.next);			\
+		     (void) prefetch(pos->member.next);			\
 	     &pos->member != (head); 					\
 	     pos = list_entry(pos->member.next, typeof(*pos), member),	\
-		     prefetch(pos->member.next))
+		     (void) prefetch(pos->member.next))
 
 /**
  * list_for_each_entry_reverse - iterate backwards over list of given type.
-- 
2.1.4

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

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/3] conntrack: add support for netmask filtering
  2015-01-13 11:55 ` [PATCH 1/3] conntrack: add support for netmask filtering Asbjørn Sloth Tønnesen
@ 2015-01-15 13:13   ` Pablo Neira Ayuso
  0 siblings, 0 replies; 5+ messages in thread
From: Pablo Neira Ayuso @ 2015-01-15 13:13 UTC (permalink / raw)
  To: Asbjørn Sloth Tønnesen; +Cc: netfilter-devel, fw

On Tue, Jan 13, 2015 at 11:55:10AM +0000, Asbjørn Sloth Tønnesen wrote:
> This patch extends --mask-src and --mask-dst to also work
> with the conntrack table, with commands -L, -D and -E.

This is useful to everyone, thanks a lot.

Several comments:

* Could you add tests to tests/conntrack/testsuite/ ? There is a very
  simple tool that you can compile and run the script.

* I guess the answer is no, but does this break backward? The former
  syntax needs to work still to avoid breaking existing scripts.

* Could you help consolidate the filtering code?

static int ct_filter(struct nf_conntrack *obj, struct nf_conntrack *ct)
{
        if (filter_nat(obj, ct) ||
            filter_mark(ct) ||
            filter_label(ct) ||
            filter_address(obj, ct))
                return 1;

        return 0;
}

From event and dump this should be the same.

For deletion, I can see no connlabel support. @Florian: Any reason to
skip deletion per connlabel filtering?

Update is a bit more problematic since --mark is interpreted to be the
new mark, but we have no way to filter by mark and set new one (that
kind of sucks since there is not easy way to support this unless we
add some --old-mark option).

more nitpick comments below.

> Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
> ---
>  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;

Any chance you can pass global_family as parameter?

> +	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) {

Can you use a switch (family) instead?

> +		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])

You can probably wrap this code in a function so we can later on reuse
it if needed. ct_ip6_cmp() ?

> +				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");

Ignore the return value. It shouldn't happen that we unset and already
unset attribute. No need for this error message.

> +}
> +
> +static void
> +network_prepare(void)

Rename this to ct_filter_init() so someone else later can reuse it to
add more filtering capabilities.
--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2015-01-15 13:10 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-01-13 11:55 conntrack: netmask filtering support Asbjørn Sloth Tønnesen
2015-01-13 11:55 ` [PATCH 1/3] conntrack: add support for netmask filtering Asbjørn Sloth Tønnesen
2015-01-15 13:13   ` Pablo Neira Ayuso
2015-01-13 11:55 ` [PATCH 2/3] conntrack: add support for CIDR notation Asbjørn Sloth Tønnesen
2015-01-13 11:55 ` [PATCH 3/3] fix unused value warning Asbjørn Sloth Tønnesen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).