[packages/ipset] - updated to 7.14

adamg adamg at pld-linux.org
Wed Jul 28 23:48:09 CEST 2021


commit 819319f418f8e80d5f762bbd8b79aa173e189f79
Author: Adam Gołębiowski <adamg at pld-linux.org>
Date:   Wed Jul 28 23:47:36 2021 +0200

    - updated to 7.14

 git.patch  | 1866 ------------------------------------------------------------
 ipset.spec |    8 +-
 2 files changed, 3 insertions(+), 1871 deletions(-)
---
diff --git a/ipset.spec b/ipset.spec
index 40dc9af..1c62603 100644
--- a/ipset.spec
+++ b/ipset.spec
@@ -22,20 +22,19 @@ exit 1
 %define		_enable_debug_packages	0
 %endif
 
-%define		rel	2
+%define		rel	1
 %define		pname	ipset
 Summary:	IP sets utility
 Summary(pl.UTF-8):	Narzędzie do zarządzania zbiorami IP
 Name:		%{pname}%{?_pld_builder:%{?with_kernel:-kernel}}%{_alt_kernel}
-Version:	7.11
+Version:	7.14
 Release:	%{rel}%{?_pld_builder:%{?with_kernel:@%{_kernel_ver_str}}}
 License:	GPL v2
 Group:		Networking/Admin
 #Source0Download: http://ipset.netfilter.org/install.html
 Source0:	http://ipset.netfilter.org/%{pname}-%{version}.tar.bz2
-# Source0-md5:	7c17aca72bcf852f5bc95582aaa60408
+# Source0-md5:	a624b3de000a14b9fd2518a9a806ef1c
 Source1:	%{pname}.init
-Patch0:		git.patch
 URL:		http://ipset.netfilter.org/
 BuildRequires:	autoconf >= 2.63
 BuildRequires:	automake
@@ -185,7 +184,6 @@ done\
 
 %prep
 %setup -q -n %{pname}-%{version}
-%patch0 -p1
 
 %build
 %{__aclocal}
