xt_set.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674
  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. /* 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. 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. struct ip_set_adt_opt n = { \
  36. .family = f, \
  37. .dim = d, \
  38. .flags = fs, \
  39. .cmdflags = cfs, \
  40. .ext.timeout = t, \
  41. }
  42. /* Revision 0 interface: backward compatible with netfilter/iptables */
  43. static bool
  44. set_match_v0(const struct sk_buff *skb, struct xt_action_param *par)
  45. {
  46. const struct xt_set_info_match_v0 *info = par->matchinfo;
  47. ADT_OPT(opt, par->family, info->match_set.u.compat.dim,
  48. info->match_set.u.compat.flags, 0, UINT_MAX);
  49. return match_set(info->match_set.index, skb, par, &opt,
  50. info->match_set.u.compat.flags & IPSET_INV_MATCH);
  51. }
  52. static void
  53. compat_flags(struct xt_set_info_v0 *info)
  54. {
  55. u_int8_t i;
  56. /* Fill out compatibility data according to enum ip_set_kopt */
  57. info->u.compat.dim = IPSET_DIM_ZERO;
  58. if (info->u.flags[0] & IPSET_MATCH_INV)
  59. info->u.compat.flags |= IPSET_INV_MATCH;
  60. for (i = 0; i < IPSET_DIM_MAX-1 && info->u.flags[i]; i++) {
  61. info->u.compat.dim++;
  62. if (info->u.flags[i] & IPSET_SRC)
  63. info->u.compat.flags |= (1<<info->u.compat.dim);
  64. }
  65. }
  66. static int
  67. set_match_v0_checkentry(const struct xt_mtchk_param *par)
  68. {
  69. struct xt_set_info_match_v0 *info = par->matchinfo;
  70. ip_set_id_t index;
  71. index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
  72. if (index == IPSET_INVALID_ID) {
  73. pr_warn("Cannot find set identified by id %u to match\n",
  74. info->match_set.index);
  75. return -ENOENT;
  76. }
  77. if (info->match_set.u.flags[IPSET_DIM_MAX-1] != 0) {
  78. pr_warn("Protocol error: set match dimension is over the limit!\n");
  79. ip_set_nfnl_put(par->net, info->match_set.index);
  80. return -ERANGE;
  81. }
  82. /* Fill out compatibility data */
  83. compat_flags(&info->match_set);
  84. return 0;
  85. }
  86. static void
  87. set_match_v0_destroy(const struct xt_mtdtor_param *par)
  88. {
  89. struct xt_set_info_match_v0 *info = par->matchinfo;
  90. ip_set_nfnl_put(par->net, info->match_set.index);
  91. }
  92. /* Revision 1 match */
  93. static bool
  94. set_match_v1(const struct sk_buff *skb, struct xt_action_param *par)
  95. {
  96. const struct xt_set_info_match_v1 *info = par->matchinfo;
  97. ADT_OPT(opt, par->family, info->match_set.dim,
  98. info->match_set.flags, 0, UINT_MAX);
  99. if (opt.flags & IPSET_RETURN_NOMATCH)
  100. opt.cmdflags |= IPSET_FLAG_RETURN_NOMATCH;
  101. return match_set(info->match_set.index, skb, par, &opt,
  102. info->match_set.flags & IPSET_INV_MATCH);
  103. }
  104. static int
  105. set_match_v1_checkentry(const struct xt_mtchk_param *par)
  106. {
  107. struct xt_set_info_match_v1 *info = par->matchinfo;
  108. ip_set_id_t index;
  109. index = ip_set_nfnl_get_byindex(par->net, info->match_set.index);
  110. if (index == IPSET_INVALID_ID) {
  111. pr_warn("Cannot find set identified by id %u to match\n",
  112. info->match_set.index);
  113. return -ENOENT;
  114. }
  115. if (info->match_set.dim > IPSET_DIM_MAX) {
  116. pr_warn("Protocol error: set match dimension is over the limit!\n");
  117. ip_set_nfnl_put(par->net, info->match_set.index);
  118. return -ERANGE;
  119. }
  120. return 0;
  121. }
  122. static void
  123. set_match_v1_destroy(const struct xt_mtdtor_param *par)
  124. {
  125. struct xt_set_info_match_v1 *info = par->matchinfo;
  126. ip_set_nfnl_put(par->net, info->match_set.index);
  127. }
  128. /* Revision 3 match */
  129. static bool
  130. match_counter(u64 counter, const struct ip_set_counter_match *info)
  131. {
  132. switch (info->op) {
  133. case IPSET_COUNTER_NONE:
  134. return true;
  135. case IPSET_COUNTER_EQ:
  136. return counter == info->value;
  137. case IPSET_COUNTER_NE:
  138. return counter != info->value;
  139. case IPSET_COUNTER_LT:
  140. return counter < info->value;
  141. case IPSET_COUNTER_GT:
  142. return counter > info->value;
  143. }
  144. return false;
  145. }
  146. static bool
  147. set_match_v3(const struct sk_buff *skb, struct xt_action_param *par)
  148. {
  149. const struct xt_set_info_match_v3 *info = par->matchinfo;
  150. ADT_OPT(opt, par->family, info->match_set.dim,
  151. info->match_set.flags, info->flags, UINT_MAX);
  152. int ret;
  153. if (info->packets.op != IPSET_COUNTER_NONE ||
  154. info->bytes.op != IPSET_COUNTER_NONE)
  155. opt.cmdflags |= IPSET_FLAG_MATCH_COUNTERS;
  156. ret = match_set(info->match_set.index, skb, par, &opt,
  157. info->match_set.flags & IPSET_INV_MATCH);
  158. if (!(ret && opt.cmdflags & IPSET_FLAG_MATCH_COUNTERS))
  159. return ret;
  160. if (!match_counter(opt.ext.packets, &info->packets))
  161. return 0;
  162. return match_counter(opt.ext.bytes, &info->bytes);
  163. }
  164. #define set_match_v3_checkentry set_match_v1_checkentry
  165. #define set_match_v3_destroy set_match_v1_destroy
  166. /* Revision 0 interface: backward compatible with netfilter/iptables */
  167. static unsigned int
  168. set_target_v0(struct sk_buff *skb, const struct xt_action_param *par)
  169. {
  170. const struct xt_set_info_target_v0 *info = par->targinfo;
  171. ADT_OPT(add_opt, par->family, info->add_set.u.compat.dim,
  172. info->add_set.u.compat.flags, 0, UINT_MAX);
  173. ADT_OPT(del_opt, par->family, info->del_set.u.compat.dim,
  174. info->del_set.u.compat.flags, 0, UINT_MAX);
  175. if (info->add_set.index != IPSET_INVALID_ID)
  176. ip_set_add(info->add_set.index, skb, par, &add_opt);
  177. if (info->del_set.index != IPSET_INVALID_ID)
  178. ip_set_del(info->del_set.index, skb, par, &del_opt);
  179. return XT_CONTINUE;
  180. }
  181. static int
  182. set_target_v0_checkentry(const struct xt_tgchk_param *par)
  183. {
  184. struct xt_set_info_target_v0 *info = par->targinfo;
  185. ip_set_id_t index;
  186. if (info->add_set.index != IPSET_INVALID_ID) {
  187. index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
  188. if (index == IPSET_INVALID_ID) {
  189. pr_warn("Cannot find add_set index %u as target\n",
  190. info->add_set.index);
  191. return -ENOENT;
  192. }
  193. }
  194. if (info->del_set.index != IPSET_INVALID_ID) {
  195. index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
  196. if (index == IPSET_INVALID_ID) {
  197. pr_warn("Cannot find del_set index %u as target\n",
  198. info->del_set.index);
  199. if (info->add_set.index != IPSET_INVALID_ID)
  200. ip_set_nfnl_put(par->net, info->add_set.index);
  201. return -ENOENT;
  202. }
  203. }
  204. if (info->add_set.u.flags[IPSET_DIM_MAX-1] != 0 ||
  205. info->del_set.u.flags[IPSET_DIM_MAX-1] != 0) {
  206. pr_warn("Protocol error: SET target dimension is over the limit!\n");
  207. if (info->add_set.index != IPSET_INVALID_ID)
  208. ip_set_nfnl_put(par->net, info->add_set.index);
  209. if (info->del_set.index != IPSET_INVALID_ID)
  210. ip_set_nfnl_put(par->net, info->del_set.index);
  211. return -ERANGE;
  212. }
  213. /* Fill out compatibility data */
  214. compat_flags(&info->add_set);
  215. compat_flags(&info->del_set);
  216. return 0;
  217. }
  218. static void
  219. set_target_v0_destroy(const struct xt_tgdtor_param *par)
  220. {
  221. const struct xt_set_info_target_v0 *info = par->targinfo;
  222. if (info->add_set.index != IPSET_INVALID_ID)
  223. ip_set_nfnl_put(par->net, info->add_set.index);
  224. if (info->del_set.index != IPSET_INVALID_ID)
  225. ip_set_nfnl_put(par->net, info->del_set.index);
  226. }
  227. /* Revision 1 target */
  228. static unsigned int
  229. set_target_v1(struct sk_buff *skb, const struct xt_action_param *par)
  230. {
  231. const struct xt_set_info_target_v1 *info = par->targinfo;
  232. ADT_OPT(add_opt, par->family, info->add_set.dim,
  233. info->add_set.flags, 0, UINT_MAX);
  234. ADT_OPT(del_opt, par->family, info->del_set.dim,
  235. info->del_set.flags, 0, UINT_MAX);
  236. if (info->add_set.index != IPSET_INVALID_ID)
  237. ip_set_add(info->add_set.index, skb, par, &add_opt);
  238. if (info->del_set.index != IPSET_INVALID_ID)
  239. ip_set_del(info->del_set.index, skb, par, &del_opt);
  240. return XT_CONTINUE;
  241. }
  242. static int
  243. set_target_v1_checkentry(const struct xt_tgchk_param *par)
  244. {
  245. const struct xt_set_info_target_v1 *info = par->targinfo;
  246. ip_set_id_t index;
  247. if (info->add_set.index != IPSET_INVALID_ID) {
  248. index = ip_set_nfnl_get_byindex(par->net, info->add_set.index);
  249. if (index == IPSET_INVALID_ID) {
  250. pr_warn("Cannot find add_set index %u as target\n",
  251. info->add_set.index);
  252. return -ENOENT;
  253. }
  254. }
  255. if (info->del_set.index != IPSET_INVALID_ID) {
  256. index = ip_set_nfnl_get_byindex(par->net, info->del_set.index);
  257. if (index == IPSET_INVALID_ID) {
  258. pr_warn("Cannot find del_set index %u as target\n",
  259. info->del_set.index);
  260. if (info->add_set.index != IPSET_INVALID_ID)
  261. ip_set_nfnl_put(par->net, info->add_set.index);
  262. return -ENOENT;
  263. }
  264. }
  265. if (info->add_set.dim > IPSET_DIM_MAX ||
  266. info->del_set.dim > IPSET_DIM_MAX) {
  267. pr_warn("Protocol error: SET target dimension is over the limit!\n");
  268. if (info->add_set.index != IPSET_INVALID_ID)
  269. ip_set_nfnl_put(par->net, info->add_set.index);
  270. if (info->del_set.index != IPSET_INVALID_ID)
  271. ip_set_nfnl_put(par->net, info->del_set.index);
  272. return -ERANGE;
  273. }
  274. return 0;
  275. }
  276. static void
  277. set_target_v1_destroy(const struct xt_tgdtor_param *par)
  278. {
  279. const struct xt_set_info_target_v1 *info = par->targinfo;
  280. if (info->add_set.index != IPSET_INVALID_ID)
  281. ip_set_nfnl_put(par->net, info->add_set.index);
  282. if (info->del_set.index != IPSET_INVALID_ID)
  283. ip_set_nfnl_put(par->net, info->del_set.index);
  284. }
  285. /* Revision 2 target */
  286. static unsigned int
  287. set_target_v2(struct sk_buff *skb, const struct xt_action_param *par)
  288. {
  289. const struct xt_set_info_target_v2 *info = par->targinfo;
  290. ADT_OPT(add_opt, par->family, info->add_set.dim,
  291. info->add_set.flags, info->flags, info->timeout);
  292. ADT_OPT(del_opt, par->family, info->del_set.dim,
  293. info->del_set.flags, 0, UINT_MAX);
  294. /* Normalize to fit into jiffies */
  295. if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
  296. add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
  297. add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
  298. if (info->add_set.index != IPSET_INVALID_ID)
  299. ip_set_add(info->add_set.index, skb, par, &add_opt);
  300. if (info->del_set.index != IPSET_INVALID_ID)
  301. ip_set_del(info->del_set.index, skb, par, &del_opt);
  302. return XT_CONTINUE;
  303. }
  304. #define set_target_v2_checkentry set_target_v1_checkentry
  305. #define set_target_v2_destroy set_target_v1_destroy
  306. /* Revision 3 target */
  307. static unsigned int
  308. set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)
  309. {
  310. const struct xt_set_info_target_v3 *info = par->targinfo;
  311. ADT_OPT(add_opt, par->family, info->add_set.dim,
  312. info->add_set.flags, info->flags, info->timeout);
  313. ADT_OPT(del_opt, par->family, info->del_set.dim,
  314. info->del_set.flags, 0, UINT_MAX);
  315. ADT_OPT(map_opt, par->family, info->map_set.dim,
  316. info->map_set.flags, 0, UINT_MAX);
  317. int ret;
  318. /* Normalize to fit into jiffies */
  319. if (add_opt.ext.timeout != IPSET_NO_TIMEOUT &&
  320. add_opt.ext.timeout > UINT_MAX/MSEC_PER_SEC)
  321. add_opt.ext.timeout = UINT_MAX/MSEC_PER_SEC;
  322. if (info->add_set.index != IPSET_INVALID_ID)
  323. ip_set_add(info->add_set.index, skb, par, &add_opt);
  324. if (info->del_set.index != IPSET_INVALID_ID)
  325. ip_set_del(info->del_set.index, skb, par, &del_opt);
  326. if (info->map_set.index != IPSET_INVALID_ID) {
  327. map_opt.cmdflags |= info->flags & (IPSET_FLAG_MAP_SKBMARK |
  328. IPSET_FLAG_MAP_SKBPRIO |
  329. IPSET_FLAG_MAP_SKBQUEUE);
  330. ret = match_set(info->map_set.index, skb, par, &map_opt,
  331. info->map_set.flags & IPSET_INV_MATCH);
  332. if (!ret)
  333. return XT_CONTINUE;
  334. if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBMARK)
  335. skb->mark = (skb->mark & ~(map_opt.ext.skbmarkmask))
  336. ^ (map_opt.ext.skbmark);
  337. if (map_opt.cmdflags & IPSET_FLAG_MAP_SKBPRIO)
  338. skb->priority = map_opt.ext.skbprio;
  339. if ((map_opt.cmdflags & IPSET_FLAG_MAP_SKBQUEUE) &&
  340. skb->dev &&
  341. skb->dev->real_num_tx_queues > map_opt.ext.skbqueue)
  342. skb_set_queue_mapping(skb, map_opt.ext.skbqueue);
  343. }
  344. return XT_CONTINUE;
  345. }
  346. static int
  347. set_target_v3_checkentry(const struct xt_tgchk_param *par)
  348. {
  349. const struct xt_set_info_target_v3 *info = par->targinfo;
  350. ip_set_id_t index;
  351. if (info->add_set.index != IPSET_INVALID_ID) {
  352. index = ip_set_nfnl_get_byindex(par->net,
  353. info->add_set.index);
  354. if (index == IPSET_INVALID_ID) {
  355. pr_warn("Cannot find add_set index %u as target\n",
  356. info->add_set.index);
  357. return -ENOENT;
  358. }
  359. }
  360. if (info->del_set.index != IPSET_INVALID_ID) {
  361. index = ip_set_nfnl_get_byindex(par->net,
  362. info->del_set.index);
  363. if (index == IPSET_INVALID_ID) {
  364. pr_warn("Cannot find del_set index %u as target\n",
  365. info->del_set.index);
  366. if (info->add_set.index != IPSET_INVALID_ID)
  367. ip_set_nfnl_put(par->net,
  368. info->add_set.index);
  369. return -ENOENT;
  370. }
  371. }
  372. if (info->map_set.index != IPSET_INVALID_ID) {
  373. if (strncmp(par->table, "mangle", 7)) {
  374. pr_warn("--map-set only usable from mangle table\n");
  375. return -EINVAL;
  376. }
  377. if (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |
  378. (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&
  379. !(par->hook_mask & (1 << NF_INET_FORWARD |
  380. 1 << NF_INET_LOCAL_OUT |
  381. 1 << NF_INET_POST_ROUTING))) {
  382. pr_warn("mapping of prio or/and queue is allowed only"
  383. "from OUTPUT/FORWARD/POSTROUTING chains\n");
  384. return -EINVAL;
  385. }
  386. index = ip_set_nfnl_get_byindex(par->net,
  387. info->map_set.index);
  388. if (index == IPSET_INVALID_ID) {
  389. pr_warn("Cannot find map_set index %u as target\n",
  390. info->map_set.index);
  391. if (info->add_set.index != IPSET_INVALID_ID)
  392. ip_set_nfnl_put(par->net,
  393. info->add_set.index);
  394. if (info->del_set.index != IPSET_INVALID_ID)
  395. ip_set_nfnl_put(par->net,
  396. info->del_set.index);
  397. return -ENOENT;
  398. }
  399. }
  400. if (info->add_set.dim > IPSET_DIM_MAX ||
  401. info->del_set.dim > IPSET_DIM_MAX ||
  402. info->map_set.dim > IPSET_DIM_MAX) {
  403. pr_warn("Protocol error: SET target dimension "
  404. "is over the limit!\n");
  405. if (info->add_set.index != IPSET_INVALID_ID)
  406. ip_set_nfnl_put(par->net, info->add_set.index);
  407. if (info->del_set.index != IPSET_INVALID_ID)
  408. ip_set_nfnl_put(par->net, info->del_set.index);
  409. if (info->map_set.index != IPSET_INVALID_ID)
  410. ip_set_nfnl_put(par->net, info->map_set.index);
  411. return -ERANGE;
  412. }
  413. return 0;
  414. }
  415. static void
  416. set_target_v3_destroy(const struct xt_tgdtor_param *par)
  417. {
  418. const struct xt_set_info_target_v3 *info = par->targinfo;
  419. if (info->add_set.index != IPSET_INVALID_ID)
  420. ip_set_nfnl_put(par->net, info->add_set.index);
  421. if (info->del_set.index != IPSET_INVALID_ID)
  422. ip_set_nfnl_put(par->net, info->del_set.index);
  423. if (info->map_set.index != IPSET_INVALID_ID)
  424. ip_set_nfnl_put(par->net, info->map_set.index);
  425. }
  426. static struct xt_match set_matches[] __read_mostly = {
  427. {
  428. .name = "set",
  429. .family = NFPROTO_IPV4,
  430. .revision = 0,
  431. .match = set_match_v0,
  432. .matchsize = sizeof(struct xt_set_info_match_v0),
  433. .checkentry = set_match_v0_checkentry,
  434. .destroy = set_match_v0_destroy,
  435. .me = THIS_MODULE
  436. },
  437. {
  438. .name = "set",
  439. .family = NFPROTO_IPV4,
  440. .revision = 1,
  441. .match = set_match_v1,
  442. .matchsize = sizeof(struct xt_set_info_match_v1),
  443. .checkentry = set_match_v1_checkentry,
  444. .destroy = set_match_v1_destroy,
  445. .me = THIS_MODULE
  446. },
  447. {
  448. .name = "set",
  449. .family = NFPROTO_IPV6,
  450. .revision = 1,
  451. .match = set_match_v1,
  452. .matchsize = sizeof(struct xt_set_info_match_v1),
  453. .checkentry = set_match_v1_checkentry,
  454. .destroy = set_match_v1_destroy,
  455. .me = THIS_MODULE
  456. },
  457. /* --return-nomatch flag support */
  458. {
  459. .name = "set",
  460. .family = NFPROTO_IPV4,
  461. .revision = 2,
  462. .match = set_match_v1,
  463. .matchsize = sizeof(struct xt_set_info_match_v1),
  464. .checkentry = set_match_v1_checkentry,
  465. .destroy = set_match_v1_destroy,
  466. .me = THIS_MODULE
  467. },
  468. {
  469. .name = "set",
  470. .family = NFPROTO_IPV6,
  471. .revision = 2,
  472. .match = set_match_v1,
  473. .matchsize = sizeof(struct xt_set_info_match_v1),
  474. .checkentry = set_match_v1_checkentry,
  475. .destroy = set_match_v1_destroy,
  476. .me = THIS_MODULE
  477. },
  478. /* counters support: update, match */
  479. {
  480. .name = "set",
  481. .family = NFPROTO_IPV4,
  482. .revision = 3,
  483. .match = set_match_v3,
  484. .matchsize = sizeof(struct xt_set_info_match_v3),
  485. .checkentry = set_match_v3_checkentry,
  486. .destroy = set_match_v3_destroy,
  487. .me = THIS_MODULE
  488. },
  489. {
  490. .name = "set",
  491. .family = NFPROTO_IPV6,
  492. .revision = 3,
  493. .match = set_match_v3,
  494. .matchsize = sizeof(struct xt_set_info_match_v3),
  495. .checkentry = set_match_v3_checkentry,
  496. .destroy = set_match_v3_destroy,
  497. .me = THIS_MODULE
  498. },
  499. };
  500. static struct xt_target set_targets[] __read_mostly = {
  501. {
  502. .name = "SET",
  503. .revision = 0,
  504. .family = NFPROTO_IPV4,
  505. .target = set_target_v0,
  506. .targetsize = sizeof(struct xt_set_info_target_v0),
  507. .checkentry = set_target_v0_checkentry,
  508. .destroy = set_target_v0_destroy,
  509. .me = THIS_MODULE
  510. },
  511. {
  512. .name = "SET",
  513. .revision = 1,
  514. .family = NFPROTO_IPV4,
  515. .target = set_target_v1,
  516. .targetsize = sizeof(struct xt_set_info_target_v1),
  517. .checkentry = set_target_v1_checkentry,
  518. .destroy = set_target_v1_destroy,
  519. .me = THIS_MODULE
  520. },
  521. {
  522. .name = "SET",
  523. .revision = 1,
  524. .family = NFPROTO_IPV6,
  525. .target = set_target_v1,
  526. .targetsize = sizeof(struct xt_set_info_target_v1),
  527. .checkentry = set_target_v1_checkentry,
  528. .destroy = set_target_v1_destroy,
  529. .me = THIS_MODULE
  530. },
  531. /* --timeout and --exist flags support */
  532. {
  533. .name = "SET",
  534. .revision = 2,
  535. .family = NFPROTO_IPV4,
  536. .target = set_target_v2,
  537. .targetsize = sizeof(struct xt_set_info_target_v2),
  538. .checkentry = set_target_v2_checkentry,
  539. .destroy = set_target_v2_destroy,
  540. .me = THIS_MODULE
  541. },
  542. {
  543. .name = "SET",
  544. .revision = 2,
  545. .family = NFPROTO_IPV6,
  546. .target = set_target_v2,
  547. .targetsize = sizeof(struct xt_set_info_target_v2),
  548. .checkentry = set_target_v2_checkentry,
  549. .destroy = set_target_v2_destroy,
  550. .me = THIS_MODULE
  551. },
  552. /* --map-set support */
  553. {
  554. .name = "SET",
  555. .revision = 3,
  556. .family = NFPROTO_IPV4,
  557. .target = set_target_v3,
  558. .targetsize = sizeof(struct xt_set_info_target_v3),
  559. .checkentry = set_target_v3_checkentry,
  560. .destroy = set_target_v3_destroy,
  561. .me = THIS_MODULE
  562. },
  563. {
  564. .name = "SET",
  565. .revision = 3,
  566. .family = NFPROTO_IPV6,
  567. .target = set_target_v3,
  568. .targetsize = sizeof(struct xt_set_info_target_v3),
  569. .checkentry = set_target_v3_checkentry,
  570. .destroy = set_target_v3_destroy,
  571. .me = THIS_MODULE
  572. },
  573. };
  574. static int __init xt_set_init(void)
  575. {
  576. int ret = xt_register_matches(set_matches, ARRAY_SIZE(set_matches));
  577. if (!ret) {
  578. ret = xt_register_targets(set_targets,
  579. ARRAY_SIZE(set_targets));
  580. if (ret)
  581. xt_unregister_matches(set_matches,
  582. ARRAY_SIZE(set_matches));
  583. }
  584. return ret;
  585. }
  586. static void __exit xt_set_fini(void)
  587. {
  588. xt_unregister_matches(set_matches, ARRAY_SIZE(set_matches));
  589. xt_unregister_targets(set_targets, ARRAY_SIZE(set_targets));
  590. }
  591. module_init(xt_set_init);
  592. module_exit(xt_set_fini);