From beb810dbccee098add0347d551eb5362e404fbdc Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Mon, 27 May 2019 21:01:25 +0200 Subject: iprule: fix missing ip rules after a reload (FS#2296) Since commit 5cf79759a24e9bb2a6a3aef7c83d73efb9bf2df3 (iprule: rework interface based rules to handle dynamic interfaces) the rule comparison is broken and doesn't correctly recognize matching rules. This in turn break the reloading as adding the "new" rule fails because it already exists and it then delete the "old" rule. The comparison is broken because it now include fields that are not defining the rule itself, as well as some pointer to malloced strings. To fix this we move back the offending fields in the iprule struct before the 'flags' field and match the malloced strings separately. Signed-off-by: Alban Bedel Signed-off-by: Hans Dedecker --- iprule.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) (limited to 'iprule.c') diff --git a/iprule.c b/iprule.c index 3e57888..c3a629f 100644 --- a/iprule.c +++ b/iprule.c @@ -290,7 +290,7 @@ iprule_add(struct blob_attr *attr, bool v6) rule->flags |= IPRULE_GOTO; } - vlist_add(&iprules, &rule->node, &rule->flags); + vlist_add(&iprules, &rule->node, rule); return; error: @@ -320,7 +320,32 @@ iprule_update_complete(void) static int rule_cmp(const void *k1, const void *k2, void *ptr) { - return memcmp(k1, k2, sizeof(struct iprule)-offsetof(struct iprule, flags)); + const struct iprule *r1 = k1, *r2 = k2; + int ret; + + /* First compare the interface names */ + if (r1->flags & IPRULE_IN || r2->flags & IPRULE_IN) { + char *str1 = r1->flags & IPRULE_IN ? r1->in_iface : ""; + char *str2 = r2->flags & IPRULE_IN ? r2->in_iface : ""; + + ret = strcmp(str1, str2); + if (ret) + return ret; + } + + if (r1->flags & IPRULE_OUT || r2->flags & IPRULE_OUT) { + char *str1 = r1->flags & IPRULE_OUT ? r1->out_iface : ""; + char *str2 = r2->flags & IPRULE_OUT ? r2->out_iface : ""; + + ret = strcmp(str1, str2); + if (ret) + return ret; + } + + /* Next compare everything after the flags field */ + return memcmp(k1 + offsetof(struct iprule, flags), + k2 + offsetof(struct iprule, flags), + sizeof(struct iprule) - offsetof(struct iprule, flags)); } static void deregister_interfaces(struct iprule *rule) -- cgit v1.2.3