~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/netfilter/xt_set.c

Version: ~ [ linux-5.5-rc1 ] ~ [ linux-5.4.2 ] ~ [ linux-5.3.15 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.88 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.158 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.206 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.206 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.78 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* Copyright (C) 2000-2002 Joakim Axelsson <gozem@linux.nu>
  2  *                         Patrick Schaaf <bof@bof.de>
  3  *                         Martin Josefsson <gandalf@wlug.westbo.se>
  4  * Copyright (C) 2003-2013 Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License version 2 as
  8  * published by the Free Software Foundation.
  9  */
 10 
 11 /* Kernel module which implements the set match and SET target
 12  * for netfilter/iptables. */
 13 
 14 #include <linux/module.h>
 15 #include <linux/skbuff.h>
 16 
 17 #include <linux/netfilter/x_tables.h>
 18 #include <linux/netfilter/xt_set.h>
 19 #include <linux/netfilter/ipset/ip_set_timeout.h>
 20 
 21 MODULE_LICENSE("GPL");
 22 MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
 23 MODULE_DESCRIPTION("Xtables: IP set match and target module");
 24 MODULE_ALIAS("xt_SET");
 25 MODULE_ALIAS("ipt_set");
 26 MODULE_ALIAS("ip6t_set");
 27 MODULE_ALIAS("ipt_SET");
 28 MODULE_ALIAS("ip6t_SET");
 29 
 30 static inline int
 31 match_set(ip_set_id_t index, const struct sk_buff *skb,
 32           const struct xt_action_param *par,
 33           struct ip_set_adt_opt *opt, int inv)
 34 {
 35         if (ip_set_test(index, skb, par, opt))
 36                 inv = !inv;
 37         return inv;
 38 }
 39 
 40 #define ADT_OPT(n, f, d, fs, cfs, t)    \
 41 struct ip_set_adt_opt n = {             \
 42         .family = f,                    \
 43         .dim = d,                       \
 44         .flags = fs,                    \
 45         .cmdflags = cfs,                \
 46         .ext.timeout = t,               \
 47 }
 48 
 49 /* Revision 0 interface: backward compatible with netfilter/iptables */
 50 
 51 static bool
 52 set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
 53 {
 54         const struct xt_set_info_match_v0 *info = par->matchinfo;
 55         ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
 56                 info->match_set.u.compat.flags, 0, UINT_MAX);
 57 
 58         return match_set(info->match_set.index, skb, par, &opt,
 59                          info->match_set.u.compat.flags & IPSET_INV_MATCH);
 60 }
 61 
 62 static void
 63 compat_flags(struct xt_set_info_v0 *info)
 64 {
 65         u_int8_t i;
 66 
 67         /* Fill out compatibility data according to enum ip_set_kopt */
 68         info->u.compat.dim = IPSET_DIM_ZERO;
 69         if (info->u.flags[0] & IPSET_MATCH_INV)
 70                 info->u.compat.flags |= IPSET_INV_MATCH;
 71         for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
 72                 info->u.compat.dim++;
 73                 if (info->u.flags[i] & IPSET_SRC)
 74                         info->u.compat.flags |= (1<<info->u.compat.dim);
 75         }
 76 }
 77 
 78 static int
 79 set_match_v0_checkentry(const struct xt_mtchk_param *par)
 80 {
 81         struct xt_set_info_match_v0 *info = par->matchinfo;
 82         ip_set_id_t index;
 83 
 84         index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
 85 
 86         if (index == IPSET_INVALID_ID) {
 87                 pr_warning("Cannot find set identified by id %u to match\n",
 88                            info->match_set.index);
 89                 return -ENOENT;
 90         }
 91         if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
 92                 pr_warning("Protocol error: set match dimension "
 93                            "is over the limit!\n");
 94                 ip_set_nfnl_put(par->net, info->match_set.index);
 95                 return -ERANGE;
 96         }
 97 
 98         /* Fill out compatibility data */
 99         compat_flags(&info->match_set);
