]> git.pld-linux.org Git - packages/ipset.git/blame - git.patch
- added fixes from upstream git to allow building with kernel 5.13, rel 2
[packages/ipset.git] / git.patch
CommitLineData
67259089
JR
1diff --git a/configure.ac b/configure.ac
2index bd6116c..eb6c334 100644
3--- a/configure.ac
4+++ b/configure.ac
5@@ -7,6 +7,7 @@ AC_CONFIG_HEADER([config.h])
6 AM_INIT_AUTOMAKE([foreign subdir-objects tar-pax])
7 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
8
9+AC_PROG_LN_S
10 AC_ENABLE_STATIC
11 LT_INIT([dlopen])
12 LT_CONFIG_LTDL_DIR([libltdl])
13@@ -786,6 +787,56 @@ else
14 AC_SUBST(HAVE_NLA_POLICY_EXACT_LEN, undef)
15 fi
16
17+AC_MSG_CHECKING([kernel source for nfnl_msg_put() in nfnetlink.h])
18+if test -f $ksourcedir/include/linux/netfilter/nfnetlink.h && \
19+ $GREP -q 'nfnl_msg_put' $ksourcedir/include/linux/netfilter/nfnetlink.h; then
20+ AC_MSG_RESULT(yes)
21+ AC_SUBST(HAVE_NFNL_MSG_PUT, define)
22+else
23+ AC_MSG_RESULT(no)
24+ AC_SUBST(HAVE_NFNL_MSG_PUT, undef)
25+fi
26+
27+AC_MSG_CHECKING([kernel source for struct nfnl_info in nfnl_callback function])
28+if test -f $ksourcedir/include/linux/netfilter/nfnetlink.h && \
29+ $AWK '/^struct nfnl_callback /,/^}/' $ksourcedir/include/linux/netfilter/nfnetlink.h | $GREP -q 'struct nfnl_info'; then
30+ AC_MSG_RESULT(yes)
31+ AC_SUBST(HAVE_NFNL_INFO_IN_NFNL_CALLBACK, define)
32+else
33+ AC_MSG_RESULT(no)
34+ AC_SUBST(HAVE_NFNL_INFO_IN_NFNL_CALLBACK, undef)
35+fi
36+
37+AC_MSG_CHECKING([kernel source for enum nfnl_callback_type])
38+if test -f $ksourcedir/include/linux/netfilter/nfnetlink.h && \
39+ $GREP -q 'enum nfnl_callback_type ' $ksourcedir/include/linux/netfilter/nfnetlink.h; then
40+ AC_MSG_RESULT(yes)
41+ AC_SUBST(HAVE_NFNL_CALLBACK_TYPE, define)
42+else
43+ AC_MSG_RESULT(no)
44+ AC_SUBST(HAVE_NFNL_CALLBACK_TYPE, undef)
45+fi
46+
47+AC_MSG_CHECKING([kernel source of handling -EAGAIN in nfnetlink_unicast])
48+if test -f $ksourcedir/net/netfilter/nfnetlink.c && \
49+ $AWK '/nfnetlink_unicast\(/,/^}/' $ksourcedir/net/netfilter/nfnetlink.c | $GREP -q 'err == -EAGAIN'; then
50+ AC_MSG_RESULT(yes)
51+ AC_SUBST(HAVE_EAGAIN_IN_NFNETLINK_UNICAST, define)
52+else
53+ AC_MSG_RESULT(no)
54+ AC_SUBST(HAVE_EAGAIN_IN_NFNETLINK_UNICAST, undef)
55+fi
56+
57+AC_MSG_CHECKING([kernel source for nlmsg_unicast which returns zero in case of success])
58+if test -f $ksourcedir/include/net/netlink.h && \
59+ $AWK '/static inline int nlmsg_unicast\(/,/^}/' $ksourcedir/include/net/netlink.h | $GREP -q 'err > 0'; then
60+ AC_MSG_RESULT(yes)
61+ AC_SUBST(HAVE_NLMSG_UNICAST, define)
62+else
63+ AC_MSG_RESULT(no)
64+ AC_SUBST(HAVE_NLMSG_UNICAST, undef)
65+fi
66+
67 AC_MSG_CHECKING([kernel source for kvzalloc() in mm.h])
68 if test -f $ksourcedir/include/linux/mm.h && \
69 $GREP -q 'static inline void \*kvzalloc(' $ksourcedir/include/linux/mm.h; then
70diff --git a/include/libipset/Makefile.am b/include/libipset/Makefile.am
71index c7f7b2b..2c04029 100644
72--- a/include/libipset/Makefile.am
73+++ b/include/libipset/Makefile.am
74@@ -17,6 +17,7 @@ pkginclude_HEADERS = \
75 transport.h \
76 types.h \
77 ipset.h \
78- utils.h
79+ utils.h \
80+ xlate.h
81
82 EXTRA_DIST = debug.h icmp.h icmpv6.h
83diff --git a/include/libipset/xlate.h b/include/libipset/xlate.h
84new file mode 100644
85index 0000000..6569768
86--- /dev/null
87+++ b/include/libipset/xlate.h
88@@ -0,0 +1,6 @@
89+#ifndef LIBIPSET_XLATE_H
90+#define LIBIPSET_XLATE_H
91+
92+int ipset_xlate_argv(struct ipset *ipset, int argc, char *argv[]);
93+
94+#endif
95diff --git a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
96index 96a4cf4..4d2c446 100644
97--- a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
98+++ b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
99@@ -62,6 +62,11 @@
100 #@HAVE_KVZALLOC@ HAVE_KVZALLOC
101 #@HAVE_GFP_KERNEL_ACCOUNT@ HAVE_GFP_KERNEL_ACCOUNT
102 #@HAVE_NLA_STRSCPY@ HAVE_NLA_STRSCPY
103+#@HAVE_NFNL_MSG_PUT@ HAVE_NFNL_MSG_PUT
104+#@HAVE_NFNL_INFO_IN_NFNL_CALLBACK@ HAVE_NFNL_INFO_IN_NFNL_CALLBACK
105+#@HAVE_NFNL_CALLBACK_TYPE@ HAVE_NFNL_CALLBACK_TYPE
106+#@HAVE_EAGAIN_IN_NFNETLINK_UNICAST@ HAVE_EAGAIN_IN_NFNETLINK_UNICAST
107+#@HAVE_NLMSG_UNICAST@ HAVE_NLMSG_UNICAST
108
109 #ifdef HAVE_EXPORT_SYMBOL_GPL_IN_MODULE_H
110 #include <linux/module.h>
111@@ -348,18 +353,44 @@ static inline int nla_put_in6_addr(struct sk_buff *skb, int attrtype,
112 }
113 #endif
114
115-#ifdef HAVE_PASSING_EXTENDED_ACK_TO_CALLBACKS
116-#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e) fn(net, nl, skb, nlh, cda, e)
117-#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e) fn(net, nl, skb, ad, nlh, cda, e)
118-#define IPSET_SOCK_NET(net, ctnl) net
119+#ifdef HAVE_NFNL_INFO_IN_NFNL_CALLBACK
120+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i) fn(skb, i, cda)
121+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(net, nl, skb, ad, nlh, cda, i)
122+#define IPSET_SOCK_NET(n, ctnl, i) (i)->net
123+#define INFO_NLH(i, n) (i)->nlh
124+#define INFO_NET(i, n) (i)->net
125+#define INFO_SK(i, n) (i)->sk
126+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l) call_ad(net, ctnl, skb, set, tb, adt, flags, l)
127+#elif defined(HAVE_PASSING_EXTENDED_ACK_TO_CALLBACKS)
128+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i) fn(net, nl, skb, nlh, cda, e)
129+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(net, nl, skb, ad, nlh, cda, e)
130+#define IPSET_SOCK_NET(net, ctnl, i) net
131+#define INFO_NLH(i, n) n
132+#define INFO_NET(i, n) n
133+#define INFO_SK(i, n) n
134+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l) call_ad(net, ctnl, skb, set, tb, adt, flags, l)
135 #elif defined(HAVE_NET_IN_NFNL_CALLBACK_FN)
136-#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e) fn(net, nl, skb, nlh, cda)
137-#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e) fn(net, nl, skb, ad, nlh, cda)
138-#define IPSET_SOCK_NET(net, ctnl) net
139+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i) fn(net, nl, skb, nlh, cda)
140+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(net, nl, skb, ad, nlh, cda)
141+#define IPSET_SOCK_NET(net, ctnl, i) net
142+#define INFO_NLH(i, n) n
143+#define INFO_NET(i, n) n
144+#define INFO_SK(i, n) n
145+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l) call_ad(net, ctnl, skb, set, tb, adt, flags, l)
146 #else
147-#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e) fn(nl, skb, nlh, cda)
148-#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e) fn(nl, skb, ad, nlh, cda)
149-#define IPSET_SOCK_NET(net, ctnl) sock_net(ctnl)
150+#define IPSET_CBFN(fn, net, nl, skb, nlh, cda, e, i) fn(nl, skb, nlh, cda)
151+#define IPSET_CBFN_AD(fn, net, nl, skb, ad, nlh, cda, e, i) fn(nl, skb, ad, nlh, cda)
152+#define IPSET_SOCK_NET(net, ctnl, i) sock_net(ctnl)
153+#define INFO_NLH(i, n) n
154+#define INFO_NET(i, n) n
155+#define INFO_SK(i, n) n
156+#define CALL_AD(net, ctnl, skb, set, tb, adt, flags, l) call_ad(ctnl, skb, set, tb, adt, flags, l)
157+#endif
158+
159+#ifdef HAVE_NFNL_CALLBACK_TYPE
160+#define SET_NFNL_CALLBACK_TYPE(t) .type = t,
161+#else
162+#define SET_NFNL_CALLBACK_TYPE(t)
163 #endif
164
165 #ifndef HAVE_TC_SKB_PROTOCOL
166@@ -406,6 +437,36 @@ static inline u16 nfnl_msg_type(u8 subsys, u8 msg_type)
167 }
168 #endif
169
170+#ifndef HAVE_NFNL_MSG_PUT
171+#include <linux/netfilter/nfnetlink.h>
172+static inline void nfnl_fill_hdr(struct nlmsghdr *nlh, u8 family, u8 version,
173+ __be16 res_id)
174+{
175+ struct nfgenmsg *nfmsg;
176+
177+ nfmsg = nlmsg_data(nlh);
178+ nfmsg->nfgen_family = family;
179+ nfmsg->version = version;
180+ nfmsg->res_id = res_id;
181+}
182+
183+static inline struct nlmsghdr *nfnl_msg_put(struct sk_buff *skb, u32 portid,
184+ u32 seq, int type, int flags,
185+ u8 family, u8 version,
186+ __be16 res_id)
187+{
188+ struct nlmsghdr *nlh;
189+
190+ nlh = nlmsg_put(skb, portid, seq, type, sizeof(struct nfgenmsg), flags);
191+ if (!nlh)
192+ return NULL;
193+
194+ nfnl_fill_hdr(nlh, family, version, res_id);
195+
196+ return nlh;
197+}
198+#endif
199+
200 #ifdef HAVE_NETLINK_EXTENDED_ACK
201 #define NETLINK_ACK(in_skb, nlh, err, extack) netlink_ack(in_skb, nlh, err, extack)
202 #else
203@@ -459,6 +520,23 @@ static inline ssize_t strscpy(char * dest, const char * src, size_t count)
204 #define nla_strscpy nla_strlcpy
205 #endif
206
207+#if !defined(HAVE_EAGAIN_IN_NFNETLINK_UNICAST) || !defined(HAVE_NLMSG_UNICAST)
208+#define NFNETLINK_UNICAST(cntl, skb, net, portid) ipset_nfnetlink_unicast(cntl, skb, portid)
209+static inline int ipset_nfnetlink_unicast(struct sock *ctnl, struct sk_buff *skb, u32 portid)
210+{
211+ int err = netlink_unicast(ctnl, skb, portid, MSG_DONTWAIT);
212+
213+ if (err > 0)
214+ err = 0;
215+ if (err == -EAGAIN)
216+ err = -ENOBUFS;
217+
218+ return err;
219+}
220+#else
221+#define NFNETLINK_UNICAST(cntl, skb, net, portid) nfnetlink_unicast(skb, net, portid)
222+#endif
223+
224 #ifndef smp_mb__before_atomic
225 #define smp_mb__before_atomic() smp_mb()
226 #define smp_mb__after_atomic() smp_mb()
227diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c
228index 63a7955..0fdafb7 100644
229--- a/kernel/net/netfilter/ipset/ip_set_core.c
230+++ b/kernel/net/netfilter/ipset/ip_set_core.c
231@@ -964,20 +964,9 @@ static struct nlmsghdr *
232 start_msg(struct sk_buff *skb, u32 portid, u32 seq, unsigned int flags,
233 enum ipset_cmd cmd)
234 {
235- struct nlmsghdr *nlh;
236- struct nfgenmsg *nfmsg;
237-
238- nlh = nlmsg_put(skb, portid, seq, nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd),
239- sizeof(*nfmsg), flags);
240- if (!nlh)
241- return NULL;
242-
243- nfmsg = nlmsg_data(nlh);
244- nfmsg->nfgen_family = NFPROTO_IPV4;
245- nfmsg->version = NFNETLINK_V0;
246- nfmsg->res_id = 0;
247-
248- return nlh;
249+ return nfnl_msg_put(skb, portid, seq,
250+ nfnl_msg_type(NFNL_SUBSYS_IPSET, cmd), flags,
251+ NFPROTO_IPV4, NFNETLINK_V0, 0);
252 }
253
254 /* Create a set */
255@@ -1047,7 +1036,8 @@ static int
256 IPSET_CBFN(ip_set_none, struct net *net, struct sock *ctnl,
257 struct sk_buff *skb, const struct nlmsghdr *nlh,
258 const struct nlattr * const attr[],
259- struct netlink_ext_ack *extack)
260+ struct netlink_ext_ack *extack,
261+ const struct nfnl_info *info)
262 {
263 return -EOPNOTSUPP;
264 }
265@@ -1056,16 +1046,17 @@ static int
266 IPSET_CBFN(ip_set_create, struct net *n, struct sock *ctnl,
267 struct sk_buff *skb, const struct nlmsghdr *nlh,
268 const struct nlattr * const attr[],
269- struct netlink_ext_ack *extack)
270+ struct netlink_ext_ack *extack,
271+ const struct nfnl_info *info)
272 {
273- struct net *net = IPSET_SOCK_NET(n, ctnl);
274+ struct net *net = IPSET_SOCK_NET(n, ctnl, info);
275 struct ip_set_net *inst = ip_set_pernet(net);
276 struct ip_set *set, *clash = NULL;
277 ip_set_id_t index = IPSET_INVALID_ID;
278 struct nlattr *tb[IPSET_ATTR_CREATE_MAX + 1] = {};
279 const char *name, *typename;
280 u8 family, revision;
281- u32 flags = flag_exist(nlh);
282+ u32 flags = flag_exist(INFO_NLH(info, nlh));
283 int ret = 0;
284
285 if (unlikely(protocol_min_failed(attr) ||
286@@ -1116,7 +1107,7 @@ IPSET_CBFN(ip_set_create, struct net *n, struct sock *ctnl,
287 /* Set create flags depending on the type revision */
288 set->flags |= set->type->create_flags[revision];
289
290- ret = set->type->create(net, set, tb, flags);
291+ ret = set->type->create(INFO_NET(info, net), set, tb, flags);
292 if (ret != 0)
293 goto put_out;
294
295@@ -1202,9 +1193,10 @@ static int
296 IPSET_CBFN(ip_set_destroy, struct net *net, struct sock *ctnl,
297 struct sk_buff *skb, const struct nlmsghdr *nlh,
298 const struct nlattr * const attr[],
299- struct netlink_ext_ack *extack)
300+ struct netlink_ext_ack *extack,
301+ const struct nfnl_info *info)
302 {
303- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
304+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
305 struct ip_set *s;
306 ip_set_id_t i;
307 int ret = 0;
308@@ -1246,7 +1238,7 @@ IPSET_CBFN(ip_set_destroy, struct net *net, struct sock *ctnl,
309 /* Modified by ip_set_destroy() only, which is serialized */
310 inst->is_destroyed = false;
311 } else {
312- u32 flags = flag_exist(nlh);
313+ u32 flags = flag_exist(INFO_NLH(info, nlh));
314 s = find_set_and_id(inst, nla_data(attr[IPSET_ATTR_SETNAME]),
315 &i);
316 if (!s) {
317@@ -1284,9 +1276,10 @@ static int
318 IPSET_CBFN(ip_set_flush, struct net *net, struct sock *ctnl,
319 struct sk_buff *skb, const struct nlmsghdr *nlh,
320 const struct nlattr * const attr[],
321- struct netlink_ext_ack *extack)
322+ struct netlink_ext_ack *extack,
323+ const struct nfnl_info *info)
324 {
325- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
326+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
327 struct ip_set *s;
328 ip_set_id_t i;
329
330@@ -1325,9 +1318,10 @@ static int
331 IPSET_CBFN(ip_set_rename, struct net *net, struct sock *ctnl,
332 struct sk_buff *skb, const struct nlmsghdr *nlh,
333 const struct nlattr * const attr[],
334- struct netlink_ext_ack *extack)
335+ struct netlink_ext_ack *extack,
336+ const struct nfnl_info *info)
337 {
338- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
339+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
340 struct ip_set *set, *s;
341 const char *name2;
342 ip_set_id_t i;
343@@ -1376,9 +1370,10 @@ static int
344 IPSET_CBFN(ip_set_swap, struct net *net, struct sock *ctnl,
345 struct sk_buff *skb, const struct nlmsghdr *nlh,
346 const struct nlattr * const attr[],
347- struct netlink_ext_ack *extack)
348+ struct netlink_ext_ack *extack,
349+ const struct nfnl_info *info)
350 {
351- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
352+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
353 struct ip_set *from, *to;
354 ip_set_id_t from_id, to_id;
355 char from_name[IPSET_MAXNAMELEN];
356@@ -1706,7 +1701,8 @@ static int
357 IPSET_CBFN(ip_set_dump, struct net *net, struct sock *ctnl,
358 struct sk_buff *skb, const struct nlmsghdr *nlh,
359 const struct nlattr * const attr[],
360- struct netlink_ext_ack *extack)
361+ struct netlink_ext_ack *extack,
362+ const struct nfnl_info *info)
363 {
364 if (unlikely(protocol_min_failed(attr)))
365 return -IPSET_ERR_PROTOCOL;
366@@ -1728,7 +1724,7 @@ IPSET_CBFN(ip_set_dump, struct net *net, struct sock *ctnl,
367 .dump = ip_set_dump_do,
368 .done = ip_set_dump_done,
369 };
370- return netlink_dump_start(ctnl, skb, nlh, &c);
371+ return netlink_dump_start(INFO_SK(info, ctnl), skb, INFO_NLH(info, nlh), &c);
372 }
373 #endif
374 }
375@@ -1745,8 +1741,8 @@ static const struct nla_policy ip_set_adt_policy[IPSET_ATTR_CMD_MAX + 1] = {
376 };
377
378 static int
379-call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
380- struct nlattr *tb[], enum ipset_adt adt,
381+CALL_AD(struct net *net, struct sock *ctnl, struct sk_buff *skb,
382+ struct ip_set *set, struct nlattr *tb[], enum ipset_adt adt,
383 u32 flags, bool use_lineno)
384 {
385 int ret;
386@@ -1798,8 +1794,7 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
387
388 *errline = lineno;
389
390- netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb),
391- MSG_DONTWAIT);
392+ NFNETLINK_UNICAST(ctnl, skb2, net, NETLINK_PORTID(skb));
393 /* Signal netlink not to send its ACK/errmsg. */
394 return -EINTR;
395 }
396@@ -1807,19 +1802,18 @@ call_ad(struct sock *ctnl, struct sk_buff *skb, struct ip_set *set,
397 return ret;
398 }
399
400-static int
401-IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
402- struct sk_buff *skb,
403- enum ipset_adt adt,
404- const struct nlmsghdr *nlh,
405- const struct nlattr * const attr[],
406- struct netlink_ext_ack *extack)
407-{
408- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
409+static int IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
410+ struct sk_buff *skb,
411+ enum ipset_adt adt,
412+ const struct nlmsghdr *nlh,
413+ const struct nlattr * const attr[],
414+ struct netlink_ext_ack *extack, const struct nfnl_info *info)
415+{
416+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
417 struct ip_set *set;
418 struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
419 const struct nlattr *nla;
420- u32 flags = flag_exist(nlh);
421+ u32 flags = flag_exist(INFO_NLH(info, nlh));
422 bool use_lineno;
423 int ret = 0;
424
425@@ -1844,7 +1838,7 @@ IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
426 attr[IPSET_ATTR_DATA],
427 set->type->adt_policy, NULL))
428 return -IPSET_ERR_PROTOCOL;
429- ret = call_ad(ctnl, skb, set, tb, adt, flags,
430+ ret = CALL_AD(net, ctnl, skb, set, tb, adt, flags,
431 use_lineno);
432 } else {
433 int nla_rem;
434@@ -1855,7 +1849,7 @@ IPSET_CBFN_AD(ip_set_ad, struct net *net, struct sock *ctnl,
435 NLA_PARSE_NESTED(tb, IPSET_ATTR_ADT_MAX, nla,
436 set->type->adt_policy, NULL))
437 return -IPSET_ERR_PROTOCOL;
438- ret = call_ad(ctnl, skb, set, tb, adt,
439+ ret = CALL_AD(net, ctnl, skb, set, tb, adt,
440 flags, use_lineno);
441 if (ret < 0)
442 return ret;
443@@ -1868,20 +1862,22 @@ static int
444 IPSET_CBFN(ip_set_uadd, struct net *net, struct sock *ctnl,
445 struct sk_buff *skb, const struct nlmsghdr *nlh,
446 const struct nlattr * const attr[],
447- struct netlink_ext_ack *extack)
448+ struct netlink_ext_ack *extack,
449+ const struct nfnl_info *info)
450 {
451- return IPSET_CBFN_AD(ip_set_ad, net, ctnl, skb,
452- IPSET_ADD, nlh, attr, extack);
453+ return IPSET_CBFN_AD(ip_set_ad, INFO_NET(info, net), INFO_SK(info, ctnl), skb,
454+ IPSET_ADD, INFO_NLH(info, nlh), attr, extack, info);
455 }
456
457 static int
458 IPSET_CBFN(ip_set_udel, struct net *net, struct sock *ctnl,
459 struct sk_buff *skb, const struct nlmsghdr *nlh,
460 const struct nlattr * const attr[],
461- struct netlink_ext_ack *extack)
462+ struct netlink_ext_ack *extack,
463+ const struct nfnl_info *info)
464 {
465- return IPSET_CBFN_AD(ip_set_ad, net, ctnl, skb,
466- IPSET_DEL, nlh, attr, extack);
467+ return IPSET_CBFN_AD(ip_set_ad, INFO_NET(info, net), INFO_SK(info, ctnl), skb,
468+ IPSET_DEL, INFO_NLH(info, nlh), attr, extack, info);
469 }
470
471 static int
472@@ -1889,9 +1885,10 @@ IPSET_CBFN(ip_set_utest, struct net *net, struct sock *ctnl,
473 struct sk_buff *skb,
474 const struct nlmsghdr *nlh,
475 const struct nlattr * const attr[],
476- struct netlink_ext_ack *extack)
477+ struct netlink_ext_ack *extack,
478+ const struct nfnl_info *info)
479 {
480- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
481+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
482 struct ip_set *set;
483 struct nlattr *tb[IPSET_ATTR_ADT_MAX + 1] = {};
484 int ret = 0;
485@@ -1927,13 +1924,13 @@ static int
486 IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
487 struct sk_buff *skb, const struct nlmsghdr *nlh,
488 const struct nlattr * const attr[],
489- struct netlink_ext_ack *extack)
490+ struct netlink_ext_ack *extack,
491+ const struct nfnl_info *info)
492 {
493- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
494+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
495 const struct ip_set *set;
496 struct sk_buff *skb2;
497 struct nlmsghdr *nlh2;
498- int ret = 0;
499
500 if (unlikely(protocol_min_failed(attr) ||
501 !attr[IPSET_ATTR_SETNAME]))
502@@ -1947,7 +1944,7 @@ IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
503 if (!skb2)
504 return -ENOMEM;
505
506- nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
507+ nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
508 IPSET_CMD_HEADER);
509 if (!nlh2)
510 goto nlmsg_failure;
511@@ -1959,11 +1956,7 @@ IPSET_CBFN(ip_set_header, struct net *net, struct sock *ctnl,
512 goto nla_put_failure;
513 nlmsg_end(skb2, nlh2);
514
515- ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
516- if (ret < 0)
517- return ret;
518-
519- return 0;
520+ return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
521
522 nla_put_failure:
523 nlmsg_cancel(skb2, nlh2);
524@@ -1985,7 +1978,8 @@ static int
525 IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
526 struct sk_buff *skb, const struct nlmsghdr *nlh,
527 const struct nlattr * const attr[],
528- struct netlink_ext_ack *extack)
529+ struct netlink_ext_ack *extack,
530+ const struct nfnl_info *info)
531 {
532 struct sk_buff *skb2;
533 struct nlmsghdr *nlh2;
534@@ -2008,7 +2002,7 @@ IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
535 if (!skb2)
536 return -ENOMEM;
537
538- nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
539+ nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
540 IPSET_CMD_TYPE);
541 if (!nlh2)
542 goto nlmsg_failure;
543@@ -2021,11 +2015,7 @@ IPSET_CBFN(ip_set_type, struct net *net, struct sock *ctnl,
544 nlmsg_end(skb2, nlh2);
545
546 pr_debug("Send TYPE, nlmsg_len: %u\n", nlh2->nlmsg_len);
547- ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
548- if (ret < 0)
549- return ret;
550-
551- return 0;
552+ return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
553
554 nla_put_failure:
555 nlmsg_cancel(skb2, nlh2);
556@@ -2045,11 +2035,11 @@ static int
557 IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
558 struct sk_buff *skb, const struct nlmsghdr *nlh,
559 const struct nlattr * const attr[],
560- struct netlink_ext_ack *extack)
561+ struct netlink_ext_ack *extack,
562+ const struct nfnl_info *info)
563 {
564 struct sk_buff *skb2;
565 struct nlmsghdr *nlh2;
566- int ret = 0;
567
568 if (unlikely(!attr[IPSET_ATTR_PROTOCOL]))
569 return -IPSET_ERR_PROTOCOL;
570@@ -2058,7 +2048,7 @@ IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
571 if (!skb2)
572 return -ENOMEM;
573
574- nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
575+ nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
576 IPSET_CMD_PROTOCOL);
577 if (!nlh2)
578 goto nlmsg_failure;
579@@ -2068,11 +2058,7 @@ IPSET_CBFN(ip_set_protocol, struct net *net, struct sock *ctnl,
580 goto nla_put_failure;
581 nlmsg_end(skb2, nlh2);
582
583- ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
584- if (ret < 0)
585- return ret;
586-
587- return 0;
588+ return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
589
590 nla_put_failure:
591 nlmsg_cancel(skb2, nlh2);
592@@ -2087,14 +2073,14 @@ static int
593 IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
594 struct sk_buff *skb, const struct nlmsghdr *nlh,
595 const struct nlattr * const attr[],
596- struct netlink_ext_ack *extack)
597+ struct netlink_ext_ack *extack,
598+ const struct nfnl_info *info)
599 {
600- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
601+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
602 struct sk_buff *skb2;
603 struct nlmsghdr *nlh2;
604 ip_set_id_t id = IPSET_INVALID_ID;
605 const struct ip_set *set;
606- int ret = 0;
607
608 if (unlikely(protocol_failed(attr) ||
609 !attr[IPSET_ATTR_SETNAME]))
610@@ -2108,7 +2094,7 @@ IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
611 if (!skb2)
612 return -ENOMEM;
613
614- nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
615+ nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
616 IPSET_CMD_GET_BYNAME);
617 if (!nlh2)
618 goto nlmsg_failure;
619@@ -2118,11 +2104,7 @@ IPSET_CBFN(ip_set_byname, struct net *net, struct sock *ctnl,
620 goto nla_put_failure;
621 nlmsg_end(skb2, nlh2);
622
623- ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
624- if (ret < 0)
625- return ret;
626-
627- return 0;
628+ return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
629
630 nla_put_failure:
631 nlmsg_cancel(skb2, nlh2);
632@@ -2140,14 +2122,14 @@ static int
633 IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
634 struct sk_buff *skb, const struct nlmsghdr *nlh,
635 const struct nlattr * const attr[],
636- struct netlink_ext_ack *extack)
637+ struct netlink_ext_ack *extack,
638+ const struct nfnl_info *info)
639 {
640- struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl));
641+ struct ip_set_net *inst = ip_set_pernet(IPSET_SOCK_NET(net, ctnl, info));
642 struct sk_buff *skb2;
643 struct nlmsghdr *nlh2;
644 ip_set_id_t id = IPSET_INVALID_ID;
645 const struct ip_set *set;
646- int ret = 0;
647
648 if (unlikely(protocol_failed(attr) ||
649 !attr[IPSET_ATTR_INDEX]))
650@@ -2164,7 +2146,7 @@ IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
651 if (!skb2)
652 return -ENOMEM;
653
654- nlh2 = start_msg(skb2, NETLINK_PORTID(skb), nlh->nlmsg_seq, 0,
655+ nlh2 = start_msg(skb2, NETLINK_PORTID(skb), INFO_NLH(info, nlh)->nlmsg_seq, 0,
656 IPSET_CMD_GET_BYINDEX);
657 if (!nlh2)
658 goto nlmsg_failure;
659@@ -2173,11 +2155,7 @@ IPSET_CBFN(ip_set_byindex, struct net *net, struct sock *ctnl,
660 goto nla_put_failure;
661 nlmsg_end(skb2, nlh2);
662
663- ret = netlink_unicast(ctnl, skb2, NETLINK_PORTID(skb), MSG_DONTWAIT);
664- if (ret < 0)
665- return ret;
666-
667- return 0;
668+ return NFNETLINK_UNICAST(INFO_SK(info, ctnl), skb2, INFO_NET(info, net), NETLINK_PORTID(skb));
669
670 nla_put_failure:
671 nlmsg_cancel(skb2, nlh2);
672@@ -2189,80 +2167,96 @@ nlmsg_failure:
673 static const struct nfnl_callback ip_set_netlink_subsys_cb[IPSET_MSG_MAX] = {
674 [IPSET_CMD_NONE] = {
675 .call = ip_set_none,
676+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
677 .attr_count = IPSET_ATTR_CMD_MAX,
678 },
679 [IPSET_CMD_CREATE] = {
680 .call = ip_set_create,
681+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
682 .attr_count = IPSET_ATTR_CMD_MAX,
683 .policy = ip_set_create_policy,
684 },
685 [IPSET_CMD_DESTROY] = {
686 .call = ip_set_destroy,
687+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
688 .attr_count = IPSET_ATTR_CMD_MAX,
689 .policy = ip_set_setname_policy,
690 },
691 [IPSET_CMD_FLUSH] = {
692 .call = ip_set_flush,
693+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
694 .attr_count = IPSET_ATTR_CMD_MAX,
695 .policy = ip_set_setname_policy,
696 },
697 [IPSET_CMD_RENAME] = {
698 .call = ip_set_rename,
699+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
700 .attr_count = IPSET_ATTR_CMD_MAX,
701 .policy = ip_set_setname2_policy,
702 },
703 [IPSET_CMD_SWAP] = {
704 .call = ip_set_swap,
705+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
706 .attr_count = IPSET_ATTR_CMD_MAX,
707 .policy = ip_set_setname2_policy,
708 },
709 [IPSET_CMD_LIST] = {
710 .call = ip_set_dump,
711+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
712 .attr_count = IPSET_ATTR_CMD_MAX,
713 .policy = ip_set_dump_policy,
714 },
715 [IPSET_CMD_SAVE] = {
716 .call = ip_set_dump,
717+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
718 .attr_count = IPSET_ATTR_CMD_MAX,
719 .policy = ip_set_setname_policy,
720 },
721 [IPSET_CMD_ADD] = {
722 .call = ip_set_uadd,
723+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
724 .attr_count = IPSET_ATTR_CMD_MAX,
725 .policy = ip_set_adt_policy,
726 },
727 [IPSET_CMD_DEL] = {
728 .call = ip_set_udel,
729+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
730 .attr_count = IPSET_ATTR_CMD_MAX,
731 .policy = ip_set_adt_policy,
732 },
733 [IPSET_CMD_TEST] = {
734 .call = ip_set_utest,
735+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
736 .attr_count = IPSET_ATTR_CMD_MAX,
737 .policy = ip_set_adt_policy,
738 },
739 [IPSET_CMD_HEADER] = {
740 .call = ip_set_header,
741+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
742 .attr_count = IPSET_ATTR_CMD_MAX,
743 .policy = ip_set_setname_policy,
744 },
745 [IPSET_CMD_TYPE] = {
746 .call = ip_set_type,
747+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
748 .attr_count = IPSET_ATTR_CMD_MAX,
749 .policy = ip_set_type_policy,
750 },
751 [IPSET_CMD_PROTOCOL] = {
752 .call = ip_set_protocol,
753+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
754 .attr_count = IPSET_ATTR_CMD_MAX,
755 .policy = ip_set_protocol_policy,
756 },
757 [IPSET_CMD_GET_BYNAME] = {
758 .call = ip_set_byname,
759+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
760 .attr_count = IPSET_ATTR_CMD_MAX,
761 .policy = ip_set_setname_policy,
762 },
763 [IPSET_CMD_GET_BYINDEX] = {
764 .call = ip_set_byindex,
765+ SET_NFNL_CALLBACK_TYPE(NFNL_CB_MUTEX)
766 .attr_count = IPSET_ATTR_CMD_MAX,
767 .policy = ip_set_index_policy,
768 },
769diff --git a/lib/ipset.c b/lib/ipset.c
770index 6729919..73e67db 100644
771--- a/lib/ipset.c
772+++ b/lib/ipset.c
773@@ -13,6 +13,7 @@
774 #include <stdio.h> /* printf */
775 #include <stdlib.h> /* exit */
776 #include <string.h> /* str* */
777+#include <inttypes.h> /* PRIu64 */
778
779 #include <config.h>
780
781@@ -28,6 +29,7 @@
782 #include <libipset/utils.h> /* STREQ */
783 #include <libipset/ipset.h> /* prototypes */
784 #include <libipset/ip_set_compiler.h> /* compiler attributes */
785+#include <libipset/list_sort.h> /* lists */
786
787 static char program_name[] = PACKAGE;
788 static char program_version[] = PACKAGE_VERSION;
789@@ -50,6 +52,17 @@ struct ipset {
790 char *newargv[MAX_ARGS];
791 int newargc;
792 const char *filename; /* Input/output filename */
793+ bool xlate;
794+ struct list_head xlate_sets;
795+};
796+
797+struct ipset_xlate_set {
798+ struct list_head list;
799+ char name[IPSET_MAXNAMELEN];
800+ uint8_t netmask;
801+ uint8_t family;
802+ bool interval;
803+ const struct ipset_type *type;
804 };
805
806 /* Commands and environment options */
807@@ -923,20 +936,33 @@ static const char *cmd_prefix[] = {
808 [IPSET_TEST] = "test SETNAME",
809 };
810
811-/* Workhorses */
812+static const struct ipset_xlate_set *
813+ipset_xlate_set_get(struct ipset *ipset, const char *name)
814+{
815+ const struct ipset_xlate_set *set;
816
817-/**
818- * ipset_parse_argv - parse and argv array and execute the command
819- * @ipset: ipset structure
820- * @argc: length of the array
821- * @argv: array of strings
822- *
823- * Parse an array of strings and execute the ipset command.
824- *
825- * Returns 0 on success or a negative error code.
826- */
827-int
828-ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
829+ list_for_each_entry(set, &ipset->xlate_sets, list) {
830+ if (!strcmp(set->name, name))
831+ return set;
832+ }
833+
834+ return NULL;
835+}
836+
837+static const struct ipset_type *ipset_xlate_type_get(struct ipset *ipset,
838+ const char *name)
839+{
840+ const struct ipset_xlate_set *set;
841+
842+ set = ipset_xlate_set_get(ipset, name);
843+ if (!set)
844+ return NULL;
845+
846+ return set->type;
847+}
848+
849+static int
850+ipset_parser(struct ipset *ipset, int oargc, char *oargv[])
851 {
852 int ret = 0;
853 enum ipset_cmd cmd = IPSET_CMD_NONE;
854@@ -1243,7 +1269,7 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
855 return ipset->custom_error(ipset,
856 p, IPSET_PARAMETER_PROBLEM,
857 "Unknown argument %s", argv[1]);
858- return restore(ipset);
859+ return IPSET_CMD_RESTORE;
860 case IPSET_CMD_ADD:
861 case IPSET_CMD_DEL:
862 case IPSET_CMD_TEST:
863@@ -1253,7 +1279,12 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
864 if (ret < 0)
865 return ipset->standard_error(ipset, p);
866
867- type = ipset_type_get(session, cmd);
868+ if (!ipset->xlate) {
869+ type = ipset_type_get(session, cmd);
870+ } else {
871+ type = ipset_xlate_type_get(ipset, arg0);
872+ ipset_session_data_set(session, IPSET_OPT_TYPE, type);
873+ }
874 if (type == NULL)
875 return ipset->standard_error(ipset, p);
876
877@@ -1280,6 +1311,37 @@ ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
878 if (argc > 1)
879 return ipset->custom_error(ipset, p, IPSET_PARAMETER_PROBLEM,
880 "Unknown argument %s", argv[1]);
881+
882+ return cmd;
883+}
884+
885+/* Workhorses */
886+
887+/**
888+ * ipset_parse_argv - parse and argv array and execute the command
889+ * @ipset: ipset structure
890+ * @argc: length of the array
891+ * @argv: array of strings
892+ *
893+ * Parse an array of strings and execute the ipset command.
894+ *
895+ * Returns 0 on success or a negative error code.
896+ */
897+int
898+ipset_parse_argv(struct ipset *ipset, int oargc, char *oargv[])
899+{
900+ struct ipset_session *session = ipset->session;
901+ void *p = ipset_session_printf_private(session);
902+ enum ipset_cmd cmd;
903+ int ret;
904+
905+ cmd = ipset_parser(ipset, oargc, oargv);
906+ if (cmd < 0)
907+ return cmd;
908+
909+ if (cmd == IPSET_CMD_RESTORE)
910+ return restore(ipset);
911+
912 ret = ipset_cmd(session, cmd, ipset->restore_line);
913 D("ret %d", ret);
914 /* In the case of warning, the return code is success */
915@@ -1455,6 +1517,9 @@ ipset_init(void)
916 return NULL;
917 }
918 ipset_custom_printf(ipset, NULL, NULL, NULL, NULL);
919+
920+ INIT_LIST_HEAD(&ipset->xlate_sets);
921+
922 return ipset;
923 }
924
925@@ -1469,6 +1534,8 @@ ipset_init(void)
926 int
927 ipset_fini(struct ipset *ipset)
928 {
929+ struct ipset_xlate_set *xlate_set, *next;
930+
931 assert(ipset);
932
933 if (ipset->session)
934@@ -1477,6 +1544,497 @@ ipset_fini(struct ipset *ipset)
935 if (ipset->newargv[0])
936 free(ipset->newargv[0]);
937
938+ list_for_each_entry_safe(xlate_set, next, &ipset->xlate_sets, list)
939+ free(xlate_set);
940+
941 free(ipset);
942 return 0;
943 }
944+
945+/* Ignore the set family, use inet. */
946+static const char *ipset_xlate_family(uint8_t family)
947+{
948+ return "inet";
949+}
950+
951+enum ipset_xlate_set_type {
952+ IPSET_XLATE_TYPE_UNKNOWN = 0,
953+ IPSET_XLATE_TYPE_HASH_MAC,
954+ IPSET_XLATE_TYPE_HASH_IP,
955+ IPSET_XLATE_TYPE_HASH_IP_MAC,
956+ IPSET_XLATE_TYPE_HASH_NET_IFACE,
957+ IPSET_XLATE_TYPE_HASH_NET_PORT,
958+ IPSET_XLATE_TYPE_HASH_NET_PORT_NET,
959+ IPSET_XLATE_TYPE_HASH_NET_NET,
960+ IPSET_XLATE_TYPE_HASH_NET,
961+ IPSET_XLATE_TYPE_HASH_IP_PORT_NET,
962+ IPSET_XLATE_TYPE_HASH_IP_PORT_IP,
963+ IPSET_XLATE_TYPE_HASH_IP_MARK,
964+ IPSET_XLATE_TYPE_HASH_IP_PORT,
965+ IPSET_XLATE_TYPE_BITMAP_PORT,
966+ IPSET_XLATE_TYPE_BITMAP_IP_MAC,
967+ IPSET_XLATE_TYPE_BITMAP_IP,
968+};
969+
970+static enum ipset_xlate_set_type ipset_xlate_set_type(const char *typename)
971+{
972+ if (!strcmp(typename, "hash:mac"))
973+ return IPSET_XLATE_TYPE_HASH_MAC;
974+ else if (!strcmp(typename, "hash:ip"))
975+ return IPSET_XLATE_TYPE_HASH_IP;
976+ else if (!strcmp(typename, "hash:ip,mac"))
977+ return IPSET_XLATE_TYPE_HASH_IP_MAC;
978+ else if (!strcmp(typename, "hash:net,iface"))
979+ return IPSET_XLATE_TYPE_HASH_NET_IFACE;
980+ else if (!strcmp(typename, "hash:net,port"))
981+ return IPSET_XLATE_TYPE_HASH_NET_PORT;
982+ else if (!strcmp(typename, "hash:net,port,net"))
983+ return IPSET_XLATE_TYPE_HASH_NET_PORT_NET;
984+ else if (!strcmp(typename, "hash:net,net"))
985+ return IPSET_XLATE_TYPE_HASH_NET_NET;
986+ else if (!strcmp(typename, "hash:net"))
987+ return IPSET_XLATE_TYPE_HASH_NET;
988+ else if (!strcmp(typename, "hash:ip,port,net"))
989+ return IPSET_XLATE_TYPE_HASH_IP_PORT_NET;
990+ else if (!strcmp(typename, "hash:ip,port,ip"))
991+ return IPSET_XLATE_TYPE_HASH_IP_PORT_IP;
992+ else if (!strcmp(typename, "hash:ip,mark"))
993+ return IPSET_XLATE_TYPE_HASH_IP_MARK;
994+ else if (!strcmp(typename, "hash:ip,port"))
995+ return IPSET_XLATE_TYPE_HASH_IP_PORT;
996+ else if (!strcmp(typename, "hash:ip"))
997+ return IPSET_XLATE_TYPE_HASH_IP;
998+ else if (!strcmp(typename, "bitmap:port"))
999+ return IPSET_XLATE_TYPE_BITMAP_PORT;
1000+ else if (!strcmp(typename, "bitmap:ip,mac"))
1001+ return IPSET_XLATE_TYPE_BITMAP_IP_MAC;
1002+ else if (!strcmp(typename, "bitmap:ip"))
1003+ return IPSET_XLATE_TYPE_BITMAP_IP;
1004+
1005+ return IPSET_XLATE_TYPE_UNKNOWN;
1006+}
1007+
1008+#define NFT_SET_INTERVAL (1 << 0)
1009+
1010+static const char *
1011+ipset_xlate_type_to_nftables(int family, enum ipset_xlate_set_type type,
1012+ uint32_t *flags)
1013+{
1014+ switch (type) {
1015+ case IPSET_XLATE_TYPE_HASH_MAC:
1016+ return "ether_addr";
1017+ case IPSET_XLATE_TYPE_HASH_IP:
1018+ if (family == AF_INET)
1019+ return "ipv4_addr";
1020+ else if (family == AF_INET6)
1021+ return "ipv6_addr";
1022+ break;
1023+ case IPSET_XLATE_TYPE_HASH_IP_MAC:
1024+ if (family == AF_INET)
1025+ return "ipv4_addr . ether_addr";
1026+ else if (family == AF_INET6)
1027+ return "ipv6_addr . ether_addr";
1028+ break;
1029+ case IPSET_XLATE_TYPE_HASH_NET_IFACE:
1030+ *flags |= NFT_SET_INTERVAL;
1031+ if (family == AF_INET)
1032+ return "ipv4_addr . ifname";
1033+ else if (family == AF_INET6)
1034+ return "ipv6_addr . ifname";
1035+ break;
1036+ case IPSET_XLATE_TYPE_HASH_NET_PORT:
1037+ *flags |= NFT_SET_INTERVAL;
1038+ if (family == AF_INET)
1039+ return "ipv4_addr . inet_proto . inet_service";
1040+ else if (family == AF_INET6)
1041+ return "ipv6_addr . inet_proto . inet_service";
1042+ break;
1043+ case IPSET_XLATE_TYPE_HASH_NET_PORT_NET:
1044+ *flags |= NFT_SET_INTERVAL;
1045+ if (family == AF_INET)
1046+ return "ipv4_addr . inet_proto . inet_service . ipv4_addr";
1047+ else if (family == AF_INET6)
1048+ return "ipv6_addr . inet_proto . inet_service . ipv6_addr";
1049+ break;
1050+ case IPSET_XLATE_TYPE_HASH_NET_NET:
1051+ *flags |= NFT_SET_INTERVAL;
1052+ if (family == AF_INET)
1053+ return "ipv4_addr . ipv4_addr";
1054+ else if (family == AF_INET6)
1055+ return "ipv6_addr . ipv6_addr";
1056+ break;
1057+ case IPSET_XLATE_TYPE_HASH_NET:
1058+ *flags |= NFT_SET_INTERVAL;
1059+ if (family == AF_INET)
1060+ return "ipv4_addr";
1061+ else if (family == AF_INET6)
1062+ return "ipv6_addr";
1063+ break;
1064+ case IPSET_XLATE_TYPE_HASH_IP_PORT_NET:
1065+ *flags |= NFT_SET_INTERVAL;
1066+ if (family == AF_INET)
1067+ return "ipv4_addr . inet_proto . inet_service . ipv4_addr";
1068+ else if (family == AF_INET6)
1069+ return "ipv6_addr . inet_proto . inet_service . ipv6_addr";
1070+ break;
1071+ case IPSET_XLATE_TYPE_HASH_IP_PORT_IP:
1072+ if (family == AF_INET)
1073+ return "ipv4_addr . inet_proto . inet_service . ipv4_addr";
1074+ else if (family == AF_INET6)
1075+ return "ipv6_addr . inet_proto . inet_service . ipv6_addr";
1076+ break;
1077+ case IPSET_XLATE_TYPE_HASH_IP_MARK:
1078+ if (family == AF_INET)
1079+ return "ipv4_addr . mark";
1080+ else if (family == AF_INET6)
1081+ return "ipv6_addr . mark";
1082+ break;
1083+ case IPSET_XLATE_TYPE_HASH_IP_PORT:
1084+ if (family == AF_INET)
1085+ return "ipv4_addr . inet_proto . inet_service";
1086+ else if (family == AF_INET6)
1087+ return "ipv6_addr . inet_proto . inet_service";
1088+ break;
1089+ case IPSET_XLATE_TYPE_BITMAP_PORT:
1090+ return "inet_service";
1091+ case IPSET_XLATE_TYPE_BITMAP_IP_MAC:
1092+ if (family == AF_INET)
1093+ return "ipv4_addr . ether_addr";
1094+ else if (family == AF_INET6)
1095+ return "ipv6_addr . ether_addr";
1096+ break;
1097+ case IPSET_XLATE_TYPE_BITMAP_IP:
1098+ if (family == AF_INET)
1099+ return "ipv4_addr";
1100+ else if (family == AF_INET6)
1101+ return "ipv6_addr";
1102+ break;
1103+ }
1104+ /* This should not ever happen. */
1105+ return "unknown";
1106+}
1107+
1108+static int ipset_xlate(struct ipset *ipset, enum ipset_cmd cmd,
1109+ const char *table)
1110+{
1111+ const char *set, *typename, *nft_type;
1112+ const struct ipset_type *ipset_type;
1113+ struct ipset_xlate_set *xlate_set;
1114+ enum ipset_xlate_set_type type;
1115+ struct ipset_session *session;
1116+ const uint32_t *cadt_flags;
1117+ const uint32_t *timeout;
1118+ const uint32_t *maxelem;
1119+ struct ipset_data *data;
1120+ const uint8_t *netmask;
1121+ const char *comment;
1122+ uint32_t flags = 0;
1123+ uint8_t family;
1124+ char buf[64];
1125+ bool concat;
1126+ char *term;
1127+ int i;
1128+
1129+ session = ipset_session(ipset);
1130+ data = ipset_session_data(session);
1131+
1132+ set = ipset_data_get(data, IPSET_SETNAME);
1133+ family = ipset_data_family(data);
1134+
1135+ switch (cmd) {
1136+ case IPSET_CMD_CREATE:
1137+ /* Not supported. */
1138+ if (ipset_data_test(data, IPSET_OPT_MARKMASK)) {
1139+ printf("# %s", ipset->cmdline);
1140+ break;
1141+ }
1142+ cadt_flags = ipset_data_get(data, IPSET_OPT_CADT_FLAGS);
1143+
1144+ /* Ignore:
1145+ * - IPSET_FLAG_WITH_COMMENT
1146+ * - IPSET_FLAG_WITH_FORCEADD
1147+ */
1148+ if (cadt_flags &&
1149+ (*cadt_flags & (IPSET_FLAG_BEFORE |
1150+ IPSET_FLAG_PHYSDEV |
1151+ IPSET_FLAG_NOMATCH |
1152+ IPSET_FLAG_WITH_SKBINFO |
1153+ IPSET_FLAG_IFACE_WILDCARD))) {
1154+ printf("# %s", ipset->cmdline);
1155+ break;
1156+ }
1157+
1158+ typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
1159+ type = ipset_xlate_set_type(typename);
1160+ nft_type = ipset_xlate_type_to_nftables(family, type, &flags);
1161+
1162+ printf("add set %s %s %s { type %s; ",
1163+ ipset_xlate_family(family), table, set, nft_type);
1164+ if (cadt_flags) {
1165+ if (*cadt_flags & IPSET_FLAG_WITH_COUNTERS)
1166+ printf("counter; ");
1167+ }
1168+ timeout = ipset_data_get(data, IPSET_OPT_TIMEOUT);
1169+ if (timeout)
1170+ printf("timeout %us; ", *timeout);
1171+ maxelem = ipset_data_get(data, IPSET_OPT_MAXELEM);
1172+ if (maxelem)
1173+ printf("size %u; ", *maxelem);
1174+
1175+ netmask = ipset_data_get(data, IPSET_OPT_NETMASK);
1176+ if (netmask &&
1177+ ((family == AF_INET && *netmask < 32) ||
1178+ (family == AF_INET6 && *netmask < 128)))
1179+ flags |= NFT_SET_INTERVAL;
1180+
1181+ if (flags & NFT_SET_INTERVAL)
1182+ printf("flags interval; ");
1183+
1184+ /* These create-specific options are safe to be ignored:
1185+ * - IPSET_OPT_GC
1186+ * - IPSET_OPT_HASHSIZE
1187+ * - IPSET_OPT_PROBES
1188+ * - IPSET_OPT_RESIZE
1189+ * - IPSET_OPT_SIZE
1190+ * - IPSET_OPT_FORCEADD
1191+ *
1192+ * Ranges and CIDR are safe to be ignored too:
1193+ * - IPSET_OPT_IP_FROM
1194+ * - IPSET_OPT_IP_TO
1195+ * - IPSET_OPT_PORT_FROM
1196+ * - IPSET_OPT_PORT_TO
1197+ */
1198+
1199+ printf("}\n");
1200+
1201+ xlate_set = calloc(1, sizeof(*xlate_set));
1202+ if (!xlate_set)
1203+ return -1;
1204+
1205+ snprintf(xlate_set->name, sizeof(xlate_set->name), "%s", set);
1206+ ipset_type = ipset_types();
1207+ while (ipset_type) {
1208+ if (!strcmp(ipset_type->name, typename))
1209+ break;
1210+ ipset_type = ipset_type->next;
1211+ }
1212+
1213+ xlate_set->family = family;
1214+ xlate_set->type = ipset_type;
1215+ if (netmask) {
1216+ xlate_set->netmask = *netmask;
1217+ xlate_set->interval = true;
1218+ }
1219+ list_add_tail(&xlate_set->list, &ipset->xlate_sets);
1220+ break;
1221+ case IPSET_CMD_DESTROY:
1222+ printf("del set %s %s %s\n",
1223+ ipset_xlate_family(family), table, set);
1224+ break;
1225+ case IPSET_CMD_FLUSH:
1226+ if (!set) {
1227+ printf("# %s", ipset->cmdline);
1228+ } else {
1229+ printf("flush set %s %s %s\n",
1230+ ipset_xlate_family(family), table, set);
1231+ }
1232+ break;
1233+ case IPSET_CMD_RENAME:
1234+ printf("# %s", ipset->cmdline);
1235+ return -1;
1236+ case IPSET_CMD_SWAP:
1237+ printf("# %s", ipset->cmdline);
1238+ return -1;
1239+ case IPSET_CMD_LIST:
1240+ if (!set) {
1241+ printf("list sets %s\n",
1242+ ipset_xlate_family(family), table);
1243+ } else {
1244+ printf("list set %s %s %s\n",
1245+ ipset_xlate_family(family), table, set);
1246+ }
1247+ break;
1248+ case IPSET_CMD_SAVE:
1249+ printf("# %s", ipset->cmdline);
1250+ return -1;
1251+ case IPSET_CMD_ADD:
1252+ case IPSET_CMD_DEL:
1253+ case IPSET_CMD_TEST:
1254+ /* Not supported. */
1255+ if (ipset_data_test(data, IPSET_OPT_NOMATCH) ||
1256+ ipset_data_test(data, IPSET_OPT_SKBINFO) ||
1257+ ipset_data_test(data, IPSET_OPT_SKBMARK) ||
1258+ ipset_data_test(data, IPSET_OPT_SKBPRIO) ||
1259+ ipset_data_test(data, IPSET_OPT_SKBQUEUE) ||
1260+ ipset_data_test(data, IPSET_OPT_IFACE_WILDCARD)) {
1261+ printf("# %s", ipset->cmdline);
1262+ break;
1263+ }
1264+ printf("%s element %s %s %s { ",
1265+ cmd == IPSET_CMD_ADD ? "add" :
1266+ cmd == IPSET_CMD_DEL ? "delete" : "get",
1267+ ipset_xlate_family(family), table, set);
1268+
1269+ typename = ipset_data_get(data, IPSET_OPT_TYPENAME);
1270+ type = ipset_xlate_set_type(typename);
1271+
1272+ xlate_set = (struct ipset_xlate_set *)
1273+ ipset_xlate_set_get(ipset, set);
1274+ if (xlate_set && xlate_set->interval)
1275+ netmask = &xlate_set->netmask;
1276+ else
1277+ netmask = NULL;
1278+
1279+ concat = false;
1280+ if (ipset_data_test(data, IPSET_OPT_IP)) {
1281+ ipset_print_data(buf, sizeof(buf), data, IPSET_OPT_IP, 0);
1282+ printf("%s", buf);
1283+ if (netmask)
1284+ printf("/%u ", *netmask);
1285+ else
1286+ printf(" ");
1287+
1288+ concat = true;
1289+ }
1290+ if (ipset_data_test(data, IPSET_OPT_MARK)) {
1291+ ipset_print_mark(buf, sizeof(buf), data, IPSET_OPT_MARK, 0);
1292+ printf("%s%s ", concat ? ". " : "", buf);
1293+ }
1294+ if (ipset_data_test(data, IPSET_OPT_IFACE)) {
1295+ ipset_print_data(buf, sizeof(buf), data, IPSET_OPT_IFACE, 0);
1296+ printf("%s%s ", concat ? ". " : "", buf);
1297+ }
1298+ if (ipset_data_test(data, IPSET_OPT_ETHER)) {
1299+ ipset_print_ether(buf, sizeof(buf), data, IPSET_OPT_ETHER, 0);
1300+ for (i = 0; i < strlen(buf); i++)
1301+ buf[i] = tolower(buf[i]);
1302+
1303+ printf("%s%s ", concat ? ". " : "", buf);
1304+ concat = true;
1305+ }
1306+ if (ipset_data_test(data, IPSET_OPT_PORT)) {
1307+ ipset_print_proto_port(buf, sizeof(buf), data, IPSET_OPT_PORT, 0);
1308+ term = strchr(buf, ':');
1309+ if (term) {
1310+ *term = '\0';
1311+ printf("%s%s ", concat ? ". " : "", buf);
1312+ }
1313+ ipset_print_data(buf, sizeof(buf), data, IPSET_OPT_PORT, 0);
1314+ printf("%s%s ", concat ? ". " : "", buf);
1315+ }
1316+ if (ipset_data_test(data, IPSET_OPT_IP2)) {
1317+ ipset_print_ip(buf, sizeof(buf), data, IPSET_OPT_IP2, 0);
1318+ printf("%s%s", concat ? ". " : "", buf);
1319+ if (netmask)
1320+ printf("/%u ", *netmask);
1321+ else
1322+ printf(" ");
1323+ }
1324+ if (ipset_data_test(data, IPSET_OPT_PACKETS) &&
1325+ ipset_data_test(data, IPSET_OPT_BYTES)) {
1326+ const uint64_t *pkts, *bytes;
1327+
1328+ pkts = ipset_data_get(data, IPSET_OPT_PACKETS);
1329+ bytes = ipset_data_get(data, IPSET_OPT_BYTES);
1330+
1331+ printf("counter packets %" PRIu64 " bytes %" PRIu64 " ",
1332+ *pkts, *bytes);
1333+ }
1334+ timeout = ipset_data_get(data, IPSET_OPT_TIMEOUT);
1335+ if (timeout)
1336+ printf("timeout %us ", *timeout);
1337+
1338+ comment = ipset_data_get(data, IPSET_OPT_ADT_COMMENT);
1339+ if (comment)
1340+ printf("comment \"%s\" ", comment);
1341+
1342+ printf("}\n");
1343+ break;
1344+ case IPSET_CMD_GET_BYNAME:
1345+ printf("# %s", ipset->cmdline);
1346+ return -1;
1347+ case IPSET_CMD_GET_BYINDEX:
1348+ printf("# %s", ipset->cmdline);
1349+ return -1;
1350+ default:
1351+ break;
1352+ }
1353+
1354+ return 0;
1355+}
1356+
1357+static int ipset_xlate_restore(struct ipset *ipset)
1358+{
1359+ struct ipset_session *session = ipset_session(ipset);
1360+ struct ipset_data *data = ipset_session_data(session);
1361+ void *p = ipset_session_printf_private(session);
1362+ const char *filename;
1363+ enum ipset_cmd cmd;
1364+ FILE *f = stdin;
1365+ int ret = 0;
1366+ char *c;
1367+
1368+ if (ipset->filename) {
1369+ f = fopen(ipset->filename, "r");
1370+ if (!f) {
1371+ fprintf(stderr, "cannot open file `%s'\n", filename);
1372+ return -1;
1373+ }
1374+ }
1375+
1376+ /* TODO: Allow to specify the table name other than 'global'. */
1377+ printf("add table inet global\n");
1378+
1379+ while (fgets(ipset->cmdline, sizeof(ipset->cmdline), f)) {
1380+ ipset->restore_line++;
1381+ c = ipset->cmdline;
1382+ while (isspace(c[0]))
1383+ c++;
1384+ if (c[0] == '\0' || c[0] == '#')
1385+ continue;
1386+ else if (STREQ(c, "COMMIT\n") || STREQ(c, "COMMIT\r\n"))
1387+ continue;
1388+
1389+ ret = build_argv(ipset, c);
1390+ if (ret < 0)
1391+ return ret;
1392+
1393+ cmd = ipset_parser(ipset, ipset->newargc, ipset->newargv);
1394+ if (cmd < 0)
1395+ ipset->standard_error(ipset, p);
1396+
1397+ /* TODO: Allow to specify the table name other than 'global'. */
1398+ ret = ipset_xlate(ipset, cmd, "global");
1399+ if (ret < 0)
1400+ break;
1401+
1402+ ipset_data_reset(data);
1403+ }
1404+
1405+ if (filename)
1406+ fclose(f);
1407+
1408+ return ret;
1409+}
1410+
1411+int ipset_xlate_argv(struct ipset *ipset, int argc, char *argv[])
1412+{
1413+ enum ipset_cmd cmd;
1414+ int ret;
1415+
1416+ ipset->xlate = true;
1417+
1418+ cmd = ipset_parser(ipset, argc, argv);
1419+ if (cmd < 0)
1420+ return cmd;
1421+
1422+ if (cmd == IPSET_CMD_RESTORE) {
1423+ ret = ipset_xlate_restore(ipset);
1424+ } else {
1425+ fprintf(stderr, "This command is not supported, "
1426+ "use `ipset-translate restore < file'\n");
1427+ ret = -1;
1428+ }
1429+
1430+ return ret;
1431+}
1432diff --git a/lib/parse.c b/lib/parse.c
1433index f3f2d11..9cba252 100644
1434--- a/lib/parse.c
1435+++ b/lib/parse.c
1436@@ -41,6 +41,9 @@
1437 #define syntax_err(fmt, args...) \
1438 ipset_err(session, "Syntax error: " fmt , ## args)
1439
1440+#define syntax_err_ll(errtype, fmt, args...) \
1441+ ipset_session_report(session, errtype, "Syntax error: " fmt , ## args)
1442+
1443 static char *
1444 ipset_strchr(const char *str, const char *sep)
1445 {
1446@@ -87,7 +90,8 @@ string_to_number_ll(struct ipset_session *session,
1447 const char *str,
1448 unsigned long long min,
1449 unsigned long long max,
1450- unsigned long long *ret)
1451+ unsigned long long *ret,
1452+ enum ipset_err_type errtype)
1453 {
1454 unsigned long long number = 0;
1455 char *end;
1456@@ -104,13 +108,13 @@ string_to_number_ll(struct ipset_session *session,
1457 errno = ERANGE;
1458 }
1459 if (errno == ERANGE && max)
1460- return syntax_err("'%s' is out of range %llu-%llu",
1461- str, min, max);
1462+ return syntax_err_ll(errtype, "'%s' is out of range %llu-%llu",
1463+ str, min, max);
1464 else if (errno == ERANGE)
1465- return syntax_err("'%s' is out of range %llu-%llu",
1466- str, min, ULLONG_MAX);
1467+ return syntax_err_ll(errtype, "'%s' is out of range %llu-%llu",
1468+ str, min, ULLONG_MAX);
1469 else
1470- return syntax_err("'%s' is invalid as number", str);
1471+ return syntax_err_ll(errtype, "'%s' is invalid as number", str);
1472 }
1473
1474 static int
1475@@ -120,7 +124,7 @@ string_to_u8(struct ipset_session *session,
1476 int err;
1477 unsigned long long num = 0;
1478
1479- err = string_to_number_ll(session, str, 0, 255, &num);
1480+ err = string_to_number_ll(session, str, 0, 255, &num, IPSET_ERROR);
1481 *ret = num;
1482
1483 return err;
1484@@ -141,12 +145,13 @@ string_to_cidr(struct ipset_session *session,
1485
1486 static int
1487 string_to_u16(struct ipset_session *session,
1488- const char *str, uint16_t *ret)
1489+ const char *str, uint16_t *ret,
1490+ enum ipset_err_type errtype)
1491 {
1492 int err;
1493 unsigned long long num = 0;
1494
1495- err = string_to_number_ll(session, str, 0, USHRT_MAX, &num);
1496+ err = string_to_number_ll(session, str, 0, USHRT_MAX, &num, errtype);
1497 *ret = num;
1498
1499 return err;
1500@@ -159,7 +164,8 @@ string_to_u32(struct ipset_session *session,
1501 int err;
1502 unsigned long long num = 0;
1503
1504- err = string_to_number_ll(session, str, 0, UINT_MAX, &num);
1505+ err = string_to_number_ll(session, str, 0, UINT_MAX, &num,
1506+ IPSET_ERROR);
1507 *ret = num;
1508
1509 return err;
1510@@ -319,7 +325,7 @@ ipset_parse_port(struct ipset_session *session,
1511 assert(opt == IPSET_OPT_PORT || opt == IPSET_OPT_PORT_TO);
1512 assert(str);
1513
1514- if (string_to_u16(session, str, &port) == 0) {
1515+ if (string_to_u16(session, str, &port, IPSET_WARNING) == 0) {
1516 return ipset_session_data_set(session, opt, &port);
1517 }
1518 /* Error is stored as warning in session report */
1519@@ -1335,7 +1341,8 @@ ipset_parse_timeout(struct ipset_session *session,
1520 assert(opt == IPSET_OPT_TIMEOUT);
1521 assert(str);
1522
1523- err = string_to_number_ll(session, str, 0, (UINT_MAX>>1)/1000, &llnum);
1524+ err = string_to_number_ll(session, str, 0, (UINT_MAX>>1)/1000, &llnum,
1525+ IPSET_ERROR);
1526 if (err == 0) {
1527 /* Timeout is expected to be 32bits wide, so we have
1528 to convert it here */
1529@@ -1579,7 +1586,8 @@ ipset_parse_uint64(struct ipset_session *session,
1530 assert(session);
1531 assert(str);
1532
1533- err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value);
1534+ err = string_to_number_ll(session, str, 0, ULLONG_MAX - 1, &value,
1535+ IPSET_ERROR);
1536 if (err)
1537 return err;
1538
1539@@ -1623,7 +1631,7 @@ ipset_parse_uint16(struct ipset_session *session,
1540 assert(session);
1541 assert(str);
1542
1543- err = string_to_u16(session, str, &value);
1544+ err = string_to_u16(session, str, &value, IPSET_ERROR);
1545 if (err == 0)
1546 return ipset_session_data_set(session, opt, &value);
1547
1548diff --git a/src/Makefile.am b/src/Makefile.am
1549index 438fcec..95dea07 100644
1550--- a/src/Makefile.am
1551+++ b/src/Makefile.am
1552@@ -12,10 +12,16 @@ AM_LDFLAGS = -static
1553 endif
1554 endif
1555
1556-dist_man_MANS = ipset.8
1557+dist_man_MANS = ipset.8 ipset-translate.8
1558
1559 sparse-check: $(ipset_SOURCES:.c=.d)
1560
1561 %.d: %.c
1562 $(IPSET_AM_V_CHECK)\
1563 $(SPARSE) -I.. $(SPARSE_FLAGS) $(AM_CFLAGS) $(AM_CPPFLAGS) $< || :
1564+
1565+install-exec-hook:
1566+ ${LN_S} -f "${sbindir}/ipset" "${DESTDIR}${sbindir}/ipset-translate";
1567+
1568+uninstall-hook:
1569+ rm -f ${DESTDIR}${sbindir}/ipset-translate
1570diff --git a/src/ipset-translate.8 b/src/ipset-translate.8
1571new file mode 100644
1572index 0000000..bb4e737
1573--- /dev/null
1574+++ b/src/ipset-translate.8
1575@@ -0,0 +1,91 @@
1576+.\"
1577+.\" (C) Copyright 2021, Pablo Neira Ayuso <pablo@netfilter.org>
1578+.\"
1579+.\" %%%LICENSE_START(GPLv2+_DOC_FULL)
1580+.\" This is free documentation; you can redistribute it and/or
1581+.\" modify it under the terms of the GNU General Public License as
1582+.\" published by the Free Software Foundation; either version 2 of
1583+.\" the License, or (at your option) any later version.
1584+.\"
1585+.\" The GNU General Public License's references to "object code"
1586+.\" and "executables" are to be interpreted as the output of any
1587+.\" document formatting or typesetting system, including
1588+.\" intermediate and printed output.
1589+.\"
1590+.\" This manual is distributed in the hope that it will be useful,
1591+.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
1592+.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1593+.\" GNU General Public License for more details.
1594+.\"
1595+.\" You should have received a copy of the GNU General Public
1596+.\" License along with this manual; if not, see
1597+.\" <http://www.gnu.org/licenses/>.
1598+.\" %%%LICENSE_END
1599+.\"
1600+.TH IPSET-TRANSLATE 8 "May 31, 2021"
1601+
1602+.SH NAME
1603+ipset-translate \(em translation tool to migrate from ipset to nftables
1604+.SH DESCRIPTION
1605+This tool allows system administrators to translate a given IP sets file
1606+to \fBnftables(8)\fP.
1607+
1608+The only available command is:
1609+
1610+.IP \[bu] 2
1611+ipset-translate restores < file.ipt
1612+
1613+.SH USAGE
1614+The \fBipset-translate\fP tool reads an IP sets file in the syntax produced by
1615+\fBipset(8)\fP save. No set modifications occur, this tool is a text converter.
1616+
1617+.SH EXAMPLES
1618+Basic operation examples.
1619+
1620+Single command translation, assuming the original file:
1621+
1622+.nf
1623+create test1 hash:ip,port family inet counters timeout 300 hashsize 1024 maxelem 65536 bucketsize 12 initval 0xb5c4be5d
1624+add test1 1.1.1.1,udp:20
1625+add test1 1.1.1.1,21
1626+create test2 hash:ip,port family inet hashsize 1024 maxelem 65536 bucketsize 12 initval 0xb5c4be5d
1627+.fi
1628+
1629+which results in the following translation:
1630+
1631+.nf
1632+root@machine:~# ipset-translate restore < file.ipt
1633+add set inet global test1 { type ipv4_addr . inet_proto . inet_service; counter; timeout 300s; size 65536; }
1634+add element inet global test1 { 1.1.1.1 . udp . 20 }
1635+add element inet global test1 { 1.1.1.1 . tcp . 21 }
1636+add set inet global test2 { type ipv4_addr . inet_proto . inet_service; size 65536; }
1637+.fi
1638+
1639+.SH LIMITATIONS
1640+A few IP sets options may be not supported because they are not yet implemented
1641+in \fBnftables(8)\fP.
1642+
1643+Contrary to \fBnftables(8)\fP, IP sets are not attached to a specific table.
1644+The translation utility assumes that sets are created in a table whose name
1645+is \fBglobal\fP and family is \fBinet\fP. You might want to update the
1646+resulting translation to use a different table name and family for your sets.
1647+
1648+To get up-to-date information about this, please head to
1649+\fBhttps://wiki.nftables.org/\fP.
1650+
1651+.SH SEE ALSO
1652+\fBnft(8)\fP, \fBipset(8)\fP
1653+
1654+.SH AUTHORS
1655+The nftables framework has been written by the Netfilter Project
1656+(https://www.netfilter.org).
1657+
1658+This manual page was written by Pablo Neira Ayuso
1659+<pablo@netfilter.org>.
1660+
1661+This documentation is free/libre under the terms of the GPLv2+.
1662+
1663+This tool was funded through the NGI0 PET Fund, a fund established by NLnet with
1664+financial support from the European Commission's Next Generation Internet
1665+programme, under the aegis of DG Communications Networks, Content and Technology
1666+under grant agreement No 825310.
1667diff --git a/src/ipset.8 b/src/ipset.8
1668index 97cece9..269b9b5 100644
1669--- a/src/ipset.8
1670+++ b/src/ipset.8
1671@@ -333,7 +333,7 @@ are hex without 0x prefix.
1672 .IP
1673 ipset create foo hash:ip skbinfo
1674 .IP
1675-ipset add foo skbmark 0x1111/0xff00ffff skbprio 1:10 skbqueue 10
1676+ipset add foo 192.168.0.1 skbmark 0x1111/0xff00ffff skbprio 1:10 skbqueue 10
1677 .PP
1678 .SS hashsize
1679 This parameter is valid for the \fBcreate\fR command of all \fBhash\fR type sets.
1680diff --git a/src/ipset.c b/src/ipset.c
1681index ee36a06..6d42b60 100644
1682--- a/src/ipset.c
1683+++ b/src/ipset.c
1684@@ -9,9 +9,11 @@
1685 #include <assert.h> /* assert */
1686 #include <stdio.h> /* fprintf */
1687 #include <stdlib.h> /* exit */
1688+#include <string.h> /* strcmp */
1689
1690 #include <config.h>
1691 #include <libipset/ipset.h> /* ipset library */
1692+#include <libipset/xlate.h> /* translate to nftables */
1693
1694 int
1695 main(int argc, char *argv[])
1696@@ -29,7 +31,11 @@ main(int argc, char *argv[])
1697 exit(1);
1698 }
1699
1700- ret = ipset_parse_argv(ipset, argc, argv);
1701+ if (!strcmp(argv[0], "ipset-translate")) {
1702+ ret = ipset_xlate_argv(ipset, argc, argv);
1703+ } else {
1704+ ret = ipset_parse_argv(ipset, argc, argv);
1705+ }
1706
1707 ipset_fini(ipset);
1708
1709diff --git a/tests/xlate/runtest.sh b/tests/xlate/runtest.sh
1710new file mode 100755
1711index 0000000..a2a02c0
1712--- /dev/null
1713+++ b/tests/xlate/runtest.sh
1714@@ -0,0 +1,29 @@
1715+#!/bin/bash
1716+
1717+DIFF=$(which diff)
1718+if [ ! -x "$DIFF" ] ; then
1719+ echo "ERROR: missing diff"
1720+ exit 1
1721+fi
1722+
1723+IPSET_XLATE=$(which ipset-translate)
1724+if [ ! -x "$IPSET_XLATE" ] ; then
1725+ echo "ERROR: ipset-translate is not installed yet"
1726+ exit 1
1727+fi
1728+
1729+TMP=$(mktemp)
1730+ipset-translate restore < xlate.t &> $TMP
1731+if [ $? -ne 0 ]
1732+then
1733+ cat $TMP
1734+ echo -e "[\033[0;31mERROR\033[0m] failed to run ipset-translate"
1735+ exit 1
1736+fi
1737+${DIFF} -u xlate.t.nft $TMP
1738+if [ $? -eq 0 ]
1739+then
1740+ echo -e "[\033[0;32mOK\033[0m] tests are fine!"
1741+else
1742+ echo -e "[\033[0;31mERROR\033[0m] unexpected ipset to nftables translation"
1743+fi
1744diff --git a/tests/xlate/xlate.t b/tests/xlate/xlate.t
1745new file mode 100644
1746index 0000000..b1e7d28
1747--- /dev/null
1748+++ b/tests/xlate/xlate.t
1749@@ -0,0 +1,55 @@
1750+create hip1 hash:ip
1751+add hip1 192.168.10.2
1752+add hip1 192.168.10.3
1753+create hip2 hash:ip hashsize 128 bucketsize 255 timeout 4
1754+add hip2 192.168.10.3
1755+add hip2 192.168.10.4 timeout 10
1756+create hip3 hash:ip counters
1757+add hip3 192.168.10.3 packets 5 bytes 3456
1758+create hip4 hash:ip netmask 24
1759+add hip4 192.168.10.0
1760+create hip5 hash:ip maxelem 24
1761+add hip5 192.168.10.0
1762+create hip6 hash:ip comment
1763+add hip5 192.168.10.1
1764+add hip5 192.168.10.2 comment "this is a comment"
1765+create ipp1 hash:ip,port
1766+add ipp1 192.168.10.1,0
1767+add ipp1 192.168.10.2,5
1768+create ipp2 hash:ip,port timeout 4
1769+add ipp2 192.168.10.1,0 timeout 12
1770+add ipp2 192.168.10.2,5
1771+create ipp3 hash:ip,port counters
1772+add ipp3 192.168.10.3,20 packets 5 bytes 3456
1773+create ipp4 hash:ip,port timeout 4 counters
1774+add ipp4 192.168.10.3,20 packets 5 bytes 3456
1775+create bip1 bitmap:ip range 2.0.0.1-2.1.0.1 timeout 5
1776+create bip2 bitmap:ip range 10.0.0.0/8 netmask 24 timeout 5
1777+add bip2 10.10.10.0
1778+add bip2 10.10.20.0 timeout 12
1779+create net1 hash:net
1780+add net1 192.168.10.0/24
1781+create net2 hash:net,net
1782+add net2 192.168.10.0/24,192.168.20.0/24
1783+create hm1 hash:mac
1784+add hm1 aa:bb:cc:dd:ee:ff
1785+create him1 hash:ip,mac
1786+add him1 1.1.1.1,aa:bb:cc:dd:ee:ff
1787+create ni1 hash:net,iface
1788+add ni1 1.1.1.0/24,eth0
1789+create nip1 hash:net,port
1790+add nip1 1.1.1.0/24,22
1791+create npn1 hash:net,port,net
1792+add npn1 1.1.1.0/24,22,2.2.2.0/24
1793+create nn1 hash:net,net
1794+add nn1 1.1.1.0/24,2.2.2.0/24
1795+create ipn1 hash:ip,port,net
1796+add ipn1 1.1.1.1,22,2.2.2.0/24
1797+create ipi1 hash:ip,port,ip
1798+add ipi1 1.1.1.1,22,2.2.2.2
1799+create im1 hash:ip,mark
1800+add im1 1.1.1.1,0x123456
1801+create bp1 bitmap:port range 1-1024
1802+add bp1 22
1803+create bim1 bitmap:ip,mac range 1.1.1.0/24
1804+add bim1 1.1.1.1,aa:bb:cc:dd:ee:ff
1805diff --git a/tests/xlate/xlate.t.nft b/tests/xlate/xlate.t.nft
1806new file mode 100644
1807index 0000000..96eba3b
1808--- /dev/null
1809+++ b/tests/xlate/xlate.t.nft
1810@@ -0,0 +1,56 @@
1811+add table inet global
1812+add set inet global hip1 { type ipv4_addr; }
1813+add element inet global hip1 { 192.168.10.2 }
1814+add element inet global hip1 { 192.168.10.3 }
1815+add set inet global hip2 { type ipv4_addr; timeout 4s; }
1816+add element inet global hip2 { 192.168.10.3 }
1817+add element inet global hip2 { 192.168.10.4 timeout 10s }
1818+add set inet global hip3 { type ipv4_addr; counter; }
1819+add element inet global hip3 { 192.168.10.3 counter packets 5 bytes 3456 }
1820+add set inet global hip4 { type ipv4_addr; flags interval; }
1821+add element inet global hip4 { 192.168.10.0/24 }
1822+add set inet global hip5 { type ipv4_addr; size 24; }
1823+add element inet global hip5 { 192.168.10.0 }
1824+add set inet global hip6 { type ipv4_addr; }
1825+add element inet global hip5 { 192.168.10.1 }
1826+add element inet global hip5 { 192.168.10.2 comment "this is a comment" }
1827+add set inet global ipp1 { type ipv4_addr . inet_proto . inet_service; }
1828+add element inet global ipp1 { 192.168.10.1 . tcp . 0 }
1829+add element inet global ipp1 { 192.168.10.2 . tcp . 5 }
1830+add set inet global ipp2 { type ipv4_addr . inet_proto . inet_service; timeout 4s; }
1831+add element inet global ipp2 { 192.168.10.1 . tcp . 0 timeout 12s }
1832+add element inet global ipp2 { 192.168.10.2 . tcp . 5 }
1833+add set inet global ipp3 { type ipv4_addr . inet_proto . inet_service; counter; }
1834+add element inet global ipp3 { 192.168.10.3 . tcp . 20 counter packets 5 bytes 3456 }
1835+add set inet global ipp4 { type ipv4_addr . inet_proto . inet_service; counter; timeout 4s; }
1836+add element inet global ipp4 { 192.168.10.3 . tcp . 20 counter packets 5 bytes 3456 }
1837+add set inet global bip1 { type ipv4_addr; timeout 5s; }
1838+add set inet global bip2 { type ipv4_addr; timeout 5s; flags interval; }
1839+add element inet global bip2 { 10.10.10.0/24 }
1840+add element inet global bip2 { 10.10.20.0/24 timeout 12s }
1841+add set inet global net1 { type ipv4_addr; flags interval; }
1842+add element inet global net1 { 192.168.10.0/24 }
1843+add set inet global net2 { type ipv4_addr . ipv4_addr; flags interval; }
1844+add element inet global net2 { 192.168.10.0/24 . 192.168.20.0/24 }
1845+add set inet global hm1 { type ether_addr; }
1846+add element inet global hm1 { aa:bb:cc:dd:ee:ff }
1847+add set inet global him1 { type ipv4_addr . ether_addr; }
1848+add element inet global him1 { 1.1.1.1 . aa:bb:cc:dd:ee:ff }
1849+add set inet global ni1 { type ipv4_addr . ifname; flags interval; }
1850+add element inet global ni1 { 1.1.1.0/24 . eth0 }
1851+add set inet global nip1 { type ipv4_addr . inet_proto . inet_service; flags interval; }
1852+add element inet global nip1 { 1.1.1.0/24 . tcp . 22 }
1853+add set inet global npn1 { type ipv4_addr . inet_proto . inet_service . ipv4_addr; flags interval; }
1854+add element inet global npn1 { 1.1.1.0/24 . tcp . 22 . 2.2.2.0/24 }
1855+add set inet global nn1 { type ipv4_addr . ipv4_addr; flags interval; }
1856+add element inet global nn1 { 1.1.1.0/24 . 2.2.2.0/24 }
1857+add set inet global ipn1 { type ipv4_addr . inet_proto . inet_service . ipv4_addr; flags interval; }
1858+add element inet global ipn1 { 1.1.1.1 . tcp . 22 . 2.2.2.0/24 }
1859+add set inet global ipi1 { type ipv4_addr . inet_proto . inet_service . ipv4_addr; }
1860+add element inet global ipi1 { 1.1.1.1 . tcp . 22 . 2.2.2.2 }
1861+add set inet global im1 { type ipv4_addr . mark; }
1862+add element inet global im1 { 1.1.1.1 . 0x00123456 }
1863+add set inet global bp1 { type inet_service; }
1864+add element inet global bp1 { 22 }
1865+add set inet global bim1 { type ipv4_addr . ether_addr; }
1866+add element inet global bim1 { 1.1.1.1 . aa:bb:cc:dd:ee:ff }
This page took 0.25 seconds and 4 git commands to generate.