diff options
author | Patrick McHardy <kaber@trash.net> | 2006-05-29 21:25:58 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-06-18 00:29:09 -0400 |
commit | c95261693467f0aeac7fafa69860ddfb02bc12f8 (patch) | |
tree | 07d8686091cfe893d021e6d897983331fc596b3c | |
parent | 7d8c50181778b6ba10c2bba9a2f22db9493bb245 (diff) |
[NETFILTER]: amanda helper: convert to textsearch infrastructure
When a port number within a packet is replaced by a differently sized
number only the packet is resized, but not the copy of the data.
Following port numbers are rewritten based on their offsets within
the copy, leading to packet corruption.
Convert the amanda helper to the textsearch infrastructure to avoid
the copy entirely.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-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 d4072533da21..1540e227890f 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 a604b1ccfdaa..0a7bd7f04061 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); |