+ unsigned char *p, *mask = NULL;
+ struct xtables_rule_match *m;
+
+#define SZ(x) XT_ALIGN(sizeof(struct x))
+
+#ifndef DISABLE_IPV6
+ if (r->h->family == FW3_FAMILY_V6)
+ {
+ s = SZ(ip6t_entry);
+
+ for (m = r->matches; m; m = m->next)
+ s += SZ(ip6t_entry_match) + m->match->size;
+
+ s += SZ(ip6t_entry_target) + r->target->size;
+
+ mask = fw3_alloc(s);
+ memset(mask, 0xFF, SZ(ip6t_entry));
+ p = mask + SZ(ip6t_entry);
+
+ for (m = r->matches; m; m = m->next)
+ {
+ memset(p, 0xFF, SZ(ip6t_entry_match) + m->match->userspacesize);
+ p += SZ(ip6t_entry_match) + m->match->size;
+ }
+
+ memset(p, 0xFF, SZ(ip6t_entry_target) + r->target->userspacesize);
+ }
+ else
+#endif
+ {
+ s = SZ(ipt_entry);
+
+ for (m = r->matches; m; m = m->next)
+ s += SZ(ipt_entry_match) + m->match->size;
+
+ s += SZ(ipt_entry_target) + r->target->size;
+
+ mask = fw3_alloc(s);
+ memset(mask, 0xFF, SZ(ipt_entry));
+ p = mask + SZ(ipt_entry);
+
+ for (m = r->matches; m; m = m->next)
+ {
+ memset(p, 0xFF, SZ(ipt_entry_match) + m->match->userspacesize);
+ p += SZ(ipt_entry_match) + m->match->size;
+ }
+
+ memset(p, 0xFF, SZ(ipt_entry_target) + r->target->userspacesize);
+ }
+
+ return mask;
+}
+
+static void *
+rule_build(struct fw3_ipt_rule *r)
+{
+ size_t s;
+ struct xtables_rule_match *m;
+
+#ifndef DISABLE_IPV6
+ if (r->h->family == FW3_FAMILY_V6)
+ {
+ struct ip6t_entry *e6;
+
+ s = XT_ALIGN(sizeof(struct ip6t_entry));
+
+ for (m = r->matches; m; m = m->next)
+ s += m->match->m->u.match_size;
+
+ e6 = fw3_alloc(s + r->target->t->u.target_size);
+
+ memcpy(e6, &r->e6, sizeof(struct ip6t_entry));
+
+ e6->target_offset = s;
+ e6->next_offset = s + r->target->t->u.target_size;
+
+ s = 0;
+
+ for (m = r->matches; m; m = m->next)
+ {
+ memcpy(e6->elems + s, m->match->m, m->match->m->u.match_size);
+ s += m->match->m->u.match_size;
+ }
+
+ memcpy(e6->elems + s, r->target->t, r->target->t->u.target_size);
+
+ return e6;
+ }
+ else
+#endif
+ {
+ struct ipt_entry *e;
+
+ s = XT_ALIGN(sizeof(struct ipt_entry));
+
+ for (m = r->matches; m; m = m->next)
+ s += m->match->m->u.match_size;
+
+ e = fw3_alloc(s + r->target->t->u.target_size);
+
+ memcpy(e, &r->e, sizeof(struct ipt_entry));
+
+ e->target_offset = s;
+ e->next_offset = s + r->target->t->u.target_size;
+
+ s = 0;
+
+ for (m = r->matches; m; m = m->next)
+ {
+ memcpy(e->elems + s, m->match->m, m->match->m->u.match_size);
+ s += m->match->m->u.match_size;
+ }
+
+ memcpy(e->elems + s, r->target->t, r->target->t->u.target_size);
+
+ return e;
+ }
+}
+
+void
+__fw3_ipt_rule_append(struct fw3_ipt_rule *r, bool repl, const char *fmt, ...)
+{
+ void *rule;
+ unsigned char *mask;
+