+static int
+get_rule_id(const void *base, unsigned int start, unsigned int end)
+{
+ uint32_t id;
+ unsigned int i;
+ const struct xt_entry_match *em;
+
+ for (i = start; i < end; i += em->u.match_size)
+ {
+ em = base + i;
+
+ if (strcmp(em->u.user.name, "id"))
+ continue;
+
+ memcpy(&id, em->data, sizeof(id));
+
+ if ((id & FW3_ID_MASK) != FW3_ID_MAGIC)
+ continue;
+
+ return (id & ~FW3_ID_MASK);
+ }
+
+ return -1;
+}
+
+void
+fw3_ipt_delete_id_rules(struct fw3_ipt_handle *h, const char *chain)
+{
+ unsigned int num;
+ const struct ipt_entry *e;
+ bool found;
+ int id;
+
+#ifndef DISABLE_IPV6
+ if (h->family == FW3_FAMILY_V6)
+ {
+ if (!ip6tc_is_chain(chain, h->handle))
+ return;
+
+ do {
+ found = false;
+
+ const struct ip6t_entry *e6;
+ for (num = 0, e6 = ip6tc_first_rule(chain, h->handle);
+ e6 != NULL;
+ num++, e6 = ip6tc_next_rule(e6, h->handle))
+ {
+ id = get_rule_id(e6, sizeof(*e6), e6->target_offset);
+
+ if (id >= 0)
+ {
+ if (fw3_pr_debug)
+ debug(h, "-D %s %u\n", chain, num + 1);
+
+ ip6tc_delete_num_entry(chain, num, h->handle);
+ found = true;
+ break;
+ }
+ }
+ } while (found);
+ }
+ else
+#endif
+ {
+ if (!iptc_is_chain(chain, h->handle))
+ return;
+
+ do {
+ found = false;
+
+ for (num = 0, e = iptc_first_rule(chain, h->handle);
+ e != NULL;
+ num++, e = iptc_next_rule(e, h->handle))
+ {
+ id = get_rule_id(e, sizeof(*e), e->target_offset);
+
+ if (id >= 0)
+ {
+ if (fw3_pr_debug)
+ debug(h, "-D %s %u\n", chain, num + 1);
+
+ iptc_delete_num_entry(chain, num, h->handle);
+ found = true;
+ break;
+ }
+ }
+ } while (found);
+ }
+}
+