diff options
author | Jarno Rajahalme <jrajahalme@nicira.com> | 2015-02-02 12:35:12 -0800 |
---|---|---|
committer | Florian Westphal <fw@strlen.de> | 2015-02-13 15:11:00 +0100 |
commit | a3cd4dfb85b3ee9194ea82eb5185f9df2cb4ecf8 (patch) | |
tree | 3ec95e459b8b961e920099be94c739d3072cf4ed /src/conntrack.c | |
parent | 1c68250df4ca260392f532bf968fa28c40a7f974 (diff) | |
download | conntrack-tools-a3cd4dfb85b3ee9194ea82eb5185f9df2cb4ecf8.tar.gz conntrack-tools-a3cd4dfb85b3ee9194ea82eb5185f9df2cb4ecf8.zip |
conntrack: fix setting labels in updates
When updating labels we always have to send the same sized bitmask as
we received, as the bits we do omit will otherwise cleared as "padding".
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 either.
Finally, kernel only retains old bit values that we send as zeroes in
BOTH the label and the mask, due to XOR used in bit manipulation.
This patch fixes all these issues and allows updates to set new labels
without accidentally clearing old ones.
Signed-off-by: Jarno Rajahalme <jrajahalme@nicira.com>
Signed-off-by: Florian Westphal <fw@strlen.de>
Diffstat (limited to 'src/conntrack.c')
-rw-r--r-- | src/conntrack.c | 24 |
1 files changed, 19 insertions, 5 deletions
diff --git a/src/conntrack.c b/src/conntrack.c index 1e45ca8..f6d7d9a 100644 --- a/src/conntrack.c +++ b/src/conntrack.c @@ -1422,17 +1422,31 @@ static void copy_label(struct nf_conntrack *tmp, const struct nf_conntrack *ct) if (options & CT_OPT_ADD_LABEL) { if (ctb == NULL) { - newmask = xnfct_bitmask_clone(tmpl.label_modify); - nfct_set_attr(tmp, ATTR_CONNLABELS, newmask); + 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)) + 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); + } } - - newmask = xnfct_bitmask_clone(tmpl.label_modify); nfct_set_attr(tmp, ATTR_CONNLABELS_MASK, newmask); } else if (ctb != NULL) { /* CT_OPT_DEL_LABEL */ |