xt_conntrack.c 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * xt_conntrack - Netfilter module to match connection tracking
  3. * information. (Superset of Rusty's minimalistic state match.)
  4. *
  5. * (C) 2001 Marc Boucher (marc@mbsi.ca).
  6. * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
  7. * Copyright © CC Computer Consultants GmbH, 2007 - 2008
  8. *
  9. * This program is free software; you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2 as
  11. * published by the Free Software Foundation.
  12. */
  13. #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14. #include <linux/module.h>
  15. #include <linux/skbuff.h>
  16. #include <net/ipv6.h>
  17. #include <linux/netfilter/x_tables.h>
  18. #include <linux/netfilter/xt_conntrack.h>
  19. #include <net/netfilter/nf_conntrack.h>
  20. MODULE_LICENSE("GPL");
  21. MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
  22. MODULE_AUTHOR("Jan Engelhardt <jengelh@medozas.de>");
  23. MODULE_DESCRIPTION("Xtables: connection tracking state match");
  24. MODULE_ALIAS("ipt_conntrack");
  25. MODULE_ALIAS("ip6t_conntrack");
  26. static bool
  27. conntrack_addrcmp(const union nf_inet_addr *kaddr,
  28. const union nf_inet_addr *uaddr,
  29. const union nf_inet_addr *umask, unsigned int l3proto)
  30. {
  31. if (l3proto == NFPROTO_IPV4)
  32. return ((kaddr->ip ^ uaddr->ip) & umask->ip) == 0;
  33. else if (l3proto == NFPROTO_IPV6)
  34. return ipv6_masked_addr_cmp(&kaddr->in6, &umask->in6,
  35. &uaddr->in6) == 0;
  36. else
  37. return false;
  38. }
  39. static inline bool
  40. conntrack_mt_origsrc(const struct nf_conn *ct,
  41. const struct xt_conntrack_mtinfo2 *info,
  42. u_int8_t family)
  43. {
  44. return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3,
  45. &info->origsrc_addr, &info->origsrc_mask, family);
  46. }
  47. static inline bool
  48. conntrack_mt_origdst(const struct nf_conn *ct,
  49. const struct xt_conntrack_mtinfo2 *info,
  50. u_int8_t family)
  51. {
  52. return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3,
  53. &info->origdst_addr, &info->origdst_mask, family);
  54. }
  55. static inline bool
  56. conntrack_mt_replsrc(const struct nf_conn *ct,
  57. const struct xt_conntrack_mtinfo2 *info,
  58. u_int8_t family)
  59. {
  60. return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3,
  61. &info->replsrc_addr, &info->replsrc_mask, family);
  62. }
  63. static inline bool
  64. conntrack_mt_repldst(const struct nf_conn *ct,
  65. const struct xt_conntrack_mtinfo2 *info,
  66. u_int8_t family)
  67. {
  68. return conntrack_addrcmp(&ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3,
  69. &info->repldst_addr, &info->repldst_mask, family);
  70. }
  71. static inline bool
  72. ct_proto_port_check(const struct xt_conntrack_mtinfo2 *info,
  73. const struct nf_conn *ct)
  74. {
  75. const struct nf_conntrack_tuple *tuple;
  76. tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  77. if ((info->match_flags & XT_CONNTRACK_PROTO) &&
  78. (nf_ct_protonum(ct) == info->l4proto) ^
  79. !(info->invert_flags & XT_CONNTRACK_PROTO))
  80. return false;
  81. /* Shortcut to match all recognized protocols by using ->src.all. */
  82. if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
  83. (tuple->src.u.all == info->origsrc_port) ^
  84. !(info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
  85. return false;
  86. if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
  87. (tuple->dst.u.all == info->origdst_port) ^
  88. !(info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
  89. return false;
  90. tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
  91. if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
  92. (tuple->src.u.all == info->replsrc_port) ^
  93. !(info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
  94. return false;
  95. if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
  96. (tuple->dst.u.all == info->repldst_port) ^
  97. !(info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
  98. return false;
  99. return true;
  100. }
  101. static inline bool
  102. port_match(u16 min, u16 max, u16 port, bool invert)
  103. {
  104. return (port >= min && port <= max) ^ invert;
  105. }
  106. static inline bool
  107. ct_proto_port_check_v3(const struct xt_conntrack_mtinfo3 *info,
  108. const struct nf_conn *ct)
  109. {
  110. const struct nf_conntrack_tuple *tuple;
  111. tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  112. if ((info->match_flags & XT_CONNTRACK_PROTO) &&
  113. (nf_ct_protonum(ct) == info->l4proto) ^
  114. !(info->invert_flags & XT_CONNTRACK_PROTO))
  115. return false;
  116. /* Shortcut to match all recognized protocols by using ->src.all. */
  117. if ((info->match_flags & XT_CONNTRACK_ORIGSRC_PORT) &&
  118. !port_match(info->origsrc_port, info->origsrc_port_high,
  119. ntohs(tuple->src.u.all),
  120. info->invert_flags & XT_CONNTRACK_ORIGSRC_PORT))
  121. return false;
  122. if ((info->match_flags & XT_CONNTRACK_ORIGDST_PORT) &&
  123. !port_match(info->origdst_port, info->origdst_port_high,
  124. ntohs(tuple->dst.u.all),
  125. info->invert_flags & XT_CONNTRACK_ORIGDST_PORT))
  126. return false;
  127. tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
  128. if ((info->match_flags & XT_CONNTRACK_REPLSRC_PORT) &&
  129. !port_match(info->replsrc_port, info->replsrc_port_high,
  130. ntohs(tuple->src.u.all),
  131. info->invert_flags & XT_CONNTRACK_REPLSRC_PORT))
  132. return false;
  133. if ((info->match_flags & XT_CONNTRACK_REPLDST_PORT) &&
  134. !port_match(info->repldst_port, info->repldst_port_high,
  135. ntohs(tuple->dst.u.all),
  136. info->invert_flags & XT_CONNTRACK_REPLDST_PORT))
  137. return false;
  138. return true;
  139. }
  140. static bool
  141. conntrack_mt(const struct sk_buff *skb, struct xt_action_param *par,
  142. u16 state_mask, u16 status_mask)
  143. {
  144. const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
  145. enum ip_conntrack_info ctinfo;
  146. const struct nf_conn *ct;
  147. unsigned int statebit;
  148. ct = nf_ct_get(skb, &ctinfo);
  149. if (ct) {
  150. if (nf_ct_is_untracked(ct))
  151. statebit = XT_CONNTRACK_STATE_UNTRACKED;
  152. else
  153. statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  154. } else
  155. statebit = XT_CONNTRACK_STATE_INVALID;
  156. if (info->match_flags & XT_CONNTRACK_STATE) {
  157. if (ct != NULL) {
  158. if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
  159. statebit |= XT_CONNTRACK_STATE_SNAT;
  160. if (test_bit(IPS_DST_NAT_BIT, &ct->status))
  161. statebit |= XT_CONNTRACK_STATE_DNAT;
  162. }
  163. if (!!(state_mask & statebit) ^
  164. !(info->invert_flags & XT_CONNTRACK_STATE))
  165. return false;
  166. }
  167. if (ct == NULL)
  168. return info->match_flags & XT_CONNTRACK_STATE;
  169. if ((info->match_flags & XT_CONNTRACK_DIRECTION) &&
  170. (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL) ^
  171. !(info->invert_flags & XT_CONNTRACK_DIRECTION))
  172. return false;
  173. if (info->match_flags & XT_CONNTRACK_ORIGSRC)
  174. if (conntrack_mt_origsrc(ct, info, par->family) ^
  175. !(info->invert_flags & XT_CONNTRACK_ORIGSRC))
  176. return false;
  177. if (info->match_flags & XT_CONNTRACK_ORIGDST)
  178. if (conntrack_mt_origdst(ct, info, par->family) ^
  179. !(info->invert_flags & XT_CONNTRACK_ORIGDST))
  180. return false;
  181. if (info->match_flags & XT_CONNTRACK_REPLSRC)
  182. if (conntrack_mt_replsrc(ct, info, par->family) ^
  183. !(info->invert_flags & XT_CONNTRACK_REPLSRC))
  184. return false;
  185. if (info->match_flags & XT_CONNTRACK_REPLDST)
  186. if (conntrack_mt_repldst(ct, info, par->family) ^
  187. !(info->invert_flags & XT_CONNTRACK_REPLDST))
  188. return false;
  189. if (par->match->revision != 3) {
  190. if (!ct_proto_port_check(info, ct))
  191. return false;
  192. } else {
  193. if (!ct_proto_port_check_v3(par->matchinfo, ct))
  194. return false;
  195. }
  196. if ((info->match_flags & XT_CONNTRACK_STATUS) &&
  197. (!!(status_mask & ct->status) ^
  198. !(info->invert_flags & XT_CONNTRACK_STATUS)))
  199. return false;
  200. if (info->match_flags & XT_CONNTRACK_EXPIRES) {
  201. unsigned long expires = 0;
  202. if (timer_pending(&ct->timeout))
  203. expires = (ct->timeout.expires - jiffies) / HZ;
  204. if ((expires >= info->expires_min &&
  205. expires <= info->expires_max) ^
  206. !(info->invert_flags & XT_CONNTRACK_EXPIRES))
  207. return false;
  208. }
  209. return true;
  210. }
  211. static bool
  212. conntrack_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)
  213. {
  214. const struct xt_conntrack_mtinfo1 *info = par->matchinfo;
  215. return conntrack_mt(skb, par, info->state_mask, info->status_mask);
  216. }
  217. static bool
  218. conntrack_mt_v2(const struct sk_buff *skb, struct xt_action_param *par)
  219. {
  220. const struct xt_conntrack_mtinfo2 *info = par->matchinfo;
  221. return conntrack_mt(skb, par, info->state_mask, info->status_mask);
  222. }
  223. static bool
  224. conntrack_mt_v3(const struct sk_buff *skb, struct xt_action_param *par)
  225. {
  226. const struct xt_conntrack_mtinfo3 *info = par->matchinfo;
  227. return conntrack_mt(skb, par, info->state_mask, info->status_mask);
  228. }
  229. static int conntrack_mt_check(const struct xt_mtchk_param *par)
  230. {
  231. int ret;
  232. ret = nf_ct_l3proto_try_module_get(par->family);
  233. if (ret < 0)
  234. pr_info("cannot load conntrack support for proto=%u\n",
  235. par->family);
  236. return ret;
  237. }
  238. static void conntrack_mt_destroy(const struct xt_mtdtor_param *par)
  239. {
  240. nf_ct_l3proto_module_put(par->family);
  241. }
  242. static struct xt_match conntrack_mt_reg[] __read_mostly = {
  243. {
  244. .name = "conntrack",
  245. .revision = 1,
  246. .family = NFPROTO_UNSPEC,
  247. .matchsize = sizeof(struct xt_conntrack_mtinfo1),
  248. .match = conntrack_mt_v1,
  249. .checkentry = conntrack_mt_check,
  250. .destroy = conntrack_mt_destroy,
  251. .me = THIS_MODULE,
  252. },
  253. {
  254. .name = "conntrack",
  255. .revision = 2,
  256. .family = NFPROTO_UNSPEC,
  257. .matchsize = sizeof(struct xt_conntrack_mtinfo2),
  258. .match = conntrack_mt_v2,
  259. .checkentry = conntrack_mt_check,
  260. .destroy = conntrack_mt_destroy,
  261. .me = THIS_MODULE,
  262. },
  263. {
  264. .name = "conntrack",
  265. .revision = 3,
  266. .family = NFPROTO_UNSPEC,
  267. .matchsize = sizeof(struct xt_conntrack_mtinfo3),
  268. .match = conntrack_mt_v3,
  269. .checkentry = conntrack_mt_check,
  270. .destroy = conntrack_mt_destroy,
  271. .me = THIS_MODULE,
  272. },
  273. };
  274. static int __init conntrack_mt_init(void)
  275. {
  276. return xt_register_matches(conntrack_mt_reg,
  277. ARRAY_SIZE(conntrack_mt_reg));
  278. }
  279. static void __exit conntrack_mt_exit(void)
  280. {
  281. xt_unregister_matches(conntrack_mt_reg, ARRAY_SIZE(conntrack_mt_reg));
  282. }
  283. module_init(conntrack_mt_init);
  284. module_exit(conntrack_mt_exit);