diff mbox

[conntrack,4/5,v2] conntrack: add support for netmask filtering

Message ID 1453720548-14413-4-git-send-email-ast@fiberby.dk
State Accepted
Delegated to: Pablo Neira
Headers show

Commit Message

Asbjørn Sloth Tønnesen Jan. 25, 2016, 11:15 a.m. UTC
This patch extends --mask-src and --mask-dst to also work
with the conntrack table, with commands -L, -D, -E and -U.

Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
---

Notes:
    This is almost completely backward compatible,
    since the --mask-* arguments previously gave
    an error is used with these commands and the
    conntrack table.
    
    I have changed the global_family to filter_family,
    and it is only used to pass the family to the callback,
    the alternative would be to change the data argument of
    the callbacks to a struct.

 conntrack.8     |   7 ++-
 src/conntrack.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 150 insertions(+), 15 deletions(-)

Comments

Pablo Neira Ayuso Feb. 1, 2016, 11:04 a.m. UTC | #1
On Mon, Jan 25, 2016 at 11:15:47AM +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, -E and -U.
> 
> Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
> ---
> 
> Notes:
>     This is almost completely backward compatible,
>     since the --mask-* arguments previously gave
>     an error is used with these commands and the
>     conntrack table.
>     
>     I have changed the global_family to filter_family,
>     and it is only used to pass the family to the callback,
>     the alternative would be to change the data argument of
>     the callbacks to a struct.

I see changes with regards to previous patchset, not we don't use
cidr. I think this is better since it allows a more compact way.

I prefer the cidr-based approach, any reason to drop it?
--
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
Asbjørn Sloth Tønnesen Feb. 1, 2016, 12:17 p.m. UTC | #2
Hi Pablo,

On Mon, 1 Feb 2016 12:04:23 +0100, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Mon, Jan 25, 2016 at 11:15:47AM +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, -E and -U.
> > 
> > Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
> > ---
> > 
> > Notes:
> >     This is almost completely backward compatible,
> >     since the --mask-* arguments previously gave
> >     an error is used with these commands and the
> >     conntrack table.
> >     
> >     I have changed the global_family to filter_family,
> >     and it is only used to pass the family to the callback,
> >     the alternative would be to change the data argument of
> >     the callbacks to a struct.
> 
> I see changes with regards to previous patchset, not we don't use
> cidr. I think this is better since it allows a more compact way.
> 
> I prefer the cidr-based approach, any reason to drop it?

I decided to split them up in several patchsets, each having its
own merits. The netmask and CIDR patches are related, but one is about
filtering, and the other about adding some sugar to the option parsing.

BTW: I mistakenly also marked the test patch v2, but this only is the only one
in this patchset from the old one.
Pablo Neira Ayuso Feb. 1, 2016, 5:56 p.m. UTC | #3
On Mon, Feb 01, 2016 at 12:17:02PM +0000, Asbjørn Sloth Tønnesen wrote:
> Hi Pablo,
> 
> On Mon, 1 Feb 2016 12:04:23 +0100, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > On Mon, Jan 25, 2016 at 11:15:47AM +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, -E and -U.
> > > 
> > > Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
> > > ---
> > > 
> > > Notes:
> > >     This is almost completely backward compatible,
> > >     since the --mask-* arguments previously gave
> > >     an error is used with these commands and the
> > >     conntrack table.
> > >     
> > >     I have changed the global_family to filter_family,
> > >     and it is only used to pass the family to the callback,
> > >     the alternative would be to change the data argument of
> > >     the callbacks to a struct.
> > 
> > I see changes with regards to previous patchset, not we don't use
> > cidr. I think this is better since it allows a more compact way.
> > 
> > I prefer the cidr-based approach, any reason to drop it?
> 
> I decided to split them up in several patchsets, each having its
> own merits. The netmask and CIDR patches are related, but one is about
> filtering, and the other about adding some sugar to the option parsing.

But we don't get anything with this extra option since it's basically
equivalent to the cidr based filtering, right?

> BTW: I mistakenly also marked the test patch v2, but this only is
> the only one in this patchset from the old one.

No problem.
--
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
Asbjørn Sloth Tønnesen Feb. 2, 2016, 3:55 p.m. UTC | #4
Hi Pablo,

