summaryrefslogtreecommitdiffstats
path: root/src/conntrack.c
diff options
context:
space:
mode:
authorJarno Rajahalme <jrajahalme@nicira.com>2015-02-02 12:35:12 -0800
committerFlorian Westphal <fw@strlen.de>2015-02-13 15:11:00 +0100
commita3cd4dfb85b3ee9194ea82eb5185f9df2cb4ecf8 (patch)
tree3ec95e459b8b961e920099be94c739d3072cf4ed /src/conntrack.c
parent1c68250df4ca260392f532bf968fa28c40a7f974 (diff)
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.c24
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 */