From: Pablo Neira Ayuso <pablo@netfilter.org>
To: "Asbjørn Sloth Tønnesen" <ast@fiberby.dk>
Cc: netfilter-devel@vger.kernel.org, fw@strlen.de
Subject: Re: [PATCH 1/3] conntrack: add support for netmask filtering
Date: Thu, 15 Jan 2015 14:13:40 +0100 [thread overview]
Message-ID: <20150115131340.GA8929@salvia> (raw)
In-Reply-To: <1421150112-3836-2-git-send-email-ast@fiberby.dk>
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
next prev parent reply other threads:[~2015-01-15 13:10 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
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 [this message]
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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150115131340.GA8929@salvia \
--to=pablo@netfilter.org \
--cc=ast@fiberby.dk \
--cc=fw@strlen.de \
--cc=netfilter-devel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).