diff --git a/git.patch b/git.patch
deleted file mode 100644
index ddd3326..0000000
--- a/git.patch
+++ /dev/null
@@ -1,1866 +0,0 @@
-diff --git a/configure.ac b/configure.ac
-index bd6116c..eb6c334 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -7,6 +7,7 @@ AC_CONFIG_HEADER([config.h])
- AM_INIT_AUTOMAKE([foreign subdir-objects tar-pax])
- m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
- 
-+AC_PROG_LN_S
- AC_ENABLE_STATIC
- LT_INIT([dlopen])
- LT_CONFIG_LTDL_DIR([libltdl])
-@@ -786,6 +787,56 @@ else
- 	AC_SUBST(HAVE_NLA_POLICY_EXACT_LEN, undef)
- fi
- 
-+AC_MSG_CHECKING([kernel source for nfnl_msg_put() in nfnetlink.h])
-+if test -f $ksourcedir/include/linux/netfilter/nfnetlink.h && \
-+   $GREP -q 'nfnl_msg_put' $ksourcedir/include/linux/netfilter/nfnetlink.h; then
-+	AC_MSG_RESULT(yes)
-+	AC_SUBST(HAVE_NFNL_MSG_PUT, define)
-+else
-+	AC_MSG_RESULT(no)
-+	AC_SUBST(HAVE_NFNL_MSG_PUT, undef)
-+fi
-+
-+AC_MSG_CHECKING([kernel source for struct nfnl_info in nfnl_callback function])
-+if test -f $ksourcedir/include/linux/netfilter/nfnetlink.h && \
-+   $AWK '/^struct nfnl_callback /,/^}/' $ksourcedir/include/linux/netfilter/nfnetlink.h | $GREP -q 'struct nfnl_info'; then
-+	AC_MSG_RESULT(yes)
-+	AC_SUBST(HAVE_NFNL_INFO_IN_NFNL_CALLBACK, define)
-+else
-+	AC_MSG_RESULT(no)
-+	AC_SUBST(HAVE_NFNL_INFO_IN_NFNL_CALLBACK, undef)
-+fi
-+
-+AC_MSG_CHECKING([kernel source for enum nfnl_callback_type])
-+if test -f $ksourcedir/include/linux/netfilter/nfnetlink.h && \
-+   $GREP -q 'enum nfnl_callback_type ' $ksourcedir/include/linux/netfilter/nfnetlink.h; then
-+	AC_MSG_RESULT(yes)
-+	AC_SUBST(HAVE_NFNL_CALLBACK_TYPE, define)
-+else
-+	AC_MSG_RESULT(no)
-+	AC_SUBST(HAVE_NFNL_CALLBACK_TYPE, undef)
-+fi
-+
-+AC_MSG_CHECKING([kernel source of handling -EAGAIN in nfnetlink_unicast])
-+if test -f $ksourcedir/net/netfilter/nfnetlink.c && \
-+   $AWK '/nfnetlink_unicast\(/,/^}/' $ksourcedir/net/netfilter/nfnetlink.c | $GREP -q 'err == -EAGAIN'; then
-+	AC_MSG_RESULT(yes)
-+	AC_SUBST(HAVE_EAGAIN_IN_NFNETLINK_UNICAST, define)
-+else
-+	AC_MSG_RESULT(no)
-+	AC_SUBST(HAVE_EAGAIN_IN_NFNETLINK_UNICAST, undef)
-+fi
-+
-+AC_MSG_CHECKING([kernel source for nlmsg_unicast which returns zero in case of success])
-+if test -f $ksourcedir/include/net/netlink.h && \
-+   $AWK '/static inline int nlmsg_unicast\(/,/^}/' $ksourcedir/include/net/netlink.h | $GREP -q 'err > 0'; then
-+	AC_MSG_RESULT(yes)
-+	AC_SUBST(HAVE_NLMSG_UNICAST, define)
-+else
-+	AC_MSG_RESULT(no)
-+	AC_SUBST(HAVE_NLMSG_UNICAST, undef)
-+fi
-+
- AC_MSG_CHECKING([kernel source for kvzalloc() in mm.h])
- if test -f $ksourcedir/include/linux/mm.h && \
-    $GREP -q 'static inline void \*kvzalloc(' $ksourcedir/include/linux/mm.h; then
-diff --git a/include/libipset/Makefile.am b/include/libipset/Makefile.am
-index c7f7b2b..2c04029 100644
---- a/include/libipset/Makefile.am
-+++ b/include/libipset/Makefile.am
-@@ -17,6 +17,7 @@ pkginclude_HEADERS = \
- 	transport.h \
- 	types.h \
- 	ipset.h \
--	utils.h
-+	utils.h \
-+	xlate.h
- 
- EXTRA_DIST = debug.h icmp.h icmpv6.h
-diff --git a/include/libipset/xlate.h b/include/libipset/xlate.h
-new file mode 100644
-index 0000000..6569768
---- /dev/null
-+++ b/include/libipset/xlate.h
-@@ -0,0 +1,6 @@
-+#ifndef LIBIPSET_XLATE_H
-+#define LIBIPSET_XLATE_H
-+
-+int ipset_xlate_argv(struct ipset *ipset, int argc, char *argv[]);
-+
-+#endif
-diff --git a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
-index 96a4cf4..4d2c446 100644
---- a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
-+++ b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
-@@ -62,6 +62,11 @@
- #@HAVE_KVZALLOC@ HAVE_KVZALLOC
- #@HAVE_GFP_KERNEL_ACCOUNT@ HAVE_GFP_KERNEL_ACCOUNT
- #@HAVE_NLA_STRSCPY@ HAVE_NLA_STRSCPY
-+#@HAVE_NFNL_MSG_PUT@ HAVE_NFNL_MSG_PUT
-+#@HAVE_NFNL_INFO_IN_NFNL_CALLBACK@ HAVE_NFNL_INFO_IN_NFNL_CALLBACK
-+#@HAVE_NFNL_CALLBACK_TYPE@ HAVE_NFNL_CALLBACK_TYPE
-+#@HAVE_EAGAIN_IN_NFNETLINK_UNICAST@ HAVE_EAGAIN_IN_NFNETLINK_UNICAST
-+#@HAVE_NLMSG_UNICAST@ HAVE_NLMSG_UNICAST
- 
- #ifdef HAVE_EXPORT_SYMBOL_GPL_IN_MODULE_H
- #include <linux/module.h>
-@@ -348,18 +353,44 @@ static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype,
- }
- #endif
- 
--#ifdef HAVE_PASSING_EXTENDED_ACK_TO_CALLBACKS
--#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e)	fn(net, nl, skb, nlh, cda, e)
--#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e) fn(net, nl, skb, ad, nlh, cda, e)
--#define IPSET_SOCK_NET(net, ctnl)			net
-+#ifdef HAVE_NFNL_INFO_IN_NFNL_CALLBACK
-+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i)	fn(skb, i, cda)
-+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(net, nl, skb, ad, nlh, cda, i)
-+#define IPSET_SOCK_NET(n, ctnl, i)			(i)->net
-+#define INFO_NLH(i, n)					(i)->nlh
-+#define INFO_NET(i, n)					(i)->net
-+#define INFO_SK(i, n)					(i)->sk
-+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l)	call_ad(net, ctnl, skb, set, tb, adt, flags, l)
-+#elif defined(HAVE_PASSING_EXTENDED_ACK_TO_CALLBACKS)
-+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i)	fn(net, nl, skb, nlh, cda, e)
-+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(net, nl, skb, ad, nlh, cda, e)
-+#define IPSET_SOCK_NET(net, ctnl, i)			net
-+#define INFO_NLH(i, n)					n
-+#define INFO_NET(i, n)					n
-+#define INFO_SK(i, n)					n
-+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l)	call_ad(net, ctnl, skb, set, tb, adt, flags, l)
- #elif defined(HAVE_NET_IN_NFNL_CALLBACK_FN)
--#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e)	fn(net, nl, skb, nlh, cda)
--#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e) fn(net, nl, skb, ad, nlh, cda)
--#define IPSET_SOCK_NET(net, ctnl)			net
-+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i)	fn(net, nl, skb, nlh, cda)
-+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(net, nl, skb, ad, nlh, cda)
-+#define IPSET_SOCK_NET(net, ctnl, i)			net
-+#define INFO_NLH(i, n)					n
-+#define INFO_NET(i, n)					n
-+#define INFO_SK(i, n)					n
-+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l)	call_ad(net, ctnl, skb, set, tb, adt, flags, l)
- #else
--#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e)	fn(nl, skb, nlh, cda)
--#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e) fn(nl, skb, ad, nlh, cda)
--#define IPSET_SOCK_NET(net, ctnl)			sock_net(ctnl)
-+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i)	fn(nl, skb, nlh, cda)
-+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(nl, skb, ad, nlh, cda)
-+#define IPSET_SOCK_NET(net, ctnl, i)			sock_net(ctnl)
-+#define INFO_NLH(i, n)					n
-+#define INFO_NET(i, n)					n
-+#define INFO_SK(i, n)					n
-+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l)	call_ad(ctnl, skb, set, tb, adt, flags, l)
-+#endif
-+
-+#ifdef HAVE_NFNL_CALLBACK_TYPE
-+#define SET_NFNL_CALLBACK_TYPE(t) 	.type = t,
-+#else
-+#define SET_NFNL_CALLBACK_TYPE(t)
- #endif
- 
- #ifndef HAVE_TC_SKB_PROTOCOL
-@@ -406,6 +437,36 @@ static inline u16 nfnl_msg_type(u8 subsys, u8 msg_type)
- }
- #endif
- 
-+#ifndef HAVE_NFNL_MSG_PUT
-+#include <linux/netfilter/nfnetlink.h>
-+static inline void nfnl_fill_hdr(struct nlmsghdr *nlh, u8 family, u8 version,
-+				 __be16 res_id)
-+{
-+	struct nfgenmsg *nfmsg;
-+
-+	nfmsg = nlmsg_data(nlh);
-+	nfmsg->nfgen_family = family;
-+	nfmsg->version = version;
-+	nfmsg->res_id = res_id;
-+}
-+
-+static inline struct nlmsghdr *nfnl_msg_put(struct sk_buff *skb, u32 portid,
-+					    u32 seq, int type, int flags,
-+					    u8 family, u8 version,
-+					    __be16 res_id)
-+{
-+	struct nlmsghdr *nlh;
-+
-+	nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
-+	if (!nlh)
-+		return NULL;
-+
-+	nfnl_fill_hdr(nlh, family, version, res_id);
-+
-+	return nlh;
-+}
-+#endif
-+
- #ifdef HAVE_NETLINK_EXTENDED_ACK
- #define NETLINK_ACK(in_skb, nlh, err, extack)	netlink_ack(in_skb, nlh, err, extack)
- #else
-@@ -459,6 +520,23 @@ static inline ssize_t strscpy(char * dest, const char * src, size_t count)
- #define nla_strscpy	nla_strlcpy
- #endif
- 
-+#if !defined(HAVE_EAGAIN_IN_NFNETLINK_UNICAST) || !defined(HAVE_NLMSG_UNICAST)
-+#define NFNETLINK_UNICAST(cntl, skb, net, portid)	ipset_nfnetlink_unicast(cntl, skb, portid)
-+static inline int ipset_nfnetlink_unicast(struct sock *ctnl, struct sk_buff *skb, u32 portid)
-+{
-+	int err = netlink_unicast(ctnl, skb,  portid, MSG_DONTWAIT);
-+
-+	if (err > 0)
-+		err = 0;
-+	if (err == -EAGAIN)
-+		err = -ENOBUFS;
-+
-+	return err;
-+}
-+#else
-+#define NFNETLINK_UNICAST(cntl, skb, net, portid)	nfnetlink_unicast(skb, net, portid)
-+#endif
-+
- #ifndef smp_mb__before_atomic
- #define smp_mb__before_atomic()	smp_mb()
- #define smp_mb__after_atomic()	smp_mb()
-diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c
-index 63a7955..0fdafb7 100644
---- a/kernel/net/netfilter/ipset/ip_set_core.c
-+++ b/kernel/net/netfilter/ipset/ip_set_core.c
-@@ -964,20 +964,9 @@ static struct nlmsghdr *
- start_msg(struct sk_buff *skb, u32 portid, u32 seq, unsigned int flags,
- 	  enum ipset_cmd cmd)
- {
--	struct nlmsghdr *nlh;
--	struct nfgenmsg *nfmsg;
--
--	nlh = nlmsg_put(skb, portid, seq, nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd),
--			sizeof(*nfmsg), flags);
--	if (!nlh)
--		return NULL;
--
--	nfmsg = nlmsg_data(nlh);
--	nfmsg->nfgen_family = NFPROTO_IPV4;
--	nfmsg->version = NFNETLINK_V0;
--	nfmsg->res_id = 0;
--
--	return nlh;
-+	return nfnl_msg_put(skb, portid, seq,
-+			    nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd), flags,
-+			    NFPROTO_IPV4, NFNETLINK_V0, 0);
- }
- 
- /* Create a set */
-@@ -1047,7 +1036,8 @@ static int
- IPSET_CBFN(ip_set_none, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
- 	return -EOPNOTSUPP;
- }
-@@ -1056,16 +1046,17 @@ static int
- IPSET_CBFN(ip_set_create, struct net *n, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct net *net = IPSET_SOCK_NET(n, ctnl);
-+	struct net *net = IPSET_SOCK_NET(n, ctnl, info);
- 	struct ip_set_net *inst = ip_set_pernet(net);
- 	struct ip_set *set, *clash = NULL;
- 	ip_set_id_t index = IPSET_INVALID_ID;
- 	struct nlattr *tb[IPSET_ATTR_CREATE_MAX + 1] = {};
- 	const char *name, *typename;
- 	u8 family, revision;
--	u32 flags = flag_exist(nlh);
-+	u32 flags = flag_exist(INFO_NLH(info, nlh));
- 	int ret = 0;
- 
- 	if (unlikely(protocol_min_failed(attr) ||
-@@ -1116,7 +1107,7 @@ IPSET_CBFN(ip_set_create, struct net *n, struct sock *ctnl,
- 	/* Set create flags depending on the type revision */
- 	set->flags |= set->type->create_flags[revision];
- 
--	ret = set->type->create(net, set, tb, flags);
-+	ret = set->type->create(INFO_NET(info, net), set, tb, flags);
- 	if (ret != 0)
- 		goto put_out;
- 
-@@ -1202,9 +1193,10 @@ static int
- IPSET_CBFN(ip_set_destroy, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct ip_set *s;
- 	ip_set_id_t i;
- 	int ret = 0;
-@@ -1246,7 +1238,7 @@ IPSET_CBFN(ip_set_destroy, struct net *net, struct sock *ctnl,
- 		/* Modified by ip_set_destroy() only, which is serialized */
- 		inst->is_destroyed = false;
- 	} else {
--		u32 flags = flag_exist(nlh);
-+		u32 flags = flag_exist(INFO_NLH(info, nlh));
- 		s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
- 				    &i);
- 		if (!s) {
-@@ -1284,9 +1276,10 @@ static int
- IPSET_CBFN(ip_set_flush, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct ip_set *s;
- 	ip_set_id_t i;
- 
-@@ -1325,9 +1318,10 @@ static int
- IPSET_CBFN(ip_set_rename, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct ip_set *set, *s;
- 	const char *name2;
- 	ip_set_id_t i;
-@@ -1376,9 +1370,10 @@ static int
- IPSET_CBFN(ip_set_swap, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct ip_set *from, *to;
- 	ip_set_id_t from_id, to_id;
- 	char from_name[IPSET_MAXNAMELEN];
-@@ -1706,7 +1701,8 @@ static int
- IPSET_CBFN(ip_set_dump, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
- 	if (unlikely(protocol_min_failed(attr)))
- 		return -IPSET_ERR_PROTOCOL;
-@@ -1728,7 +1724,7 @@ IPSET_CBFN(ip_set_dump, struct net *net, struct sock *ctnl,
- 			.dump = ip_set_dump_do,
- 			.done = ip_set_dump_done,
- 		};
--		return netlink_dump_start(ctnl, skb, nlh, &c);
-+		return netlink_dump_start(INFO_SK(info, ctnl), skb, INFO_NLH(info, nlh), &c);
- 	}
- #endif
- }
-@@ -1745,8 +1741,8 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = {
- };
- 
- static int
--call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
--	struct nlattr *tb[], enum ipset_adt adt,
-+CALL_AD(struct net *net, struct sock *ctnl, struct sk_buff *skb,
-+	struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt,
- 	u32 flags, bool use_lineno)
- {
- 	int ret;
-@@ -1798,8 +1794,7 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
- 
- 		*errline = lineno;
- 
--		netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb),
--				MSG_DONTWAIT);
-+		NFNETLINK_UNICAST(ctnl, skb2, net, NETLINK_PORTID(skb));
- 		/* Signal netlink not to send its ACK/errmsg.  */
- 		return -EINTR;
- 	}
-@@ -1807,19 +1802,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
- 	return ret;
- }
- 
--static int
--IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
--	      struct sk_buff *skb,
--	      enum ipset_adt adt,
--	      const struct nlmsghdr *nlh,
--	      const struct nlattr * const attr[],
--	      struct netlink_ext_ack *extack)
--{
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+static int IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
-+		struct sk_buff *skb,
-+		enum ipset_adt adt,
-+		const struct nlmsghdr *nlh,
-+		const struct nlattr * const attr[],
-+		struct netlink_ext_ack *extack, const struct nfnl_info *info)
-+{
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct ip_set *set;
- 	struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
- 	const struct nlattr *nla;
--	u32 flags = flag_exist(nlh);
-+	u32 flags = flag_exist(INFO_NLH(info, nlh));
- 	bool use_lineno;
- 	int ret = 0;
- 
-@@ -1844,7 +1838,7 @@ IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
- 				     attr[IPSET_ATTR_DATA],
- 				     set->type->adt_policy, NULL))
- 			return -IPSET_ERR_PROTOCOL;
--		ret = call_ad(ctnl, skb, set, tb, adt, flags,
-+		ret = CALL_AD(net, ctnl, skb, set, tb, adt, flags,
- 			      use_lineno);
- 	} else {
- 		int nla_rem;
-@@ -1855,7 +1849,7 @@ IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
- 			    NLA_PARSE_NESTED(tb, IPSET_ATTR_ADT_MAX, nla,
- 					     set->type->adt_policy, NULL))
- 				return -IPSET_ERR_PROTOCOL;
--			ret = call_ad(ctnl, skb, set, tb, adt,
-+			ret = CALL_AD(net, ctnl, skb, set, tb, adt,
- 				      flags, use_lineno);
- 			if (ret < 0)
- 				return ret;
-@@ -1868,20 +1862,22 @@ static int
- IPSET_CBFN(ip_set_uadd, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	return IPSET_CBFN_AD(ip_set_ad, net, ctnl, skb,
--			     IPSET_ADD, nlh, attr, extack);
-+	return IPSET_CBFN_AD(ip_set_ad, INFO_NET(info, net), INFO_SK(info, ctnl), skb,
-+			     IPSET_ADD, INFO_NLH(info, nlh), attr, extack, info);
- }
- 
- static int
- IPSET_CBFN(ip_set_udel, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	return IPSET_CBFN_AD(ip_set_ad, net, ctnl, skb,
--			     IPSET_DEL, nlh, attr, extack);
-+	return IPSET_CBFN_AD(ip_set_ad, INFO_NET(info, net), INFO_SK(info, ctnl), skb,
-+			     IPSET_DEL, INFO_NLH(info, nlh), attr, extack, info);
- }
- 
- static int
-@@ -1889,9 +1885,10 @@ IPSET_CBFN(ip_set_utest, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb,
- 	   const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct ip_set *set;
- 	struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
- 	int ret = 0;
-@@ -1927,13 +1924,13 @@ static int
- IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	const struct ip_set *set;
- 	struct sk_buff *skb2;
- 	struct nlmsghdr *nlh2;
--	int ret = 0;
- 
- 	if (unlikely(protocol_min_failed(attr) ||
- 		     !attr[IPSET_ATTR_SETNAME]))
-@@ -1947,7 +1944,7 @@ IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
- 	if (!skb2)
- 		return -ENOMEM;
- 
--	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
-+	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
- 			 IPSET_CMD_HEADER);
- 	if (!nlh2)
- 		goto nlmsg_failure;
-@@ -1959,11 +1956,7 @@ IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
- 		goto nla_put_failure;
- 	nlmsg_end(skb2, nlh2);
- 
--	ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
--	if (ret < 0)
--		return ret;
--
--	return 0;
-+	return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
- 
- nla_put_failure:
- 	nlmsg_cancel(skb2, nlh2);
-@@ -1985,7 +1978,8 @@ static int
- IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
- 	struct sk_buff *skb2;
- 	struct nlmsghdr *nlh2;
-@@ -2008,7 +2002,7 @@ IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
- 	if (!skb2)
- 		return -ENOMEM;
- 
--	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
-+	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
- 			 IPSET_CMD_TYPE);
- 	if (!nlh2)
- 		goto nlmsg_failure;
-@@ -2021,11 +2015,7 @@ IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
- 	nlmsg_end(skb2, nlh2);
- 
- 	pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len);
--	ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
--	if (ret < 0)
--		return ret;
--
--	return 0;
-+	return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
- 
- nla_put_failure:
- 	nlmsg_cancel(skb2, nlh2);
-@@ -2045,11 +2035,11 @@ static int
- IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
- 	struct sk_buff *skb2;
- 	struct nlmsghdr *nlh2;
--	int ret = 0;
- 
- 	if (unlikely(!attr[IPSET_ATTR_PROTOCOL]))
- 		return -IPSET_ERR_PROTOCOL;
-@@ -2058,7 +2048,7 @@ IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
- 	if (!skb2)
- 		return -ENOMEM;
- 
--	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
-+	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
- 			 IPSET_CMD_PROTOCOL);
- 	if (!nlh2)
- 		goto nlmsg_failure;
-@@ -2068,11 +2058,7 @@ IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
- 		goto nla_put_failure;
- 	nlmsg_end(skb2, nlh2);
- 
--	ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
--	if (ret < 0)
--		return ret;
--
--	return 0;
-+	return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
- 
- nla_put_failure:
- 	nlmsg_cancel(skb2, nlh2);
-@@ -2087,14 +2073,14 @@ static int
- IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct sk_buff *skb2;
- 	struct nlmsghdr *nlh2;
- 	ip_set_id_t id = IPSET_INVALID_ID;
- 	const struct ip_set *set;
--	int ret = 0;
- 
- 	if (unlikely(protocol_failed(attr) ||
- 		     !attr[IPSET_ATTR_SETNAME]))
-@@ -2108,7 +2094,7 @@ IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
- 	if (!skb2)
- 		return -ENOMEM;
- 
--	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
-+	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
- 			 IPSET_CMD_GET_BYNAME);
- 	if (!nlh2)
- 		goto nlmsg_failure;
-@@ -2118,11 +2104,7 @@ IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
- 		goto nla_put_failure;
- 	nlmsg_end(skb2, nlh2);
- 
--	ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
--	if (ret < 0)
--		return ret;
--
--	return 0;
-+	return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
- 
- nla_put_failure:
- 	nlmsg_cancel(skb2, nlh2);
-@@ -2140,14 +2122,14 @@ static int
- IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
- 	   struct sk_buff *skb, const struct nlmsghdr *nlh,
- 	   const struct nlattr * const attr[],
--	   struct netlink_ext_ack *extack)
-+	   struct netlink_ext_ack *extack,
-+	   const struct nfnl_info *info)
- {
--	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
-+	struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
- 	struct sk_buff *skb2;
- 	struct nlmsghdr *nlh2;
- 	ip_set_id_t id = IPSET_INVALID_ID;
- 	const struct ip_set *set;
--	int ret = 0;
- 
- 	if (unlikely(protocol_failed(attr) ||
- 		     !attr[IPSET_ATTR_INDEX]))
-@@ -2164,7 +2146,7 @@ IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
- 	if (!skb2)
- 		return -ENOMEM;
- 
--	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
-+	nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
- 			 IPSET_CMD_GET_BYINDEX);
- 	if (!nlh2)
- 		goto nlmsg_failure;
-@@ -2173,11 +2155,7 @@ IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
- 		goto nla_put_failure;
- 	nlmsg_end(skb2, nlh2);
- 
--	ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
--	if (ret < 0)
--		return ret;
--
--	return 0;
-+	return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
- 
- nla_put_failure:
- 	nlmsg_cancel(skb2, nlh2);
-@@ -2189,80 +2167,96 @@ nlmsg_failure:
- static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
- 	[IPSET_CMD_NONE]	= {
- 		.call		= ip_set_none,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 	},
- 	[IPSET_CMD_CREATE]	= {
- 		.call		= ip_set_create,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_create_policy,
- 	},
- 	[IPSET_CMD_DESTROY]	= {
- 		.call		= ip_set_destroy,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname_policy,
- 	},
- 	[IPSET_CMD_FLUSH]	= {
- 		.call		= ip_set_flush,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname_policy,
- 	},
- 	[IPSET_CMD_RENAME]	= {
- 		.call		= ip_set_rename,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname2_policy,
- 	},
- 	[IPSET_CMD_SWAP]	= {
- 		.call		= ip_set_swap,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname2_policy,
- 	},
- 	[IPSET_CMD_LIST]	= {
- 		.call		= ip_set_dump,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_dump_policy,
- 	},
- 	[IPSET_CMD_SAVE]	= {
- 		.call		= ip_set_dump,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname_policy,
- 	},
- 	[IPSET_CMD_ADD]	= {
- 		.call		= ip_set_uadd,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_adt_policy,
- 	},
- 	[IPSET_CMD_DEL]	= {
- 		.call		= ip_set_udel,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_adt_policy,
- 	},
- 	[IPSET_CMD_TEST]	= {
- 		.call		= ip_set_utest,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_adt_policy,
- 	},
- 	[IPSET_CMD_HEADER]	= {
- 		.call		= ip_set_header,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname_policy,
- 	},
- 	[IPSET_CMD_TYPE]	= {
- 		.call		= ip_set_type,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_type_policy,
- 	},
- 	[IPSET_CMD_PROTOCOL]	= {
- 		.call		= ip_set_protocol,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_protocol_policy,
- 	},
- 	[IPSET_CMD_GET_BYNAME]	= {
- 		.call		= ip_set_byname,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_setname_policy,
- 	},
- 	[IPSET_CMD_GET_BYINDEX]	= {
- 		.call		= ip_set_byindex,
-+		SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
- 		.attr_count	= IPSET_ATTR_CMD_MAX,
- 		.policy		= ip_set_index_policy,
- 	},
-diff --git a/lib/ipset.c b/lib/ipset.c
-index 6729919..73e67db 100644
---- a/lib/ipset.c
-+++ b/lib/ipset.c
-@@ -13,6 +13,7 @@
- #include <stdio.h>				/* printf */
- #include <stdlib.h>				/* exit */
- #include <string.h>				/* str* */
-+#include <inttypes.h>				/* PRIu64 */
- 
- #include <config.h>
- 
-@@ -28,6 +29,7 @@
- #include <libipset/utils.h>			/* STREQ */
- #include <libipset/ipset.h>			/* prototypes */
- #include <libipset/ip_set_compiler.h>		/* compiler attributes */
-+#include <libipset/list_sort.h>			/* lists */
- 
- static char program_name[] = PACKAGE;
- static char program_version[] = PACKAGE_VERSION;
-@@ -50,6 +52,17 @@ struct ipset {
- 	char *newargv[MAX_ARGS];
- 	int newargc;
- 	const char *filename;			/* Input/output filename */
-+	bool xlate;
-+	struct list_head xlate_sets;
-+};
-+
-+struct ipset_xlate_set {
-+	struct list_head list;
-+	char name[IPSET_MAXNAMELEN];
-+	uint8_t netmask;
-+	uint8_t family;
-+	bool interval;
-+	const struct ipset_type *type;
- };
- 
- /* Commands and environment options */
-@@ -923,20 +936,33 @@ static const char *cmd_prefix[] = {
- 	[IPSET_TEST]   = "test   SETNAME",
- };
- 
--/* Workhorses */
-+static const struct ipset_xlate_set *
-+ipset_xlate_set_get(struct ipset *ipset, const char *name)
-+{
-+	const struct ipset_xlate_set *set;
- 
--/**
-- * ipset_parse_argv - parse and argv array and execute the command
-- * @ipset: ipset structure
-- * @argc: length of the array
-- * @argv: array of strings
-- *
-- * Parse an array of strings and execute the ipset command.
-- *
-- * Returns 0 on success or a negative error code.
-- */
--int
--ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
-+	list_for_each_entry(set, &ipset->xlate_sets, list) {
-+		if (!strcmp(set->name, name))
-+			return set;
-+	}
-+
-+	return NULL;
-+}
-+
-+static const struct ipset_type *ipset_xlate_type_get(struct ipset *ipset,
-+						     const char *name)
-+{
-+	const struct ipset_xlate_set *set;
-+
-+	set = ipset_xlate_set_get(ipset, name);
-+	if (!set)
-+		return NULL;
-+
-+	return set->type;
-+}
-+
-+static int
-+ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
- {
- 	int ret = 0;
- 	enum ipset_cmd cmd = IPSET_CMD_NONE;
-@@ -1243,7 +1269,7 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
- 			return ipset->custom_error(ipset,
- 				p, IPSET_PARAMETER_PROBLEM,
- 				"Unknown argument %s", argv[1]);
--		return restore(ipset);
-+		return IPSET_CMD_RESTORE;
- 	case IPSET_CMD_ADD:
- 	case IPSET_CMD_DEL:
- 	case IPSET_CMD_TEST:
-@@ -1253,7 +1279,12 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
- 		if (ret < 0)
- 			return ipset->standard_error(ipset, p);
- 
--		type = ipset_type_get(session, cmd);
-+		if (!ipset->xlate) {
-+			type = ipset_type_get(session, cmd);
-+		} else {
-+			type = ipset_xlate_type_get(ipset, arg0);
-+			ipset_session_data_set(session, IPSET_OPT_TYPE, type);
-+		}
- 		if (type == NULL)
- 			return ipset->standard_error(ipset, p);
- 
-@@ -1280,6 +1311,37 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
- 	if (argc > 1)
- 		return ipset->custom_error(ipset, p, IPSET_PARAMETER_PROBLEM,
- 			"Unknown argument %s", argv[1]);
-+
-+	return cmd;
-+}
-+
-+/* Workhorses */
-+
-+/**
-+ * ipset_parse_argv - parse and argv array and execute the command
-+ * @ipset: ipset structure
-+ * @argc: length of the array
-+ * @argv: array of strings
-+ *
-+ * Parse an array of strings and execute the ipset command.
-+ *
-+ * Returns 0 on success or a negative error code.
-+ */
-+int
-+ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
-+{
-+	struct ipset_session *session = ipset->session;
-+	void *p = ipset_session_printf_private(session);
-+	enum ipset_cmd cmd;
-+	int ret;
-+
-+	cmd = ipset_parser(ipset, oargc, oargv);
-+	if (cmd < 0)
-+		return cmd;
-+
-+	if (cmd == IPSET_CMD_RESTORE)
-+		return restore(ipset);
-+
- 	ret = ipset_cmd(session, cmd, ipset->restore_line);
- 	D("ret %d", ret);
- 	/* In the case of warning, the return code is success */
-@@ -1455,6 +1517,9 @@ ipset_init(void)
- 		return NULL;
- 	}
- 	ipset_custom_printf(ipset, NULL, NULL, NULL, NULL);
-+
-+	INIT_LIST_HEAD(&ipset->xlate_sets);
-+
- 	return ipset;
- }
- 
-@@ -1469,6 +1534,8 @@ ipset_init(void)
- int
- ipset_fini(struct ipset *ipset)
- {
-+	struct ipset_xlate_set *xlate_set, *next;
-+
- 	assert(ipset);
- 
- 	if (ipset->session)
-@@ -1477,6 +1544,497 @@ ipset_fini(struct ipset *ipset)
- 	if (ipset->newargv[0])
- 		free(ipset->newargv[0]);
- 
-+	list_for_each_entry_safe(xlate_set, next, &ipset->xlate_sets, list)
-+		free(xlate_set);
-+
- 	free(ipset);
- 	return 0;
- }
-+
-+/* Ignore the set family, use inet. */
-+static const char *ipset_xlate_family(uint8_t family)
-+{
-+	return "inet";
-+}
-+
-+enum ipset_xlate_set_type {
-+	IPSET_XLATE_TYPE_UNKNOWN	= 0,
-+	IPSET_XLATE_TYPE_HASH_MAC,
-+	IPSET_XLATE_TYPE_HASH_IP,
-+	IPSET_XLATE_TYPE_HASH_IP_MAC,
-+	IPSET_XLATE_TYPE_HASH_NET_IFACE,
-+	IPSET_XLATE_TYPE_HASH_NET_PORT,
-+	IPSET_XLATE_TYPE_HASH_NET_PORT_NET,
-+	IPSET_XLATE_TYPE_HASH_NET_NET,
-+	IPSET_XLATE_TYPE_HASH_NET,
-+	IPSET_XLATE_TYPE_HASH_IP_PORT_NET,
-+	IPSET_XLATE_TYPE_HASH_IP_PORT_IP,
-+	IPSET_XLATE_TYPE_HASH_IP_MARK,
-+	IPSET_XLATE_TYPE_HASH_IP_PORT,
-+	IPSET_XLATE_TYPE_BITMAP_PORT,
-+	IPSET_XLATE_TYPE_BITMAP_IP_MAC,
-+	IPSET_XLATE_TYPE_BITMAP_IP,
-+};
-+
-+static enum ipset_xlate_set_type ipset_xlate_set_type(const char *typename)
-+{
-+	if (!strcmp(typename, "hash:mac"))
-+		return IPSET_XLATE_TYPE_HASH_MAC;
-+	else if (!strcmp(typename, "hash:ip"))
-+		return IPSET_XLATE_TYPE_HASH_IP;
-+	else if (!strcmp(typename, "hash:ip,mac"))
-+		return IPSET_XLATE_TYPE_HASH_IP_MAC;
-+	else if (!strcmp(typename, "hash:net,iface"))
-+		return IPSET_XLATE_TYPE_HASH_NET_IFACE;
-+	else if (!strcmp(typename, "hash:net,port"))
-+		return IPSET_XLATE_TYPE_HASH_NET_PORT;
-+	else if (!strcmp(typename, "hash:net,port,net"))
-+		return IPSET_XLATE_TYPE_HASH_NET_PORT_NET;
-+	else if (!strcmp(typename, "hash:net,net"))
-+		return IPSET_XLATE_TYPE_HASH_NET_NET;
-+	else if (!strcmp(typename, "hash:net"))
-+		return IPSET_XLATE_TYPE_HASH_NET;
-+	else if (!strcmp(typename, "hash:ip,port,net"))
-+		return IPSET_XLATE_TYPE_HASH_IP_PORT_NET;
-+	else if (!strcmp(typename, "hash:ip,port,ip"))
-+		return IPSET_XLATE_TYPE_HASH_IP_PORT_IP;
-+	else if (!strcmp(typename, "hash:ip,mark"))
-+		return IPSET_XLATE_TYPE_HASH_IP_MARK;
-+	else if (!strcmp(typename, "hash:ip,port"))
-+		return IPSET_XLATE_TYPE_HASH_IP_PORT;
-+	else if (!strcmp(typename, "hash:ip"))
-+		return IPSET_XLATE_TYPE_HASH_IP;
-+	else if (!strcmp(typename, "bitmap:port"))
-+		return IPSET_XLATE_TYPE_BITMAP_PORT;
-+	else if (!strcmp(typename, "bitmap:ip,mac"))
-+		return IPSET_XLATE_TYPE_BITMAP_IP_MAC;
-+	else if (!strcmp(typename, "bitmap:ip"))
-+		return IPSET_XLATE_TYPE_BITMAP_IP;
-+
-+	return IPSET_XLATE_TYPE_UNKNOWN;
-+}
-+
-+#define NFT_SET_INTERVAL	(1 << 0)
-+
-+static const char *
-+ipset_xlate_type_to_nftables(int family, enum ipset_xlate_set_type type,
-+			     uint32_t *flags)
-+{
-+	switch (type) {
-+	case IPSET_XLATE_TYPE_HASH_MAC:
-+		return "ether_addr";
-+	case IPSET_XLATE_TYPE_HASH_IP:
-+		if (family == AF_INET)
-+			return "ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_IP_MAC:
-+		if (family == AF_INET)
-+			return "ipv4_addr . ether_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . ether_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_NET_IFACE:
-+		*flags |= NFT_SET_INTERVAL;
-+		if (family == AF_INET)
-+			return "ipv4_addr . ifname";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . ifname";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_NET_PORT:
-+		*flags |= NFT_SET_INTERVAL;
-+		if (family == AF_INET)
-+			return "ipv4_addr . inet_proto . inet_service";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . inet_proto . inet_service";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_NET_PORT_NET:
-+		*flags |= NFT_SET_INTERVAL;
-+		if (family == AF_INET)
-+			return "ipv4_addr . inet_proto . inet_service . ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . inet_proto . inet_service . ipv6_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_NET_NET:
-+		*flags |= NFT_SET_INTERVAL;
-+		if (family == AF_INET)
-+			return "ipv4_addr . ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . ipv6_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_NET:
-+		*flags |= NFT_SET_INTERVAL;
-+		if (family == AF_INET)
-+			return "ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_IP_PORT_NET:
-+		*flags |= NFT_SET_INTERVAL;
-+		if (family == AF_INET)
-+			return "ipv4_addr . inet_proto . inet_service . ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . inet_proto . inet_service . ipv6_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_IP_PORT_IP:
-+		if (family == AF_INET)
-+			return "ipv4_addr . inet_proto . inet_service . ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . inet_proto . inet_service . ipv6_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_IP_MARK:
-+		if (family == AF_INET)
-+			return "ipv4_addr . mark";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . mark";
-+		break;
-+	case IPSET_XLATE_TYPE_HASH_IP_PORT:
-+		if (family == AF_INET)
-+			return "ipv4_addr . inet_proto . inet_service";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . inet_proto . inet_service";
-+		break;
-+	case IPSET_XLATE_TYPE_BITMAP_PORT:
-+		return "inet_service";
-+	case IPSET_XLATE_TYPE_BITMAP_IP_MAC:
-+		if (family == AF_INET)
-+			return "ipv4_addr . ether_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr . ether_addr";
-+		break;
-+	case IPSET_XLATE_TYPE_BITMAP_IP:
-+		if (family == AF_INET)
-+			return "ipv4_addr";
-+		else if (family == AF_INET6)
-+			return "ipv6_addr";
-+		break;
-+	}
-+	/* This should not ever happen. */
-+	return "unknown";
-+}
-+
-+static int ipset_xlate(struct ipset *ipset, enum ipset_cmd cmd,
-+		       const char *table)
-+{
-+	const char *set, *typename, *nft_type;
-+	const struct ipset_type *ipset_type;
-+	struct ipset_xlate_set *xlate_set;
-+	enum ipset_xlate_set_type type;
-+	struct ipset_session *session;
-+	const uint32_t *cadt_flags;
-+	const uint32_t *timeout;
-+	const uint32_t *maxelem;
-+	struct ipset_data *data;
-+	const uint8_t *netmask;
-+	const char *comment;
-+	uint32_t flags = 0;
-+	uint8_t family;
-+	char buf[64];
-+	bool concat;
-+	char *term;
-+	int i;
-+
-+	session = ipset_session(ipset);
-+	data = ipset_session_data(session);
-+
-+	set = ipset_data_get(data, IPSET_SETNAME);
-+	family = ipset_data_family(data);
-+
-+	switch (cmd) {
-+	case IPSET_CMD_CREATE:
-+		/* Not supported. */
-+		if (ipset_data_test(data, IPSET_OPT_MARKMASK)) {
-+			printf("# %s", ipset->cmdline);
-+			break;
-+		}
-+		cadt_flags = ipset_data_get(data, IPSET_OPT_CADT_FLAGS);
-+
-+		/* Ignore:
-+		 * - IPSET_FLAG_WITH_COMMENT
-+		 * - IPSET_FLAG_WITH_FORCEADD
-+		 */
-+		if (cadt_flags &&
-+		    (*cadt_flags & (IPSET_FLAG_BEFORE |
-+				   IPSET_FLAG_PHYSDEV |
-+				   IPSET_FLAG_NOMATCH |
-+				   IPSET_FLAG_WITH_SKBINFO |
-+				   IPSET_FLAG_IFACE_WILDCARD))) {
-+			printf("# %s", ipset->cmdline);
-+			break;
-+		}
-+
-+		typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
-+		type = ipset_xlate_set_type(typename);
-+		nft_type = ipset_xlate_type_to_nftables(family, type, &flags);
-+
-+		printf("add set %s %s %s { type %s; ",
-+		       ipset_xlate_family(family), table, set, nft_type);
-+		if (cadt_flags) {
-+			if (*cadt_flags & IPSET_FLAG_WITH_COUNTERS)
-+				printf("counter; ");
-+		}
-+		timeout = ipset_data_get(data, IPSET_OPT_TIMEOUT);
-+		if (timeout)
-+			printf("timeout %us; ", *timeout);
-+		maxelem = ipset_data_get(data, IPSET_OPT_MAXELEM);
-+		if (maxelem)
-+			printf("size %u; ", *maxelem);
-+
-+		netmask = ipset_data_get(data, IPSET_OPT_NETMASK);
-+		if (netmask &&
-+		    ((family == AF_INET && *netmask < 32) ||
-+		     (family == AF_INET6 && *netmask < 128)))
-+			flags |= NFT_SET_INTERVAL;
-+
-+		if (flags & NFT_SET_INTERVAL)
-+			printf("flags interval; ");
-+
-+		/* These create-specific options are safe to be ignored:
-+		 * - IPSET_OPT_GC
-+		 * - IPSET_OPT_HASHSIZE
-+		 * - IPSET_OPT_PROBES
-+		 * - IPSET_OPT_RESIZE
-+		 * - IPSET_OPT_SIZE
-+		 * - IPSET_OPT_FORCEADD
-+		 *
-+		 * Ranges and CIDR are safe to be ignored too:
-+		 * - IPSET_OPT_IP_FROM
-+		 * - IPSET_OPT_IP_TO
-+		 * - IPSET_OPT_PORT_FROM
-+		 * - IPSET_OPT_PORT_TO
-+		 */
-+
-+		printf("}\n");
-+
-+		xlate_set = calloc(1, sizeof(*xlate_set));
-+		if (!xlate_set)
-+			return -1;
-+
-+		snprintf(xlate_set->name, sizeof(xlate_set->name), "%s", set);
-+		ipset_type = ipset_types();
-+		while (ipset_type) {
-+			if (!strcmp(ipset_type->name, typename))
-+				break;
-+			ipset_type = ipset_type->next;
-+		}
-+
-+		xlate_set->family = family;
-+		xlate_set->type = ipset_type;
-+		if (netmask) {
-+			xlate_set->netmask = *netmask;
-+			xlate_set->interval = true;
-+		}
-+		list_add_tail(&xlate_set->list, &ipset->xlate_sets);
-+		break;
-+	case IPSET_CMD_DESTROY:
-+		printf("del set %s %s %s\n",
-+		       ipset_xlate_family(family), table, set);
-+		break;
-+	case IPSET_CMD_FLUSH:
-+		if (!set) {
-+			printf("# %s", ipset->cmdline);
-+		} else {
-+			printf("flush set %s %s %s\n",
-+			       ipset_xlate_family(family), table, set);
-+		}
-+		break;
-+	case IPSET_CMD_RENAME:
-+		printf("# %s", ipset->cmdline);
-+		return -1;
-+	case IPSET_CMD_SWAP:
-+		printf("# %s", ipset->cmdline);
-+		return -1;
-+	case IPSET_CMD_LIST:
-+		if (!set) {
-+			printf("list sets %s\n",
-+			       ipset_xlate_family(family), table);
-+		} else {
-+			printf("list set %s %s %s\n",
-+			       ipset_xlate_family(family), table, set);
-+		}
-+		break;
-+	case IPSET_CMD_SAVE:
-+		printf("# %s", ipset->cmdline);
-+		return -1;
-+	case IPSET_CMD_ADD:
-+	case IPSET_CMD_DEL:
-+	case IPSET_CMD_TEST:
-+		/* Not supported. */
-+		if (ipset_data_test(data, IPSET_OPT_NOMATCH) ||
-+		    ipset_data_test(data, IPSET_OPT_SKBINFO) ||
-+		    ipset_data_test(data, IPSET_OPT_SKBMARK) ||
-+		    ipset_data_test(data, IPSET_OPT_SKBPRIO) ||
-+		    ipset_data_test(data, IPSET_OPT_SKBQUEUE) ||
-+		    ipset_data_test(data, IPSET_OPT_IFACE_WILDCARD)) {
-+			printf("# %s", ipset->cmdline);
-+			break;
-+		}
-+		printf("%s element %s %s %s { ",
-+		       cmd == IPSET_CMD_ADD ? "add" :
-+				cmd == IPSET_CMD_DEL ? "delete" : "get",
-+		       ipset_xlate_family(family), table, set);
-+
-+		typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
-+		type = ipset_xlate_set_type(typename);
-+
-+		xlate_set = (struct ipset_xlate_set *)
-+				ipset_xlate_set_get(ipset, set);
-+		if (xlate_set && xlate_set->interval)
-+			netmask = &xlate_set->netmask;
-+		else
-+			netmask = NULL;
-+
-+		concat = false;
-+		if (ipset_data_test(data, IPSET_OPT_IP)) {
-+			ipset_print_data(buf, sizeof(buf), data, IPSET_OPT_IP, 0);
-+			printf("%s", buf);
-+			if (netmask)
-+				printf("/%u ", *netmask);
-+			else
-+				printf(" ");
-+
-+			concat = true;
-+		}
-+		if (ipset_data_test(data, IPSET_OPT_MARK)) {
-+			ipset_print_mark(buf, sizeof(buf), data, IPSET_OPT_MARK, 0);
-+			printf("%s%s ", concat ? ". " : "", buf);
-+		}
-+		if (ipset_data_test(data, IPSET_OPT_IFACE)) {
-+			ipset_print_data(buf, sizeof(buf), data, IPSET_OPT_IFACE, 0);
-+			printf("%s%s ", concat ? ". " : "", buf);
-+		}
-+		if (ipset_data_test(data, IPSET_OPT_ETHER)) {
-+			ipset_print_ether(buf, sizeof(buf), data, IPSET_OPT_ETHER, 0);
-+			for (i = 0; i < strlen(buf); i++)
-+				buf[i] = tolower(buf[i]);
-+
-+			printf("%s%s ", concat ? ". " : "", buf);
-+			concat = true;
-+		}
-+		if (ipset_data_test(data, IPSET_OPT_PORT)) {
-+			ipset_print_proto_port(buf, sizeof(buf), data, IPSET_OPT_PORT, 0);
-+			term = strchr(buf, ':');
-+			if (term) {
-+				*term = '\0';
-+				printf("%s%s ", concat ? ". " : "", buf);
-+			}
-+			ipset_print_data(buf, sizeof(buf), data, IPSET_OPT_PORT, 0);
-+			printf("%s%s ", concat ? ". " : "", buf);
-+		}
-+		if (ipset_data_test(data, IPSET_OPT_IP2)) {
-+			ipset_print_ip(buf, sizeof(buf), data, IPSET_OPT_IP2, 0);
-+			printf("%s%s", concat ? ". " : "", buf);
-+			if (netmask)
-+				printf("/%u ", *netmask);
-+			else
-+				printf(" ");
-+		}
-+		if (ipset_data_test(data, IPSET_OPT_PACKETS) &&
-+		    ipset_data_test(data, IPSET_OPT_BYTES)) {
-+			const uint64_t *pkts, *bytes;
-+
-+			pkts = ipset_data_get(data, IPSET_OPT_PACKETS);
-+			bytes = ipset_data_get(data, IPSET_OPT_BYTES);
-+
-+			printf("counter packets %" PRIu64 " bytes %" PRIu64 " ",
-+			       *pkts, *bytes);
-+		}
-+		timeout = ipset_data_get(data, IPSET_OPT_TIMEOUT);
-+		if (timeout)
-+			printf("timeout %us ", *timeout);
-+
-+		comment = ipset_data_get(data, IPSET_OPT_ADT_COMMENT);
-+		if (comment)
-+			printf("comment \"%s\" ", comment);
-+
-+		printf("}\n");
-+		break;
-+	case IPSET_CMD_GET_BYNAME:
-+		printf("# %s", ipset->cmdline);
-+		return -1;
-+	case IPSET_CMD_GET_BYINDEX:
-+		printf("# %s", ipset->cmdline);
-+		return -1;
-+	default:
-+		break;
-+	}
-+
-+	return 0;
-+}
-+
-+static int ipset_xlate_restore(struct ipset *ipset)
-+{
-+	struct ipset_session *session = ipset_session(ipset);
-+	struct ipset_data *data = ipset_session_data(session);
-+	void *p = ipset_session_printf_private(session);
-+	const char *filename;
-+	enum ipset_cmd cmd;
-+	FILE *f = stdin;
-+	int ret = 0;
-+	char *c;
-+
-+	if (ipset->filename) {
-+		f = fopen(ipset->filename, "r");
-+		if (!f) {
-+			fprintf(stderr, "cannot open file `%s'\n", filename);
-+			return -1;
-+		}
-+	}
-+
-+	/* TODO: Allow to specify the table name other than 'global'. */
-+	printf("add table inet global\n");
-+
-+	while (fgets(ipset->cmdline, sizeof(ipset->cmdline), f)) {
-+		ipset->restore_line++;
-+		c = ipset->cmdline;
-+		while (isspace(c[0]))
-+			c++;
-+		if (c[0] == '\0' || c[0] == '#')
-+			continue;
-+		else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n"))
-+			continue;
-+
-+		ret = build_argv(ipset, c);
-+		if (ret < 0)
-+			return ret;
-+
-+		cmd = ipset_parser(ipset, ipset->newargc, ipset->newargv);
-+		if (cmd < 0)
-+			ipset->standard_error(ipset, p);
-+
-+		/* TODO: Allow to specify the table name other than 'global'. */
-+		ret = ipset_xlate(ipset, cmd, "global");
-+		if (ret < 0)
-+			break;
-+
-+		ipset_data_reset(data);
-+	}
-+
-+	if (filename)
-+		fclose(f);
-+
-+	return ret;
-+}
-+
-+int ipset_xlate_argv(struct ipset *ipset, int argc, char *argv[])
-+{
-+	enum ipset_cmd cmd;
-+	int ret;
-+
-+	ipset->xlate = true;
-+
-+	cmd = ipset_parser(ipset, argc, argv);
-+	if (cmd < 0)
-+		return cmd;
-+
-+	if (cmd == IPSET_CMD_RESTORE) {
-+		ret = ipset_xlate_restore(ipset);
-+	} else {
-+		fprintf(stderr, "This command is not supported, "
-+				"use `ipset-translate restore < file'\n");
-+		ret = -1;
-+	}
-+
-+	return ret;
-+}
-diff --git a/lib/parse.c b/lib/parse.c
-index f3f2d11..9cba252 100644
---- a/lib/parse.c
-+++ b/lib/parse.c
-@@ -41,6 +41,9 @@
- #define syntax_err(fmt, args...) \
- 	ipset_err(session, "Syntax error: " fmt , ## args)
- 
-+#define syntax_err_ll(errtype, fmt, args...) \
-+	ipset_session_report(session, errtype, "Syntax error: " fmt , ## args)
-+
- static char *
- ipset_strchr(const char *str, const char *sep)
- {
-@@ -87,7 +90,8 @@ string_to_number_ll(struct ipset_session *session,
- 		    const char *str,
- 		    unsigned long long min,
- 		    unsigned long long max,
--		    unsigned long long *ret)
-+		    unsigned long long *ret,
-+		    enum ipset_err_type errtype)
- {
- 	unsigned long long number = 0;
- 	char *end;
-@@ -104,13 +108,13 @@ string_to_number_ll(struct ipset_session *session,
- 			errno = ERANGE;
- 	}
- 	if (errno == ERANGE && max)
--		return syntax_err("'%s' is out of range %llu-%llu",
--				  str, min, max);
-+		return syntax_err_ll(errtype, "'%s' is out of range %llu-%llu",
-+				     str, min, max);
- 	else if (errno == ERANGE)
--		return syntax_err("'%s' is out of range %llu-%llu",
--				  str, min, ULLONG_MAX);
-+		return syntax_err_ll(errtype, "'%s' is out of range %llu-%llu",
-+				     str, min, ULLONG_MAX);
- 	else
--		return syntax_err("'%s' is invalid as number", str);
-+		return syntax_err_ll(errtype, "'%s' is invalid as number", str);
- }
- 
- static int
-@@ -120,7 +124,7 @@ string_to_u8(struct ipset_session *session,
- 	int err;
- 	unsigned long long num = 0;
- 
--	err = string_to_number_ll(session, str, 0, 255, &num);
-+	err = string_to_number_ll(session, str, 0, 255, &num, IPSET_ERROR);
- 	*ret = num;
- 
- 	return err;
-@@ -141,12 +145,13 @@ string_to_cidr(struct ipset_session *session,
- 
- static int
- string_to_u16(struct ipset_session *session,
--	      const char *str, uint16_t *ret)
-+	      const char *str, uint16_t *ret,
-+	      enum ipset_err_type errtype)
- {
- 	int err;
- 	unsigned long long num = 0;
- 
--	err = string_to_number_ll(session, str, 0, USHRT_MAX, &num);
-+	err = string_to_number_ll(session, str, 0, USHRT_MAX, &num, errtype);
- 	*ret = num;
- 
- 	return err;
-@@ -159,7 +164,8 @@ string_to_u32(struct ipset_session *session,
- 	int err;
- 	unsigned long long num = 0;
- 
--	err = string_to_number_ll(session, str, 0, UINT_MAX, &num);
-+	err = string_to_number_ll(session, str, 0, UINT_MAX, &num,
-+				  IPSET_ERROR);
- 	*ret = num;
- 
- 	return err;
-@@ -319,7 +325,7 @@ ipset_parse_port(struct ipset_session *session,
- 	assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
- 	assert(str);
- 
--	if (string_to_u16(session, str, &port) == 0) {
-+	if (string_to_u16(session, str, &port, IPSET_WARNING) == 0) {
- 		return ipset_session_data_set(session, opt, &port);
- 	}
- 	/* Error is stored as warning in session report */
-@@ -1335,7 +1341,8 @@ ipset_parse_timeout(struct ipset_session *session,
- 	assert(opt == IPSET_OPT_TIMEOUT);
- 	assert(str);
- 
--	err = string_to_number_ll(session, str, 0, (UINT_MAX>>1)/1000, &llnum);
-+	err = string_to_number_ll(session, str, 0, (UINT_MAX>>1)/1000, &llnum,
-+				  IPSET_ERROR);
- 	if (err == 0) {
- 		/* Timeout is expected to be 32bits wide, so we have
- 		   to convert it here */
-@@ -1579,7 +1586,8 @@ ipset_parse_uint64(struct ipset_session *session,
- 	assert(session);
- 	assert(str);
- 
--	err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value);
-+	err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value,
-+				  IPSET_ERROR);
- 	if (err)
- 		return err;
- 
-@@ -1623,7 +1631,7 @@ ipset_parse_uint16(struct ipset_session *session,
- 	assert(session);
- 	assert(str);
- 
--	err = string_to_u16(session, str, &value);
-+	err = string_to_u16(session, str, &value, IPSET_ERROR);
- 	if (err == 0)
- 		return ipset_session_data_set(session, opt, &value);
- 
-diff --git a/src/Makefile.am b/src/Makefile.am
-index 438fcec..95dea07 100644
---- a/src/Makefile.am
-+++ b/src/Makefile.am
-@@ -12,10 +12,16 @@ AM_LDFLAGS	= -static
- endif
- endif
- 
--dist_man_MANS = ipset.8
-+dist_man_MANS = ipset.8 ipset-translate.8
- 
- sparse-check: $(ipset_SOURCES:.c=.d)
- 
- %.d: %.c
- 	$(IPSET_AM_V_CHECK)\
- 	$(SPARSE) -I.. $(SPARSE_FLAGS) $(AM_CFLAGS) $(AM_CPPFLAGS) $< || :
-+
-+install-exec-hook:
-+	${LN_S} -f "${sbindir}/ipset" "${DESTDIR}${sbindir}/ipset-translate";
-+
-+uninstall-hook:
-+	rm -f ${DESTDIR}${sbindir}/ipset-translate
-diff --git a/src/ipset-translate.8 b/src/ipset-translate.8
-new file mode 100644
-index 0000000..bb4e737
---- /dev/null
-+++ b/src/ipset-translate.8
-@@ -0,0 +1,91 @@
-+.\"
-+.\" (C) Copyright 2021, Pablo Neira Ayuso <pablo at netfilter.org>
-+.\"
-+.\" %%%LICENSE_START(GPLv2+_DOC_FULL)
-+.\" This is free documentation; you can redistribute it and/or
-+.\" modify it under the terms of the GNU General Public License as
-+.\" published by the Free Software Foundation; either version 2 of
-+.\" the License, or (at your option) any later version.
-+.\"
-+.\" The GNU General Public License's references to "object code"
-+.\" and "executables" are to be interpreted as the output of any
-+.\" document formatting or typesetting system, including
-+.\" intermediate and printed output.
-+.\"
-+.\" This manual is distributed in the hope that it will be useful,
-+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
-+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+.\" GNU General Public License for more details.
-+.\"
-+.\" You should have received a copy of the GNU General Public
-+.\" License along with this manual; if not, see
-+.\" <http://www.gnu.org/licenses/>.
-+.\" %%%LICENSE_END
-+.\"
-+.TH IPSET-TRANSLATE 8 "May 31, 2021"
-+
-+.SH NAME
-+ipset-translate \(em translation tool to migrate from ipset to nftables
-+.SH DESCRIPTION
-+This tool allows system administrators to translate a given IP sets file
-+to \fBnftables(8)\fP.
-+
-+The only available command is:
-+
-+.IP \[bu] 2
-+ipset-translate restores < file.ipt
-+
-+.SH USAGE
-+The \fBipset-translate\fP tool reads an IP sets file in the syntax produced by
-+\fBipset(8)\fP save. No set modifications occur, this tool is a text converter.
-+
-+.SH EXAMPLES
-+Basic operation examples.
-+
-+Single command translation, assuming the original file:
-+
-+.nf
-+create test1 hash:ip,port family inet counters timeout 300 hashsize 1024 maxelem 65536 bucketsize 12 initval 0xb5c4be5d
-+add test1 1.1.1.1,udp:20
-+add test1 1.1.1.1,21
-+create test2 hash:ip,port family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xb5c4be5d
-+.fi
-+
-+which results in the following translation:
-+
-+.nf
-+root at machine:~# ipset-translate restore < file.ipt
-+add set inet global test1 { type ipv4_addr . inet_proto . inet_service; counter; timeout 300s; size 65536; }
-+add element inet global test1 { 1.1.1.1 . udp . 20 }
-+add element inet global test1 { 1.1.1.1 . tcp . 21 }
-+add set inet global test2 { type ipv4_addr . inet_proto . inet_service; size 65536; }
-+.fi
-+
-+.SH LIMITATIONS
-+A few IP sets options may be not supported because they are not yet implemented
-+in \fBnftables(8)\fP.
-+
-+Contrary to \fBnftables(8)\fP, IP sets are not attached to a specific table.
-+The translation utility assumes that sets are created in a table whose name
-+is \fBglobal\fP and family is \fBinet\fP. You might want to update the
-+resulting translation to use a different table name and family for your sets.
-+
-+To get up-to-date information about this, please head to
-+\fBhttps://wiki.nftables.org/\fP.
-+
-+.SH SEE ALSO
-+\fBnft(8)\fP, \fBipset(8)\fP
-+
-+.SH AUTHORS
-+The nftables framework has been written by the Netfilter Project
-+(https://www.netfilter.org).
-+
-+This manual page was written by Pablo Neira Ayuso
-+<pablo at netfilter.org>.
-+
-+This documentation is free/libre under the terms of the GPLv2+.
-+
-+This tool was funded through the NGI0 PET Fund, a fund established by NLnet with
-+financial support from the European Commission's Next Generation Internet
-+programme, under the aegis of DG Communications Networks, Content and Technology
-+under grant agreement No 825310.
-diff --git a/src/ipset.8 b/src/ipset.8
-index 97cece9..269b9b5 100644
---- a/src/ipset.8
-+++ b/src/ipset.8
-@@ -333,7 +333,7 @@ are hex without 0x prefix.
- .IP
- ipset create foo hash:ip skbinfo
- .IP
--ipset add foo skbmark 0x1111/0xff00ffff skbprio 1:10 skbqueue 10
-+ipset add foo 192.168.0.1 skbmark 0x1111/0xff00ffff skbprio 1:10 skbqueue 10
- .PP
- .SS hashsize
- This parameter is valid for the \fBcreate\fR command of all \fBhash\fR type sets.
-diff --git a/src/ipset.c b/src/ipset.c
-index ee36a06..6d42b60 100644
---- a/src/ipset.c
-+++ b/src/ipset.c
-@@ -9,9 +9,11 @@
- #include <assert.h>			/* assert */
- #include <stdio.h>			/* fprintf */
- #include <stdlib.h>			/* exit */
-+#include <string.h>			/* strcmp */
- 
- #include <config.h>
- #include <libipset/ipset.h>		/* ipset library */
-+#include <libipset/xlate.h>		/* translate to nftables */
- 
- int
- main(int argc, char *argv[])
-@@ -29,7 +31,11 @@ main(int argc, char *argv[])
- 		exit(1);
- 	}
- 
--	ret = ipset_parse_argv(ipset, argc, argv);
-+	if (!strcmp(argv[0], "ipset-translate")) {
-+		ret = ipset_xlate_argv(ipset, argc, argv);
-+	} else {
-+		ret = ipset_parse_argv(ipset, argc, argv);
-+	}
- 
- 	ipset_fini(ipset);
- 
-diff --git a/tests/xlate/runtest.sh b/tests/xlate/runtest.sh
-new file mode 100755
-index 0000000..a2a02c0
---- /dev/null
-+++ b/tests/xlate/runtest.sh
-@@ -0,0 +1,29 @@
-+#!/bin/bash
-+
-+DIFF=$(which diff)
-+if [ ! -x "$DIFF" ] ; then
-+	echo "ERROR: missing diff"
-+	exit 1
-+fi
-+
-+IPSET_XLATE=$(which ipset-translate)
-+if [ ! -x "$IPSET_XLATE" ] ; then
-+	echo "ERROR: ipset-translate is not installed yet"
-+	exit 1
-+fi
-+
-+TMP=$(mktemp)
-+ipset-translate restore < xlate.t &> $TMP
-+if [ $? -ne 0 ]
-+then
-+	cat $TMP
-+	echo -e "[\033[0;31mERROR\033[0m] failed to run ipset-translate"
-+	exit 1
-+fi
-+${DIFF} -u xlate.t.nft $TMP
-+if [ $? -eq 0 ]
-+then
-+	echo -e "[\033[0;32mOK\033[0m] tests are fine!"
-+else
-+	echo -e "[\033[0;31mERROR\033[0m] unexpected ipset to nftables translation"
-+fi
-diff --git a/tests/xlate/xlate.t b/tests/xlate/xlate.t
-new file mode 100644
-index 0000000..b1e7d28
---- /dev/null
-+++ b/tests/xlate/xlate.t
-@@ -0,0 +1,55 @@
-+create hip1 hash:ip
-+add hip1 192.168.10.2
-+add hip1 192.168.10.3
-+create hip2 hash:ip hashsize 128 bucketsize 255 timeout 4
-+add hip2 192.168.10.3
-+add hip2 192.168.10.4 timeout 10
-+create hip3 hash:ip counters
-+add hip3 192.168.10.3 packets 5 bytes 3456
-+create hip4 hash:ip netmask 24
-+add hip4 192.168.10.0
-+create hip5 hash:ip maxelem 24
-+add hip5 192.168.10.0
-+create hip6 hash:ip comment
-+add hip5 192.168.10.1
-+add hip5 192.168.10.2 comment "this is a comment"
-+create ipp1 hash:ip,port
-+add ipp1 192.168.10.1,0
-+add ipp1 192.168.10.2,5
-+create ipp2 hash:ip,port timeout 4
-+add ipp2 192.168.10.1,0 timeout 12
-+add ipp2 192.168.10.2,5
-+create ipp3 hash:ip,port counters
-+add ipp3 192.168.10.3,20 packets 5 bytes 3456
-+create ipp4 hash:ip,port timeout 4 counters
-+add ipp4 192.168.10.3,20 packets 5 bytes 3456
-+create bip1 bitmap:ip range 2.0.0.1-2.1.0.1 timeout 5
-+create bip2 bitmap:ip range 10.0.0.0/8 netmask 24 timeout 5
-+add bip2 10.10.10.0
-+add bip2 10.10.20.0 timeout 12
-+create net1 hash:net
-+add net1 192.168.10.0/24
-+create net2 hash:net,net
-+add net2 192.168.10.0/24,192.168.20.0/24
-+create hm1 hash:mac
-+add hm1 aa:bb:cc:dd:ee:ff
-+create him1 hash:ip,mac
-+add him1 1.1.1.1,aa:bb:cc:dd:ee:ff
-+create ni1 hash:net,iface
-+add ni1 1.1.1.0/24,eth0
-+create nip1 hash:net,port
-+add nip1 1.1.1.0/24,22
-+create npn1 hash:net,port,net
-+add npn1 1.1.1.0/24,22,2.2.2.0/24
-+create nn1 hash:net,net
-+add nn1 1.1.1.0/24,2.2.2.0/24
-+create ipn1 hash:ip,port,net
-+add ipn1 1.1.1.1,22,2.2.2.0/24
-+create ipi1 hash:ip,port,ip
-+add ipi1 1.1.1.1,22,2.2.2.2
-+create im1 hash:ip,mark
-+add im1 1.1.1.1,0x123456
-+create bp1 bitmap:port range 1-1024
-+add bp1 22
-+create bim1 bitmap:ip,mac range 1.1.1.0/24
-+add bim1 1.1.1.1,aa:bb:cc:dd:ee:ff
-diff --git a/tests/xlate/xlate.t.nft b/tests/xlate/xlate.t.nft
-new file mode 100644
-index 0000000..96eba3b
---- /dev/null
-+++ b/tests/xlate/xlate.t.nft
-@@ -0,0 +1,56 @@
-+add table inet global
-+add set inet global hip1 { type ipv4_addr; }
-+add element inet global hip1 { 192.168.10.2 }
-+add element inet global hip1 { 192.168.10.3 }
-+add set inet global hip2 { type ipv4_addr; timeout 4s; }
-+add element inet global hip2 { 192.168.10.3 }
-+add element inet global hip2 { 192.168.10.4 timeout 10s }
-+add set inet global hip3 { type ipv4_addr; counter; }
-+add element inet global hip3 { 192.168.10.3 counter packets 5 bytes 3456 }
-+add set inet global hip4 { type ipv4_addr; flags interval; }
-+add element inet global hip4 { 192.168.10.0/24 }
-+add set inet global hip5 { type ipv4_addr; size 24; }
-+add element inet global hip5 { 192.168.10.0 }
-+add set inet global hip6 { type ipv4_addr; }
-+add element inet global hip5 { 192.168.10.1 }
-+add element inet global hip5 { 192.168.10.2 comment "this is a comment" }
-+add set inet global ipp1 { type ipv4_addr . inet_proto . inet_service; }
-+add element inet global ipp1 { 192.168.10.1 . tcp . 0 }
-+add element inet global ipp1 { 192.168.10.2 . tcp . 5 }
-+add set inet global ipp2 { type ipv4_addr . inet_proto . inet_service; timeout 4s; }
-+add element inet global ipp2 { 192.168.10.1 . tcp . 0 timeout 12s }
-+add element inet global ipp2 { 192.168.10.2 . tcp . 5 }
-+add set inet global ipp3 { type ipv4_addr . inet_proto . inet_service; counter; }
-+add element inet global ipp3 { 192.168.10.3 . tcp . 20 counter packets 5 bytes 3456 }
-+add set inet global ipp4 { type ipv4_addr . inet_proto . inet_service; counter; timeout 4s; }
-+add element inet global ipp4 { 192.168.10.3 . tcp . 20 counter packets 5 bytes 3456 }
-+add set inet global bip1 { type ipv4_addr; timeout 5s; }
-+add set inet global bip2 { type ipv4_addr; timeout 5s; flags interval; }
-+add element inet global bip2 { 10.10.10.0/24 }
-+add element inet global bip2 { 10.10.20.0/24 timeout 12s }
-+add set inet global net1 { type ipv4_addr; flags interval; }
-+add element inet global net1 { 192.168.10.0/24 }
-+add set inet global net2 { type ipv4_addr . ipv4_addr; flags interval; }
-+add element inet global net2 { 192.168.10.0/24 . 192.168.20.0/24 }
-+add set inet global hm1 { type ether_addr; }
-+add element inet global hm1 { aa:bb:cc:dd:ee:ff }
-+add set inet global him1 { type ipv4_addr . ether_addr; }
-+add element inet global him1 { 1.1.1.1 . aa:bb:cc:dd:ee:ff }
-+add set inet global ni1 { type ipv4_addr . ifname; flags interval; }
-+add element inet global ni1 { 1.1.1.0/24 . eth0 }
-+add set inet global nip1 { type ipv4_addr . inet_proto . inet_service; flags interval; }
-+add element inet global nip1 { 1.1.1.0/24 . tcp . 22 }
-+add set inet global npn1 { type ipv4_addr . inet_proto . inet_service . ipv4_addr; flags interval; }
-+add element inet global npn1 { 1.1.1.0/24 . tcp . 22 . 2.2.2.0/24 }
-+add set inet global nn1 { type ipv4_addr . ipv4_addr; flags interval; }
-+add element inet global nn1 { 1.1.1.0/24 . 2.2.2.0/24 }
-+add set inet global ipn1 { type ipv4_addr . inet_proto . inet_service . ipv4_addr; flags interval; }
-+add element inet global ipn1 { 1.1.1.1 . tcp . 22 . 2.2.2.0/24 }
-+add set inet global ipi1 { type ipv4_addr . inet_proto . inet_service . ipv4_addr; }
-+add element inet global ipi1 { 1.1.1.1 . tcp . 22 . 2.2.2.2 }
-+add set inet global im1 { type ipv4_addr . mark; }
-+add element inet global im1 { 1.1.1.1 . 0x00123456 }
-+add set inet global bp1 { type inet_service; }
-+add element inet global bp1 { 22 }
-+add set inet global bim1 { type ipv4_addr . ether_addr; }
-+add element inet global bim1 { 1.1.1.1 . aa:bb:cc:dd:ee:ff }
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/ipset.git/commitdiff/819319f418f8e80d5f762bbd8b79aa173e189f79



More information about the pld-cvs-commit mailing list