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