diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/Kconfig | 2 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_amanda.c | 143 |
2 files changed, 96 insertions, 49 deletions
diff --git a/net/ipv4/netfilter/Kconfig b/net/ipv4/netfilter/Kconfig index d4072533da2..1540e227890 100644 --- a/net/ipv4/netfilter/Kconfig +++ b/net/ipv4/netfilter/Kconfig | |||
@@ -142,6 +142,8 @@ config IP_NF_TFTP | |||
142 | config IP_NF_AMANDA | 142 | config IP_NF_AMANDA |
143 | tristate "Amanda backup protocol support" | 143 | tristate "Amanda backup protocol support" |
144 | depends on IP_NF_CONNTRACK | 144 | depends on IP_NF_CONNTRACK |
145 | select TEXTSEARCH | ||
146 | select TEXTSEARCH_KMP | ||
145 | help | 147 | help |
146 | If you are running the Amanda backup package <http://www.amanda.org/> | 148 | If you are running the Amanda backup package <http://www.amanda.org/> |
147 | on this machine or machines that will be MASQUERADED through this | 149 | on this machine or machines that will be MASQUERADED through this |
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c index a604b1ccfda..0a7bd7f0406 100644 --- a/net/ipv4/netfilter/ip_conntrack_amanda.c +++ b/net/ipv4/netfilter/ip_conntrack_amanda.c | |||
@@ -17,33 +17,29 @@ | |||
17 | * this value. | 17 | * this value. |
18 | * | 18 | * |
19 | */ | 19 | */ |
20 | |||
21 | #include <linux/in.h> | ||
22 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
23 | #include <linux/module.h> | 21 | #include <linux/module.h> |
24 | #include <linux/netfilter.h> | ||
25 | #include <linux/ip.h> | ||
26 | #include <linux/moduleparam.h> | 22 | #include <linux/moduleparam.h> |
23 | #include <linux/textsearch.h> | ||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/in.h> | ||
26 | #include <linux/ip.h> | ||
27 | #include <linux/udp.h> | 27 | #include <linux/udp.h> |
28 | #include <net/checksum.h> | ||
29 | #include <net/udp.h> | ||
30 | 28 | ||
29 | #include <linux/netfilter.h> | ||
31 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | 30 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> |
32 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> | 31 | #include <linux/netfilter_ipv4/ip_conntrack_amanda.h> |
33 | 32 | ||
34 | static unsigned int master_timeout = 300; | 33 | static unsigned int master_timeout = 300; |
34 | static char *ts_algo = "kmp"; | ||
35 | 35 | ||
36 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); | 36 | MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>"); |
37 | MODULE_DESCRIPTION("Amanda connection tracking module"); | 37 | MODULE_DESCRIPTION("Amanda connection tracking module"); |
38 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
39 | module_param(master_timeout, uint, 0600); | 39 | module_param(master_timeout, uint, 0600); |
40 | MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); | 40 | MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); |
41 | 41 | module_param(ts_algo, charp, 0400); | |
42 | static const char *conns[] = { "DATA ", "MESG ", "INDEX " }; | 42 | MODULE_PARM_DESC(ts_algo, "textsearch algorithm to use (default kmp)"); |
43 | |||
44 | /* This is slow, but it's simple. --RR */ | ||
45 | static char *amanda_buffer; | ||
46 | static DEFINE_SPINLOCK(amanda_buffer_lock); | ||
47 | 43 | ||
48 | unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb, | 44 | unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb, |
49 | enum ip_conntrack_info ctinfo, | 45 | enum ip_conntrack_info ctinfo, |
@@ -52,12 +48,48 @@ unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb, | |||
52 | struct ip_conntrack_expect *exp); | 48 | struct ip_conntrack_expect *exp); |
53 | EXPORT_SYMBOL_GPL(ip_nat_amanda_hook); | 49 | EXPORT_SYMBOL_GPL(ip_nat_amanda_hook); |
54 | 50 | ||
51 | enum amanda_strings { | ||
52 | SEARCH_CONNECT, | ||
53 | SEARCH_NEWLINE, | ||
54 | SEARCH_DATA, | ||
55 | SEARCH_MESG, | ||
56 | SEARCH_INDEX, | ||
57 | }; | ||
58 | |||
59 | static struct { | ||
60 | char *string; | ||
61 | size_t len; | ||
62 | struct ts_config *ts; | ||
63 | } search[] = { | ||
64 | [SEARCH_CONNECT] = { | ||
65 | .string = "CONNECT ", | ||
66 | .len = 8, | ||
67 | }, | ||
68 | [SEARCH_NEWLINE] = { | ||
69 | .string = "\n", | ||
70 | .len = 1, | ||
71 | }, | ||
72 | [SEARCH_DATA] = { | ||
73 | .string = "DATA ", | ||
74 | .len = 5, | ||
75 | }, | ||
76 | [SEARCH_MESG] = { | ||
77 | .string = "MESG ", | ||
78 | .len = 5, | ||
79 | }, | ||
80 | [SEARCH_INDEX] = { | ||
81 | .string = "INDEX ", | ||
82 | .len = 6, | ||
83 | }, | ||
84 | }; | ||
85 | |||
55 | static int help(struct sk_buff **pskb, | 86 | static int help(struct sk_buff **pskb, |
56 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) | 87 | struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) |
57 | { | 88 | { |
89 | struct ts_state ts; | ||
58 | struct ip_conntrack_expect *exp; | 90 | struct ip_conntrack_expect *exp; |
59 | char *data, *data_limit, *tmp; | 91 | unsigned int dataoff, start, stop, off, i; |
60 | unsigned int dataoff, i; | 92 | char pbuf[sizeof("65535")], *tmp; |
61 | u_int16_t port, len; | 93 | u_int16_t port, len; |
62 | int ret = NF_ACCEPT; | 94 | int ret = NF_ACCEPT; |
63 | 95 | ||
@@ -77,29 +109,34 @@ static int help(struct sk_buff **pskb, | |||
77 | return NF_ACCEPT; | 109 | return NF_ACCEPT; |
78 | } | 110 | } |
79 | 111 | ||
80 | spin_lock_bh(&amanda_buffer_lock); | 112 | memset(&ts, 0, sizeof(ts)); |
81 | skb_copy_bits(*pskb, dataoff, amanda_buffer, (*pskb)->len - dataoff); | 113 | start = skb_find_text(*pskb, dataoff, (*pskb)->len, |
82 | data = amanda_buffer; | 114 | search[SEARCH_CONNECT].ts, &ts); |
83 | data_limit = amanda_buffer + (*pskb)->len - dataoff; | 115 | if (start == UINT_MAX) |
84 | *data_limit = '\0'; | ||
85 | |||
86 | /* Search for the CONNECT string */ | ||
87 | data = strstr(data, "CONNECT "); | ||
88 | if (!data) | ||
89 | goto out; | 116 | goto out; |
90 | data += strlen("CONNECT "); | 117 | start += dataoff + search[SEARCH_CONNECT].len; |
91 | 118 | ||
92 | /* Only search first line. */ | 119 | memset(&ts, 0, sizeof(ts)); |
93 | if ((tmp = strchr(data, '\n'))) | 120 | stop = skb_find_text(*pskb, start, (*pskb)->len, |
94 | *tmp = '\0'; | 121 | search[SEARCH_NEWLINE].ts, &ts); |
122 | if (stop == UINT_MAX) | ||
123 | goto out; | ||
124 | stop += start; | ||
95 | 125 | ||
96 | for (i = 0; i < ARRAY_SIZE(conns); i++) { | 126 | for (i = SEARCH_DATA; i <= SEARCH_INDEX; i++) { |
97 | char *match = strstr(data, conns[i]); | 127 | memset(&ts, 0, sizeof(ts)); |
98 | if (!match) | 128 | off = skb_find_text(*pskb, start, stop, search[i].ts, &ts); |
129 | if (off == UINT_MAX) | ||
99 | continue; | 130 | continue; |
100 | tmp = data = match + strlen(conns[i]); | 131 | off += start + search[i].len; |
101 | port = simple_strtoul(data, &data, 10); | 132 | |
102 | len = data - tmp; | 133 | len = min_t(unsigned int, sizeof(pbuf) - 1, stop - off); |
134 | if (skb_copy_bits(*pskb, off, pbuf, len)) | ||
135 | break; | ||
136 | pbuf[len] = '\0'; | ||
137 | |||
138 | port = simple_strtoul(pbuf, &tmp, 10); | ||
139 | len = tmp - pbuf; | ||
103 | if (port == 0 || len > 5) | 140 | if (port == 0 || len > 5) |
104 | break; | 141 | break; |
105 | 142 | ||
@@ -125,8 +162,7 @@ static int help(struct sk_buff **pskb, | |||
125 | exp->mask.dst.u.tcp.port = 0xFFFF; | 162 | exp->mask.dst.u.tcp.port = 0xFFFF; |
126 | 163 | ||
127 | if (ip_nat_amanda_hook) | 164 | if (ip_nat_amanda_hook) |
128 | ret = ip_nat_amanda_hook(pskb, ctinfo, | 165 | ret = ip_nat_amanda_hook(pskb, ctinfo, off - dataoff, |
129 | tmp - amanda_buffer, | ||
130 | len, exp); | 166 | len, exp); |
131 | else if (ip_conntrack_expect_related(exp) != 0) | 167 | else if (ip_conntrack_expect_related(exp) != 0) |
132 | ret = NF_DROP; | 168 | ret = NF_DROP; |
@@ -134,12 +170,11 @@ static int help(struct sk_buff **pskb, | |||
134 | } | 170 | } |
135 | 171 | ||
136 | out: | 172 | out: |
137 | spin_unlock_bh(&amanda_buffer_lock); | ||
138 | return ret; | 173 | return ret; |
139 | } | 174 | } |
140 | 175 | ||
141 | static struct ip_conntrack_helper amanda_helper = { | 176 | static struct ip_conntrack_helper amanda_helper = { |
142 | .max_expected = ARRAY_SIZE(conns), | 177 | .max_expected = 3, |
143 | .timeout = 180, | 178 | .timeout = 180, |
144 | .me = THIS_MODULE, | 179 | .me = THIS_MODULE, |
145 | .help = help, | 180 | .help = help, |
@@ -155,26 +190,36 @@ static struct ip_conntrack_helper amanda_helper = { | |||
155 | 190 | ||
156 | static void __exit ip_conntrack_amanda_fini(void) | 191 | static void __exit ip_conntrack_amanda_fini(void) |
157 | { | 192 | { |
193 | int i; | ||
194 | |||
158 | ip_conntrack_helper_unregister(&amanda_helper); | 195 | ip_conntrack_helper_unregister(&amanda_helper); |
159 | kfree(amanda_buffer); | 196 | for (i = 0; i < ARRAY_SIZE(search); i++) |
197 | textsearch_destroy(search[i].ts); | ||
160 | } | 198 | } |
161 | 199 | ||
162 | static int __init ip_conntrack_amanda_init(void) | 200 | static int __init ip_conntrack_amanda_init(void) |
163 | { | 201 | { |
164 | int ret; | 202 | int ret, i; |
165 | 203 | ||
166 | amanda_buffer = kmalloc(65536, GFP_KERNEL); | 204 | ret = -ENOMEM; |
167 | if (!amanda_buffer) | 205 | for (i = 0; i < ARRAY_SIZE(search); i++) { |
168 | return -ENOMEM; | 206 | search[i].ts = textsearch_prepare(ts_algo, search[i].string, |
169 | 207 | search[i].len, | |
170 | ret = ip_conntrack_helper_register(&amanda_helper); | 208 | GFP_KERNEL, TS_AUTOLOAD); |
171 | if (ret < 0) { | 209 | if (search[i].ts == NULL) |
172 | kfree(amanda_buffer); | 210 | goto err; |
173 | return ret; | ||
174 | } | 211 | } |
212 | ret = ip_conntrack_helper_register(&amanda_helper); | ||
213 | if (ret < 0) | ||
214 | goto err; | ||
175 | return 0; | 215 | return 0; |
176 | 216 | ||
177 | 217 | err: | |
218 | for (; i >= 0; i--) { | ||
219 | if (search[i].ts) | ||
220 | textsearch_destroy(search[i].ts); | ||
221 | } | ||
222 | return ret; | ||
178 | } | 223 | } |
179 | 224 | ||
180 | module_init(ip_conntrack_amanda_init); | 225 | module_init(ip_conntrack_amanda_init); |