nf_conntrack_amanda.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. /* Amanda extension for IP connection tracking
  2. *
  3. * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
  4. * based on HW's ip_conntrack_irc.c as well as other modules
  5. * (C) 2006 Patrick McHardy <kaber@trash.net>
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License
  9. * as published by the Free Software Foundation; either version
  10. * 2 of the License, or (at your option) any later version.
  11. */
  12. #include <linux/kernel.h>
  13. #include <linux/module.h>
  14. #include <linux/moduleparam.h>
  15. #include <linux/textsearch.h>
  16. #include <linux/skbuff.h>
  17. #include <linux/in.h>
  18. #include <linux/udp.h>
  19. #include <linux/netfilter.h>
  20. #include <linux/gfp.h>
  21. #include <net/netfilter/nf_conntrack.h>
  22. #include <net/netfilter/nf_conntrack_expect.h>
  23. #include <net/netfilter/nf_conntrack_ecache.h>
  24. #include <net/netfilter/nf_conntrack_helper.h>
  25. #include <linux/netfilter/nf_conntrack_amanda.h>
  26. static unsigned int master_timeout __read_mostly = 300;
  27. static char *ts_algo = "kmp";
  28. MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
  29. MODULE_DESCRIPTION("Amanda connection tracking module");
  30. MODULE_LICENSE("GPL");
  31. MODULE_ALIAS("ip_conntrack_amanda");
  32. MODULE_ALIAS_NFCT_HELPER("amanda");
  33. module_param(master_timeout, uint, 0600);
  34. MODULE_PARM_DESC(master_timeout, "timeout for the master connection");
  35. module_param(ts_algo, charp, 0400);
  36. MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)");
  37. unsigned int (*nf_nat_amanda_hook)(struct sk_buff *skb,
  38. enum ip_conntrack_info ctinfo,
  39. unsigned int protoff,
  40. unsigned int matchoff,
  41. unsigned int matchlen,
  42. struct nf_conntrack_expect *exp)
  43. __read_mostly;
  44. EXPORT_SYMBOL_GPL(nf_nat_amanda_hook);
  45. enum amanda_strings {
  46. SEARCH_CONNECT,
  47. SEARCH_NEWLINE,
  48. SEARCH_DATA,
  49. SEARCH_MESG,
  50. SEARCH_INDEX,
  51. };
  52. static struct {
  53. const char *string;
  54. size_t len;
  55. struct ts_config *ts;
  56. } search[] __read_mostly = {
  57. [SEARCH_CONNECT] = {
  58. .string = "CONNECT ",
  59. .len = 8,
  60. },
  61. [SEARCH_NEWLINE] = {
  62. .string = "\n",
  63. .len = 1,
  64. },
  65. [SEARCH_DATA] = {
  66. .string = "DATA ",
  67. .len = 5,
  68. },
  69. [SEARCH_MESG] = {
  70. .string = "MESG ",
  71. .len = 5,
  72. },
  73. [SEARCH_INDEX] = {
  74. .string = "INDEX ",
  75. .len = 6,
  76. },
  77. };
  78. static int amanda_help(struct sk_buff *skb,
  79. unsigned int protoff,
  80. struct nf_conn *ct,
  81. enum ip_conntrack_info ctinfo)
  82. {
  83. struct nf_conntrack_expect *exp;
  84. struct nf_conntrack_tuple *tuple;
  85. unsigned int dataoff, start, stop, off, i;
  86. char pbuf[sizeof("65535")], *tmp;
  87. u_int16_t len;
  88. __be16 port;
  89. int ret = NF_ACCEPT;
  90. typeof(nf_nat_amanda_hook) nf_nat_amanda;
  91. /* Only look at packets from the Amanda server */
  92. if (CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL)
  93. return NF_ACCEPT;
  94. /* increase the UDP timeout of the master connection as replies from
  95. * Amanda clients to the server can be quite delayed */
  96. nf_ct_refresh(ct, skb, master_timeout * HZ);
  97. /* No data? */
  98. dataoff = protoff + sizeof(struct udphdr);
  99. if (dataoff >= skb->len) {
  100. net_err_ratelimited("amanda_help: skblen = %u\n", skb->len);
  101. return NF_ACCEPT;
  102. }
  103. start = skb_find_text(skb, dataoff, skb->len,
  104. search[SEARCH_CONNECT].ts);
  105. if (start == UINT_MAX)
  106. goto out;
  107. start += dataoff + search[SEARCH_CONNECT].len;
  108. stop = skb_find_text(skb, start, skb->len,
  109. search[SEARCH_NEWLINE].ts);
  110. if (stop == UINT_MAX)
  111. goto out;
  112. stop += start;
  113. for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) {
  114. off = skb_find_text(skb, start, stop, search[i].ts);
  115. if (off == UINT_MAX)
  116. continue;
  117. off += start + search[i].len;
  118. len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off);
  119. if (skb_copy_bits(skb, off, pbuf, len))
  120. break;
  121. pbuf[len] = '\0';
  122. port = htons(simple_strtoul(pbuf, &tmp, 10));
  123. len = tmp - pbuf;
  124. if (port == 0 || len > 5)
  125. break;
  126. exp = nf_ct_expect_alloc(ct);
  127. if (exp == NULL) {
  128. nf_ct_helper_log(skb, ct, "cannot alloc expectation");
  129. ret = NF_DROP;
  130. goto out;
  131. }
  132. tuple = &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
  133. nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
  134. nf_ct_l3num(ct),
  135. &tuple->src.u3, &tuple->dst.u3,
  136. IPPROTO_TCP, NULL, &port);
  137. nf_nat_amanda = rcu_dereference(nf_nat_amanda_hook);
  138. if (nf_nat_amanda && ct->status & IPS_NAT_MASK)
  139. ret = nf_nat_amanda(skb, ctinfo, protoff,
  140. off - dataoff, len, exp);
  141. else if (nf_ct_expect_related(exp) != 0) {
  142. nf_ct_helper_log(skb, ct, "cannot add expectation");
  143. ret = NF_DROP;
  144. }
  145. nf_ct_expect_put(exp);
  146. }
  147. out:
  148. return ret;
  149. }
  150. static const struct nf_conntrack_expect_policy amanda_exp_policy = {
  151. .max_expected = 3,
  152. .timeout = 180,
  153. };
  154. static struct nf_conntrack_helper amanda_helper[2] __read_mostly = {
  155. {
  156. .name = "amanda",
  157. .me = THIS_MODULE,
  158. .help = amanda_help,
  159. .tuple.src.l3num = AF_INET,
  160. .tuple.src.u.udp.port = cpu_to_be16(10080),
  161. .tuple.dst.protonum = IPPROTO_UDP,
  162. .expect_policy = &amanda_exp_policy,
  163. },
  164. {
  165. .name = "amanda",
  166. .me = THIS_MODULE,
  167. .help = amanda_help,
  168. .tuple.src.l3num = AF_INET6,
  169. .tuple.src.u.udp.port = cpu_to_be16(10080),
  170. .tuple.dst.protonum = IPPROTO_UDP,
  171. .expect_policy = &amanda_exp_policy,
  172. },
  173. };
  174. static void __exit nf_conntrack_amanda_fini(void)
  175. {
  176. int i;
  177. nf_conntrack_helper_unregister(&amanda_helper[0]);
  178. nf_conntrack_helper_unregister(&amanda_helper[1]);
  179. for (i = 0; i < ARRAY_SIZE(search); i++)
  180. textsearch_destroy(search[i].ts);
  181. }
  182. static int __init nf_conntrack_amanda_init(void)
  183. {
  184. int ret, i;
  185. for (i = 0; i < ARRAY_SIZE(search); i++) {
  186. search[i].ts = textsearch_prepare(ts_algo, search[i].string,
  187. search[i].len,
  188. GFP_KERNEL, TS_AUTOLOAD);
  189. if (IS_ERR(search[i].ts)) {
  190. ret = PTR_ERR(search[i].ts);
  191. goto err1;
  192. }
  193. }
  194. ret = nf_conntrack_helper_register(&amanda_helper[0]);
  195. if (ret < 0)
  196. goto err1;
  197. ret = nf_conntrack_helper_register(&amanda_helper[1]);
  198. if (ret < 0)
  199. goto err2;
  200. return 0;
  201. err2:
  202. nf_conntrack_helper_unregister(&amanda_helper[0]);
  203. err1:
  204. while (--i >= 0)
  205. textsearch_destroy(search[i].ts);
  206. return ret;
  207. }
  208. module_init(nf_conntrack_amanda_init);
  209. module_exit(nf_conntrack_amanda_fini);