On Mon, 1 Feb 2016 18:56:25 +0100, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> On Mon, Feb 01, 2016 at 12:17:02PM +0000, Asbjørn Sloth Tønnesen wrote:
> > On Mon, 1 Feb 2016 12:04:23 +0100, Pablo Neira Ayuso <pablo@netfilter.org> wrote:
> > > On Mon, Jan 25, 2016 at 11:15:47AM +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, -E and -U.
> > > > 
> > > > Signed-off-by: Asbjørn Sloth Tønnesen <ast@fiberby.dk>
> > > > ---
> > > > 
> > > > Notes:
> > > >     This is almost completely backward compatible,
> > > >     since the --mask-* arguments previously gave
> > > >     an error is used with these commands and the
> > > >     conntrack table.
> > > >     
> > > >     I have changed the global_family to filter_family,
> > > >     and it is only used to pass the family to the callback,
> > > >     the alternative would be to change the data argument of
> > > >     the callbacks to a struct.
> > > 
> > > I see changes with regards to previous patchset, not we don't use
> > > cidr. I think this is better since it allows a more compact way.
> > > 
> > > I prefer the cidr-based approach, any reason to drop it?
> > 
> > I decided to split them up in several patchsets, each having its
> > own merits. The netmask and CIDR patches are related, but one is about
> > filtering, and the other about adding some sugar to the option parsing.
> 
> But we don't get anything with this extra option since it's basically
> equivalent to the cidr based filtering, right?

Except backwards compatability for the expectation table, on the other hand
--mask-* has been broken since August, but thats only v1.4.3 so properly not
long enough to just drop it.

Since the filtering internally uses a bitmask in ct.mask, then keeping the --mask-*
option for all cases is simpler, since it uses the same option flags.

Keeping them also makes it possible to inject funky bitmasks.
Pablo Neira Ayuso Feb. 2, 2016, 4:34 p.m. UTC | #5
On Tue, Feb 02, 2016 at 03:55:53PM +0000, Asbjørn Sloth Tønnesen wrote:
> Keeping them also makes it possible to inject funky bitmasks.

Good point, will get another look into these remaining patchset asap.
Busy with netdev 1.1 organization stuff.

Thanks.
--
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
Pablo Neira Ayuso Feb. 16, 2016, 6:18 p.m. UTC | #6
On Mon, Jan 25, 2016 at 11:15:47AM +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, -E and -U.

Applied, thanks for your patience.
--
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
diff mbox

Patch

diff --git a/conntrack.8 b/conntrack.8
index 970c2d7..5bba1b1 100644
--- a/conntrack.8
+++ b/conntrack.8
@@ -191,10 +191,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", "\-U \-\-update" 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 3fc9c24..34785f3 100644
--- a/src/conntrack.c
+++ b/src/conntrack.c
@@ -377,13 +377,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,2,2},
+/*CT_LIST*/   {2,2,2,2,2,0,2,2,0,0,0,2,2,0,2,0,2,2,2,2,2,0,2,2,2,0,0,2,2},
 /*CT_CREATE*/ {3,3,3,3,1,1,2,0,0,0,0,0,0,2,2,0,0,2,2,0,0,0,0,2,0,2,0,2,2},