100 
101         return 0;
102 }
103 
104 static void
105 set_match_v0_destroy(const struct xt_mtdtor_param *par)
106 {
107         struct xt_set_info_match_v0 *info = par->matchinfo;
108 
109         ip_set_nfnl_put(par->net, info->match_set.index);
110 }
111 
112 /* Revision 1 match */
113 
114 static bool
115 set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
116 {
117         const struct xt_set_info_match_v1 *info = par->matchinfo;
118         ADT_OPT(opt, par->family, info->match_set.dim,
119                 info->match_set.flags, 0, UINT_MAX);
120 
121         if (opt.flags & IPSET_RETURN_NOMATCH)
122                 opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
123 
124         return match_set(info->match_set.index, skb, par, &opt,
125                          info->match_set.flags & IPSET_INV_MATCH);
126 }
127 
128 static int
129 set_match_v1_checkentry(const struct xt_mtchk_param *par)
130 {
131         struct xt_set_info_match_v1 *info = par->matchinfo;
132         ip_set_id_t index;
133 
134         index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
135 
136         if (index == IPSET_INVALID_ID) {
137                 pr_warning("Cannot find set identified by id %u to match\n",
138                            info->match_set.index);
139                 return -ENOENT;
140         }
141         if (info->match_set.dim > IPSET_DIM_MAX) {
142                 pr_warning("Protocol error: set match dimension "
143                            "is over the limit!\n");
144                 ip_set_nfnl_put(par->net, info->match_set.index);
145                 return -ERANGE;
146         }
147 
148         return 0;
149 }
150 
151 static void
152 set_match_v1_destroy(const struct xt_mtdtor_param *par)
153 {
154         struct xt_set_info_match_v1 *info = par->matchinfo;
155 
156         ip_set_nfnl_put(par->net, info->match_set.index);
157 }
158 
159 /* Revision 3 match */
160 
161 static bool
162 match_counter(u64 counter, const struct ip_set_counter_match *info)
163 {
164         switch (info->op) {
165         case IPSET_COUNTER_NONE:
166                 return true;
167         case IPSET_COUNTER_EQ:
168                 return counter == info->value;
169         case IPSET_COUNTER_NE:
170                 return counter != info->value;
171         case IPSET_COUNTER_LT:
172                 return counter < info->value;
173         case IPSET_COUNTER_GT:
174                 return counter > info->value;
175         }
176         return false;
177 }
178 
179 static bool
180 set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
181 {
182         const struct xt_set_info_match_v3 *info = par->matchinfo;
183         ADT_OPT(opt, par->family, info->match_set.dim,
184                 info->match_set.flags, info->flags, UINT_MAX);
185         int ret;
186 
187         if (info->packets.op != IPSET_COUNTER_NONE ||
188             info->bytes.op != IPSET_COUNTER_NONE)
189                 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
190 
191         ret = match_set(info->match_set.index, skb, par, &opt,
192                         info->match_set.flags & IPSET_INV_MATCH);
193 
194         if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
195                 return ret;
196 
197         if (!match_counter(opt.ext.packets, &info->packets))
198                 return 0;
199         return match_counter(opt.ext.bytes, &info->bytes);
200 }
201 
202 #define set_match_v3_checkentry set_match_v1_checkentry
203 #define set_match_v3_destroy    set_match_v1_destroy
204 
205 /* Revision 0 interface: backward compatible with netfilter/iptables */
206 
207 static unsigned int
208 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
209 {
210         const struct xt_set_info_target_v0 *info = par->targinfo;
211         ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
212                 info->add_set.u.compat.flags, 0, UINT_MAX);
213         ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
214                 info->del_set.u.compat.flags, 0, UINT_MAX);
215 
216         if (info->add_set.index != IPSET_INVALID_ID)
217                 ip_set_add(info->add_set.index, skb, par, &add_opt);
218         if (info->del_set.index != IPSET_INVALID_ID)
219                 ip_set_del(info->del_set.index, skb, par, &del_opt);
220 
221         return XT_CONTINUE;
222 }
223 
224 static int
225 set_target_v0_checkentry(const struct xt_tgchk_param *par)
226 {
227         struct xt_set_info_target_v0 *info = par->targinfo;
228         ip_set_id_t index;
229 
230         if (info->add_set.index != IPSET_INVALID_ID) {
231                 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
232                 if (index == IPSET_INVALID_ID) {
233                         pr_warning("Cannot find add_set index %u as target\n",
234                                    info->add_set.index);
235                         return -ENOENT;
236                 }
237         }
238 
239         if (info->del_set.index != IPSET_INVALID_ID) {
240                 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
241                 if (index == IPSET_INVALID_ID) {
242                         pr_warning("Cannot find del_set index %u as target\n",
243                                    info->del_set.index);
244                         if (info->add_set.index != IPSET_INVALID_ID)
245                                 ip_set_nfnl_put(par->net, info->add_set.index);
246                         return -ENOENT;
247                 }
248         }
249         if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
250             info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
251                 pr_warning("Protocol error: SET target dimension "
252                            "is over the limit!\n");
253                 if (info->add_set.index != IPSET_INVALID_ID)
254                         ip_set_nfnl_put(par->net, info->add_set.index);
255                 if (info->del_set.index != IPSET_INVALID_ID)
256                         ip_set_nfnl_put(par->net, info->del_set.index);
257                 return -ERANGE;
258         }
259 
260         /* Fill out compatibility data */
261         compat_flags(&info->add_set);
262         compat_flags(&info->del_set);
263 
264         return 0;
265 }
266 
267 static void
268 set_target_v0_destroy(const struct xt_tgdtor_param *par)
269 {
270         const struct xt_set_info_target_v0 *info = par->targinfo;
271 
272         if (info->add_set.index != IPSET_INVALID_ID)
273                 ip_set_nfnl_put(par->net, info->add_set.index);
274         if (info->del_set.index != IPSET_INVALID_ID)
275                 ip_set_nfnl_put(par->net, info->del_set.index);
276 }
277 
278 /* Revision 1 target */
279 
280 static unsigned int
281 set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
282 {
283         const struct xt_set_info_target_v1 *info = par->targinfo;
284         ADT_OPT(add_opt, par->family, info->add_set.dim,
285                 info->add_set.flags, 0, UINT_MAX);
286         ADT_OPT(del_opt, par->family, info->del_set.dim,
287                 info->del_set.flags, 0, UINT_MAX);
288 
289         if (info->add_set.index != IPSET_INVALID_ID)
290                 ip_set_add(info->add_set.index, skb, par, &add_opt);
291         if (info->del_set.index != IPSET_INVALID_ID)
292                 ip_set_del(info->del_set.index, skb, par, &del_opt);
293 
294         return XT_CONTINUE;
295 }
296 
297 static int
298 set_target_v1_checkentry(const struct xt_tgchk_param *par)
299 {
300         const struct xt_set_info_target_v1 *info = par->targinfo;
301         ip_set_id_t index;
302 
303         if (info->add_set.index != IPSET_INVALID_ID) {
304                 index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
305                 if (index == IPSET_INVALID_ID) {
306                         pr_warning("Cannot find add_set index %u as target\n",
307                                    info->add_set.index);
308                         return -ENOENT;
309                 }
310         }
311 
312         if (info->del_set.index != IPSET_INVALID_ID) {
313                 index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
314                 if (index == IPSET_INVALID_ID) {
315                         pr_warning("Cannot find del_set index %u as target\n",
316                                    info->del_set.index);
317                         if (info->add_set.index != IPSET_INVALID_ID)
318                                 ip_set_nfnl_put(par->net, info->add_set.index);
319                         return -ENOENT;
320                 }
321         }
322         if (info->add_set.dim > IPSET_DIM_MAX ||
323             info->del_set.dim > IPSET_DIM_MAX) {
324                 pr_warning("Protocol error: SET target dimension "
325                            "is over the limit!\n");
326                 if (info->add_set.index != IPSET_INVALID_ID)
327                         ip_set_nfnl_put(par->net, info->add_set.index);
328                 if (info->del_set.index != IPSET_INVALID_ID)
329                         ip_set_nfnl_put(par->net, info->del_set.index);
330                 return -ERANGE;
331         }
332 
333         return 0;
334 }
335 
336 static void
337 set_target_v1_destroy(const struct xt_tgdtor_param *par)
338 {
339         const struct xt_set_info_target_v1 *info = par->targinfo;
340 
341         if (info->add_set.index != IPSET_INVALID_ID)
342                 ip_set_nfnl_put(par->net, info->add_set.index);
343         if (info->del_set.index != IPSET_INVALID_ID)
344                 ip_set_nfnl_put(par->net, info->del_set.index);
345 }
346 
347 /* Revision 2 target */
348 
349 static unsigned int
350 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
351 {
352         const struct xt_set_info_target_v2 *info = par->targinfo;
353         ADT_OPT(add_opt, par->family, info->add_set.dim,
354                 info->add_set.flags, info->flags, info->timeout);
355         ADT_OPT(del_opt, par->family, info->del_set.dim,
356                 info->del_set.flags, 0, UINT_MAX);
357 
358         /* Normalize to fit into jiffies */
359         if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
360             add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
361                 add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
362         if (info->add_set.index != IPSET_INVALID_ID)
363                 ip_set_add(info->add_set.index, skb, par, &add_opt);
364         if (info->del_set.index != IPSET_INVALID_ID)
365                 ip_set_del(info->del_set.index, skb, par, &del_opt);
366 
367         return XT_CONTINUE;
368 }
369 
370 #define set_target_v2_checkentry        set_target_v1_checkentry
371 #define set_target_v2_destroy           set_target_v1_destroy
372 
373 static struct xt_match set_matches[] __read_mostly = {
374         {
375                 .name           = "set",
376                 .family         = NFPROTO_IPV4,
377                 .revision       = 0,
378                 .match          = set_match_v0,
379                 .matchsize      = sizeof(struct xt_set_info_match_v0),
380                 .checkentry     = set_match_v0_checkentry,
381                 .destroy        = set_match_v0_destroy,
382                 .me             = THIS_MODULE
383         },
384         {
385                 .name           = "set",
386                 .family         = NFPROTO_IPV4,
387                 .revision       = 1,
388                 .match          = set_match_v1,
389                 .matchsize      = sizeof(struct xt_set_info_match_v1),
390                 .checkentry     = set_match_v1_checkentry,
391                 .destroy        = set_match_v1_destroy,
392                 .me             = THIS_MODULE
393         },
394         {
395                 .name           = "set",
396                 .family         = NFPROTO_IPV6,
397                 .revision       = 1,
398                 .match          = set_match_v1,
399                 .matchsize      = sizeof(struct xt_set_info_match_v1),
400                 .checkentry     = set_match_v1_checkentry,
401                 .destroy        = set_match_v1_destroy,
402                 .me             = THIS_MODULE
403         },
404         /* --return-nomatch flag support */
405         {
406                 .name           = "set",
407                 .family         = NFPROTO_IPV4,
408                 .revision       = 2,
409                 .match          = set_match_v1,
410                 .matchsize      = sizeof(struct xt_set_info_match_v1),
411                 .checkentry     = set_match_v1_checkentry,
412                 .destroy        = set_match_v1_destroy,
413                 .me             = THIS_MODULE
414         },
415         {
416                 .name           = "set",
417                 .family         = NFPROTO_IPV6,
418                 .revision       = 2,
419                 .match          = set_match_v1,
420                 .matchsize      = sizeof(struct xt_set_info_match_v1),
421                 .checkentry     = set_match_v1_checkentry,
422                 .destroy        = set_match_v1_destroy,
423                 .me             = THIS_MODULE
424         },
425         /* counters support: update, match */
426         {
427                 .name           = "set",
428                 .family         = NFPROTO_IPV4,
429                 .revision       = 3,
430                 .match          = set_match_v3,
431                 .matchsize      = sizeof(struct xt_set_info_match_v3),
432                 .checkentry     = set_match_v3_checkentry,
433                 .destroy        = set_match_v3_destroy,
434                 .me             = THIS_MODULE
435         },
436         {
437                 .name           = "set",
438                 .family         = NFPROTO_IPV6,
439                 .revision       = 3,
440                 .match          = set_match_v3,
441                 .matchsize      = sizeof(struct xt_set_info_match_v3),
442                 .checkentry     = set_match_v3_checkentry,
443                 .destroy        = set_match_v3_destroy,
444                 .me             = THIS_MODULE
445         },
446 };
447 
448 static struct xt_target set_targets[] __read_mostly = {
449         {
450                 .name           = "SET",
451                 .revision       = 0,
452                 .family         = NFPROTO_IPV4,
453                 .target         = set_target_v0,
454                 .targetsize     = sizeof(struct xt_set_info_target_v0),
455                 .checkentry     = set_target_v0_checkentry,
456                 .destroy        = set_target_v0_destroy,
457                 .me             = THIS_MODULE
458         },
459         {
460                 .name           = "SET",
461                 .revision       = 1,
462                 .family         = NFPROTO_IPV4,
463                 .target         = set_target_v1,
464                 .targetsize     = sizeof(struct xt_set_info_target_v1),
465                 .checkentry     = set_target_v1_checkentry,
466                 .destroy        = set_target_v1_destroy,
467                 .me             = THIS_MODULE
468         },
469         {
470                 .name           = "SET",
471                 .revision       = 1,
472                 .family         = NFPROTO_IPV6,
473                 .target         = set_target_v1,
474                 .targetsize     = sizeof(struct xt_set_info_target_v1),
475                 .checkentry     = set_target_v1_checkentry,
476                 .destroy        = set_target_v1_destroy,
477                 .me             = THIS_MODULE
478         },
479         /* --timeout and --exist flags support */
480         {
481                 .name           = "SET",
482                 .revision       = 2,
483                 .family         = NFPROTO_IPV4,
484                 .target         = set_target_v2,
485                 .targetsize     = sizeof(struct xt_set_info_target_v2),
486                 .checkentry     = set_target_v2_checkentry,
487                 .destroy        = set_target_v2_destroy,
488                 .me             = THIS_MODULE
489         },
490         {
491                 .name           = "SET",
492                 .revision       = 2,
493                 .family         = NFPROTO_IPV6,
494                 .target         = set_target_v2,
495                 .targetsize     = sizeof(struct xt_set_info_target_v2),
496                 .checkentry     = set_target_v2_checkentry,
497                 .destroy        = set_target_v2_destroy,
498                 .me             = THIS_MODULE
499         },
500 };
501 
502 static int __init xt_set_init(void)
503 {
504         int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
505 
506         if (!ret) {
507                 ret = xt_register_targets(set_targets,
508                                           ARRAY_SIZE(set_targets));
509                 if (ret)
510                         xt_unregister_matches(set_matches,
511                                               ARRAY_SIZE(set_matches));
512         }
513         return ret;
514 }
515 
516 static void __exit xt_set_fini(void)
517 {
518         xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
519         xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
520 }
521 
522 module_init(xt_set_init);
523 module_exit(xt_set_fini);
524 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp