PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/net/netfilter/xt_set.c

https://bitbucket.org/Don2x/mod-kernel-m7-sources
C | 435 lines | 360 code | 57 blank | 18 comment | 68 complexity | f1e36fc4bc68921d97aaaf0c1e8cd912 MD5 | raw file
  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-2011 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. /* Kernel module which implements the set match and SET target
  11. * for netfilter/iptables. */
  12. #include <linux/module.h>
  13. #include <linux/skbuff.h>
  14. #include <linux/netfilter/x_tables.h>
  15. #include <linux/netfilter/xt_set.h>
  16. #include <linux/netfilter/ipset/ip_set_timeout.h>
  17. MODULE_LICENSE("GPL");
  18. MODULE_AUTHOR("Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>");
  19. MODULE_DESCRIPTION("Xtables: IP set match and target module");
  20. MODULE_ALIAS("xt_SET");
  21. MODULE_ALIAS("ipt_set");
  22. MODULE_ALIAS("ip6t_set");
  23. MODULE_ALIAS("ipt_SET");
  24. MODULE_ALIAS("ip6t_SET");
  25. static inline int
  26. match_set(ip_set_id_t index, const struct sk_buff *skb,
  27. const struct xt_action_param *par,
  28. const struct ip_set_adt_opt *opt, int inv)
  29. {
  30. if (ip_set_test(index, skb, par, opt))
  31. inv = !inv;
  32. return inv;
  33. }
  34. #define ADT_OPT(n, f, d, fs, cfs, t) \
  35. const struct ip_set_adt_opt n = { \
  36. .family = f, \
  37. .dim = d, \
  38. .flags = fs, \
  39. .cmdflags = cfs, \
  40. .timeout = t, \
  41. }
  42. #define ADT_MOPT(n, f, d, fs, cfs, t) \
  43. struct ip_set_adt_opt n = { \
  44. .family = f, \
  45. .dim = d, \
  46. .flags = fs, \
  47. .cmdflags = cfs, \
  48. .timeout = t, \
  49. }
  50. /* Revision 0 interface: backward compatible with netfilter/iptables */
  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. return match_set(info->match_set.index, skb, par, &opt,
  58. info->match_set.u.compat.flags & IPSET_INV_MATCH);
  59. }
  60. static void
  61. compat_flags(struct xt_set_info_v0 *info)
  62. {
  63. u_int8_t i;
  64. /* Fill out compatibility data according to enum ip_set_kopt */
  65. info->u.compat.dim = IPSET_DIM_ZERO;
  66. if (info->u.flags[0] & IPSET_MATCH_INV)
  67. info->u.compat.flags |= IPSET_INV_MATCH;
  68. for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
  69. info->u.compat.dim++;
  70. if (info->u.flags[i] & IPSET_SRC)
  71. info->u.compat.flags |= (1<<info->u.compat.dim);
  72. }
  73. }
  74. static int
  75. set_match_v0_checkentry(const struct xt_mtchk_param *par)
  76. {
  77. struct xt_set_info_match_v0 *info = par->matchinfo;
  78. ip_set_id_t index;
  79. index = ip_set_nfnl_get_byindex(info->match_set.index);
  80. if (index == IPSET_INVALID_ID) {
  81. pr_warning("Cannot find set indentified by id %u to match\n",
  82. info->match_set.index);
  83. return -ENOENT;
  84. }
  85. if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
  86. pr_warning("Protocol error: set match dimension "
  87. "is over the limit!\n");
  88. ip_set_nfnl_put(info->match_set.index);
  89. return -ERANGE;
  90. }
  91. /* Fill out compatibility data */
  92. compat_flags(&info->match_set);
  93. return 0;
  94. }
  95. static void
  96. set_match_v0_destroy(const struct xt_mtdtor_param *par)
  97. {
  98. struct xt_set_info_match_v0 *info = par->matchinfo;
  99. ip_set_nfnl_put(info->match_set.index);
  100. }
  101. static unsigned int
  102. set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
  103. {
  104. const struct xt_set_info_target_v0 *info = par->targinfo;
  105. ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
  106. info->add_set.u.compat.flags, 0, UINT_MAX);
  107. ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
  108. info->del_set.u.compat.flags, 0, UINT_MAX);
  109. if (info->add_set.index != IPSET_INVALID_ID)
  110. ip_set_add(info->add_set.index, skb, par, &add_opt);
  111. if (info->del_set.index != IPSET_INVALID_ID)
  112. ip_set_del(info->del_set.index, skb, par, &del_opt);
  113. return XT_CONTINUE;
  114. }
  115. static int
  116. set_target_v0_checkentry(const struct xt_tgchk_param *par)
  117. {
  118. struct xt_set_info_target_v0 *info = par->targinfo;
  119. ip_set_id_t index;
  120. if (info->add_set.index != IPSET_INVALID_ID) {
  121. index = ip_set_nfnl_get_byindex(info->add_set.index);
  122. if (index == IPSET_INVALID_ID) {
  123. pr_warning("Cannot find add_set index %u as target\n",
  124. info->add_set.index);
  125. return -ENOENT;
  126. }
  127. }
  128. if (info->del_set.index != IPSET_INVALID_ID) {
  129. index = ip_set_nfnl_get_byindex(info->del_set.index);
  130. if (index == IPSET_INVALID_ID) {
  131. pr_warning("Cannot find del_set index %u as target\n",
  132. info->del_set.index);
  133. if (info->add_set.index != IPSET_INVALID_ID)
  134. ip_set_nfnl_put(info->add_set.index);
  135. return -ENOENT;
  136. }
  137. }
  138. if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
  139. info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
  140. pr_warning("Protocol error: SET target dimension "
  141. "is over the limit!\n");
  142. if (info->add_set.index != IPSET_INVALID_ID)
  143. ip_set_nfnl_put(info->add_set.index);
  144. if (info->del_set.index != IPSET_INVALID_ID)
  145. ip_set_nfnl_put(info->del_set.index);
  146. return -ERANGE;
  147. }
  148. /* Fill out compatibility data */
  149. compat_flags(&info->add_set);
  150. compat_flags(&info->del_set);
  151. return 0;
  152. }
  153. static void
  154. set_target_v0_destroy(const struct xt_tgdtor_param *par)
  155. {
  156. const struct xt_set_info_target_v0 *info = par->targinfo;
  157. if (info->add_set.index != IPSET_INVALID_ID)
  158. ip_set_nfnl_put(info->add_set.index);
  159. if (info->del_set.index != IPSET_INVALID_ID)
  160. ip_set_nfnl_put(info->del_set.index);
  161. }
  162. /* Revision 1 match and target */
  163. static bool
  164. set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
  165. {
  166. const struct xt_set_info_match_v1 *info = par->matchinfo;
  167. ADT_OPT(opt, par->family, info->match_set.dim,
  168. info->match_set.flags, 0, UINT_MAX);
  169. return match_set(info->match_set.index, skb, par, &opt,
  170. info->match_set.flags & IPSET_INV_MATCH);
  171. }
  172. static int
  173. set_match_v1_checkentry(const struct xt_mtchk_param *par)
  174. {
  175. struct xt_set_info_match_v1 *info = par->matchinfo;
  176. ip_set_id_t index;
  177. index = ip_set_nfnl_get_byindex(info->match_set.index);
  178. if (index == IPSET_INVALID_ID) {
  179. pr_warning("Cannot find set indentified by id %u to match\n",
  180. info->match_set.index);
  181. return -ENOENT;
  182. }
  183. if (info->match_set.dim > IPSET_DIM_MAX) {
  184. pr_warning("Protocol error: set match dimension "
  185. "is over the limit!\n");
  186. ip_set_nfnl_put(info->match_set.index);
  187. return -ERANGE;
  188. }
  189. return 0;
  190. }
  191. static void
  192. set_match_v1_destroy(const struct xt_mtdtor_param *par)
  193. {
  194. struct xt_set_info_match_v1 *info = par->matchinfo;
  195. ip_set_nfnl_put(info->match_set.index);
  196. }
  197. static unsigned int
  198. set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
  199. {
  200. const struct xt_set_info_target_v1 *info = par->targinfo;
  201. ADT_OPT(add_opt, par->family, info->add_set.dim,
  202. info->add_set.flags, 0, UINT_MAX);
  203. ADT_OPT(del_opt, par->family, info->del_set.dim,
  204. info->del_set.flags, 0, UINT_MAX);
  205. if (info->add_set.index != IPSET_INVALID_ID)
  206. ip_set_add(info->add_set.index, skb, par, &add_opt);
  207. if (info->del_set.index != IPSET_INVALID_ID)
  208. ip_set_del(info->del_set.index, skb, par, &del_opt);
  209. return XT_CONTINUE;
  210. }
  211. static int
  212. set_target_v1_checkentry(const struct xt_tgchk_param *par)
  213. {
  214. const struct xt_set_info_target_v1 *info = par->targinfo;
  215. ip_set_id_t index;
  216. if (info->add_set.index != IPSET_INVALID_ID) {
  217. index = ip_set_nfnl_get_byindex(info->add_set.index);
  218. if (index == IPSET_INVALID_ID) {
  219. pr_warning("Cannot find add_set index %u as target\n",
  220. info->add_set.index);
  221. return -ENOENT;
  222. }
  223. }
  224. if (info->del_set.index != IPSET_INVALID_ID) {
  225. index = ip_set_nfnl_get_byindex(info->del_set.index);
  226. if (index == IPSET_INVALID_ID) {
  227. pr_warning("Cannot find del_set index %u as target\n",
  228. info->del_set.index);
  229. if (info->add_set.index != IPSET_INVALID_ID)
  230. ip_set_nfnl_put(info->add_set.index);
  231. return -ENOENT;
  232. }
  233. }
  234. if (info->add_set.dim > IPSET_DIM_MAX ||
  235. info->del_set.dim > IPSET_DIM_MAX) {
  236. pr_warning("Protocol error: SET target dimension "
  237. "is over the limit!\n");
  238. if (info->add_set.index != IPSET_INVALID_ID)
  239. ip_set_nfnl_put(info->add_set.index);
  240. if (info->del_set.index != IPSET_INVALID_ID)
  241. ip_set_nfnl_put(info->del_set.index);
  242. return -ERANGE;
  243. }
  244. return 0;
  245. }
  246. static void
  247. set_target_v1_destroy(const struct xt_tgdtor_param *par)
  248. {
  249. const struct xt_set_info_target_v1 *info = par->targinfo;
  250. if (info->add_set.index != IPSET_INVALID_ID)
  251. ip_set_nfnl_put(info->add_set.index);
  252. if (info->del_set.index != IPSET_INVALID_ID)
  253. ip_set_nfnl_put(info->del_set.index);
  254. }
  255. /* Revision 2 target */
  256. static unsigned int
  257. set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
  258. {
  259. const struct xt_set_info_target_v2 *info = par->targinfo;
  260. ADT_MOPT(add_opt, par->family, info->add_set.dim,
  261. info->add_set.flags, info->flags, info->timeout);
  262. ADT_OPT(del_opt, par->family, info->del_set.dim,
  263. info->del_set.flags, 0, UINT_MAX);
  264. /* Normalize to fit into jiffies */
  265. if (add_opt.timeout != IPSET_NO_TIMEOUT &&
  266. add_opt.timeout > UINT_MAX/MSEC_PER_SEC)
  267. add_opt.timeout = UINT_MAX/MSEC_PER_SEC;
  268. if (info->add_set.index != IPSET_INVALID_ID)
  269. ip_set_add(info->add_set.index, skb, par, &add_opt);
  270. if (info->del_set.index != IPSET_INVALID_ID)
  271. ip_set_del(info->del_set.index, skb, par, &del_opt);
  272. return XT_CONTINUE;
  273. }
  274. #define set_target_v2_checkentry set_target_v1_checkentry
  275. #define set_target_v2_destroy set_target_v1_destroy
  276. static struct xt_match set_matches[] __read_mostly = {
  277. {
  278. .name = "set",
  279. .family = NFPROTO_IPV4,
  280. .revision = 0,
  281. .match = set_match_v0,
  282. .matchsize = sizeof(struct xt_set_info_match_v0),
  283. .checkentry = set_match_v0_checkentry,
  284. .destroy = set_match_v0_destroy,
  285. .me = THIS_MODULE
  286. },
  287. {
  288. .name = "set",
  289. .family = NFPROTO_IPV4,
  290. .revision = 1,
  291. .match = set_match_v1,
  292. .matchsize = sizeof(struct xt_set_info_match_v1),
  293. .checkentry = set_match_v1_checkentry,
  294. .destroy = set_match_v1_destroy,
  295. .me = THIS_MODULE
  296. },
  297. {
  298. .name = "set",
  299. .family = NFPROTO_IPV6,
  300. .revision = 1,
  301. .match = set_match_v1,
  302. .matchsize = sizeof(struct xt_set_info_match_v1),
  303. .checkentry = set_match_v1_checkentry,
  304. .destroy = set_match_v1_destroy,
  305. .me = THIS_MODULE
  306. },
  307. };
  308. static struct xt_target set_targets[] __read_mostly = {
  309. {
  310. .name = "SET",
  311. .revision = 0,
  312. .family = NFPROTO_IPV4,
  313. .target = set_target_v0,
  314. .targetsize = sizeof(struct xt_set_info_target_v0),
  315. .checkentry = set_target_v0_checkentry,
  316. .destroy = set_target_v0_destroy,
  317. .me = THIS_MODULE
  318. },
  319. {
  320. .name = "SET",
  321. .revision = 1,
  322. .family = NFPROTO_IPV4,
  323. .target = set_target_v1,
  324. .targetsize = sizeof(struct xt_set_info_target_v1),
  325. .checkentry = set_target_v1_checkentry,
  326. .destroy = set_target_v1_destroy,
  327. .me = THIS_MODULE
  328. },
  329. {
  330. .name = "SET",
  331. .revision = 1,
  332. .family = NFPROTO_IPV6,
  333. .target = set_target_v1,
  334. .targetsize = sizeof(struct xt_set_info_target_v1),
  335. .checkentry = set_target_v1_checkentry,
  336. .destroy = set_target_v1_destroy,
  337. .me = THIS_MODULE
  338. },
  339. {
  340. .name = "SET",
  341. .revision = 2,
  342. .family = NFPROTO_IPV4,
  343. .target = set_target_v2,
  344. .targetsize = sizeof(struct xt_set_info_target_v2),
  345. .checkentry = set_target_v2_checkentry,
  346. .destroy = set_target_v2_destroy,
  347. .me = THIS_MODULE
  348. },
  349. {
  350. .name = "SET",
  351. .revision = 2,
  352. .family = NFPROTO_IPV6,
  353. .target = set_target_v2,
  354. .targetsize = sizeof(struct xt_set_info_target_v2),
  355. .checkentry = set_target_v2_checkentry,
  356. .destroy = set_target_v2_destroy,
  357. .me = THIS_MODULE
  358. },
  359. };
  360. static int __init xt_set_init(void)
  361. {
  362. int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
  363. if (!ret) {
  364. ret = xt_register_targets(set_targets,
  365. ARRAY_SIZE(set_targets));
  366. if (ret)
  367. xt_unregister_matches(set_matches,
  368. ARRAY_SIZE(set_matches));
  369. }
  370. return ret;
  371. }
  372. static void __exit xt_set_fini(void)
  373. {
  374. xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
  375. xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
  376. }
  377. module_init(xt_set_init);
  378. module_exit(xt_set_fini);