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