-/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0},
-/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,0,0,0,2,2,2,2,2,2,0,0,0,2,2,0,0,2,2},
+/*CT_UPDATE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,0,2,2,2,0,0},
+/*CT_DELETE*/ {2,2,2,2,2,2,2,0,0,0,0,2,2,0,2,2,2,2,2,2,0,0,0,2,2,0,0,2,2},
 /*CT_GET*/    {3,3,3,3,1,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,0,0,0,0,2,0,0,0,0},
 /*CT_FLUSH*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,2,2},
+/*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,2,2},
 /*VERSION*/   {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
 /*HELP*/      {0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
 /*EXP_LIST*/  {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0},
@@ -465,6 +465,26 @@  static const int opt2attr[] = {
 	[')']	= ATTR_REPL_ZONE,
 };
 
+enum ct_direction {
+	DIR_SRC = 0,
+	DIR_DST = 1,
+};
+
+union ct_address {
+	uint32_t v4;
+	uint32_t v6[4];
+};
+
+static struct ct_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",
@@ -507,8 +527,7 @@  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";
+	;
 
 static const char usage_update_parameters[] =
 	"Updating parameters and options:\n"
@@ -529,6 +548,8 @@  static const char usage_parameters[] =
 	"  --orig-zone value\t\tSet zone for original direction\n"
 	"  --reply-zone value\t\tSet zone for reply direction\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
@@ -547,6 +568,7 @@  static LIST_HEAD(proto_list);
 
 static unsigned int options;
 static struct nfct_labelmap *labelmap;
+static int filter_family;
 
 void register_proto(struct ctproto_handler *h)
 {
@@ -1006,11 +1028,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)
 {
@@ -1215,11 +1232,68 @@  filter_nat(const struct nf_conntrack *obj, const struct nf_conntrack *ct)
 }
 
 static int
+nfct_ip6_net_cmp(const union ct_address *addr, const struct ct_network *net)
+{
+	int i;
+	for (i=0;i<4;i++)
+		if ((addr->v6[i] & net->netmask.v6[i]) != net->network.v6[i])
+			return 1;
+	return 0;
+}
+
+static int
+nfct_ip_net_cmp(int family, const union ct_address *addr,
+                const struct ct_network *net)
+{
+	switch(family) {
+	case AF_INET:
+		return (addr->v4 & net->netmask.v4) != net->network.v4;
+	case AF_INET6:
+		return nfct_ip6_net_cmp(addr, net);
+	default:
+		return 0;
+	}
+}
+
+static int
+nfct_filter_network_direction(const struct nf_conntrack *ct, enum ct_direction dir)
+{
+	const int family = filter_family;
+	const union ct_address *address;
+	enum nf_conntrack_attr attr;
+	struct ct_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);
+
+	return nfct_ip_net_cmp(family, address, net);
+}
+
+static int
+filter_network(const struct nf_conntrack *ct)
+{
+	if (options & CT_OPT_MASK_SRC) {
+		if (nfct_filter_network_direction(ct, DIR_SRC))
+			return 1;
+	}
+
+	if (options & CT_OPT_MASK_DST) {
+		if (nfct_filter_network_direction(ct, DIR_DST))
+			return 1;
+	}
+	return 0;
+}
+
+static int
 nfct_filter(struct nf_conntrack *obj, struct nf_conntrack *ct)
 {
 	if (filter_nat(obj, ct) ||
 	    filter_mark(ct) ||
-	    filter_label(ct))
+	    filter_label(ct) ||
+	    filter_network(ct))
 		return 1;
 
 	if (options & CT_COMPARISON &&
@@ -1490,7 +1564,8 @@  static int update_cb(enum nf_conntrack_msg_type type,
 	struct nf_conntrack *obj = data, *tmp;
 
 	if (filter_nat(obj, ct) ||
-	    filter_label(ct))
+	    filter_label(ct) ||
+	    filter_network(ct))
 		return NFCT_CB_CONTINUE;
 
 	if (nfct_attr_is_set(obj, ATTR_ID) && nfct_attr_is_set(ct, ATTR_ID) &&
@@ -1934,6 +2009,54 @@  static void labelmap_init(void)
 		perror("nfct_labelmap_new");
 }
 
+static void
+nfct_network_attr_prepare(const int family, enum ct_direction dir)
+{
+	const union ct_address *address, *netmask;
+	enum nf_conntrack_attr attr;
+	int i;
+	struct ct_network *net = &dir2network[dir];
+
+	attr = famdir2attr[family == AF_INET6][dir];
+
+	address = nfct_get_attr(tmpl.ct, attr);
+	netmask = nfct_get_attr(tmpl.mask, attr);
+
+	switch(family) {
+	case AF_INET:
+		net->network.v4 = address->v4 & netmask->v4;
+		break;
+	case AF_INET6:
+		for (i=0;i<4;i++)
+			net->network.v6[i] = address->v6[i] & netmask->v6[i];
+		break;
+	}
+
+	memcpy(&net->netmask, netmask, sizeof(union ct_address));
+
+	/* avoid exact source matching */
+	nfct_attr_unset(tmpl.ct, attr);
+}
+
+static void
+nfct_filter_init(const int family)
+{
+	filter_family = family;
+	if (options & CT_OPT_MASK_SRC) {
+		if (!(options & CT_OPT_ORIG_SRC))
+			exit_error(PARAMETER_PROBLEM,
+			           "Can't use --mask-src without --src");
+		nfct_network_attr_prepare(family, 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");
+		nfct_network_attr_prepare(family, DIR_DST);
+	}
+}
+
 static void merge_bitmasks(struct nfct_bitmask **current,
 			  struct nfct_bitmask *src)
 {
@@ -2289,6 +2412,8 @@  int main(int argc, char *argv[])
 			exit_error(PARAMETER_PROBLEM, "Can't use -z with "
 						      "filtering parameters");
 
+		nfct_filter_init(family);
+
 		nfct_callback_register(cth, NFCT_T_ALL, dump_cb, tmpl.ct);
 
 		filter_dump = nfct_filter_dump_create();
@@ -2375,6 +2500,8 @@  int main(int argc, char *argv[])
 		if (!cth || !ith)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 
+		nfct_filter_init(family);
+
 		nfct_callback_register(cth, NFCT_T_ALL, update_cb, tmpl.ct);
 
 		res = nfct_query(cth, NFCT_Q_DUMP, &family);
@@ -2388,6 +2515,8 @@  int main(int argc, char *argv[])
 		if (!cth || !ith)
 			exit_error(OTHER_PROBLEM, "Can't open handler");
 
+		nfct_filter_init(family);
+
 		nfct_callback_register(cth, NFCT_T_ALL, delete_cb, tmpl.ct);
 
 		filter_dump = nfct_filter_dump_create();
@@ -2489,6 +2618,9 @@  int main(int argc, char *argv[])
 			fprintf(stderr, "NOTICE: Netlink socket buffer size "
 					"has been set to %zu bytes.\n", ret);
 		}
+
+		nfct_filter_init(family);
+
 		signal(SIGINT, event_sighandler);
 		signal(SIGTERM, event_sighandler);
 		nfct_callback_register(cth, NFCT_T_ALL, event_cb, tmpl.ct);