]> git.pld-linux.org Git - packages/ipset.git/blob - git.patch
- added fixes from upstream git to allow building with kernel 5.13, rel 2
[packages/ipset.git] / git.patch
1 diff --git a/configure.ac b/configure.ac
2 index 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
70 diff --git a/include/libipset/Makefile.am b/include/libipset/Makefile.am
71 index 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
83 diff --git a/include/libipset/xlate.h b/include/libipset/xlate.h
84 new file mode 100644
85 index 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
95 diff --git a/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in b/kernel/include/linux/netfilter/ipset/ip_set_compat.h.in
96 index 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()
227 diff --git a/kernel/net/netfilter/ipset/ip_set_core.c b/kernel/net/netfilter/ipset/ip_set_core.c
228 index 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         },
769 diff --git a/lib/ipset.c b/lib/ipset.c
770 index 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 +}
1432 diff --git a/lib/parse.c b/lib/parse.c
1433 index 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  
1548 diff --git a/src/Makefile.am b/src/Makefile.am
1549 index 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
1570 diff --git a/src/ipset-translate.8 b/src/ipset-translate.8
1571 new file mode 100644
1572 index 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.
1667 diff --git a/src/ipset.8 b/src/ipset.8
1668 index 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.
1680 diff --git a/src/ipset.c b/src/ipset.c
1681 index 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  
1709 diff --git a/tests/xlate/runtest.sh b/tests/xlate/runtest.sh
1710 new file mode 100755
1711 index 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
1744 diff --git a/tests/xlate/xlate.t b/tests/xlate/xlate.t
1745 new file mode 100644
1746 index 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
1805 diff --git a/tests/xlate/xlate.t.nft b/tests/xlate/xlate.t.nft
1806 new file mode 100644
1807 index 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.193847 seconds and 3 git commands to generate.