xt_set.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  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/version.h>
  15. #include <linux/netfilter/x_tables.h>
  16. #include <linux/netfilter/xt_set.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. u8 pf, u8 dim, u8 flags, int inv)
  28. {
  29. if (ip_set_test(index, skb, pf, dim, flags))
  30. inv = !inv;
  31. return inv;
  32. }
  33. /* Revision 0 interface: backward compatible with netfilter/iptables */
  34. static bool
  35. set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
  36. {
  37. const struct xt_set_info_match_v0 *info = par->matchinfo;
  38. return match_set(info->match_set.index, skb, par->family,
  39. info->match_set.u.compat.dim,
  40. info->match_set.u.compat.flags,
  41. info->match_set.u.compat.flags & IPSET_INV_MATCH);
  42. }
  43. static void
  44. compat_flags(struct xt_set_info_v0 *info)
  45. {
  46. u_int8_t i;
  47. /* Fill out compatibility data according to enum ip_set_kopt */
  48. info->u.compat.dim = IPSET_DIM_ZERO;
  49. if (info->u.flags[0] & IPSET_MATCH_INV)
  50. info->u.compat.flags |= IPSET_INV_MATCH;
  51. for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
  52. info->u.compat.dim++;
  53. if (info->u.flags[i] & IPSET_SRC)
  54. info->u.compat.flags |= (1<<info->u.compat.dim);
  55. }
  56. }
  57. static int
  58. set_match_v0_checkentry(const struct xt_mtchk_param *par)
  59. {
  60. struct xt_set_info_match_v0 *info = par->matchinfo;
  61. ip_set_id_t index;
  62. index = ip_set_nfnl_get_byindex(info->match_set.index);
  63. if (index == IPSET_INVALID_ID) {
  64. pr_warning("Cannot find set indentified by id %u to match\n",
  65. info->match_set.index);
  66. return -ENOENT;
  67. }
  68. if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
  69. pr_warning("Protocol error: set match dimension "
  70. "is over the limit!\n");
  71. ip_set_nfnl_put(info->match_set.index);
  72. return -ERANGE;
  73. }
  74. /* Fill out compatibility data */
  75. compat_flags(&info->match_set);
  76. return 0;
  77. }
  78. static void
  79. set_match_v0_destroy(const struct xt_mtdtor_param *par)
  80. {
  81. struct xt_set_info_match_v0 *info = par->matchinfo;
  82. ip_set_nfnl_put(info->match_set.index);
  83. }
  84. static unsigned int
  85. set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
  86. {
  87. const struct xt_set_info_target_v0 *info = par->targinfo;
  88. if (info->add_set.index != IPSET_INVALID_ID)
  89. ip_set_add(info->add_set.index, skb, par->family,
  90. info->add_set.u.compat.dim,
  91. info->add_set.u.compat.flags);
  92. if (info->del_set.index != IPSET_INVALID_ID)
  93. ip_set_del(info->del_set.index, skb, par->family,
  94. info->del_set.u.compat.dim,
  95. info->del_set.u.compat.flags);
  96. return XT_CONTINUE;
  97. }
  98. static int
  99. set_target_v0_checkentry(const struct xt_tgchk_param *par)
  100. {
  101. struct xt_set_info_target_v0 *info = par->targinfo;
  102. ip_set_id_t index;
  103. if (info->add_set.index != IPSET_INVALID_ID) {
  104. index = ip_set_nfnl_get_byindex(info->add_set.index);
  105. if (index == IPSET_INVALID_ID) {
  106. pr_warning("Cannot find add_set index %u as target\n",
  107. info->add_set.index);
  108. return -ENOENT;
  109. }
  110. }
  111. if (info->del_set.index != IPSET_INVALID_ID) {
  112. index = ip_set_nfnl_get_byindex(info->del_set.index);
  113. if (index == IPSET_INVALID_ID) {
  114. pr_warning("Cannot find del_set index %u as target\n",
  115. info->del_set.index);
  116. if (info->add_set.index != IPSET_INVALID_ID)
  117. ip_set_nfnl_put(info->add_set.index);
  118. return -ENOENT;
  119. }
  120. }
  121. if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
  122. info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
  123. pr_warning("Protocol error: SET target dimension "
  124. "is over the limit!\n");
  125. if (info->add_set.index != IPSET_INVALID_ID)
  126. ip_set_nfnl_put(info->add_set.index);
  127. if (info->del_set.index != IPSET_INVALID_ID)
  128. ip_set_nfnl_put(info->del_set.index);
  129. return -ERANGE;
  130. }
  131. /* Fill out compatibility data */
  132. compat_flags(&info->add_set);
  133. compat_flags(&info->del_set);
  134. return 0;
  135. }
  136. static void
  137. set_target_v0_destroy(const struct xt_tgdtor_param *par)
  138. {
  139. const struct xt_set_info_target_v0 *info = par->targinfo;
  140. if (info->add_set.index != IPSET_INVALID_ID)
  141. ip_set_nfnl_put(info->add_set.index);
  142. if (info->del_set.index != IPSET_INVALID_ID)
  143. ip_set_nfnl_put(info->del_set.index);
  144. }
  145. /* Revision 1: current interface to netfilter/iptables */
  146. static bool
  147. set_match(const struct sk_buff *skb, struct xt_action_param *par)
  148. {
  149. const struct xt_set_info_match *info = par->matchinfo;
  150. return match_set(info->match_set.index, skb, par->family,
  151. info->match_set.dim,
  152. info->match_set.flags,
  153. info->match_set.flags & IPSET_INV_MATCH);
  154. }
  155. static int
  156. set_match_checkentry(const struct xt_mtchk_param *par)
  157. {
  158. struct xt_set_info_match *info = par->matchinfo;
  159. ip_set_id_t index;
  160. index = ip_set_nfnl_get_byindex(info->match_set.index);
  161. if (index == IPSET_INVALID_ID) {
  162. pr_warning("Cannot find set indentified by id %u to match\n",
  163. info->match_set.index);
  164. return -ENOENT;
  165. }
  166. if (info->match_set.dim > IPSET_DIM_MAX) {
  167. pr_warning("Protocol error: set match dimension "
  168. "is over the limit!\n");
  169. ip_set_nfnl_put(info->match_set.index);
  170. return -ERANGE;
  171. }
  172. return 0;
  173. }
  174. static void
  175. set_match_destroy(const struct xt_mtdtor_param *par)
  176. {
  177. struct xt_set_info_match *info = par->matchinfo;
  178. ip_set_nfnl_put(info->match_set.index);
  179. }
  180. static unsigned int
  181. set_target(struct sk_buff *skb, const struct xt_action_param *par)
  182. {
  183. const struct xt_set_info_target *info = par->targinfo;
  184. if (info->add_set.index != IPSET_INVALID_ID)
  185. ip_set_add(info->add_set.index,
  186. skb, par->family,
  187. info->add_set.dim,
  188. info->add_set.flags);
  189. if (info->del_set.index != IPSET_INVALID_ID)
  190. ip_set_del(info->del_set.index,
  191. skb, par->family,
  192. info->del_set.dim,
  193. info->del_set.flags);
  194. return XT_CONTINUE;
  195. }
  196. static int
  197. set_target_checkentry(const struct xt_tgchk_param *par)
  198. {
  199. const struct xt_set_info_target *info = par->targinfo;
  200. ip_set_id_t index;
  201. if (info->add_set.index != IPSET_INVALID_ID) {
  202. index = ip_set_nfnl_get_byindex(info->add_set.index);
  203. if (index == IPSET_INVALID_ID) {
  204. pr_warning("Cannot find add_set index %u as target\n",
  205. info->add_set.index);
  206. return -ENOENT;
  207. }
  208. }
  209. if (info->del_set.index != IPSET_INVALID_ID) {
  210. index = ip_set_nfnl_get_byindex(info->del_set.index);
  211. if (index == IPSET_INVALID_ID) {
  212. pr_warning("Cannot find del_set index %u as target\n",
  213. info->del_set.index);
  214. if (info->add_set.index != IPSET_INVALID_ID)
  215. ip_set_nfnl_put(info->add_set.index);
  216. return -ENOENT;
  217. }
  218. }
  219. if (info->add_set.dim > IPSET_DIM_MAX ||
  220. info->del_set.dim > IPSET_DIM_MAX) {
  221. pr_warning("Protocol error: SET target dimension "
  222. "is over the limit!\n");
  223. if (info->add_set.index != IPSET_INVALID_ID)
  224. ip_set_nfnl_put(info->add_set.index);
  225. if (info->del_set.index != IPSET_INVALID_ID)
  226. ip_set_nfnl_put(info->del_set.index);
  227. return -ERANGE;
  228. }
  229. return 0;
  230. }
  231. static void
  232. set_target_destroy(const struct xt_tgdtor_param *par)
  233. {
  234. const struct xt_set_info_target *info = par->targinfo;
  235. if (info->add_set.index != IPSET_INVALID_ID)
  236. ip_set_nfnl_put(info->add_set.index);
  237. if (info->del_set.index != IPSET_INVALID_ID)
  238. ip_set_nfnl_put(info->del_set.index);
  239. }
  240. static struct xt_match set_matches[] __read_mostly = {
  241. {
  242. .name = "set",
  243. .family = NFPROTO_IPV4,
  244. .revision = 0,
  245. .match = set_match_v0,
  246. .matchsize = sizeof(struct xt_set_info_match_v0),
  247. .checkentry = set_match_v0_checkentry,
  248. .destroy = set_match_v0_destroy,
  249. .me = THIS_MODULE
  250. },
  251. {
  252. .name = "set",
  253. .family = NFPROTO_IPV4,
  254. .revision = 1,
  255. .match = set_match,
  256. .matchsize = sizeof(struct xt_set_info_match),
  257. .checkentry = set_match_checkentry,
  258. .destroy = set_match_destroy,
  259. .me = THIS_MODULE
  260. },
  261. {
  262. .name = "set",
  263. .family = NFPROTO_IPV6,
  264. .revision = 1,
  265. .match = set_match,
  266. .matchsize = sizeof(struct xt_set_info_match),
  267. .checkentry = set_match_checkentry,
  268. .destroy = set_match_destroy,
  269. .me = THIS_MODULE
  270. },
  271. };
  272. static struct xt_target set_targets[] __read_mostly = {
  273. {
  274. .name = "SET",
  275. .revision = 0,
  276. .family = NFPROTO_IPV4,
  277. .target = set_target_v0,
  278. .targetsize = sizeof(struct xt_set_info_target_v0),
  279. .checkentry = set_target_v0_checkentry,
  280. .destroy = set_target_v0_destroy,
  281. .me = THIS_MODULE
  282. },
  283. {
  284. .name = "SET",
  285. .revision = 1,
  286. .family = NFPROTO_IPV4,
  287. .target = set_target,
  288. .targetsize = sizeof(struct xt_set_info_target),
  289. .checkentry = set_target_checkentry,
  290. .destroy = set_target_destroy,
  291. .me = THIS_MODULE
  292. },
  293. {
  294. .name = "SET",
  295. .revision = 1,
  296. .family = NFPROTO_IPV6,
  297. .target = set_target,
  298. .targetsize = sizeof(struct xt_set_info_target),
  299. .checkentry = set_target_checkentry,
  300. .destroy = set_target_destroy,
  301. .me = THIS_MODULE
  302. },
  303. };
  304. static int __init xt_set_init(void)
  305. {
  306. int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
  307. if (!ret) {
  308. ret = xt_register_targets(set_targets,
  309. ARRAY_SIZE(set_targets));
  310. if (ret)
  311. xt_unregister_matches(set_matches,
  312. ARRAY_SIZE(set_matches));
  313. }
  314. return ret;
  315. }
  316. static void __exit xt_set_fini(void)
  317. {
  318. xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
  319. xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
  320. }
  321. module_init(xt_set_init);
  322. module_exit(xt_set_fini);