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

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

Version: ~ [ linux-5.12-rc7 ] ~ [ linux-5.11.13 ] ~ [ linux-5.10.29 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.111 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.186 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.230 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.266 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.266 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ 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(info->match_set.index);
 85 
 86         if (index == IPSET_INVALID_ID) {
 87                 pr_warning("Cannot find set indentified 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(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(info->match_set.index);
110 }
111 
112 static unsigned int
113 set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
114 {
115         const struct xt_set_info_target_v0 *info = par->targinfo;
116         ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
117                 info->add_set.u.compat.flags, 0, UINT_MAX);
118         ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
119                 info->del_set.u.compat.flags, 0, UINT_MAX);
120 
121         if (info->add_set.index != IPSET_INVALID_ID)
122                 ip_set_add(info->add_set.index, skb, par, &add_opt);
123         if (info->del_set.index != IPSET_INVALID_ID)
124                 ip_set_del(info->del_set.index, skb, par, &del_opt);
125 
126         return XT_CONTINUE;
127 }
128 
129 static int
130 set_target_v0_checkentry(const struct xt_tgchk_param *par)
131 {
132         struct xt_set_info_target_v0 *info = par->targinfo;
133         ip_set_id_t index;
134 
135         if (info->add_set.index != IPSET_INVALID_ID) {
136                 index = ip_set_nfnl_get_byindex(info->add_set.index);
137                 if (index == IPSET_INVALID_ID) {
138                         pr_warning("Cannot find add_set index %u as target\n",
139                                    info->add_set.index);
140                         return -ENOENT;
141                 }
142         }
143 
144         if (info->del_set.index != IPSET_INVALID_ID) {
145                 index = ip_set_nfnl_get_byindex(info->del_set.index);
146                 if (index == IPSET_INVALID_ID) {
147                         pr_warning("Cannot find del_set index %u as target\n",
148                                    info->del_set.index);
149                         if (info->add_set.index != IPSET_INVALID_ID)
150                                 ip_set_nfnl_put(info->add_set.index);
151                         return -ENOENT;
152                 }
153         }
154         if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
155             info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
156                 pr_warning("Protocol error: SET target dimension "
157                            "is over the limit!\n");
158                 if (info->add_set.index != IPSET_INVALID_ID)
159                         ip_set_nfnl_put(info->add_set.index);
160                 if (info->del_set.index != IPSET_INVALID_ID)
161                         ip_set_nfnl_put(info->del_set.index);
162                 return -ERANGE;
163         }
164 
165         /* Fill out compatibility data */
166         compat_flags(&info->add_set);
167         compat_flags(&info->del_set);
168 
169         return 0;
170 }
171 
172 static void
173 set_target_v0_destroy(const struct xt_tgdtor_param *par)
174 {
175         const struct xt_set_info_target_v0 *info = par->targinfo;
176 
177         if (info->add_set.index != IPSET_INVALID_ID)
178                 ip_set_nfnl_put(info->add_set.index);
179         if (info->del_set.index != IPSET_INVALID_ID)
180                 ip_set_nfnl_put(info->del_set.index);
181 }
182 
183 /* Revision 1 match and target */
184 
185 static bool
186 set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
187 {
188         const struct xt_set_info_match_v1 *info = par->matchinfo;
189         ADT_OPT(opt, par->family, info->match_set.dim,
190                 info->match_set.flags, 0, UINT_MAX);
191 
192         if (opt.flags & IPSET_RETURN_NOMATCH)
193                 opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
194 
195         return match_set(info->match_set.index, skb, par, &opt,
196                          info->match_set.flags & IPSET_INV_MATCH);
197 }
198 
199 static int
200 set_match_v1_checkentry(const struct xt_mtchk_param *par)
201 {
202         struct xt_set_info_match_v1 *info = par->matchinfo;
203         ip_set_id_t index;
204 
205         index = ip_set_nfnl_get_byindex(info->match_set.index);
206 
207         if (index == IPSET_INVALID_ID) {
208                 pr_warning("Cannot find set indentified by id %u to match\n",
209                            info->match_set.index);
210                 return -ENOENT;
211         }
212         if (info->match_set.dim > IPSET_DIM_MAX) {
213                 pr_warning("Protocol error: set match dimension "
214                            "is over the limit!\n");
215                 ip_set_nfnl_put(info->match_set.index);
216                 return -ERANGE;
217         }
218 
219         return 0;
220 }
221 
222 static void
223 set_match_v1_destroy(const struct xt_mtdtor_param *par)
224 {
225         struct xt_set_info_match_v1 *info = par->matchinfo;
226 
227         ip_set_nfnl_put(info->match_set.index);
228 }
229 
230 static unsigned int
231 set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
232 {
233         const struct xt_set_info_target_v1 *info = par->targinfo;
234         ADT_OPT(add_opt, par->family, info->add_set.dim,
235                 info->add_set.flags, 0, UINT_MAX);
236         ADT_OPT(del_opt, par->family, info->del_set.dim,
237                 info->del_set.flags, 0, UINT_MAX);
238 
239         if (info->add_set.index != IPSET_INVALID_ID)
240                 ip_set_add(info->add_set.index, skb, par, &add_opt);
241         if (info->del_set.index != IPSET_INVALID_ID)
242                 ip_set_del(info->del_set.index, skb, par, &del_opt);
243 
244         return XT_CONTINUE;
245 }
246 
247 static int
248 set_target_v1_checkentry(const struct xt_tgchk_param *par)
249 {
250         const struct xt_set_info_target_v1 *info = par->targinfo;
251         ip_set_id_t index;
252 
253         if (info->add_set.index != IPSET_INVALID_ID) {
254                 index = ip_set_nfnl_get_byindex(info->add_set.index);
255                 if (index == IPSET_INVALID_ID) {
256                         pr_warning("Cannot find add_set index %u as target\n",
257                                    info->add_set.index);
258                         return -ENOENT;
259                 }
260         }
261 
262         if (info->del_set.index != IPSET_INVALID_ID) {
263                 index = ip_set_nfnl_get_byindex(info->del_set.index);
264                 if (index == IPSET_INVALID_ID) {
265                         pr_warning("Cannot find del_set index %u as target\n",
266                                    info->del_set.index);
267                         if (info->add_set.index != IPSET_INVALID_ID)
268                                 ip_set_nfnl_put(info->add_set.index);
269                         return -ENOENT;
270                 }
271         }
272         if (info->add_set.dim > IPSET_DIM_MAX ||
273             info->del_set.dim > IPSET_DIM_MAX) {
274                 pr_warning("Protocol error: SET target dimension "
275                            "is over the limit!\n");
276                 if (info->add_set.index != IPSET_INVALID_ID)
277                         ip_set_nfnl_put(info->add_set.index);
278                 if (info->del_set.index != IPSET_INVALID_ID)
279                         ip_set_nfnl_put(info->del_set.index);
280                 return -ERANGE;
281         }
282 
283         return 0;
284 }
285 
286 static void
287 set_target_v1_destroy(const struct xt_tgdtor_param *par)
288 {
289         const struct xt_set_info_target_v1 *info = par->targinfo;
290 
291         if (info->add_set.index != IPSET_INVALID_ID)
292                 ip_set_nfnl_put(info->add_set.index);
293         if (info->del_set.index != IPSET_INVALID_ID)
294                 ip_set_nfnl_put(info->del_set.index);
295 }
296 
297 /* Revision 2 target */
298 
299 static unsigned int
300 set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
301 {
302         const struct xt_set_info_target_v2 *info = par->targinfo;
303         ADT_OPT(add_opt, par->family, info->add_set.dim,
304                 info->add_set.flags, info->flags, info->timeout);
305         ADT_OPT(del_opt, par->family, info->del_set.dim,
306                 info->del_set.flags, 0, UINT_MAX);
307 
308         /* Normalize to fit into jiffies */
309         if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
310             add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
311                 add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
312         if (info->add_set.index != IPSET_INVALID_ID)
313                 ip_set_add(info->add_set.index, skb, par, &add_opt);
314         if (info->del_set.index != IPSET_INVALID_ID)
315                 ip_set_del(info->del_set.index, skb, par, &del_opt);
316 
317         return XT_CONTINUE;
318 }
319 
320 #define set_target_v2_checkentry        set_target_v1_checkentry
321 #define set_target_v2_destroy           set_target_v1_destroy
322 
323 /* Revision 3 match */
324 
325 static bool
326 match_counter(u64 counter, const struct ip_set_counter_match *info)
327 {
328         switch (info->op) {
329         case IPSET_COUNTER_NONE:
330                 return true;
331         case IPSET_COUNTER_EQ:
332                 return counter == info->value;
333         case IPSET_COUNTER_NE:
334                 return counter != info->value;
335         case IPSET_COUNTER_LT:
336                 return counter < info->value;
337         case IPSET_COUNTER_GT:
338                 return counter > info->value;
339         }
340         return false;
341 }
342 
343 static bool
344 set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
345 {
346         const struct xt_set_info_match_v3 *info = par->matchinfo;
347         ADT_OPT(opt, par->family, info->match_set.dim,
348                 info->match_set.flags, info->flags, UINT_MAX);
349         int ret;
350 
351         if (info->packets.op != IPSET_COUNTER_NONE ||
352             info->bytes.op != IPSET_COUNTER_NONE)
353                 opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
354 
355         ret = match_set(info->match_set.index, skb, par, &opt,
356                         info->match_set.flags & IPSET_INV_MATCH);
357 
358         if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
359                 return ret;
360 
361         if (!match_counter(opt.ext.packets, &info->packets))
362                 return 0;
363         return match_counter(opt.ext.bytes, &info->bytes);
364 }
365 
366 #define set_match_v3_checkentry set_match_v1_checkentry
367 #define set_match_v3_destroy    set_match_v1_destroy
368 
369 static struct xt_match set_matches[] __read_mostly = {
370         {
371                 .name           = "set",
372                 .family         = NFPROTO_IPV4,
373                 .revision       = 0,
374                 .match          = set_match_v0,
375                 .matchsize      = sizeof(struct xt_set_info_match_v0),
376                 .checkentry     = set_match_v0_checkentry,
377                 .destroy        = set_match_v0_destroy,
378                 .me             = THIS_MODULE
379         },
380         {
381                 .name           = "set",
382                 .family         = NFPROTO_IPV4,
383                 .revision       = 1,
384                 .match          = set_match_v1,
385                 .matchsize      = sizeof(struct xt_set_info_match_v1),
386                 .checkentry     = set_match_v1_checkentry,
387                 .destroy        = set_match_v1_destroy,
388                 .me             = THIS_MODULE
389         },
390         {
391                 .name           = "set",
392                 .family         = NFPROTO_IPV6,
393                 .revision       = 1,
394                 .match          = set_match_v1,
395                 .matchsize      = sizeof(struct xt_set_info_match_v1),
396                 .checkentry     = set_match_v1_checkentry,
397                 .destroy        = set_match_v1_destroy,
398                 .me             = THIS_MODULE
399         },
400         /* --return-nomatch flag support */
401         {
402                 .name           = "set",
403                 .family         = NFPROTO_IPV4,
404                 .revision       = 2,
405                 .match          = set_match_v1,
406                 .matchsize      = sizeof(struct xt_set_info_match_v1),
407                 .checkentry     = set_match_v1_checkentry,
408                 .destroy        = set_match_v1_destroy,
409                 .me             = THIS_MODULE
410         },
411         {
412                 .name           = "set",
413                 .family         = NFPROTO_IPV6,
414                 .revision       = 2,
415                 .match          = set_match_v1,
416                 .matchsize      = sizeof(struct xt_set_info_match_v1),
417                 .checkentry     = set_match_v1_checkentry,
418                 .destroy        = set_match_v1_destroy,
419                 .me             = THIS_MODULE
420         },
421         /* counters support: update, match */
422         {
423                 .name           = "set",
424                 .family         = NFPROTO_IPV4,
425                 .revision       = 3,
426                 .match          = set_match_v3,
427                 .matchsize      = sizeof(struct xt_set_info_match_v3),
428                 .checkentry     = set_match_v3_checkentry,
429                 .destroy        = set_match_v3_destroy,
430                 .me             = THIS_MODULE
431         },
432         {
433                 .name           = "set",
434                 .family         = NFPROTO_IPV6,
435                 .revision       = 3,
436                 .match          = set_match_v3,
437                 .matchsize      = sizeof(struct xt_set_info_match_v3),
438                 .checkentry     = set_match_v3_checkentry,
439                 .destroy        = set_match_v3_destroy,
440                 .me             = THIS_MODULE
441         },
442 };
443 
444 static struct xt_target set_targets[] __read_mostly = {
445         {
446                 .name           = "SET",
447                 .revision       = 0,
448                 .family         = NFPROTO_IPV4,
449                 .target         = set_target_v0,
450                 .targetsize     = sizeof(struct xt_set_info_target_v0),
451                 .checkentry     = set_target_v0_checkentry,
452                 .destroy        = set_target_v0_destroy,
453                 .me             = THIS_MODULE
454         },
455         {
456                 .name           = "SET",
457                 .revision       = 1,
458                 .family         = NFPROTO_IPV4,
459                 .target         = set_target_v1,
460                 .targetsize     = sizeof(struct xt_set_info_target_v1),
461                 .checkentry     = set_target_v1_checkentry,
462                 .destroy        = set_target_v1_destroy,
463                 .me             = THIS_MODULE
464         },
465         {
466                 .name           = "SET",
467                 .revision       = 1,
468                 .family         = NFPROTO_IPV6,
469                 .target         = set_target_v1,
470                 .targetsize     = sizeof(struct xt_set_info_target_v1),
471                 .checkentry     = set_target_v1_checkentry,
472                 .destroy        = set_target_v1_destroy,
473                 .me             = THIS_MODULE
474         },
475         /* --timeout and --exist flags support */
476         {
477                 .name           = "SET",
478                 .revision       = 2,
479                 .family         = NFPROTO_IPV4,
480                 .target         = set_target_v2,
481                 .targetsize     = sizeof(struct xt_set_info_target_v2),
482                 .checkentry     = set_target_v2_checkentry,
483                 .destroy        = set_target_v2_destroy,
484                 .me             = THIS_MODULE
485         },
486         {
487                 .name           = "SET",
488                 .revision       = 2,
489                 .family         = NFPROTO_IPV6,
490                 .target         = set_target_v2,
491                 .targetsize     = sizeof(struct xt_set_info_target_v2),
492                 .checkentry     = set_target_v2_checkentry,
493                 .destroy        = set_target_v2_destroy,
494                 .me             = THIS_MODULE
495         },
496 };
497 
498 static int __init xt_set_init(void)
499 {
500         int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
501 
502         if (!ret) {
503                 ret = xt_register_targets(set_targets,
504                                           ARRAY_SIZE(set_targets));
505                 if (ret)
506                         xt_unregister_matches(set_matches,
507                                               ARRAY_SIZE(set_matches));
508         }
509         return ret;
510 }
511 
512 static void __exit xt_set_fini(void)
513 {
514         xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
515         xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
516 }
517 
518 module_init(xt_set_init);
519 module_exit(xt_set_fini);
520 

~ [ 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