xt_conntrack.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /* Kernel module to match connection tracking information.
  2. * Superset of Rusty's minimalistic state match.
  3. *
  4. * (C) 2001 Marc Boucher (marc@mbsi.ca).
  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. #include <linux/module.h>
  11. #include <linux/skbuff.h>
  12. #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
  13. #include <linux/netfilter_ipv4/ip_conntrack.h>
  14. #include <linux/netfilter_ipv4/ip_conntrack_tuple.h>
  15. #else
  16. #include <net/netfilter/nf_conntrack.h>
  17. #endif
  18. #include <linux/netfilter/x_tables.h>
  19. #include <linux/netfilter/xt_conntrack.h>
  20. #include <net/netfilter/nf_conntrack_compat.h>
  21. MODULE_LICENSE("GPL");
  22. MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
  23. MODULE_DESCRIPTION("iptables connection tracking match module");
  24. MODULE_ALIAS("ipt_conntrack");
  25. #if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
  26. static int
  27. match(const struct sk_buff *skb,
  28. const struct net_device *in,
  29. const struct net_device *out,
  30. const struct xt_match *match,
  31. const void *matchinfo,
  32. int offset,
  33. unsigned int protoff,
  34. int *hotdrop)
  35. {
  36. const struct xt_conntrack_info *sinfo = matchinfo;
  37. struct ip_conntrack *ct;
  38. enum ip_conntrack_info ctinfo;
  39. unsigned int statebit;
  40. ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
  41. #define FWINV(bool, invflg) ((bool) ^ !!(sinfo->invflags & invflg))
  42. if (ct == &ip_conntrack_untracked)
  43. statebit = XT_CONNTRACK_STATE_UNTRACKED;
  44. else if (ct)
  45. statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  46. else
  47. statebit = XT_CONNTRACK_STATE_INVALID;
  48. if (sinfo->flags & XT_CONNTRACK_STATE) {
  49. if (ct) {
  50. if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
  51. statebit |= XT_CONNTRACK_STATE_SNAT;
  52. if (test_bit(IPS_DST_NAT_BIT, &ct->status))
  53. statebit |= XT_CONNTRACK_STATE_DNAT;
  54. }
  55. if (FWINV((statebit & sinfo->statemask) == 0,
  56. XT_CONNTRACK_STATE))
  57. return 0;
  58. }
  59. if (ct == NULL) {
  60. if (sinfo->flags & ~XT_CONNTRACK_STATE)
  61. return 0;
  62. return 1;
  63. }
  64. if (sinfo->flags & XT_CONNTRACK_PROTO &&
  65. FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
  66. sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
  67. XT_CONNTRACK_PROTO))
  68. return 0;
  69. if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
  70. FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip &
  71. sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
  72. sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
  73. XT_CONNTRACK_ORIGSRC))
  74. return 0;
  75. if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
  76. FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip &
  77. sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
  78. sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
  79. XT_CONNTRACK_ORIGDST))
  80. return 0;
  81. if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
  82. FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip &
  83. sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
  84. sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
  85. XT_CONNTRACK_REPLSRC))
  86. return 0;
  87. if (sinfo->flags & XT_CONNTRACK_REPLDST &&
  88. FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip &
  89. sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
  90. sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
  91. XT_CONNTRACK_REPLDST))
  92. return 0;
  93. if (sinfo->flags & XT_CONNTRACK_STATUS &&
  94. FWINV((ct->status & sinfo->statusmask) == 0,
  95. XT_CONNTRACK_STATUS))
  96. return 0;
  97. if (sinfo->flags & XT_CONNTRACK_EXPIRES) {
  98. unsigned long expires = timer_pending(&ct->timeout) ?
  99. (ct->timeout.expires - jiffies)/HZ : 0;
  100. if (FWINV(!(expires >= sinfo->expires_min &&
  101. expires <= sinfo->expires_max),
  102. XT_CONNTRACK_EXPIRES))
  103. return 0;
  104. }
  105. return 1;
  106. }
  107. #else /* CONFIG_IP_NF_CONNTRACK */
  108. static int
  109. match(const struct sk_buff *skb,
  110. const struct net_device *in,
  111. const struct net_device *out,
  112. const struct xt_match *match,
  113. const void *matchinfo,
  114. int offset,
  115. unsigned int protoff,
  116. int *hotdrop)
  117. {
  118. const struct xt_conntrack_info *sinfo = matchinfo;
  119. struct nf_conn *ct;
  120. enum ip_conntrack_info ctinfo;
  121. unsigned int statebit;
  122. ct = nf_ct_get((struct sk_buff *)skb, &ctinfo);
  123. #define FWINV(bool,invflg) ((bool) ^ !!(sinfo->invflags & invflg))
  124. if (ct == &nf_conntrack_untracked)
  125. statebit = XT_CONNTRACK_STATE_UNTRACKED;
  126. else if (ct)
  127. statebit = XT_CONNTRACK_STATE_BIT(ctinfo);
  128. else
  129. statebit = XT_CONNTRACK_STATE_INVALID;
  130. if (sinfo->flags & XT_CONNTRACK_STATE) {
  131. if (ct) {
  132. if (test_bit(IPS_SRC_NAT_BIT, &ct->status))
  133. statebit |= XT_CONNTRACK_STATE_SNAT;
  134. if (test_bit(IPS_DST_NAT_BIT, &ct->status))
  135. statebit |= XT_CONNTRACK_STATE_DNAT;
  136. }
  137. if (FWINV((statebit & sinfo->statemask) == 0,
  138. XT_CONNTRACK_STATE))
  139. return 0;
  140. }
  141. if (ct == NULL) {
  142. if (sinfo->flags & ~XT_CONNTRACK_STATE)
  143. return 0;
  144. return 1;
  145. }
  146. if (sinfo->flags & XT_CONNTRACK_PROTO &&
  147. FWINV(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum !=
  148. sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.protonum,
  149. XT_CONNTRACK_PROTO))
  150. return 0;
  151. if (sinfo->flags & XT_CONNTRACK_ORIGSRC &&
  152. FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip &
  153. sinfo->sipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
  154. sinfo->tuple[IP_CT_DIR_ORIGINAL].src.ip,
  155. XT_CONNTRACK_ORIGSRC))
  156. return 0;
  157. if (sinfo->flags & XT_CONNTRACK_ORIGDST &&
  158. FWINV((ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip &
  159. sinfo->dipmsk[IP_CT_DIR_ORIGINAL].s_addr) !=
  160. sinfo->tuple[IP_CT_DIR_ORIGINAL].dst.ip,
  161. XT_CONNTRACK_ORIGDST))
  162. return 0;
  163. if (sinfo->flags & XT_CONNTRACK_REPLSRC &&
  164. FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip &
  165. sinfo->sipmsk[IP_CT_DIR_REPLY].s_addr) !=
  166. sinfo->tuple[IP_CT_DIR_REPLY].src.ip,
  167. XT_CONNTRACK_REPLSRC))
  168. return 0;
  169. if (sinfo->flags & XT_CONNTRACK_REPLDST &&
  170. FWINV((ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip &
  171. sinfo->dipmsk[IP_CT_DIR_REPLY].s_addr) !=
  172. sinfo->tuple[IP_CT_DIR_REPLY].dst.ip,
  173. XT_CONNTRACK_REPLDST))
  174. return 0;
  175. if (sinfo->flags & XT_CONNTRACK_STATUS &&
  176. FWINV((ct->status & sinfo->statusmask) == 0,
  177. XT_CONNTRACK_STATUS))
  178. return 0;
  179. if(sinfo->flags & XT_CONNTRACK_EXPIRES) {
  180. unsigned long expires = timer_pending(&ct->timeout) ?
  181. (ct->timeout.expires - jiffies)/HZ : 0;
  182. if (FWINV(!(expires >= sinfo->expires_min &&
  183. expires <= sinfo->expires_max),
  184. XT_CONNTRACK_EXPIRES))
  185. return 0;
  186. }
  187. return 1;
  188. }
  189. #endif /* CONFIG_NF_IP_CONNTRACK */
  190. static int
  191. checkentry(const char *tablename,
  192. const void *ip,
  193. const struct xt_match *match,
  194. void *matchinfo,
  195. unsigned int hook_mask)
  196. {
  197. if (nf_ct_l3proto_try_module_get(match->family) < 0) {
  198. printk(KERN_WARNING "can't load conntrack support for "
  199. "proto=%d\n", match->family);
  200. return 0;
  201. }
  202. return 1;
  203. }
  204. static void destroy(const struct xt_match *match, void *matchinfo)
  205. {
  206. nf_ct_l3proto_module_put(match->family);
  207. }
  208. static struct xt_match conntrack_match = {
  209. .name = "conntrack",
  210. .match = match,
  211. .checkentry = checkentry,
  212. .destroy = destroy,
  213. .matchsize = sizeof(struct xt_conntrack_info),
  214. .family = AF_INET,
  215. .me = THIS_MODULE,
  216. };
  217. static int __init xt_conntrack_init(void)
  218. {
  219. return xt_register_match(&conntrack_match);
  220. }
  221. static void __exit xt_conntrack_fini(void)
  222. {
  223. xt_unregister_match(&conntrack_match);
  224. }
  225. module_init(xt_conntrack_init);
  226. module_exit(xt_conntrack_fini);