summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomasz Bursztyka <tomasz.bursztyka@linux.intel.com>2013-01-13 16:42:11 +0100
committerPablo Neira Ayuso <pablo@netfilter.org>2013-12-30 23:50:22 +0100
commit0391677c1a0b28c14d01febd9628a543e8e5fd62 (patch)
treeb9b7715693c1284f1839abab621266ab02994747
parent5a1b519d1e26767fa1f0de15b0f7e125531a1719 (diff)
xtables: add IPv6 support
Summary of changes to add IPv6 support to the xtables utility: * modify all commands (add, delete, replace, check and listing) to support IPv6 addresses. And for the internal nft library: * add family to struct nft_handle and modify all caller to use this family instead of the hardcoded AF_INET. * move code that we can re-use for IPv4 and IPv6 into helper functions. * add IPv6 rule printing support. * add support to parse IPv6 address. Pablo added several improvements to this patch: * added basic xtables-save and xtables-restore support (so it defaults to IPv4) * fixed a couple of bugs found while testing * added reference when -f is used to point to -m frag (until we can make this consistent with IPv4). Note that we use one single xtables binary utility for IPv4 and IPv6. Signed-off-by: Tomasz Bursztyka <tomasz.bursztyka@linux.intel.com> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
-rw-r--r--iptables/nft.c655
-rw-r--r--iptables/nft.h1
-rw-r--r--iptables/xtables-restore.c4
-rw-r--r--iptables/xtables-save.c4
-rw-r--r--iptables/xtables.c400
5 files changed, 772 insertions, 292 deletions
diff --git a/iptables/nft.c b/iptables/nft.c
index 46c8c948..43b13deb 100644
--- a/iptables/nft.c
+++ b/iptables/nft.c
@@ -34,7 +34,9 @@
#include <string.h>
#include <linux/netfilter/x_tables.h>
-#include <linux/netfilter_ipv4/ip_tables.h> /* FIXME: only IPV4 by now */
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <netinet/ip6.h>
#include <linux/netlink.h>
#include <linux/netfilter/nfnetlink.h>
@@ -248,7 +250,7 @@ nft_table_builtin_add(struct nft_handle *h, struct builtin_table *_t,
NFT_TABLE_F_DORMANT);
}
- nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, AF_INET,
+ nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, h->family,
NLM_F_ACK|NLM_F_EXCL, h->seq);
nft_table_nlmsg_build_payload(nlh, t);
nft_table_free(t);
@@ -294,7 +296,7 @@ nft_chain_builtin_add(struct nft_handle *h, struct builtin_table *table,
return;
/* NLM_F_CREATE requests module autoloading */
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
NLM_F_ACK|NLM_F_EXCL|NLM_F_CREATE,
h->seq);
nft_chain_nlmsg_build_payload(nlh, c);
@@ -410,7 +412,7 @@ int nft_table_add(struct nft_handle *h, const struct nft_table *t)
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
- nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, AF_INET,
+ nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, h->family,
NLM_F_ACK|NLM_F_EXCL, h->seq);
nft_table_nlmsg_build_payload(nlh, t);
@@ -422,7 +424,7 @@ int nft_chain_add(struct nft_handle *h, const struct nft_chain *c)
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
NLM_F_ACK|NLM_F_EXCL, h->seq);
nft_chain_nlmsg_build_payload(nlh, c);
@@ -464,7 +466,7 @@ int nft_table_wake_dormant(struct nft_handle *h, const char *table)
nft_table_attr_set(t, NFT_TABLE_ATTR_NAME, (char *)table);
nft_table_attr_set_u32(t, NFT_TABLE_ATTR_FLAGS, 0);
- nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, AF_INET,
+ nlh = nft_table_nlmsg_build_hdr(buf, NFT_MSG_NEWTABLE, h->family,
NLM_F_ACK, h->seq);
nft_table_nlmsg_build_payload(nlh, t);
nft_table_free(t);
@@ -525,7 +527,7 @@ __nft_chain_set(struct nft_handle *h, const char *table,
counters->pcnt);
}
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
NLM_F_ACK, h->seq);
nft_chain_nlmsg_build_payload(nlh, c);
@@ -741,6 +743,78 @@ static void add_counters(struct nft_rule *r, uint64_t packets, uint64_t bytes)
nft_rule_add_expr(r, expr);
}
+static void add_iniface(struct nft_rule *r, char *iface, int invflags)
+{
+ int iface_len;
+ uint32_t op;
+
+ iface_len = strlen(iface);
+
+ if (invflags & IPT_INV_VIA_IN)
+ op = NFT_CMP_NEQ;
+ else
+ op = NFT_CMP_EQ;
+
+ if (iface[iface_len - 1] == '+') {
+ add_meta(r, NFT_META_IIFNAME);
+ add_cmp_ptr(r, op, iface, iface_len - 1);
+ } else {
+ add_meta(r, NFT_META_IIF);
+ add_cmp_u32(r, if_nametoindex(iface), op);
+ }
+}
+
+static void add_outiface(struct nft_rule *r, char *iface, int invflags)
+{
+ int iface_len;
+ uint32_t op;
+
+ iface_len = strlen(iface);
+
+ if (invflags & IPT_INV_VIA_OUT)
+ op = NFT_CMP_NEQ;
+ else
+ op = NFT_CMP_EQ;
+
+ if (iface[iface_len - 1] == '+') {
+ add_meta(r, NFT_META_OIFNAME);
+ add_cmp_ptr(r, op, iface, iface_len - 1);
+ } else {
+ add_meta(r, NFT_META_OIF);
+ add_cmp_u32(r, if_nametoindex(iface), op);
+ }
+}
+
+static void add_addr(struct nft_rule *r, int offset,
+ void *data, size_t len, int invflags)
+{
+ uint32_t op;
+
+ add_payload(r, offset, len);
+
+ if (invflags & IPT_INV_SRCIP || invflags & IPT_INV_DSTIP)
+ op = NFT_CMP_NEQ;
+ else
+ op = NFT_CMP_EQ;
+
+ add_cmp_ptr(r, op, data, len);
+}
+
+static void add_proto(struct nft_rule *r, int offset, size_t len,
+ uint32_t proto, int invflags)
+{
+ uint32_t op;
+
+ add_payload(r, offset, len);
+
+ if (invflags & XT_INV_PROTO)
+ op = NFT_CMP_NEQ;
+ else
+ op = NFT_CMP_EQ;
+
+ add_cmp_u32(r, proto, op);
+}
+
int
nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
struct iptables_command_state *cs,
@@ -753,6 +827,7 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
int ret = 1;
uint32_t op;
int flags = append ? NLM_F_APPEND : 0;
+ int ip_flags = 0;
/* If built-in chains don't exist for this table, create them */
nft_chain_builtin_init(h, table, chain, NF_ACCEPT);
@@ -768,77 +843,72 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
nft_rule_attr_set(r, NFT_RULE_ATTR_TABLE, (char *)table);
nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, (char *)chain);
- if (cs->fw.ip.iniface[0] != '\0') {
- int iface_len = strlen(cs->fw.ip.iniface);
-
- if (cs->fw.ip.invflags & IPT_INV_VIA_IN)
- op = NFT_CMP_NEQ;
- else
- op = NFT_CMP_EQ;
-
- if (cs->fw.ip.iniface[iface_len - 1] == '+') {
- add_meta(r, NFT_META_IIFNAME);
- add_cmp_ptr(r, op, cs->fw.ip.iniface, iface_len - 1);
- } else {
- add_meta(r, NFT_META_IIF);
- add_cmp_u32(r, if_nametoindex(cs->fw.ip.iniface), op);
+ switch (h->family) {
+ case AF_INET:
+ if (cs->fw.ip.iniface[0] != '\0')
+ add_iniface(r, cs->fw.ip.iniface, cs->fw.ip.invflags);
+
+ if (cs->fw.ip.outiface[0] != '\0')
+ add_outiface(r, cs->fw.ip.outiface,
+ cs->fw.ip.invflags);
+
+ if (cs->fw.ip.src.s_addr != 0)
+ add_addr(r, offsetof(struct iphdr, saddr),
+ &cs->fw.ip.src.s_addr, 4,
+ cs->fw.ip.invflags);
+
+ if (cs->fw.ip.dst.s_addr != 0)
+ add_addr(r, offsetof(struct iphdr, daddr),
+ &cs->fw.ip.dst.s_addr, 4,
+ cs->fw.ip.invflags);
+
+ if (cs->fw.ip.proto != 0)
+ add_proto(r, offsetof(struct iphdr, protocol), 1,
+ cs->fw.ip.proto, cs->fw.ip.invflags);
+
+ if (cs->fw.ip.flags & IPT_F_FRAG) {
+ add_payload(r, offsetof(struct iphdr, frag_off), 2);
+ /* get the 13 bits that contain the fragment offset */
+ add_bitwise_u16(r, 0x1fff, !0x1fff);
+
+ /* if offset is non-zero, this is a fragment */
+ if (cs->fw.ip.invflags & IPT_INV_FRAG)
+ op = NFT_CMP_EQ;
+ else
+ op = NFT_CMP_NEQ;
+
+ add_cmp_u16(r, 0, op);
}
- }
- if (cs->fw.ip.outiface[0] != '\0') {
- int iface_len = strlen(cs->fw.ip.outiface);
- if (cs->fw.ip.invflags & IPT_INV_VIA_OUT)
- op = NFT_CMP_NEQ;
- else
- op = NFT_CMP_EQ;
+ ip_flags = cs->fw.ip.flags;
- if (cs->fw.ip.outiface[iface_len - 1] == '+') {
- add_meta(r, NFT_META_OIFNAME);
- add_cmp_ptr(r, op, cs->fw.ip.outiface, iface_len - 1);
- } else {
- add_meta(r, NFT_META_OIF);
- add_cmp_u32(r, if_nametoindex(cs->fw.ip.outiface), op);
- }
- }
- if (cs->fw.ip.src.s_addr != 0) {
- add_payload(r, offsetof(struct iphdr, saddr), 4);
- if (cs->fw.ip.invflags & IPT_INV_SRCIP)
- op = NFT_CMP_NEQ;
- else
- op = NFT_CMP_EQ;
+ break;
+ case AF_INET6:
+ if (cs->fw6.ipv6.iniface[0] != '\0')
+ add_iniface(r, cs->fw6.ipv6.iniface,
+ cs->fw6.ipv6.invflags);
- add_cmp_u32(r, cs->fw.ip.src.s_addr, op);
- }
- if (cs->fw.ip.dst.s_addr != 0) {
- add_payload(r, offsetof(struct iphdr, daddr), 4);
- if (cs->fw.ip.invflags & IPT_INV_DSTIP)
- op = NFT_CMP_NEQ;
- else
- op = NFT_CMP_EQ;
+ if (cs->fw6.ipv6.outiface[0] != '\0')
+ add_outiface(r, cs->fw6.ipv6.outiface,
+ cs->fw6.ipv6.invflags);
- add_cmp_u32(r, cs->fw.ip.dst.s_addr, op);
- }
- if (cs->fw.ip.proto != 0) {
- add_payload(r, offsetof(struct iphdr, protocol), 1);
- if (cs->fw.ip.invflags & XT_INV_PROTO)
- op = NFT_CMP_NEQ;
- else
- op = NFT_CMP_EQ;
+ if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src))
+ add_addr(r, offsetof(struct ip6_hdr, ip6_src),
+ &cs->fw6.ipv6.src, 16,
+ cs->fw6.ipv6.invflags);
- add_cmp_u32(r, cs->fw.ip.proto, op);
- }
- if (cs->fw.ip.flags & IPT_F_FRAG) {
- add_payload(r, offsetof(struct iphdr, frag_off), 2);
- /* get the 13 bits that contain the fragment offset */
- add_bitwise_u16(r, 0x1fff, !0x1fff);
+ if (!IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst))
+ add_addr(r, offsetof(struct ip6_hdr, ip6_dst),
+ &cs->fw6.ipv6.dst, 16,
+ cs->fw6.ipv6.invflags);
- /* if offset is non-zero, this is a fragment */
- if (cs->fw.ip.invflags & IPT_INV_FRAG)
- op = NFT_CMP_EQ;
- else
- op = NFT_CMP_NEQ;
+ if (cs->fw6.ipv6.proto != 0)
+ add_proto(r, offsetof(struct ip6_hdr, ip6_nxt), 1,
+ cs->fw6.ipv6.proto, cs->fw6.ipv6.invflags);
+
+ ip_flags = cs->fw6.ipv6.flags;
- add_cmp_u16(r, 0, op);
+ break;
}
for (matchp = cs->matches; matchp; matchp = matchp->next)
@@ -862,7 +932,7 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
add_target(r, cs->target->t);
} else if (strlen(cs->jumpto) > 0) {
/* Not standard, then it's a go / jump to chain */
- if (cs->fw.ip.flags & IPT_F_GOTO)
+ if (ip_flags & IPT_F_GOTO)
add_jumpto(r, cs->jumpto, NFT_GOTO);
else
add_jumpto(r, cs->jumpto, NFT_JUMP);
@@ -877,7 +947,7 @@ nft_rule_add(struct nft_handle *h, const char *chain, const char *table,
}
nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_NEWRULE,
- AF_INET, flags, h->seq);
+ h->family, flags, h->seq);
nft_rule_nlmsg_build_payload(nlh, r);
@@ -1205,7 +1275,7 @@ static const char *mask_to_str(uint32_t mask)
}
static void
-nft_print_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter)
+nft_print_payload_ipv4(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter)
{
uint32_t offset;
bool inv;
@@ -1249,6 +1319,48 @@ nft_print_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter)
}
static void
+nft_print_payload_ipv6(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter)
+{
+ uint32_t offset;
+ bool inv;
+
+ offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET);
+
+ switch (offset) {
+ char addr_str[INET6_ADDRSTRLEN];
+ struct in6_addr addr;
+ uint8_t proto;
+ case offsetof(struct ip6_hdr, ip6_src):
+ get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN);
+
+ if (inv)
+ printf("! -s %s ", addr_str);
+ else
+ printf("-s %s ", addr_str);
+
+ break;
+ case offsetof(struct ip6_hdr, ip6_dst):
+ get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ inet_ntop(AF_INET6, &addr, addr_str, INET6_ADDRSTRLEN);
+
+ if (inv)
+ printf("! -d %s ", addr_str);
+ else
+ printf("-d %s ", addr_str);
+
+ break;
+ case offsetof(struct ip6_hdr, ip6_nxt):
+ get_cmp_data(iter, &proto, sizeof(proto), &inv);
+ print_proto(proto, inv);
+ break;
+ default:
+ DEBUGP("unknown payload offset %d\n", offset);
+ break;
+ }
+}
+
+static void
nft_print_counters(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
bool counters)
{
@@ -1279,7 +1391,10 @@ static void nft_rule_print_save(struct nft_rule *r, bool counters)
if (strcmp(name, "counter") == 0) {
nft_print_counters(expr, iter, counters);
} else if (strcmp(name, "payload") == 0) {
- nft_print_payload(expr, iter);
+ if (nft_rule_attr_get_u8(r, NFT_RULE_ATTR_FAMILY) == AF_INET)
+ nft_print_payload_ipv4(expr, iter);
+ else
+ nft_print_payload_ipv6(expr, iter);
} else if (strcmp(name, "meta") == 0) {
nft_print_meta(expr, iter);
} else if (strcmp(name, "match") == 0) {
@@ -1334,7 +1449,7 @@ static struct nft_chain_list *nft_chain_list_get(struct nft_handle *h)
return 0;
}
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_GETCHAIN, h->family,
NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nft_chain_list_cb, list);
@@ -1446,7 +1561,7 @@ static struct nft_rule_list *nft_rule_list_get(struct nft_handle *h)
return 0;
}
- nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, AF_INET,
+ nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETRULE, h->family,
NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nft_rule_list_cb, list);
@@ -1512,7 +1627,7 @@ __nft_rule_flush(struct nft_handle *h, const char *table, const char *chain)
nft_rule_attr_set(r, NFT_RULE_ATTR_CHAIN, (char *)chain);
/* Delete all rules in this table + chain */
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, h->family,
NLM_F_ACK, h->seq);
nft_rule_nlmsg_build_payload(nlh, r);
nft_rule_free(r);
@@ -1589,7 +1704,7 @@ int nft_chain_user_add(struct nft_handle *h, const char *chain, const char *tabl
nft_chain_attr_set(c, NFT_CHAIN_ATTR_TABLE, (char *)table);
nft_chain_attr_set(c, NFT_CHAIN_ATTR_NAME, (char *)chain);
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
NLM_F_ACK|NLM_F_EXCL, h->seq);
nft_chain_nlmsg_build_payload(nlh, c);
nft_chain_free(c);
@@ -1610,7 +1725,7 @@ static int __nft_chain_del(struct nft_handle *h, struct nft_chain *c)
struct nlmsghdr *nlh;
int ret;
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_DELCHAIN, h->family,
NLM_F_ACK, h->seq);
nft_chain_nlmsg_build_payload(nlh, c);
@@ -1756,7 +1871,7 @@ int nft_chain_user_rename(struct nft_handle *h,const char *chain,
nft_chain_attr_set(c, NFT_CHAIN_ATTR_NAME, (char *)newname);
nft_chain_attr_set_u64(c, NFT_CHAIN_ATTR_HANDLE, handle);
- nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, AF_INET,
+ nlh = nft_chain_nlmsg_build_hdr(buf, NFT_MSG_NEWCHAIN, h->family,
NLM_F_ACK, h->seq);
nft_chain_nlmsg_build_payload(nlh, c);
nft_chain_free(c);
@@ -1809,7 +1924,7 @@ static struct nft_table_list *nft_table_list_get(struct nft_handle *h)
return 0;
}
- nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, AF_INET,
+ nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_GETTABLE, h->family,
NLM_F_DUMP, h->seq);
ret = mnl_talk(h, nlh, nft_table_list_cb, list);
@@ -1919,39 +2034,86 @@ match_different(const struct xt_entry_match *a,
}
static bool
-is_same(const struct iptables_command_state *a, const struct iptables_command_state *b)
+is_same(int family, const struct iptables_command_state *a,
+ const struct iptables_command_state *b)
{
unsigned int i;
+ const char *a_outiface, *a_iniface;
+ unsigned const char *a_iniface_mask, *a_outiface_mask;
+ const char *b_outiface, *b_iniface;
+ unsigned const char *b_iniface_mask, *b_outiface_mask;
/* Always compare head structures: ignore mask here. */
- if (a->fw.ip.src.s_addr != b->fw.ip.src.s_addr
- || a->fw.ip.dst.s_addr != b->fw.ip.dst.s_addr
- || a->fw.ip.smsk.s_addr != b->fw.ip.smsk.s_addr
- || a->fw.ip.dmsk.s_addr != b->fw.ip.dmsk.s_addr
- || a->fw.ip.proto != b->fw.ip.proto
- || a->fw.ip.flags != b->fw.ip.flags
- || a->fw.ip.invflags != b->fw.ip.invflags) {
- DEBUGP("different src/dst/proto/flags/invflags\n");
+ switch (family) {
+ case AF_INET:
+ if (a->fw.ip.src.s_addr != b->fw.ip.src.s_addr
+ || a->fw.ip.dst.s_addr != b->fw.ip.dst.s_addr
+ || a->fw.ip.smsk.s_addr != b->fw.ip.smsk.s_addr
+ || a->fw.ip.dmsk.s_addr != b->fw.ip.dmsk.s_addr
+ || a->fw.ip.proto != b->fw.ip.proto
+ || a->fw.ip.flags != b->fw.ip.flags
+ || a->fw.ip.invflags != b->fw.ip.invflags) {
+ DEBUGP("different src/dst/proto/flags/invflags\n");
+ return false;
+ }
+
+ a_iniface_mask = a->fw.ip.iniface_mask;
+ a_iniface = a->fw.ip.iniface;
+ a_outiface_mask = a->fw.ip.outiface_mask;
+ a_outiface = a->fw.ip.outiface;
+
+ b_iniface_mask = b->fw.ip.iniface_mask;
+ b_iniface = b->fw.ip.iniface;
+ b_outiface_mask = b->fw.ip.outiface_mask;
+ b_outiface = b->fw.ip.outiface;
+
+ break;
+ case AF_INET6:
+ if (memcmp(a->fw6.ipv6.src.s6_addr,
+ b->fw6.ipv6.src.s6_addr,
+ sizeof(struct in6_addr)) != 0 ||
+ memcmp(a->fw6.ipv6.dst.s6_addr,
+ b->fw6.ipv6.dst.s6_addr,
+ sizeof(struct in6_addr)) != 0 ||
+ a->fw6.ipv6.proto != b->fw6.ipv6.proto ||
+ a->fw6.ipv6.flags != b->fw6.ipv6.flags ||
+ a->fw6.ipv6.invflags != b->fw6.ipv6.invflags) {
+ DEBUGP("different src/dst/proto/flags/invflags\n");
+ return false;
+ }
+
+ a_iniface_mask = a->fw6.ipv6.iniface_mask;
+ a_iniface = a->fw6.ipv6.iniface;
+ a_outiface_mask = a->fw6.ipv6.outiface_mask;
+ a_outiface = a->fw6.ipv6.outiface;
+
+ b_iniface_mask = b->fw6.ipv6.iniface_mask;
+ b_iniface = b->fw6.ipv6.iniface;
+ b_outiface_mask = b->fw6.ipv6.outiface_mask;
+ b_outiface = b->fw6.ipv6.outiface;
+
+ break;
+ default:
return false;
}
for (i = 0; i < IFNAMSIZ; i++) {
- if (a->fw.ip.iniface_mask[i] != b->fw.ip.iniface_mask[i]) {
+ if (a_iniface_mask[i] != b_iniface_mask[i]) {
DEBUGP("different iniface mask %x, %x (%d)\n",
- a->fw.ip.iniface_mask[i] & 0xff, b->fw.ip.iniface_mask[i] & 0xff, i);
+ a_iniface_mask[i] & 0xff, b_iniface_mask[i] & 0xff, i);
return false;
}
- if ((a->fw.ip.iniface[i] & a->fw.ip.iniface_mask[i])
- != (b->fw.ip.iniface[i] & b->fw.ip.iniface_mask[i])) {
+ if ((a_iniface[i] & a_iniface_mask[i])
+ != (b_iniface[i] & b_iniface_mask[i])) {
DEBUGP("different iniface\n");
return false;
}
- if (a->fw.ip.outiface_mask[i] != b->fw.ip.outiface_mask[i]) {
+ if (a_outiface_mask[i] != b_outiface_mask[i]) {
DEBUGP("different outiface mask\n");
return false;
}
- if ((a->fw.ip.outiface[i] & a->fw.ip.outiface_mask[i])
- != (b->fw.ip.outiface[i] & b->fw.ip.outiface_mask[i])) {
+ if ((a_outiface[i] & a_outiface_mask[i])
+ != (b_outiface[i] & b_outiface_mask[i])) {
DEBUGP("different outiface\n");
return false;
}
@@ -1962,13 +2124,16 @@ is_same(const struct iptables_command_state *a, const struct iptables_command_st
static void
nft_parse_meta(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
- struct iptables_command_state *cs)
+ int family, struct iptables_command_state *cs)
{
uint8_t key = nft_rule_expr_get_u8(e, NFT_EXPR_META_KEY);
uint32_t value;
const char *name;
const void *ifname;
+ char *iniface, *outiface;
+ unsigned char *iniface_mask, *outiface_mask;
size_t len;
+ uint8_t *invflags;
e = nft_rule_expr_iter_next(iter);
if (e == NULL)
@@ -1980,58 +2145,75 @@ nft_parse_meta(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
return;
}
+ switch (family) {
+ case AF_INET:
+ iniface = cs->fw.ip.iniface;
+ outiface = cs->fw.ip.outiface;
+ iniface_mask = cs->fw.ip.iniface_mask;
+ outiface_mask = cs->fw.ip.outiface_mask;
+ invflags = &cs->fw.ip.invflags;
+ break;
+ case AF_INET6:
+ iniface = cs->fw6.ipv6.iniface;
+ outiface = cs->fw6.ipv6.outiface;
+ iniface_mask = cs->fw6.ipv6.iniface_mask;
+ outiface_mask = cs->fw6.ipv6.outiface_mask;
+ invflags = &cs->fw6.ipv6.invflags;
+ break;
+ default:
+ return;
+ }
+
switch(key) {
case NFT_META_IIF:
value = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_DATA);
if (nft_rule_expr_get_u8(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ)
- cs->fw.ip.invflags |= IPT_INV_VIA_IN;
+ *invflags |= IPT_INV_VIA_IN;
- if_indextoname(value, cs->fw.ip.iniface);
+ if_indextoname(value, iniface);
- memset(cs->fw.ip.iniface_mask, 0xff,
- strlen(cs->fw.ip.iniface)+1);
+ memset(iniface_mask, 0xff, strlen(iniface)+1);
break;
case NFT_META_OIF:
value = nft_rule_expr_get_u32(e, NFT_EXPR_CMP_DATA);
if (nft_rule_expr_get_u8(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ)
- cs->fw.ip.invflags |= IPT_INV_VIA_OUT;
+ *invflags |= IPT_INV_VIA_OUT;
- if_indextoname(value, cs->fw.ip.outiface);
+ if_indextoname(value, outiface);
- memset(cs->fw.ip.outiface_mask, 0xff,
- strlen(cs->fw.ip.outiface)+1);
+ memset(outiface_mask, 0xff, strlen(outiface)+1);
break;
case NFT_META_IIFNAME:
ifname = nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len);
if (nft_rule_expr_get_u8(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ)
- cs->fw.ip.invflags |= IPT_INV_VIA_IN;
+ *invflags |= IPT_INV_VIA_IN;
- memcpy(cs->fw.ip.iniface, ifname, len);
- cs->fw.ip.iniface[len] = '\0';
+ memcpy(iniface, ifname, len);
+ iniface[len] = '\0';
/* If zero, then this is an interface mask */
- if (if_nametoindex(cs->fw.ip.iniface) == 0) {
- cs->fw.ip.iniface[len] = '+';
- cs->fw.ip.iniface[len+1] = '\0';
+ if (if_nametoindex(iniface) == 0) {
+ iniface[len] = '+';
+ iniface[len+1] = '\0';
}
- memset(cs->fw.ip.iniface_mask, 0xff, len);
+ memset(iniface_mask, 0xff, len);
break;
case NFT_META_OIFNAME:
ifname = nft_rule_expr_get(e, NFT_EXPR_CMP_DATA, &len);
if (nft_rule_expr_get_u8(e, NFT_EXPR_CMP_OP) == NFT_CMP_NEQ)
- cs->fw.ip.invflags |= IPT_INV_VIA_OUT;
+ *invflags |= IPT_INV_VIA_OUT;
- memcpy(cs->fw.ip.outiface, ifname, len);
- cs->fw.ip.outiface[len] = '\0';
+ memcpy(outiface, ifname, len);
+ outiface[len] = '\0';
/* If zero, then this is an interface mask */
- if (if_nametoindex(cs->fw.ip.outiface) == 0) {
- cs->fw.ip.outiface[len] = '+';
- cs->fw.ip.outiface[len+1] = '\0';
+ if (if_nametoindex(outiface) == 0) {
+ outiface[len] = '+';
+ outiface[len+1] = '\0';
}
- memset(cs->fw.ip.outiface_mask, 0xff, len);
+ memset(outiface_mask, 0xff, len);
break;
default:
DEBUGP("unknown meta key %d\n", key);
@@ -2040,17 +2222,13 @@ nft_parse_meta(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
}
static void
-nft_parse_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
- struct iptables_command_state *cs)
+nft_parse_payload_ipv4(uint32_t offset, struct nft_rule_expr_iter *iter,
+ struct iptables_command_state *cs)
{
- uint32_t offset;
- bool inv;
-
- offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET);
-
switch(offset) {
struct in_addr addr;
uint8_t proto;
+ bool inv;
case offsetof(struct iphdr, saddr):
get_cmp_data(iter, &addr, sizeof(addr), &inv);
@@ -2085,6 +2263,56 @@ nft_parse_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
}
static void
+nft_parse_payload_ipv6(uint32_t offset, struct nft_rule_expr_iter *iter,
+ struct iptables_command_state *cs)
+{
+ switch (offset) {
+ struct in6_addr addr;
+ uint8_t proto;
+ bool inv;
+
+ case offsetof(struct ip6_hdr, ip6_src):
+ get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ memcpy(cs->fw6.ipv6.src.s6_addr, &addr, sizeof(addr));
+ if (inv)
+ cs->fw6.ipv6.invflags |= IPT_INV_SRCIP;
+ break;
+ case offsetof(struct ip6_hdr, ip6_dst):
+ get_cmp_data(iter, &addr, sizeof(addr), &inv);
+ memcpy(cs->fw6.ipv6.dst.s6_addr, &addr, sizeof(addr));
+ if (inv)
+ cs->fw6.ipv6.invflags |= IPT_INV_DSTIP;
+ break;
+ case offsetof(struct ip6_hdr, ip6_nxt):
+ get_cmp_data(iter, &proto, sizeof(proto), &inv);
+ cs->fw6.ipv6.proto = proto;
+ if (inv)
+ cs->fw6.ipv6.invflags |= IPT_INV_PROTO;
+ default:
+ DEBUGP("unknown payload offset %d\n", offset);
+ break;
+ }
+}
+
+static void
+nft_parse_payload(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
+ int family, struct iptables_command_state *cs)
+{
+ uint32_t offset;
+
+ offset = nft_rule_expr_get_u32(e, NFT_EXPR_PAYLOAD_OFFSET);
+
+ switch (family) {
+ case AF_INET:
+ nft_parse_payload_ipv4(offset, iter, cs);
+ break;
+ case AF_INET6:
+ nft_parse_payload_ipv6(offset, iter, cs);
+ break;
+ }
+}
+
+static void
nft_parse_counter(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
struct xt_counters *counters)
{
@@ -2094,7 +2322,7 @@ nft_parse_counter(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
static void
nft_parse_immediate(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
- struct iptables_command_state *cs)
+ int family, struct iptables_command_state *cs)
{
int verdict = nft_rule_expr_get_u32(e, NFT_EXPR_IMM_VERDICT);
const char *chain = nft_rule_expr_get_str(e, NFT_EXPR_IMM_CHAIN);
@@ -2111,7 +2339,10 @@ nft_parse_immediate(struct nft_rule_expr *e, struct nft_rule_expr_iter *iter,
cs->jumpto = "RETURN";
return;
case NFT_GOTO:
- cs->fw.ip.flags |= IPT_F_GOTO;
+ if (family == AF_INET)
+ cs->fw.ip.flags |= IPT_F_GOTO;
+ else
+ cs->fw6.ipv6.flags |= IPT_F_GOTO;
case NFT_JUMP:
cs->jumpto = chain;
return;
@@ -2124,6 +2355,7 @@ nft_rule_to_iptables_command_state(struct nft_rule *r,
{
struct nft_rule_expr_iter *iter;
struct nft_rule_expr *expr;
+ int family = nft_rule_attr_get_u8(r, NFT_RULE_ATTR_FAMILY);
iter = nft_rule_expr_iter_create(r);
if (iter == NULL)
@@ -2137,11 +2369,11 @@ nft_rule_to_iptables_command_state(struct nft_rule *r,
if (strcmp(name, "counter") == 0) {
nft_parse_counter(expr, iter, &cs->counters);
} else if (strcmp(name, "payload") == 0) {
- nft_parse_payload(expr, iter, cs);
+ nft_parse_payload(expr, iter, family, cs);
} else if (strcmp(name, "meta") == 0) {
- nft_parse_meta(expr, iter, cs);
+ nft_parse_meta(expr, iter, family, cs);
} else if (strcmp(name, "immediate") == 0) {
- nft_parse_immediate(expr, iter, cs);
+ nft_parse_immediate(expr, iter, family, cs);
}
expr = nft_rule_expr_iter_next(iter);
@@ -2348,7 +2580,7 @@ __nft_rule_del(struct nft_handle *h, struct nft_rule *r)
struct nlmsghdr *nlh;
int ret;
- nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, AF_INET,
+ nlh = nft_rule_nlmsg_build_hdr(buf, NFT_MSG_DELRULE, h->family,
NLM_F_ACK, h->seq);
nft_rule_nlmsg_build_payload(nlh, r);
@@ -2421,7 +2653,7 @@ nft_rule_find(struct nft_rule_list *list, const char *chain, const char *table,
nft_rule_to_iptables_command_state(r, &this);
- if (!is_same(cs, &this))
+ if (!is_same(nft_rule_attr_get_u8(r, NFT_RULE_ATTR_FAMILY), cs, &this))
goto next;
if (!find_matches(cs->matches, r)) {
@@ -2684,14 +2916,84 @@ print_match(struct nft_rule_expr *expr, int numeric)
}
static void
+print_ipv4_addr(const struct iptables_command_state *cs, unsigned int format)
+{
+ char buf[BUFSIZ];
+
+ fputc(cs->fw.ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
+ if (cs->fw.ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
+ printf(FMT("%-19s ","%s "), "anywhere");
+ else {
+ if (format & FMT_NUMERIC)
+ strcpy(buf, xtables_ipaddr_to_numeric(&cs->fw.ip.src));
+ else
+ strcpy(buf, xtables_ipaddr_to_anyname(&cs->fw.ip.src));
+ strcat(buf, xtables_ipmask_to_numeric(&cs->fw.ip.smsk));
+ printf(FMT("%-19s ","%s "), buf);
+ }
+
+ fputc(cs->fw.ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
+ if (cs->fw.ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
+ printf(FMT("%-19s ","-> %s"), "anywhere");
+ else {
+ if (format & FMT_NUMERIC)
+ strcpy(buf, xtables_ipaddr_to_numeric(&cs->fw.ip.dst));
+ else
+ strcpy(buf, xtables_ipaddr_to_anyname(&cs->fw.ip.dst));
+ strcat(buf, xtables_ipmask_to_numeric(&cs->fw.ip.dmsk));
+ printf(FMT("%-19s ","-> %s"), buf);
+ }
+}
+
+static void
+print_ipv6_addr(const struct iptables_command_state *cs, unsigned int format)
+{
+ char buf[BUFSIZ];
+
+ fputc(cs->fw6.ipv6.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
+ if (IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.src)
+ && !(format & FMT_NUMERIC))
+ printf(FMT("%-19s ","%s "), "anywhere");
+ else {
+ if (format & FMT_NUMERIC)
+ strcpy(buf,
+ xtables_ip6addr_to_numeric(&cs->fw6.ipv6.src));
+ else
+ strcpy(buf,
+ xtables_ip6addr_to_anyname(&cs->fw6.ipv6.src));
+ strcat(buf, xtables_ip6mask_to_numeric(&cs->fw6.ipv6.smsk));
+ printf(FMT("%-19s ","%s "), buf);
+ }
+
+
+ fputc(cs->fw6.ipv6.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
+ if (IN6_IS_ADDR_UNSPECIFIED(&cs->fw6.ipv6.dst)
+ && !(format & FMT_NUMERIC))
+ printf(FMT("%-19s ","-> %s"), "anywhere");
+ else {
+ if (format & FMT_NUMERIC)
+ strcpy(buf,
+ xtables_ip6addr_to_numeric(&cs->fw6.ipv6.dst));
+ else
+ strcpy(buf,
+ xtables_ip6addr_to_anyname(&cs->fw6.ipv6.dst));
+ strcat(buf, xtables_ip6mask_to_numeric(&cs->fw6.ipv6.dmsk));
+ printf(FMT("%-19s ","-> %s"), buf);
+ }
+}
+
+static void
print_firewall(const struct iptables_command_state *cs, struct nft_rule *r,
unsigned int num, unsigned int format)
{
const struct xtables_target *target = NULL;
const char *targname = NULL;
const void *targinfo = NULL;
- uint8_t flags;
- char buf[BUFSIZ];
+ int family;
+ uint8_t flags = 0;
+ uint8_t invflags = 0;
+ uint8_t proto = 0;
+ const char *iniface = NULL, *outiface = NULL;
struct nft_rule_expr_iter *iter;
struct nft_rule_expr *expr;
struct xt_entry_target *t;
@@ -2709,8 +3011,10 @@ print_firewall(const struct iptables_command_state *cs, struct nft_rule *r,
nft_rule_expr_get_str(expr, NFT_RULE_EXPR_ATTR_NAME);
if (strcmp(name, "target") == 0) {
- targname = nft_rule_expr_get_str(expr, NFT_EXPR_TG_NAME);
- targinfo = nft_rule_expr_get(expr, NFT_EXPR_TG_INFO, &target_len);
+ targname = nft_rule_expr_get_str(expr,
+ NFT_EXPR_TG_NAME);
+ targinfo = nft_rule_expr_get(expr, NFT_EXPR_TG_INFO,
+ &target_len);
break;
} else if (strcmp(name, "immediate") == 0) {
uint32_t verdict =
@@ -2727,10 +3031,12 @@ print_firewall(const struct iptables_command_state *cs, struct nft_rule *r,
targname = "RETURN";
break;
case NFT_GOTO:
- targname = nft_rule_expr_get_str(expr, NFT_EXPR_IMM_CHAIN);
+ targname = nft_rule_expr_get_str(expr,
+ NFT_EXPR_IMM_CHAIN);
break;
case NFT_JUMP:
- targname = nft_rule_expr_get_str(expr, NFT_EXPR_IMM_CHAIN);
+ targname = nft_rule_expr_get_str(expr,
+ NFT_EXPR_IMM_CHAIN);
break;
}
}
@@ -2738,7 +3044,24 @@ print_firewall(const struct iptables_command_state *cs, struct nft_rule *r,
}
nft_rule_expr_iter_destroy(iter);
- flags = cs->fw.ip.flags;
+ family = nft_rule_attr_get_u8(r, NFT_RULE_ATTR_FAMILY);
+
+ switch (family) {
+ case AF_INET:
+ flags = cs->fw.ip.flags;
+ invflags = flags = cs->fw.ip.invflags;
+ proto = cs->fw.ip.proto;
+ iniface = cs->fw.ip.iniface;
+ outiface = cs->fw.ip.outiface;
+ break;
+ case AF_INET6:
+ flags = cs->fw6.ipv6.flags;
+ invflags = cs->fw6.ipv6.invflags;
+ proto = cs->fw6.ipv6.proto;
+ iniface = cs->fw6.ipv6.iniface;
+ outiface = cs->fw6.ipv6.outiface;
+ break;
+ }
if (format & FMT_LINENUMBERS)
printf(FMT("%-4u ", "%u "), num);
@@ -2751,82 +3074,68 @@ print_firewall(const struct iptables_command_state *cs, struct nft_rule *r,
if (!(format & FMT_NOTARGET))
printf(FMT("%-9s ", "%s "), targname ? targname : "");
- fputc(cs->fw.ip.invflags & XT_INV_PROTO ? '!' : ' ', stdout);
+ fputc(invflags & XT_INV_PROTO ? '!' : ' ', stdout);
{
const char *pname =
- proto_to_name(cs->fw.ip.proto, format&FMT_NUMERIC);
+ proto_to_name(proto, format&FMT_NUMERIC);
if (pname)
printf(FMT("%-5s", "%s "), pname);
else
- printf(FMT("%-5hu", "%hu "), cs->fw.ip.proto);
+ printf(FMT("%-5hu", "%hu "), proto);
}
if (format & FMT_OPTIONS) {
if (format & FMT_NOTABLE)
fputs("opt ", stdout);
- fputc(cs->fw.ip.invflags & IPT_INV_FRAG ? '!' : '-', stdout);
+ fputc(invflags & IPT_INV_FRAG ? '!' : '-', stdout);
fputc(flags & IPT_F_FRAG ? 'f' : '-', stdout);
fputc(' ', stdout);
}
if (format & FMT_VIA) {
char iface[IFNAMSIZ+2];
- if (cs->fw.ip.invflags & IPT_INV_VIA_IN) {
+ if (invflags & IPT_INV_VIA_IN) {
iface[0] = '!';
iface[1] = '\0';
}
else iface[0] = '\0';
- if (cs->fw.ip.iniface[0] != '\0') {
- strcat(iface, cs->fw.ip.iniface);
+ if (iniface[0] != '\0') {
+ strcat(iface, iniface);
}
else if (format & FMT_NUMERIC) strcat(iface, "*");
else strcat(iface, "any");
printf(FMT(" %-6s ","in %s "), iface);
- if (cs->fw.ip.invflags & IPT_INV_VIA_OUT) {
+ if (invflags & IPT_INV_VIA_OUT) {
iface[0] = '!';
iface[1] = '\0';
}
else iface[0] = '\0';
- if (cs->fw.ip.outiface[0] != '\0') {
- strcat(iface, cs->fw.ip.outiface);
+ if (outiface[0] != '\0') {
+ strcat(iface, outiface);
}
else if (format & FMT_NUMERIC) strcat(iface, "*");
else strcat(iface, "any");
printf(FMT("%-6s ","out %s "), iface);
}
- fputc(cs->fw.ip.invflags & IPT_INV_SRCIP ? '!' : ' ', stdout);
- if (cs->fw.ip.smsk.s_addr == 0L && !(format & FMT_NUMERIC))
- printf(FMT("%-19s ","%s "), "anywhere");
- else {
- if (format & FMT_NUMERIC)
- strcpy(buf, xtables_ipaddr_to_numeric(&cs->fw.ip.src));
- else
- strcpy(buf, xtables_ipaddr_to_anyname(&cs->fw.ip.src));
- strcat(buf, xtables_ipmask_to_numeric(&cs->fw.ip.smsk));
- printf(FMT("%-19s ","%s "), buf);
- }
- fputc(cs->fw.ip.invflags & IPT_INV_DSTIP ? '!' : ' ', stdout);
- if (cs->fw.ip.dmsk.s_addr == 0L && !(format & FMT_NUMERIC))
- printf(FMT("%-19s ","-> %s"), "anywhere");
- else {
- if (format & FMT_NUMERIC)
- strcpy(buf, xtables_ipaddr_to_numeric(&cs->fw.ip.dst));
- else
- strcpy(buf, xtables_ipaddr_to_anyname(&cs->fw.ip.dst));
- strcat(buf, xtables_ipmask_to_numeric(&cs->fw.ip.dmsk));
- printf(FMT("%-19s ","-> %s"), buf);
+ switch (family) {
+ case AF_INET:
+ print_ipv4_addr(cs, format);
+ break;
+ case AF_INET6:
+ print_ipv6_addr(cs, format);
+ break;
}
if (format & FMT_NOTABLE)
fputs(" ", stdout);
#ifdef IPT_F_GOTO
- if(cs->fw.ip.flags & IPT_F_GOTO)
+ if(flags & IPT_F_GOTO)
printf("[goto] ");
#endif
diff --git a/iptables/nft.h b/iptables/nft.h
index aed2498b..1bd9ccce 100644
--- a/iptables/nft.h
+++ b/iptables/nft.h
@@ -4,6 +4,7 @@
#include "xshared.h"
struct nft_handle {
+ int family;
struct mnl_socket *nl;
uint32_t portid;
uint32_t seq;
diff --git a/iptables/xtables-restore.c b/iptables/xtables-restore.c
index 30ea813c..e83eacc3 100644
--- a/iptables/xtables-restore.c
+++ b/iptables/xtables-restore.c
@@ -161,7 +161,9 @@ static void add_param_to_argv(char *parsestart)
int
xtables_restore_main(int argc, char *argv[])
{
- struct nft_handle h;
+ struct nft_handle h = {
+ .family = AF_INET, /* default to IPv4 */
+ };
char buffer[10240];
int c;
char curtable[XT_TABLE_MAXNAMELEN + 1];
diff --git a/iptables/xtables-save.c b/iptables/xtables-save.c
index 046c948d..05d06b1e 100644
--- a/iptables/xtables-save.c
+++ b/iptables/xtables-save.c
@@ -76,7 +76,9 @@ int
xtables_save_main(int argc, char *argv[])
{
const char *tablename = NULL;
- struct nft_handle h;
+ struct nft_handle h = {
+ .family = AF_INET, /* default to AF_INET */
+ };
int c;
xtables_globals.program_name = "xtables-save";
diff --git a/iptables/xtables.c b/iptables/xtables.c
index d6045906..9c59b7d8 100644
--- a/iptables/xtables.c
+++ b/iptables/xtables.c
@@ -204,6 +204,20 @@ enum {
IPT_DOTTED_MASK
};
+struct addr_mask {
+ union {
+ struct in_addr *v4;
+ struct in6_addr *v6;
+ } addr;
+
+ unsigned int naddrs;
+
+ union {
+ struct in_addr *v4;
+ struct in6_addr *v6;
+ } mask;
+};
+
static void __attribute__((noreturn))
exit_tryhelp(int status)
{
@@ -370,6 +384,15 @@ add_command(unsigned int *cmd, const int newcmd, const int othercmds,
* return global static data.
*/
+/* These are invalid numbers as upper layer protocol */
+static int is_exthdr(uint16_t proto)
+{
+ return (proto == IPPROTO_ROUTING ||
+ proto == IPPROTO_FRAGMENT ||
+ proto == IPPROTO_AH ||
+ proto == IPPROTO_DSTOPTS);
+}
+
/* Christophe Burki wants `-p 6' to imply `-m tcp'. */
/* Can't be zero. */
static int
@@ -430,26 +453,38 @@ static int
add_entry(const char *chain,
const char *table,
struct iptables_command_state *cs,
- unsigned int nsaddrs,
- const struct in_addr saddrs[],
- const struct in_addr smasks[],
- unsigned int ndaddrs,
- const struct in_addr daddrs[],
- const struct in_addr dmasks[],
+ int family,
+ const struct addr_mask s,
+ const struct addr_mask d,
bool verbose, struct nft_handle *h, bool append)
{
unsigned int i, j;
int ret = 1;
- for (i = 0; i < nsaddrs; i++) {
- cs->fw.ip.src.s_addr = saddrs[i].s_addr;
- cs->fw.ip.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->fw.ip.dst.s_addr = daddrs[j].s_addr;
- cs->fw.ip.dmsk.s_addr = dmasks[j].s_addr;
+ for (i = 0; i < s.naddrs; i++) {
+ if (family == AF_INET) {
+ cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
+ for (j = 0; j < d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
- ret = nft_rule_add(h, chain, table,
- cs, append, 0, verbose);
+ ret = nft_rule_add(h, chain, table,
+ cs, append, 0, verbose);
+ }
+ } else if (family == AF_INET6) {
+ memcpy(&cs->fw6.ipv6.src,
+ &s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &d.addr.v6[j], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &d.mask.v6[j], sizeof(struct in6_addr));
+ ret = nft_rule_add(h, chain, table,
+ cs, append, 0, verbose);
+ }
}
}
@@ -460,14 +495,23 @@ static int
replace_entry(const char *chain, const char *table,
struct iptables_command_state *cs,
unsigned int rulenum,
- const struct in_addr *saddr, const struct in_addr *smask,
- const struct in_addr *daddr, const struct in_addr *dmask,
+ int family,
+ const struct addr_mask s,
+ const struct addr_mask d,
bool verbose, struct nft_handle *h)
{
- cs->fw.ip.src.s_addr = saddr->s_addr;
- cs->fw.ip.dst.s_addr = daddr->s_addr;
- cs->fw.ip.smsk.s_addr = smask->s_addr;
- cs->fw.ip.dmsk.s_addr = dmask->s_addr;
+ if (family == AF_INET) {
+ cs->fw.ip.src.s_addr = s.addr.v4->s_addr;
+ cs->fw.ip.dst.s_addr = d.addr.v4->s_addr;
+ cs->fw.ip.smsk.s_addr = s.mask.v4->s_addr;
+ cs->fw.ip.dmsk.s_addr = d.mask.v4->s_addr;
+ } else if (family == AF_INET6) {
+ memcpy(&cs->fw6.ipv6.src, s.addr.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dst, d.addr.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk, s.mask.v6, sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk, d.mask.v6, sizeof(struct in6_addr));
+ } else
+ return 1;
return nft_rule_replace(h, chain, table, cs, rulenum, verbose);
}
@@ -475,25 +519,38 @@ replace_entry(const char *chain, const char *table,
static int
delete_entry(const char *chain, const char *table,
struct iptables_command_state *cs,
- unsigned int nsaddrs,
- const struct in_addr saddrs[],
- const struct in_addr smasks[],
- unsigned int ndaddrs,
- const struct in_addr daddrs[],
- const struct in_addr dmasks[],
+ int family,
+ const struct addr_mask s,
+ const struct addr_mask d,
bool verbose,
struct nft_handle *h)
{
unsigned int i, j;
int ret = 1;
- for (i = 0; i < nsaddrs; i++) {
- cs->fw.ip.src.s_addr = saddrs[i].s_addr;
- cs->fw.ip.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->fw.ip.dst.s_addr = daddrs[j].s_addr;
- cs->fw.ip.dmsk.s_addr = dmasks[j].s_addr;
- ret = nft_rule_delete(h, chain, table, cs, verbose);
+ for (i = 0; i < s.naddrs; i++) {
+ if (family == AF_INET) {
+ cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
+ for (j = 0; j < d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
+ ret = nft_rule_delete(h, chain,
+ table, cs, verbose);
+ }
+ } else if (family == AF_INET6) {
+ memcpy(&cs->fw6.ipv6.src,
+ &s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &d.addr.v6[j], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &d.mask.v6[j], sizeof(struct in6_addr));
+ ret = nft_rule_delete(h, chain,
+ table, cs, verbose);
+ }
}
}
@@ -503,21 +560,37 @@ delete_entry(const char *chain, const char *table,
static int
check_entry(const char *chain, const char *table,
struct iptables_command_state *cs,
- unsigned int nsaddrs, const struct in_addr *saddrs,
- const struct in_addr *smasks, unsigned int ndaddrs,
- const struct in_addr *daddrs, const struct in_addr *dmasks,
+ int family,
+ const struct addr_mask s,
+ const struct addr_mask d,
bool verbose, struct nft_handle *h)
{
unsigned int i, j;
int ret = 1;
- for (i = 0; i < nsaddrs; i++) {
- cs->fw.ip.src.s_addr = saddrs[i].s_addr;
- cs->fw.ip.smsk.s_addr = smasks[i].s_addr;
- for (j = 0; j < ndaddrs; j++) {
- cs->fw.ip.dst.s_addr = daddrs[j].s_addr;
- cs->fw.ip.dmsk.s_addr = dmasks[j].s_addr;
- ret = nft_rule_check(h, chain, table, cs, verbose);
+ for (i = 0; i < s.naddrs; i++) {
+ if (family == AF_INET) {
+ cs->fw.ip.src.s_addr = s.addr.v4[i].s_addr;
+ cs->fw.ip.smsk.s_addr = s.mask.v4[i].s_addr;
+ for (j = 0; j < d.naddrs; j++) {
+ cs->fw.ip.dst.s_addr = d.addr.v4[j].s_addr;
+ cs->fw.ip.dmsk.s_addr = d.mask.v4[j].s_addr;
+ ret = nft_rule_check(h, chain,
+ table, cs, verbose);
+ }
+ } else if (family == AF_INET6) {
+ memcpy(&cs->fw6.ipv6.src,
+ &s.addr.v6[i], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.smsk,
+ &s.mask.v6[i], sizeof(struct in6_addr));
+ for (j = 0; j < d.naddrs; j++) {
+ memcpy(&cs->fw6.ipv6.dst,
+ &d.addr.v6[j], sizeof(struct in6_addr));
+ memcpy(&cs->fw6.ipv6.dmsk,
+ &d.mask.v6[j], sizeof(struct in6_addr));
+ ret = nft_rule_check(h, chain,
+ table, cs, verbose);
+ }
}
}
@@ -673,9 +746,8 @@ static void command_match(struct iptables_command_state *cs)
int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
{
struct iptables_command_state cs;
- unsigned int nsaddrs = 0, ndaddrs = 0;
- struct in_addr *saddrs = NULL, *smasks = NULL;
- struct in_addr *daddrs = NULL, *dmasks = NULL;
+ struct addr_mask s;
+ struct addr_mask d;
int verbose = 0;
const char *chain = NULL;
@@ -687,7 +759,21 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
struct xtables_match *m;
struct xtables_rule_match *matchp;
struct xtables_target *t;
- unsigned long long cnt;
+ unsigned long long pcnt_cnt = 0, bcnt_cnt = 0;
+
+ int family = AF_INET;
+ u_int16_t proto = 0;
+ u_int8_t flags = 0, invflags = 0;
+ char iniface[IFNAMSIZ], outiface[IFNAMSIZ];
+ unsigned char iniface_mask[IFNAMSIZ], outiface_mask[IFNAMSIZ];
+ bool goto_set = false;
+
+ memset(&s, 0, sizeof(s));
+ memset(&d, 0, sizeof(d));
+ memset(iniface, 0, sizeof(iniface));
+ memset(outiface, 0, sizeof(outiface));
+ memset(iniface_mask, 0, sizeof(iniface_mask));
+ memset(outiface_mask, 0, sizeof(outiface_mask));
memset(&cs, 0, sizeof(cs));
cs.jumpto = "";
@@ -877,7 +963,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
* Option selection
*/
case 'p':
- set_option(&cs.options, OPT_PROTOCOL, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_PROTOCOL, &invflags,
cs.invert);
/* Canonicalize into lower case */
@@ -885,31 +971,30 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
*cs.protocol = tolower(*cs.protocol);
cs.protocol = optarg;
- cs.fw.ip.proto = xtables_parse_protocol(cs.protocol);
+ proto = xtables_parse_protocol(cs.protocol);
- if (cs.fw.ip.proto == 0
- && (cs.fw.ip.invflags & XT_INV_PROTO))
+ if (proto == 0 && (invflags & XT_INV_PROTO))
xtables_error(PARAMETER_PROBLEM,
"rule would never match protocol");
break;
case 's':
- set_option(&cs.options, OPT_SOURCE, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_SOURCE, &invflags,
cs.invert);
shostnetworkmask = optarg;
break;
case 'd':
- set_option(&cs.options, OPT_DESTINATION, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_DESTINATION, &invflags,
cs.invert);
dhostnetworkmask = optarg;
break;
#ifdef IPT_F_GOTO
case 'g':
- set_option(&cs.options, OPT_JUMP, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_JUMP, &invflags,
cs.invert);
- cs.fw.ip.flags |= IPT_F_GOTO;
+ goto_set = true;
cs.jumpto = parse_target(optarg);
break;
#endif
@@ -924,11 +1009,11 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
xtables_error(PARAMETER_PROBLEM,
"Empty interface is likely to be "
"undesired");
- set_option(&cs.options, OPT_VIANAMEIN, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_VIANAMEIN, &invflags,
cs.invert);
xtables_parse_interface(optarg,
- cs.fw.ip.iniface,
- cs.fw.ip.iniface_mask);
+ iniface,
+ iniface_mask);
break;
case 'o':
@@ -936,23 +1021,28 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
xtables_error(PARAMETER_PROBLEM,
"Empty interface is likely to be "
"undesired");
- set_option(&cs.options, OPT_VIANAMEOUT, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_VIANAMEOUT, &invflags,
cs.invert);
xtables_parse_interface(optarg,
- cs.fw.ip.outiface,
- cs.fw.ip.outiface_mask);
+ outiface,
+ outiface_mask);
break;
case 'f':
- set_option(&cs.options, OPT_FRAGMENT, &cs.fw.ip.invflags,
+ if (family == AF_INET6) {
+ xtables_error(PARAMETER_PROBLEM,
+ "`-f' is not supported in IPv6, "
+ "use -m frag instead");
+ }
+ set_option(&cs.options, OPT_FRAGMENT, &invflags,
cs.invert);
- cs.fw.ip.flags |= IPT_F_FRAG;
+ flags |= IPT_F_FRAG;
break;
case 'v':
if (!verbose)
set_option(&cs.options, OPT_VERBOSE,
- &cs.fw.ip.invflags, cs.invert);
+ &invflags, cs.invert);
verbose++;
break;
@@ -961,7 +1051,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
break;
case 'n':
- set_option(&cs.options, OPT_NUMERIC, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_NUMERIC, &invflags,
cs.invert);
break;
@@ -973,7 +1063,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
break;
case 'x':
- set_option(&cs.options, OPT_EXPANDED, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_EXPANDED, &invflags,
cs.invert);
break;
@@ -986,7 +1076,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
exit(0);
case '0':
- set_option(&cs.options, OPT_LINENUMBERS, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_LINENUMBERS, &invflags,
cs.invert);
break;
@@ -996,7 +1086,7 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
case 'c':
- set_option(&cs.options, OPT_COUNTERS, &cs.fw.ip.invflags,
+ set_option(&cs.options, OPT_COUNTERS, &invflags,
cs.invert);
pcnt = optarg;
bcnt = strchr(pcnt + 1, ',');
@@ -1010,29 +1100,25 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
"-%c requires packet and byte counter",
opt2char(OPT_COUNTERS));
- if (sscanf(pcnt, "%llu", &cnt) != 1)
+ if (sscanf(pcnt, "%llu", &pcnt_cnt) != 1)
xtables_error(PARAMETER_PROBLEM,
"-%c packet counter not numeric",
opt2char(OPT_COUNTERS));
- cs.counters.pcnt = cnt;
- if (sscanf(bcnt, "%llu", &cnt) != 1)
+ if (sscanf(bcnt, "%llu", &bcnt_cnt) != 1)
xtables_error(PARAMETER_PROBLEM,
"-%c byte counter not numeric",
opt2char(OPT_COUNTERS));
- cs.counters.bcnt = cnt;
break;
case '4':
- /* This is indeed the IPv4 iptables */
+ if (family != AF_INET)
+ exit_tryhelp(2);
break;
case '6':
- /* This is not the IPv6 ip6tables */
- if (line != -1)
- return 1; /* success: line ignored */
- fprintf(stderr, "This is the IPv4 version of iptables.\n");
- exit_tryhelp(2);
+ family = AF_INET6;
+ break;
case 1: /* non option */
if (optarg[0] == '!' && optarg[1] == '\0') {
@@ -1079,27 +1165,109 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
xtables_error(PARAMETER_PROBLEM,
"nothing appropriate following !");
- if (command & (CMD_REPLACE | CMD_INSERT | CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
- if (!(cs.options & OPT_DESTINATION))
- dhostnetworkmask = "0.0.0.0/0";
- if (!(cs.options & OPT_SOURCE))
- shostnetworkmask = "0.0.0.0/0";
- }
+ switch (family) {
+ case AF_INET:
+ cs.fw.ip.proto = proto;
+ cs.fw.ip.invflags = invflags;
+ cs.fw.ip.flags = flags;
- if (shostnetworkmask)
- xtables_ipparse_multiple(shostnetworkmask, &saddrs,
- &smasks, &nsaddrs);
+ strncpy(cs.fw.ip.iniface, iniface, IFNAMSIZ);
+ memcpy(cs.fw.ip.iniface_mask,
+ iniface_mask, IFNAMSIZ*sizeof(unsigned char));
- if (dhostnetworkmask)
- xtables_ipparse_multiple(dhostnetworkmask, &daddrs,
- &dmasks, &ndaddrs);
+ strncpy(cs.fw.ip.outiface, outiface, IFNAMSIZ);
+ memcpy(cs.fw.ip.outiface_mask,
+ outiface_mask, IFNAMSIZ*sizeof(unsigned char));
- if ((nsaddrs > 1 || ndaddrs > 1) &&
- (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
- xtables_error(PARAMETER_PROBLEM, "! not allowed with multiple"
- " source or destination IP addresses");
+ if (goto_set)
+ cs.fw.ip.flags |= IPT_F_GOTO;
- if (command == CMD_REPLACE && (nsaddrs != 1 || ndaddrs != 1))
+ cs.counters.pcnt = pcnt_cnt;
+ cs.counters.bcnt = bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs.options & OPT_DESTINATION))
+ dhostnetworkmask = "0.0.0.0/0";
+ if (!(cs.options & OPT_SOURCE))
+ shostnetworkmask = "0.0.0.0/0";
+ }
+
+ if (shostnetworkmask)
+ xtables_ipparse_multiple(shostnetworkmask, &s.addr.v4,
+ &s.mask.v4, &s.naddrs);
+ if (dhostnetworkmask)
+ xtables_ipparse_multiple(dhostnetworkmask, &d.addr.v4,
+ &d.mask.v4, &d.naddrs);
+
+ if ((s.naddrs > 1 || d.naddrs > 1) &&
+ (cs.fw.ip.invflags & (IPT_INV_SRCIP | IPT_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+ break;
+ case AF_INET6:
+ if (proto != 0)
+ flags |= IP6T_F_PROTO;
+
+ cs.fw6.ipv6.proto = proto;
+ cs.fw6.ipv6.invflags = invflags;
+ cs.fw6.ipv6.flags = flags;
+
+ if (flags & IPT_F_FRAG)
+ xtables_error(PARAMETER_PROBLEM,
+ "-f is not valid on IPv6");
+
+ if (is_exthdr(cs.fw6.ipv6.proto)
+ && (cs.fw6.ipv6.invflags & XT_INV_PROTO) == 0)
+ fprintf(stderr,
+ "Warning: never matched protocol: %s. "
+ "use extension match instead.\n",
+ cs.protocol);
+
+ strncpy(cs.fw6.ipv6.iniface, iniface, IFNAMSIZ);
+ memcpy(cs.fw6.ipv6.iniface_mask,
+ iniface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ strncpy(cs.fw6.ipv6.outiface, outiface, IFNAMSIZ);
+ memcpy(cs.fw6.ipv6.outiface_mask,
+ outiface_mask, IFNAMSIZ*sizeof(unsigned char));
+
+ if (goto_set)
+ cs.fw6.ipv6.flags |= IP6T_F_GOTO;
+
+ cs.fw6.counters.pcnt = pcnt_cnt;
+ cs.fw6.counters.bcnt = bcnt_cnt;
+
+ if (command & (CMD_REPLACE | CMD_INSERT |
+ CMD_DELETE | CMD_APPEND | CMD_CHECK)) {
+ if (!(cs.options & OPT_DESTINATION))
+ dhostnetworkmask = "::0/0";
+ if (!(cs.options & OPT_SOURCE))
+ shostnetworkmask = "::0/0";
+ }
+
+ if (shostnetworkmask)
+ xtables_ip6parse_multiple(shostnetworkmask, &s.addr.v6,
+ &s.mask.v6, &s.naddrs);
+ if (dhostnetworkmask)
+ xtables_ip6parse_multiple(dhostnetworkmask, &d.addr.v6,
+ &d.mask.v6, &d.naddrs);
+
+ if ((s.naddrs > 1 || d.naddrs > 1) &&
+ (cs.fw6.ipv6.invflags & (IP6T_INV_SRCIP | IP6T_INV_DSTIP)))
+ xtables_error(PARAMETER_PROBLEM,
+ "! not allowed with multiple"
+ " source or destination IP addresses");
+ break;
+ default:
+ exit_tryhelp(2);
+ break;
+ }
+
+ h->family = family;
+
+ if (command == CMD_REPLACE && (s.naddrs != 1 || d.naddrs != 1))
xtables_error(PARAMETER_PROBLEM, "Replacement rule does not "
"specify a unique address");
@@ -1144,39 +1312,30 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
switch (command) {
case CMD_APPEND:
- ret = add_entry(chain, *table, &cs,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- cs.options&OPT_VERBOSE,
+ ret = add_entry(chain, *table, &cs, family,
+ s, d, cs.options&OPT_VERBOSE,
h, true);
break;
case CMD_DELETE:
- ret = delete_entry(chain, *table, &cs,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- cs.options&OPT_VERBOSE, h);
+ ret = delete_entry(chain, *table, &cs, family,
+ s, d, cs.options&OPT_VERBOSE, h);
break;
case CMD_DELETE_NUM:
ret = nft_rule_delete_num(h, chain, *table, rulenum - 1, verbose);
break;
case CMD_CHECK:
- ret = check_entry(chain, *table, &cs,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- cs.options&OPT_VERBOSE, h);
+ ret = check_entry(chain, *table, &cs, family,
+ s, d, cs.options&OPT_VERBOSE, h);
break;
case CMD_REPLACE:
/* FIXME replace at rulenum */
ret = replace_entry(chain, *table, &cs, rulenum - 1,
- saddrs, smasks, daddrs, dmasks,
- cs.options&OPT_VERBOSE, h);
+ family, s, d, cs.options&OPT_VERBOSE, h);
break;
case CMD_INSERT:
/* FIXME insert at rulenum */
- ret = add_entry(chain, *table, &cs,
- nsaddrs, saddrs, smasks,
- ndaddrs, daddrs, dmasks,
- cs.options&OPT_VERBOSE, h, false);
+ ret = add_entry(chain, *table, &cs, family,
+ s, d, cs.options&OPT_VERBOSE, h, false);
break;
case CMD_FLUSH:
ret = nft_rule_flush(h, chain, *table);
@@ -1242,10 +1401,17 @@ int do_commandx(struct nft_handle *h, int argc, char *argv[], char **table)
clear_rule_matches(&cs.matches);
- free(saddrs);
- free(smasks);
- free(daddrs);
- free(dmasks);
+ if (family == AF_INET) {
+ free(s.addr.v4);
+ free(s.mask.v4);
+ free(d.addr.v4);
+ free(d.mask.v4);
+ } else if (family == AF_INET6) {
+ free(s.addr.v6);
+ free(s.mask.v6);
+ free(d.addr.v6);
+ free(d.mask.v6);
+ }
xtables_free_opts(1);
return ret;