]>
Commit | Line | Data |
---|---|---|
5b1b5d4e | 1 | diff -purN linux-2.6.23-rc2.orig/include/linux/netfilter_helpers.h linux-2.6.23-rc2/include/linux/netfilter_helpers.h |
2 | --- linux-2.6.23-rc2.orig/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ linux-2.6.23-rc2/include/linux/netfilter_helpers.h 2007-08-05 10:53:55.000000000 +0200 | |
4 | @@ -0,0 +1,133 @@ | |
5 | +/* | |
6 | + * Helpers for netfiler modules. This file provides implementations for basic | |
7 | + * functions such as strncasecmp(), etc. | |
8 | + * | |
9 | + * gcc will warn for defined but unused functions, so we only include the | |
10 | + * functions requested. The following macros are used: | |
11 | + * NF_NEED_STRNCASECMP nf_strncasecmp() | |
12 | + * NF_NEED_STRTOU16 nf_strtou16() | |
13 | + * NF_NEED_STRTOU32 nf_strtou32() | |
14 | + */ | |
15 | +#ifndef _NETFILTER_HELPERS_H | |
16 | +#define _NETFILTER_HELPERS_H | |
17 | + | |
18 | +/* Only include these functions for kernel code. */ | |
19 | +#ifdef __KERNEL__ | |
20 | + | |
21 | +#include <linux/ctype.h> | |
22 | +#define iseol(c) ( (c) == '\r' || (c) == '\n' ) | |
23 | + | |
24 | +/* | |
25 | + * The standard strncasecmp() | |
26 | + */ | |
27 | +#ifdef NF_NEED_STRNCASECMP | |
28 | +static int | |
29 | +nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) | |
30 | +{ | |
31 | + if (s1 == NULL || s2 == NULL) | |
32 | + { | |
33 | + if (s1 == NULL && s2 == NULL) | |
34 | + { | |
35 | + return 0; | |
36 | + } | |
37 | + return (s1 == NULL) ? -1 : 1; | |
38 | + } | |
39 | + while (len > 0 && tolower(*s1) == tolower(*s2)) | |
40 | + { | |
41 | + len--; | |
42 | + s1++; | |
43 | + s2++; | |
44 | + } | |
45 | + return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); | |
46 | +} | |
47 | +#endif /* NF_NEED_STRNCASECMP */ | |
48 | + | |
49 | +/* | |
50 | + * Parse a string containing a 16-bit unsigned integer. | |
51 | + * Returns the number of chars used, or zero if no number is found. | |
52 | + */ | |
53 | +#ifdef NF_NEED_STRTOU16 | |
54 | +static int | |
55 | +nf_strtou16(const char* pbuf, u_int16_t* pval) | |
56 | +{ | |
57 | + int n = 0; | |
58 | + | |
59 | + *pval = 0; | |
60 | + while (isdigit(pbuf[n])) | |
61 | + { | |
62 | + *pval = (*pval * 10) + (pbuf[n] - '0'); | |
63 | + n++; | |
64 | + } | |
65 | + | |
66 | + return n; | |
67 | +} | |
68 | +#endif /* NF_NEED_STRTOU16 */ | |
69 | + | |
70 | +/* | |
71 | + * Parse a string containing a 32-bit unsigned integer. | |
72 | + * Returns the number of chars used, or zero if no number is found. | |
73 | + */ | |
74 | +#ifdef NF_NEED_STRTOU32 | |
75 | +static int | |
76 | +nf_strtou32(const char* pbuf, u_int32_t* pval) | |
77 | +{ | |
78 | + int n = 0; | |
79 | + | |
80 | + *pval = 0; | |
81 | + while (pbuf[n] >= '0' && pbuf[n] <= '9') | |
82 | + { | |
83 | + *pval = (*pval * 10) + (pbuf[n] - '0'); | |
84 | + n++; | |
85 | + } | |
86 | + | |
87 | + return n; | |
88 | +} | |
89 | +#endif /* NF_NEED_STRTOU32 */ | |
90 | + | |
91 | +/* | |
92 | + * Given a buffer and length, advance to the next line and mark the current | |
93 | + * line. | |
94 | + */ | |
95 | +#ifdef NF_NEED_NEXTLINE | |
96 | +static int | |
97 | +nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) | |
98 | +{ | |
99 | + uint off = *poff; | |
100 | + uint physlen = 0; | |
101 | + | |
102 | + if (off >= len) | |
103 | + { | |
104 | + return 0; | |
105 | + } | |
106 | + | |
107 | + while (p[off] != '\n') | |
108 | + { | |
109 | + if (len-off <= 1) | |
110 | + { | |
111 | + return 0; | |
112 | + } | |
113 | + | |
114 | + physlen++; | |
115 | + off++; | |
116 | + } | |
117 | + | |
118 | + /* if we saw a crlf, physlen needs adjusted */ | |
119 | + if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') | |
120 | + { | |
121 | + physlen--; | |
122 | + } | |
123 | + | |
124 | + /* advance past the newline */ | |
125 | + off++; | |
126 | + | |
127 | + *plineoff = *poff; | |
128 | + *plinelen = physlen; | |
129 | + *poff = off; | |
130 | + | |
131 | + return 1; | |
132 | +} | |
133 | +#endif /* NF_NEED_NEXTLINE */ | |
134 | + | |
135 | +#endif /* __KERNEL__ */ | |
136 | + | |
137 | +#endif /* _NETFILTER_HELPERS_H */ | |
138 | diff -purN linux-2.6.23-rc2.orig/include/linux/netfilter_mime.h linux-2.6.23-rc2/include/linux/netfilter_mime.h | |
139 | --- linux-2.6.23-rc2.orig/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 | |
140 | +++ linux-2.6.23-rc2/include/linux/netfilter_mime.h 2007-08-05 10:53:55.000000000 +0200 | |
141 | @@ -0,0 +1,89 @@ | |
142 | +/* | |
143 | + * MIME functions for netfilter modules. This file provides implementations | |
144 | + * for basic MIME parsing. MIME headers are used in many protocols, such as | |
145 | + * HTTP, RTSP, SIP, etc. | |
146 | + * | |
147 | + * gcc will warn for defined but unused functions, so we only include the | |
148 | + * functions requested. The following macros are used: | |
149 | + * NF_NEED_MIME_NEXTLINE nf_mime_nextline() | |
150 | + */ | |
151 | +#ifndef _NETFILTER_MIME_H | |
152 | +#define _NETFILTER_MIME_H | |
153 | + | |
154 | +/* Only include these functions for kernel code. */ | |
155 | +#ifdef __KERNEL__ | |
156 | + | |
157 | +#include <linux/ctype.h> | |
158 | + | |
159 | +/* | |
160 | + * Given a buffer and length, advance to the next line and mark the current | |
161 | + * line. If the current line is empty, *plinelen will be set to zero. If | |
162 | + * not, it will be set to the actual line length (including CRLF). | |
163 | + * | |
164 | + * 'line' in this context means logical line (includes LWS continuations). | |
165 | + * Returns 1 on success, 0 on failure. | |
166 | + */ | |
167 | +#ifdef NF_NEED_MIME_NEXTLINE | |
168 | +static int | |
169 | +nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) | |
170 | +{ | |
171 | + uint off = *poff; | |
172 | + uint physlen = 0; | |
173 | + int is_first_line = 1; | |
174 | + | |
175 | + if (off >= len) | |
176 | + { | |
177 | + return 0; | |
178 | + } | |
179 | + | |
180 | + do | |
181 | + { | |
182 | + while (p[off] != '\n') | |
183 | + { | |
184 | + if (len-off <= 1) | |
185 | + { | |
186 | + return 0; | |
187 | + } | |
188 | + | |
189 | + physlen++; | |
190 | + off++; | |
191 | + } | |
192 | + | |
193 | + /* if we saw a crlf, physlen needs adjusted */ | |
194 | + if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') | |
195 | + { | |
196 | + physlen--; | |
197 | + } | |
198 | + | |
199 | + /* advance past the newline */ | |
200 | + off++; | |
201 | + | |
202 | + /* check for an empty line */ | |
203 | + if (physlen == 0) | |
204 | + { | |
205 | + break; | |
206 | + } | |
207 | + | |
208 | + /* check for colon on the first physical line */ | |
209 | + if (is_first_line) | |
210 | + { | |
211 | + is_first_line = 0; | |
212 | + if (memchr(p+(*poff), ':', physlen) == NULL) | |
213 | + { | |
214 | + return 0; | |
215 | + } | |
216 | + } | |
217 | + } | |
218 | + while (p[off] == ' ' || p[off] == '\t'); | |
219 | + | |
220 | + *plineoff = *poff; | |
221 | + *plinelen = (physlen == 0) ? 0 : (off - *poff); | |
222 | + *poff = off; | |
223 | + | |
224 | + return 1; | |
225 | +} | |
226 | +#endif /* NF_NEED_MIME_NEXTLINE */ | |
227 | + | |
228 | +#endif /* __KERNEL__ */ | |
229 | + | |
230 | +#endif /* _NETFILTER_MIME_H */ | |
231 | diff -purN linux-2.6.23-rc2.orig/net/ipv4/netfilter/Kconfig linux-2.6.23-rc2/net/ipv4/netfilter/Kconfig | |
232 | --- linux-2.6.23-rc2.orig/net/ipv4/netfilter/Kconfig 2007-08-05 21:17:01.000000000 +0200 | |
233 | +++ linux-2.6.23-rc2/net/ipv4/netfilter/Kconfig 2007-08-05 11:04:59.000000000 +0200 | |
234 | @@ -274,6 +274,11 @@ config NF_NAT_IRC | |
235 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | |
236 | default NF_NAT && NF_CONNTRACK_IRC | |
237 | ||
238 | +config NF_NAT_RTSP | |
239 | + tristate | |
240 | + depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | |
241 | + default NF_NAT && NF_CONNTRACK_RTSP | |
242 | + | |
243 | config NF_NAT_TFTP | |
244 | tristate | |
245 | depends on IP_NF_IPTABLES && NF_CONNTRACK && NF_NAT | |
246 | diff -purN linux-2.6.23-rc2.orig/net/ipv4/netfilter/Makefile linux-2.6.23-rc2/net/ipv4/netfilter/Makefile | |
247 | --- linux-2.6.23-rc2.orig/net/ipv4/netfilter/Makefile 2007-08-05 21:14:19.000000000 +0200 | |
248 | +++ linux-2.6.23-rc2/net/ipv4/netfilter/Makefile 2007-08-05 10:53:55.000000000 +0200 | |
2380c486 | 249 | @@ -0,0 +0,1 @@ |
5b1b5d4e | 250 | +obj-$(CONFIG_NF_NAT_RTSP) += nf_nat_rtsp.o |
5b1b5d4e | 251 | diff -purN linux-2.6.23-rc2.orig/net/netfilter/Kconfig linux-2.6.23-rc2/net/netfilter/Kconfig |
252 | --- linux-2.6.23-rc2.orig/net/netfilter/Kconfig 2007-08-05 21:17:02.000000000 +0200 | |
253 | +++ linux-2.6.23-rc2/net/netfilter/Kconfig 2007-08-05 11:04:59.000000000 +0200 | |
2380c486 JR |
254 | @@ -249,6 +249,16 @@ config NF_CONNTRACK_TFTP |
255 | ||
256 | To compile it as a module, choose M here. If unsure, say N. | |
257 | ||
5b1b5d4e | 258 | +config NF_CONNTRACK_RTSP |
259 | + tristate "RTSP protocol support" | |
260 | + depends on NF_CONNTRACK | |
261 | + help | |
262 | + Support the RTSP protocol. This allows UDP transports to be setup | |
263 | + properly, including RTP and RDT. | |
264 | + | |
265 | + If you want to compile it as a module, say 'M' here and read | |
266 | + Documentation/modules.txt. If unsure, say 'Y'. | |
267 | + | |
2380c486 JR |
268 | config NF_CONNTRACK_MMS |
269 | tristate 'MMS protocol support' | |
270 | depends on NF_CONNTRACK | |
5b1b5d4e | 271 | diff -purN linux-2.6.23-rc2.orig/net/netfilter/Makefile linux-2.6.23-rc2/net/netfilter/Makefile |
272 | --- linux-2.6.23-rc2.orig/net/netfilter/Makefile 2007-08-05 21:17:02.000000000 +0200 | |
273 | +++ linux-2.6.23-rc2/net/netfilter/Makefile 2007-08-05 11:04:59.000000000 +0200 | |
d3738884 | 274 | @@ -0,0 +0,1 @@ |
5b1b5d4e | 275 | +obj-$(CONFIG_NF_CONNTRACK_RTSP) += nf_conntrack_rtsp.o |
5b1b5d4e | 276 | diff -purN linux-2.6.24-rc1.orig/include/linux/netfilter/nf_conntrack_rtsp.h linux-2.6.24-rc1/include/linux/netfilter/nf_conntrack_rtsp.h |
277 | --- linux-2.6.24-rc1.orig/include/linux/netfilter/nf_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 | |
278 | +++ linux-2.6.24-rc1/include/linux/netfilter/nf_conntrack_rtsp.h 2007-11-10 17:16:36.000000000 +0100 | |
279 | @@ -0,0 +1,63 @@ | |
280 | +/* | |
281 | + * RTSP extension for IP connection tracking. | |
282 | + * (C) 2003 by Tom Marshall <tmarshall at real.com> | |
283 | + * based on ip_conntrack_irc.h | |
284 | + * | |
285 | + * This program is free software; you can redistribute it and/or | |
286 | + * modify it under the terms of the GNU General Public License | |
287 | + * as published by the Free Software Foundation; either version | |
288 | + * 2 of the License, or (at your option) any later version. | |
289 | + */ | |
290 | +#ifndef _IP_CONNTRACK_RTSP_H | |
291 | +#define _IP_CONNTRACK_RTSP_H | |
292 | + | |
293 | +//#define IP_NF_RTSP_DEBUG 1 | |
294 | +#define IP_NF_RTSP_VERSION "0.6.21" | |
295 | + | |
296 | +#ifdef __KERNEL__ | |
297 | +/* port block types */ | |
298 | +typedef enum { | |
299 | + pb_single, /* client_port=x */ | |
300 | + pb_range, /* client_port=x-y */ | |
301 | + pb_discon /* client_port=x/y (rtspbis) */ | |
302 | +} portblock_t; | |
303 | + | |
304 | +/* We record seq number and length of rtsp headers here, all in host order. */ | |
305 | + | |
306 | +/* | |
307 | + * This structure is per expected connection. It is a member of struct | |
308 | + * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored | |
309 | + * there and we are expected to only store the length of the data which | |
310 | + * needs replaced. If a packet contains multiple RTSP messages, we create | |
311 | + * one expected connection per message. | |
312 | + * | |
313 | + * We use these variables to mark the entire header block. This may seem | |
314 | + * like overkill, but the nature of RTSP requires it. A header may appear | |
315 | + * multiple times in a message. We must treat two Transport headers the | |
316 | + * same as one Transport header with two entries. | |
317 | + */ | |
318 | +struct ip_ct_rtsp_expect | |
319 | +{ | |
320 | + u_int32_t len; /* length of header block */ | |
321 | + portblock_t pbtype; /* Type of port block that was requested */ | |
322 | + u_int16_t loport; /* Port that was requested, low or first */ | |
323 | + u_int16_t hiport; /* Port that was requested, high or second */ | |
324 | +#if 0 | |
325 | + uint method; /* RTSP method */ | |
326 | + uint cseq; /* CSeq from request */ | |
327 | +#endif | |
328 | +}; | |
329 | + | |
330 | +extern unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, | |
331 | + enum ip_conntrack_info ctinfo, | |
332 | + unsigned int matchoff, unsigned int matchlen, | |
333 | + struct ip_ct_rtsp_expect *prtspexp, | |
334 | + struct nf_conntrack_expect *exp); | |
335 | + | |
336 | +extern void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); | |
337 | + | |
338 | +#define RTSP_PORT 554 | |
339 | + | |
340 | +#endif /* __KERNEL__ */ | |
341 | + | |
342 | +#endif /* _IP_CONNTRACK_RTSP_H */ | |
343 | diff -purN linux-2.6.24-rc1.orig/net/ipv4/netfilter/nf_nat_rtsp.c linux-2.6.24-rc1/net/ipv4/netfilter/nf_nat_rtsp.c | |
344 | --- linux-2.6.24-rc1.orig/net/ipv4/netfilter/nf_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 | |
345 | +++ linux-2.6.24-rc1/net/ipv4/netfilter/nf_nat_rtsp.c 2007-11-10 17:17:21.000000000 +0100 | |
346 | @@ -0,0 +1,489 @@ | |
347 | +/* | |
348 | + * RTSP extension for TCP NAT alteration | |
349 | + * (C) 2003 by Tom Marshall <tmarshall at real.com> | |
350 | + * based on ip_nat_irc.c | |
351 | + * | |
352 | + * This program is free software; you can redistribute it and/or | |
353 | + * modify it under the terms of the GNU General Public License | |
354 | + * as published by the Free Software Foundation; either version | |
355 | + * 2 of the License, or (at your option) any later version. | |
356 | + * | |
357 | + * Module load syntax: | |
358 | + * insmod nf_nat_rtsp.o ports=port1,port2,...port<MAX_PORTS> | |
359 | + * stunaddr=<address> | |
360 | + * destaction=[auto|strip|none] | |
361 | + * | |
362 | + * If no ports are specified, the default will be port 554 only. | |
363 | + * | |
364 | + * stunaddr specifies the address used to detect that a client is using STUN. | |
365 | + * If this address is seen in the destination parameter, it is assumed that | |
366 | + * the client has already punched a UDP hole in the firewall, so we don't | |
367 | + * mangle the client_port. If none is specified, it is autodetected. It | |
368 | + * only needs to be set if you have multiple levels of NAT. It should be | |
369 | + * set to the external address that the STUN clients detect. Note that in | |
370 | + * this case, it will not be possible for clients to use UDP with servers | |
371 | + * between the NATs. | |
372 | + * | |
373 | + * If no destaction is specified, auto is used. | |
374 | + * destaction=auto: strip destination parameter if it is not stunaddr. | |
375 | + * destaction=strip: always strip destination parameter (not recommended). | |
376 | + * destaction=none: do not touch destination parameter (not recommended). | |
377 | + */ | |
378 | + | |
379 | +#include <linux/module.h> | |
380 | +#include <net/tcp.h> | |
381 | +#include <net/netfilter/nf_nat_helper.h> | |
382 | +#include <net/netfilter/nf_nat_rule.h> | |
383 | +#include <linux/netfilter/nf_conntrack_rtsp.h> | |
384 | +#include <net/netfilter/nf_conntrack_expect.h> | |
385 | + | |
386 | +#include <linux/inet.h> | |
387 | +#include <linux/ctype.h> | |
388 | +#define NF_NEED_STRNCASECMP | |
389 | +#define NF_NEED_STRTOU16 | |
390 | +#include <linux/netfilter_helpers.h> | |
391 | +#define NF_NEED_MIME_NEXTLINE | |
392 | +#include <linux/netfilter_mime.h> | |
393 | + | |
394 | +#define MAX_PORTS 8 | |
395 | +#define DSTACT_AUTO 0 | |
396 | +#define DSTACT_STRIP 1 | |
397 | +#define DSTACT_NONE 2 | |
398 | + | |
399 | +static char* stunaddr = NULL; | |
400 | +static char* destaction = NULL; | |
401 | + | |
402 | +static u_int32_t extip = 0; | |
403 | +static int dstact = 0; | |
404 | + | |
405 | +MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>"); | |
406 | +MODULE_DESCRIPTION("RTSP network address translation module"); | |
407 | +MODULE_LICENSE("GPL"); | |
408 | +module_param(stunaddr, charp, 0644); | |
409 | +MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); | |
410 | +module_param(destaction, charp, 0644); | |
411 | +MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); | |
412 | + | |
413 | +#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } | |
414 | + | |
415 | +/*** helper functions ***/ | |
416 | + | |
417 | +static void | |
418 | +get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) | |
419 | +{ | |
420 | + struct iphdr* iph = ip_hdr(skb); | |
421 | + struct tcphdr* tcph = (void *)iph + ip_hdrlen(skb); | |
422 | + | |
423 | + *pptcpdata = (char*)tcph + tcph->doff*4; | |
424 | + *ptcpdatalen = ((char*)skb_transport_header(skb) + skb->len) - *pptcpdata; | |
425 | +} | |
426 | + | |
427 | +/*** nat functions ***/ | |
428 | + | |
429 | +/* | |
430 | + * Mangle the "Transport:" header: | |
431 | + * - Replace all occurences of "client_port=<spec>" | |
432 | + * - Handle destination parameter | |
433 | + * | |
434 | + * In: | |
435 | + * ct, ctinfo = conntrack context | |
436 | + * skb = packet | |
437 | + * tranoff = Transport header offset from TCP data | |
438 | + * tranlen = Transport header length (incl. CRLF) | |
439 | + * rport_lo = replacement low port (host endian) | |
440 | + * rport_hi = replacement high port (host endian) | |
441 | + * | |
442 | + * Returns packet size difference. | |
443 | + * | |
444 | + * Assumes that a complete transport header is present, ending with CR or LF | |
445 | + */ | |
446 | +static int | |
447 | +rtsp_mangle_tran(enum ip_conntrack_info ctinfo, | |
448 | + struct nf_conntrack_expect* exp, | |
449 | + struct ip_ct_rtsp_expect* prtspexp, | |
450 | + struct sk_buff* skb, uint tranoff, uint tranlen) | |
451 | +{ | |
452 | + char* ptcp; | |
453 | + uint tcplen; | |
454 | + char* ptran; | |
455 | + char rbuf1[16]; /* Replacement buffer (one port) */ | |
456 | + uint rbuf1len; /* Replacement len (one port) */ | |
457 | + char rbufa[16]; /* Replacement buffer (all ports) */ | |
458 | + uint rbufalen; /* Replacement len (all ports) */ | |
459 | + u_int32_t newip; | |
460 | + u_int16_t loport, hiport; | |
461 | + uint off = 0; | |
462 | + uint diff; /* Number of bytes we removed */ | |
463 | + | |
464 | + struct nf_conn *ct = exp->master; | |
465 | + struct nf_conntrack_tuple *t; | |
466 | + | |
467 | + char szextaddr[15+1]; | |
468 | + uint extaddrlen; | |
469 | + int is_stun; | |
470 | + | |
471 | + get_skb_tcpdata(skb, &ptcp, &tcplen); | |
472 | + ptran = ptcp+tranoff; | |
473 | + | |
474 | + if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || | |
475 | + tranlen < 10 || !iseol(ptran[tranlen-1]) || | |
476 | + nf_strncasecmp(ptran, "Transport:", 10) != 0) | |
477 | + { | |
478 | + pr_info("sanity check failed\n"); | |
479 | + return 0; | |
480 | + } | |
481 | + off += 10; | |
482 | + SKIP_WSPACE(ptcp+tranoff, tranlen, off); | |
483 | + | |
484 | + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip; | |
485 | + t = &exp->tuple; | |
486 | + t->dst.u3.ip = newip; | |
487 | + | |
488 | + extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip)) | |
489 | + : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip)); | |
490 | + pr_debug("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); | |
491 | + | |
492 | + rbuf1len = rbufalen = 0; | |
493 | + switch (prtspexp->pbtype) | |
494 | + { | |
495 | + case pb_single: | |
496 | + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ | |
497 | + { | |
498 | + t->dst.u.udp.port = htons(loport); | |
499 | + if (nf_ct_expect_related(exp) == 0) | |
500 | + { | |
501 | + pr_debug("using port %hu\n", loport); | |
502 | + break; | |
503 | + } | |
504 | + } | |
505 | + if (loport != 0) | |
506 | + { | |
507 | + rbuf1len = sprintf(rbuf1, "%hu", loport); | |
508 | + rbufalen = sprintf(rbufa, "%hu", loport); | |
509 | + } | |
510 | + break; | |
511 | + case pb_range: | |
512 | + for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ | |
513 | + { | |
514 | + t->dst.u.udp.port = htons(loport); | |
515 | + if (nf_ct_expect_related(exp) == 0) | |
516 | + { | |
517 | + hiport = loport + 1; //~exp->mask.dst.u.udp.port; | |
518 | + pr_debug("using ports %hu-%hu\n", loport, hiport); | |
519 | + break; | |
520 | + } | |
521 | + } | |
522 | + if (loport != 0) | |
523 | + { | |
524 | + rbuf1len = sprintf(rbuf1, "%hu", loport); | |
525 | + rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); | |
526 | + } | |
527 | + break; | |
528 | + case pb_discon: | |
529 | + for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ | |
530 | + { | |
531 | + t->dst.u.udp.port = htons(loport); | |
532 | + if (nf_ct_expect_related(exp) == 0) | |
533 | + { | |
534 | + pr_debug("using port %hu (1 of 2)\n", loport); | |
535 | + break; | |
536 | + } | |
537 | + } | |
538 | + for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ | |
539 | + { | |
540 | + t->dst.u.udp.port = htons(hiport); | |
541 | + if (nf_ct_expect_related(exp) == 0) | |
542 | + { | |
543 | + pr_debug("using port %hu (2 of 2)\n", hiport); | |
544 | + break; | |
545 | + } | |
546 | + } | |
547 | + if (loport != 0 && hiport != 0) | |
548 | + { | |
549 | + rbuf1len = sprintf(rbuf1, "%hu", loport); | |
550 | + if (hiport == loport+1) | |
551 | + { | |
552 | + rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); | |
553 | + } | |
554 | + else | |
555 | + { | |
556 | + rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); | |
557 | + } | |
558 | + } | |
559 | + break; | |
560 | + } | |
561 | + | |
562 | + if (rbuf1len == 0) | |
563 | + { | |
564 | + return 0; /* cannot get replacement port(s) */ | |
565 | + } | |
566 | + | |
567 | + /* Transport: tran;field;field=val,tran;field;field=val,... */ | |
568 | + while (off < tranlen) | |
569 | + { | |
570 | + uint saveoff; | |
571 | + const char* pparamend; | |
572 | + uint nextparamoff; | |
573 | + | |
574 | + pparamend = memchr(ptran+off, ',', tranlen-off); | |
575 | + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; | |
576 | + nextparamoff = pparamend-ptcp; | |
577 | + | |
578 | + /* | |
579 | + * We pass over each param twice. On the first pass, we look for a | |
580 | + * destination= field. It is handled by the security policy. If it | |
581 | + * is present, allowed, and equal to our external address, we assume | |
582 | + * that STUN is being used and we leave the client_port= field alone. | |
583 | + */ | |
584 | + is_stun = 0; | |
585 | + saveoff = off; | |
586 | + while (off < nextparamoff) | |
587 | + { | |
588 | + const char* pfieldend; | |
589 | + uint nextfieldoff; | |
590 | + | |
591 | + pfieldend = memchr(ptran+off, ';', nextparamoff-off); | |
592 | + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; | |
593 | + | |
594 | + if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) | |
595 | + { | |
596 | + if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) | |
597 | + { | |
598 | + is_stun = 1; | |
599 | + } | |
600 | + if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) | |
601 | + { | |
602 | + diff = nextfieldoff-off; | |
603 | + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | |
604 | + off, diff, NULL, 0)) | |
605 | + { | |
606 | + /* mangle failed, all we can do is bail */ | |
607 | + nf_ct_unexpect_related(exp); | |
608 | + return 0; | |
609 | + } | |
610 | + get_skb_tcpdata(skb, &ptcp, &tcplen); | |
611 | + ptran = ptcp+tranoff; | |
612 | + tranlen -= diff; | |
613 | + nextparamoff -= diff; | |
614 | + nextfieldoff -= diff; | |
615 | + } | |
616 | + } | |
617 | + | |
618 | + off = nextfieldoff; | |
619 | + } | |
620 | + if (is_stun) | |
621 | + { | |
622 | + continue; | |
623 | + } | |
624 | + off = saveoff; | |
625 | + while (off < nextparamoff) | |
626 | + { | |
627 | + const char* pfieldend; | |
628 | + uint nextfieldoff; | |
629 | + | |
630 | + pfieldend = memchr(ptran+off, ';', nextparamoff-off); | |
631 | + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; | |
632 | + | |
633 | + if (strncmp(ptran+off, "client_port=", 12) == 0) | |
634 | + { | |
635 | + u_int16_t port; | |
636 | + uint numlen; | |
637 | + uint origoff; | |
638 | + uint origlen; | |
639 | + char* rbuf = rbuf1; | |
640 | + uint rbuflen = rbuf1len; | |
641 | + | |
642 | + off += 12; | |
643 | + origoff = (ptran-ptcp)+off; | |
644 | + origlen = 0; | |
645 | + numlen = nf_strtou16(ptran+off, &port); | |
646 | + off += numlen; | |
647 | + origlen += numlen; | |
648 | + if (port != prtspexp->loport) | |
649 | + { | |
650 | + pr_debug("multiple ports found, port %hu ignored\n", port); | |
651 | + } | |
652 | + else | |
653 | + { | |
654 | + if (ptran[off] == '-' || ptran[off] == '/') | |
655 | + { | |
656 | + off++; | |
657 | + origlen++; | |
658 | + numlen = nf_strtou16(ptran+off, &port); | |
659 | + off += numlen; | |
660 | + origlen += numlen; | |
661 | + rbuf = rbufa; | |
662 | + rbuflen = rbufalen; | |
663 | + } | |
664 | + | |
665 | + /* | |
666 | + * note we cannot just memcpy() if the sizes are the same. | |
667 | + * the mangle function does skb resizing, checks for a | |
668 | + * cloned skb, and updates the checksums. | |
669 | + * | |
670 | + * parameter 4 below is offset from start of tcp data. | |
671 | + */ | |
672 | + diff = origlen-rbuflen; | |
673 | + if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | |
674 | + origoff, origlen, rbuf, rbuflen)) | |
675 | + { | |
676 | + /* mangle failed, all we can do is bail */ | |
677 | + nf_ct_unexpect_related(exp); | |
678 | + return 0; | |
679 | + } | |
680 | + get_skb_tcpdata(skb, &ptcp, &tcplen); | |
681 | + ptran = ptcp+tranoff; | |
682 | + tranlen -= diff; | |
683 | + nextparamoff -= diff; | |
684 | + nextfieldoff -= diff; | |
685 | + } | |
686 | + } | |
687 | + | |
688 | + off = nextfieldoff; | |
689 | + } | |
690 | + | |
691 | + off = nextparamoff; | |
692 | + } | |
693 | + | |
694 | + return 1; | |
695 | +} | |
696 | + | |
697 | +static uint | |
698 | +help_out(struct sk_buff *skb, enum ip_conntrack_info ctinfo, | |
699 | + unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, | |
700 | + struct nf_conntrack_expect* exp) | |
701 | +{ | |
702 | + char* ptcp; | |
703 | + uint tcplen; | |
704 | + uint hdrsoff; | |
705 | + uint hdrslen; | |
706 | + uint lineoff; | |
707 | + uint linelen; | |
708 | + uint off; | |
709 | + | |
710 | + //struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; | |
711 | + //struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); | |
712 | + | |
713 | + get_skb_tcpdata(skb, &ptcp, &tcplen); | |
714 | + hdrsoff = matchoff;//exp->seq - ntohl(tcph->seq); | |
715 | + hdrslen = matchlen; | |
716 | + off = hdrsoff; | |
717 | + pr_debug("NAT rtsp help_out\n"); | |
718 | + | |
719 | + while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) | |
720 | + { | |
721 | + if (linelen == 0) | |
722 | + { | |
723 | + break; | |
724 | + } | |
725 | + if (off > hdrsoff+hdrslen) | |
726 | + { | |
727 | + pr_info("!! overrun !!"); | |
728 | + break; | |
729 | + } | |
730 | + pr_debug("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); | |
731 | + | |
732 | + if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) | |
733 | + { | |
734 | + uint oldtcplen = tcplen; | |
735 | + pr_debug("hdr: Transport\n"); | |
736 | + if (!rtsp_mangle_tran(ctinfo, exp, prtspexp, skb, lineoff, linelen)) | |
737 | + { | |
738 | + pr_debug("hdr: Transport mangle failed"); | |
739 | + break; | |
740 | + } | |
741 | + get_skb_tcpdata(skb, &ptcp, &tcplen); | |
742 | + hdrslen -= (oldtcplen-tcplen); | |
743 | + off -= (oldtcplen-tcplen); | |
744 | + lineoff -= (oldtcplen-tcplen); | |
745 | + linelen -= (oldtcplen-tcplen); | |
746 | + pr_debug("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); | |
747 | + } | |
748 | + } | |
749 | + | |
750 | + return NF_ACCEPT; | |
751 | +} | |
752 | + | |
753 | +static unsigned int | |
754 | +help(struct sk_buff *skb, enum ip_conntrack_info ctinfo, | |
755 | + unsigned int matchoff, unsigned int matchlen, struct ip_ct_rtsp_expect* prtspexp, | |
756 | + struct nf_conntrack_expect* exp) | |
757 | +{ | |
758 | + int dir = CTINFO2DIR(ctinfo); | |
759 | + int rc = NF_ACCEPT; | |
760 | + | |
761 | + switch (dir) | |
762 | + { | |
763 | + case IP_CT_DIR_ORIGINAL: | |
764 | + rc = help_out(skb, ctinfo, matchoff, matchlen, prtspexp, exp); | |
765 | + break; | |
766 | + case IP_CT_DIR_REPLY: | |
767 | + pr_debug("unmangle ! %u\n", ctinfo); | |
768 | + /* XXX: unmangle */ | |
769 | + rc = NF_ACCEPT; | |
770 | + break; | |
771 | + } | |
772 | + //UNLOCK_BH(&ip_rtsp_lock); | |
773 | + | |
774 | + return rc; | |
775 | +} | |
776 | + | |
777 | +static void expected(struct nf_conn* ct, struct nf_conntrack_expect *exp) | |
778 | +{ | |
779 | + struct nf_nat_multi_range_compat mr; | |
780 | + u_int32_t newdstip, newsrcip, newip; | |
781 | + | |
782 | + struct nf_conn *master = ct->master; | |
783 | + | |
784 | + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; | |
785 | + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; | |
786 | + //FIXME (how to port that ?) | |
787 | + //code from 2.4 : newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; | |
788 | + newip = newdstip; | |
789 | + | |
790 | + pr_debug("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n", | |
791 | + NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip)); | |
792 | + | |
793 | + mr.rangesize = 1; | |
794 | + // We don't want to manip the per-protocol, just the IPs. | |
795 | + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; | |
796 | + mr.range[0].min_ip = mr.range[0].max_ip = newip; | |
797 | + | |
2380c486 | 798 | + nf_nat_setup_info(ct, &mr.range[0], IP_NAT_MANIP_DST); |
5b1b5d4e | 799 | +} |
800 | + | |
801 | + | |
802 | +static void __exit fini(void) | |
803 | +{ | |
804 | + nf_nat_rtsp_hook = NULL; | |
805 | + nf_nat_rtsp_hook_expectfn = NULL; | |
806 | + synchronize_net(); | |
807 | +} | |
808 | + | |
809 | +static int __init init(void) | |
810 | +{ | |
811 | + printk("nf_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); | |
812 | + | |
813 | + BUG_ON(nf_nat_rtsp_hook); | |
814 | + nf_nat_rtsp_hook = help; | |
815 | + nf_nat_rtsp_hook_expectfn = &expected; | |
816 | + | |
817 | + if (stunaddr != NULL) | |
818 | + extip = in_aton(stunaddr); | |
819 | + | |
820 | + if (destaction != NULL) { | |
821 | + if (strcmp(destaction, "auto") == 0) | |
822 | + dstact = DSTACT_AUTO; | |
823 | + | |
824 | + if (strcmp(destaction, "strip") == 0) | |
825 | + dstact = DSTACT_STRIP; | |
826 | + | |
827 | + if (strcmp(destaction, "none") == 0) | |
828 | + dstact = DSTACT_NONE; | |
829 | + } | |
830 | + | |
831 | + return 0; | |
832 | +} | |
833 | + | |
834 | +module_init(init); | |
835 | +module_exit(fini); | |
2380c486 JR |
836 | diff -purN linux-2.6.26.orig/net/netfilter/nf_conntrack_rtsp.c linux-2.6.26/net/netfilter/nf_conntrack_rtsp.c |
837 | --- linux-2.6.26.orig/net/netfilter/nf_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 | |
838 | +++ linux-2.6.26/net/netfilter/nf_conntrack_rtsp.c 2008-07-24 16:19:36.000000000 +0200 | |
839 | @@ -0,0 +1,519 @@ | |
5b1b5d4e | 840 | +/* |
841 | + * RTSP extension for IP connection tracking | |
842 | + * (C) 2003 by Tom Marshall <tmarshall at real.com> | |
843 | + * based on ip_conntrack_irc.c | |
844 | + * | |
845 | + * This program is free software; you can redistribute it and/or | |
846 | + * modify it under the terms of the GNU General Public License | |
847 | + * as published by the Free Software Foundation; either version | |
848 | + * 2 of the License, or (at your option) any later version. | |
849 | + * | |
850 | + * Module load syntax: | |
851 | + * insmod nf_conntrack_rtsp.o ports=port1,port2,...port<MAX_PORTS> | |
852 | + * max_outstanding=n setup_timeout=secs | |
853 | + * | |
854 | + * If no ports are specified, the default will be port 554. | |
855 | + * | |
856 | + * With max_outstanding you can define the maximum number of not yet | |
857 | + * answered SETUP requests per RTSP session (default 8). | |
858 | + * With setup_timeout you can specify how long the system waits for | |
859 | + * an expected data channel (default 300 seconds). | |
860 | + * | |
861 | + * 2005-02-13: Harald Welte <laforge at netfilter.org> | |
862 | + * - port to 2.6 | |
863 | + * - update to recent post-2.6.11 api changes | |
864 | + * 2006-09-14: Steven Van Acker <deepstar at singularity.be> | |
865 | + * - removed calls to NAT code from conntrack helper: NAT no longer needed to use rtsp-conntrack | |
866 | + * 2007-04-18: Michael Guntsche <mike at it-loops.com> | |
867 | + * - Port to new NF API | |
868 | + */ | |
869 | + | |
870 | +#include <linux/module.h> | |
871 | +#include <linux/netfilter.h> | |
872 | +#include <linux/ip.h> | |
873 | +#include <linux/inet.h> | |
874 | +#include <net/tcp.h> | |
875 | + | |
876 | +#include <net/netfilter/nf_conntrack.h> | |
877 | +#include <net/netfilter/nf_conntrack_expect.h> | |
878 | +#include <net/netfilter/nf_conntrack_helper.h> | |
879 | +#include <linux/netfilter/nf_conntrack_rtsp.h> | |
880 | + | |
881 | +#define NF_NEED_STRNCASECMP | |
882 | +#define NF_NEED_STRTOU16 | |
883 | +#define NF_NEED_STRTOU32 | |
884 | +#define NF_NEED_NEXTLINE | |
885 | +#include <linux/netfilter_helpers.h> | |
886 | +#define NF_NEED_MIME_NEXTLINE | |
887 | +#include <linux/netfilter_mime.h> | |
888 | + | |
889 | +#include <linux/ctype.h> | |
890 | +#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ | |
891 | + | |
892 | +#define MAX_PORTS 8 | |
893 | +static int ports[MAX_PORTS]; | |
894 | +static int num_ports = 0; | |
895 | +static int max_outstanding = 8; | |
896 | +static unsigned int setup_timeout = 300; | |
897 | + | |
898 | +MODULE_AUTHOR("Tom Marshall <tmarshall at real.com>"); | |
899 | +MODULE_DESCRIPTION("RTSP connection tracking module"); | |
900 | +MODULE_LICENSE("GPL"); | |
901 | +module_param_array(ports, int, &num_ports, 0400); | |
902 | +MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); | |
903 | +module_param(max_outstanding, int, 0400); | |
904 | +MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); | |
905 | +module_param(setup_timeout, int, 0400); | |
906 | +MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); | |
907 | + | |
908 | +static char *rtsp_buffer; | |
909 | +static DEFINE_SPINLOCK(rtsp_buffer_lock); | |
910 | + | |
2380c486 JR |
911 | +static struct nf_conntrack_expect_policy rtsp_exp_policy; |
912 | + | |
5b1b5d4e | 913 | +unsigned int (*nf_nat_rtsp_hook)(struct sk_buff *skb, |
914 | + enum ip_conntrack_info ctinfo, | |
915 | + unsigned int matchoff, unsigned int matchlen,struct ip_ct_rtsp_expect* prtspexp, | |
916 | + struct nf_conntrack_expect *exp); | |
917 | +void (*nf_nat_rtsp_hook_expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); | |
918 | + | |
919 | +EXPORT_SYMBOL_GPL(nf_nat_rtsp_hook); | |
920 | + | |
921 | +/* | |
922 | + * Max mappings we will allow for one RTSP connection (for RTP, the number | |
923 | + * of allocated ports is twice this value). Note that SMIL burns a lot of | |
924 | + * ports so keep this reasonably high. If this is too low, you will see a | |
925 | + * lot of "no free client map entries" messages. | |
926 | + */ | |
927 | +#define MAX_PORT_MAPS 16 | |
928 | + | |
929 | +/*** default port list was here in the masq code: 554, 3030, 4040 ***/ | |
930 | + | |
931 | +#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } | |
932 | + | |
933 | +/* | |
934 | + * Parse an RTSP packet. | |
935 | + * | |
936 | + * Returns zero if parsing failed. | |
937 | + * | |
938 | + * Parameters: | |
939 | + * IN ptcp tcp data pointer | |
940 | + * IN tcplen tcp data len | |
941 | + * IN/OUT ptcpoff points to current tcp offset | |
942 | + * OUT phdrsoff set to offset of rtsp headers | |
943 | + * OUT phdrslen set to length of rtsp headers | |
944 | + * OUT pcseqoff set to offset of CSeq header | |
945 | + * OUT pcseqlen set to length of CSeq header | |
946 | + */ | |
947 | +static int | |
948 | +rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, | |
949 | + uint* phdrsoff, uint* phdrslen, | |
950 | + uint* pcseqoff, uint* pcseqlen, | |
951 | + uint* transoff, uint* translen) | |
952 | +{ | |
953 | + uint entitylen = 0; | |
954 | + uint lineoff; | |
955 | + uint linelen; | |
956 | + | |
957 | + if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) | |
958 | + return 0; | |
959 | + | |
960 | + *phdrsoff = *ptcpoff; | |
961 | + while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) { | |
962 | + if (linelen == 0) { | |
963 | + if (entitylen > 0) | |
964 | + *ptcpoff += min(entitylen, tcplen - *ptcpoff); | |
965 | + break; | |
966 | + } | |
967 | + if (lineoff+linelen > tcplen) { | |
968 | + pr_info("!! overrun !!\n"); | |
969 | + break; | |
970 | + } | |
971 | + | |
972 | + if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) { | |
973 | + *pcseqoff = lineoff; | |
974 | + *pcseqlen = linelen; | |
975 | + } | |
976 | + | |
977 | + if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) { | |
978 | + *transoff = lineoff; | |
979 | + *translen = linelen; | |
980 | + } | |
981 | + | |
982 | + if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) { | |
983 | + uint off = lineoff+15; | |
984 | + SKIP_WSPACE(ptcp+lineoff, linelen, off); | |
985 | + nf_strtou32(ptcp+off, &entitylen); | |
986 | + } | |
987 | + } | |
988 | + *phdrslen = (*ptcpoff) - (*phdrsoff); | |
989 | + | |
990 | + return 1; | |
991 | +} | |
992 | + | |
993 | +/* | |
994 | + * Find lo/hi client ports (if any) in transport header | |
995 | + * In: | |
996 | + * ptcp, tcplen = packet | |
997 | + * tranoff, tranlen = buffer to search | |
998 | + * | |
999 | + * Out: | |
1000 | + * pport_lo, pport_hi = lo/hi ports (host endian) | |
1001 | + * | |
1002 | + * Returns nonzero if any client ports found | |
1003 | + * | |
1004 | + * Note: it is valid (and expected) for the client to request multiple | |
1005 | + * transports, so we need to parse the entire line. | |
1006 | + */ | |
1007 | +static int | |
1008 | +rtsp_parse_transport(char* ptran, uint tranlen, | |
1009 | + struct ip_ct_rtsp_expect* prtspexp) | |
1010 | +{ | |
1011 | + int rc = 0; | |
1012 | + uint off = 0; | |
1013 | + | |
1014 | + if (tranlen < 10 || !iseol(ptran[tranlen-1]) || | |
1015 | + nf_strncasecmp(ptran, "Transport:", 10) != 0) { | |
1016 | + pr_info("sanity check failed\n"); | |
1017 | + return 0; | |
1018 | + } | |
1019 | + | |
1020 | + pr_debug("tran='%.*s'\n", (int)tranlen, ptran); | |
1021 | + off += 10; | |
1022 | + SKIP_WSPACE(ptran, tranlen, off); | |
1023 | + | |
1024 | + /* Transport: tran;field;field=val,tran;field;field=val,... */ | |
1025 | + while (off < tranlen) { | |
1026 | + const char* pparamend; | |
1027 | + uint nextparamoff; | |
1028 | + | |
1029 | + pparamend = memchr(ptran+off, ',', tranlen-off); | |
1030 | + pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; | |
1031 | + nextparamoff = pparamend-ptran; | |
1032 | + | |
1033 | + while (off < nextparamoff) { | |
1034 | + const char* pfieldend; | |
1035 | + uint nextfieldoff; | |
1036 | + | |
1037 | + pfieldend = memchr(ptran+off, ';', nextparamoff-off); | |
1038 | + nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; | |
1039 | + | |
1040 | + if (strncmp(ptran+off, "client_port=", 12) == 0) { | |
1041 | + u_int16_t port; | |
1042 | + uint numlen; | |
1043 | + | |
1044 | + off += 12; | |
1045 | + numlen = nf_strtou16(ptran+off, &port); | |
1046 | + off += numlen; | |
1047 | + if (prtspexp->loport != 0 && prtspexp->loport != port) | |
1048 | + pr_debug("multiple ports found, port %hu ignored\n", port); | |
1049 | + else { | |
1050 | + pr_debug("lo port found : %hu\n", port); | |
1051 | + prtspexp->loport = prtspexp->hiport = port; | |
1052 | + if (ptran[off] == '-') { | |
1053 | + off++; | |
1054 | + numlen = nf_strtou16(ptran+off, &port); | |
1055 | + off += numlen; | |
1056 | + prtspexp->pbtype = pb_range; | |
1057 | + prtspexp->hiport = port; | |
1058 | + | |
1059 | + // If we have a range, assume rtp: | |
1060 | + // loport must be even, hiport must be loport+1 | |
1061 | + if ((prtspexp->loport & 0x0001) != 0 || | |
1062 | + prtspexp->hiport != prtspexp->loport+1) { | |
1063 | + pr_debug("incorrect range: %hu-%hu, correcting\n", | |
1064 | + prtspexp->loport, prtspexp->hiport); | |
1065 | + prtspexp->loport &= 0xfffe; | |
1066 | + prtspexp->hiport = prtspexp->loport+1; | |
1067 | + } | |
1068 | + } else if (ptran[off] == '/') { | |
1069 | + off++; | |
1070 | + numlen = nf_strtou16(ptran+off, &port); | |
1071 | + off += numlen; | |
1072 | + prtspexp->pbtype = pb_discon; | |
1073 | + prtspexp->hiport = port; | |
1074 | + } | |
1075 | + rc = 1; | |
1076 | + } | |
1077 | + } | |
1078 | + | |
1079 | + /* | |
1080 | + * Note we don't look for the destination parameter here. | |
1081 | + * If we are using NAT, the NAT module will handle it. If not, | |
1082 | + * and the client is sending packets elsewhere, the expectation | |
1083 | + * will quietly time out. | |
1084 | + */ | |
1085 | + | |
1086 | + off = nextfieldoff; | |
1087 | + } | |
1088 | + | |
1089 | + off = nextparamoff; | |
1090 | + } | |
1091 | + | |
1092 | + return rc; | |
1093 | +} | |
1094 | + | |
1095 | +void expected(struct nf_conn *ct, struct nf_conntrack_expect *exp) | |
1096 | +{ | |
1097 | + typeof(nf_nat_rtsp_hook_expectfn) nf_nat_rtsp_expectfn; | |
1098 | + nf_nat_rtsp_expectfn = rcu_dereference(nf_nat_rtsp_hook_expectfn); | |
1099 | + if(nf_nat_rtsp_expectfn && ct->master->status & IPS_NAT_MASK) { | |
1100 | + nf_nat_rtsp_expectfn(ct,exp); | |
1101 | + } | |
1102 | +} | |
1103 | + | |
1104 | +/*** conntrack functions ***/ | |
1105 | + | |
1106 | +/* outbound packet: client->server */ | |
1107 | + | |
1108 | +static inline int | |
1109 | +help_out(struct sk_buff *skb, unsigned char *rb_ptr, unsigned int datalen, | |
1110 | + struct nf_conn *ct, enum ip_conntrack_info ctinfo) | |
1111 | +{ | |
1112 | + struct ip_ct_rtsp_expect expinfo; | |
1113 | + | |
1114 | + int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */ | |
1115 | + //struct tcphdr* tcph = (void*)iph + iph->ihl * 4; | |
1116 | + //uint tcplen = pktlen - iph->ihl * 4; | |
1117 | + char* pdata = rb_ptr; | |
1118 | + //uint datalen = tcplen - tcph->doff * 4; | |
1119 | + uint dataoff = 0; | |
1120 | + int ret = NF_ACCEPT; | |
1121 | + | |
1122 | + struct nf_conntrack_expect *exp; | |
1123 | + | |
1124 | + __be16 be_loport; | |
1125 | + | |
1126 | + typeof(nf_nat_rtsp_hook) nf_nat_rtsp; | |
1127 | + | |
1128 | + memset(&expinfo, 0, sizeof(expinfo)); | |
1129 | + | |
1130 | + while (dataoff < datalen) { | |
1131 | + uint cmdoff = dataoff; | |
1132 | + uint hdrsoff = 0; | |
1133 | + uint hdrslen = 0; | |
1134 | + uint cseqoff = 0; | |
1135 | + uint cseqlen = 0; | |
1136 | + uint transoff = 0; | |
1137 | + uint translen = 0; | |
1138 | + uint off; | |
1139 | + | |
1140 | + if (!rtsp_parse_message(pdata, datalen, &dataoff, | |
1141 | + &hdrsoff, &hdrslen, | |
1142 | + &cseqoff, &cseqlen, | |
1143 | + &transoff, &translen)) | |
1144 | + break; /* not a valid message */ | |
1145 | + | |
1146 | + if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) | |
1147 | + continue; /* not a SETUP message */ | |
1148 | + pr_debug("found a setup message\n"); | |
1149 | + | |
1150 | + off = 0; | |
1151 | + if(translen) { | |
1152 | + rtsp_parse_transport(pdata+transoff, translen, &expinfo); | |
1153 | + } | |
1154 | + | |
1155 | + if (expinfo.loport == 0) { | |
1156 | + pr_debug("no udp transports found\n"); | |
1157 | + continue; /* no udp transports found */ | |
1158 | + } | |
1159 | + | |
1160 | + pr_debug("udp transport found, ports=(%d,%hu,%hu)\n", | |
1161 | + (int)expinfo.pbtype, expinfo.loport, expinfo.hiport); | |
1162 | + | |
1163 | + exp = nf_ct_expect_alloc(ct); | |
1164 | + if (!exp) { | |
1165 | + ret = NF_DROP; | |
1166 | + goto out; | |
1167 | + } | |
1168 | + | |
1169 | + be_loport = htons(expinfo.loport); | |
1170 | + | |
2380c486 | 1171 | + nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT, nf_ct_l3num(ct), |
5b1b5d4e | 1172 | + &ct->tuplehash[!dir].tuple.src.u3, &ct->tuplehash[!dir].tuple.dst.u3, |
1173 | + IPPROTO_UDP, NULL, &be_loport); | |
1174 | + | |
1175 | + exp->master = ct; | |
1176 | + | |
1177 | + exp->expectfn = expected; | |
1178 | + exp->flags = 0; | |
1179 | + | |
1180 | + if (expinfo.pbtype == pb_range) { | |
1181 | + pr_debug("Changing expectation mask to handle multiple ports\n"); | |
1182 | + //exp->mask.dst.u.udp.port = 0xfffe; | |
1183 | + } | |
1184 | + | |
1185 | + pr_debug("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", | |
1186 | + NIPQUAD(exp->tuple.src.u3.ip), | |
1187 | + ntohs(exp->tuple.src.u.udp.port), | |
1188 | + NIPQUAD(exp->tuple.dst.u3.ip), | |
1189 | + ntohs(exp->tuple.dst.u.udp.port)); | |
1190 | + | |
1191 | + nf_nat_rtsp = rcu_dereference(nf_nat_rtsp_hook); | |
1192 | + if (nf_nat_rtsp && ct->status & IPS_NAT_MASK) | |
1193 | + /* pass the request off to the nat helper */ | |
1194 | + ret = nf_nat_rtsp(skb, ctinfo, hdrsoff, hdrslen, &expinfo, exp); | |
1195 | + else if (nf_ct_expect_related(exp) != 0) { | |
1196 | + pr_info("nf_conntrack_expect_related failed\n"); | |
1197 | + ret = NF_DROP; | |
1198 | + } | |
1199 | + nf_ct_expect_put(exp); | |
1200 | + goto out; | |
1201 | + } | |
1202 | +out: | |
1203 | + | |
1204 | + return ret; | |
1205 | +} | |
1206 | + | |
1207 | + | |
1208 | +static inline int | |
1209 | +help_in(struct sk_buff *skb, size_t pktlen, | |
1210 | + struct nf_conn* ct, enum ip_conntrack_info ctinfo) | |
1211 | +{ | |
1212 | + return NF_ACCEPT; | |
1213 | +} | |
1214 | + | |
1215 | +static int help(struct sk_buff *skb, unsigned int protoff, | |
1216 | + struct nf_conn *ct, enum ip_conntrack_info ctinfo) | |
1217 | +{ | |
1218 | + struct tcphdr _tcph, *th; | |
1219 | + unsigned int dataoff, datalen; | |
1220 | + char *rb_ptr; | |
1221 | + int ret = NF_DROP; | |
1222 | + | |
1223 | + /* Until there's been traffic both ways, don't look in packets. */ | |
1224 | + if (ctinfo != IP_CT_ESTABLISHED && | |
1225 | + ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { | |
1226 | + pr_debug("conntrackinfo = %u\n", ctinfo); | |
1227 | + return NF_ACCEPT; | |
1228 | + } | |
1229 | + | |
1230 | + /* Not whole TCP header? */ | |
1231 | + th = skb_header_pointer(skb,protoff, sizeof(_tcph), &_tcph); | |
1232 | + | |
1233 | + if (!th) | |
1234 | + return NF_ACCEPT; | |
1235 | + | |
1236 | + /* No data ? */ | |
1237 | + dataoff = protoff + th->doff*4; | |
1238 | + datalen = skb->len - dataoff; | |
1239 | + if (dataoff >= skb->len) | |
1240 | + return NF_ACCEPT; | |
1241 | + | |
1242 | + spin_lock_bh(&rtsp_buffer_lock); | |
1243 | + rb_ptr = skb_header_pointer(skb, dataoff, | |
1244 | + skb->len - dataoff, rtsp_buffer); | |
1245 | + BUG_ON(rb_ptr == NULL); | |
1246 | + | |
1247 | +#if 0 | |
1248 | + /* Checksum invalid? Ignore. */ | |
1249 | + /* FIXME: Source route IP option packets --RR */ | |
1250 | + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, | |
1251 | + csum_partial((char*)tcph, tcplen, 0))) | |
1252 | + { | |
1253 | + DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", | |
1254 | + tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); | |
1255 | + return NF_ACCEPT; | |
1256 | + } | |
1257 | +#endif | |
1258 | + | |
1259 | + switch (CTINFO2DIR(ctinfo)) { | |
1260 | + case IP_CT_DIR_ORIGINAL: | |
1261 | + ret = help_out(skb, rb_ptr, datalen, ct, ctinfo); | |
1262 | + break; | |
1263 | + case IP_CT_DIR_REPLY: | |
1264 | + pr_debug("IP_CT_DIR_REPLY\n"); | |
1265 | + /* inbound packet: server->client */ | |
1266 | + ret = NF_ACCEPT; | |
1267 | + break; | |
1268 | + } | |
1269 | + | |
1270 | + spin_unlock_bh(&rtsp_buffer_lock); | |
1271 | + | |
1272 | + return ret; | |
1273 | +} | |
1274 | + | |
1275 | +static struct nf_conntrack_helper rtsp_helpers[MAX_PORTS]; | |
1276 | +static char rtsp_names[MAX_PORTS][10]; | |
1277 | + | |
1278 | +/* This function is intentionally _NOT_ defined as __exit */ | |
1279 | +static void | |
1280 | +fini(void) | |
1281 | +{ | |
1282 | + int i; | |
1283 | + for (i = 0; i < num_ports; i++) { | |
1284 | + pr_debug("unregistering port %d\n", ports[i]); | |
1285 | + nf_conntrack_helper_unregister(&rtsp_helpers[i]); | |
1286 | + } | |
1287 | + kfree(rtsp_buffer); | |
1288 | +} | |
1289 | + | |
1290 | +static int __init | |
1291 | +init(void) | |
1292 | +{ | |
1293 | + int i, ret; | |
1294 | + struct nf_conntrack_helper *hlpr; | |
1295 | + char *tmpname; | |
1296 | + | |
1297 | + printk("nf_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); | |
1298 | + | |
1299 | + if (max_outstanding < 1) { | |
1300 | + printk("nf_conntrack_rtsp: max_outstanding must be a positive integer\n"); | |
1301 | + return -EBUSY; | |
1302 | + } | |
1303 | + if (setup_timeout < 0) { | |
1304 | + printk("nf_conntrack_rtsp: setup_timeout must be a positive integer\n"); | |
1305 | + return -EBUSY; | |
1306 | + } | |
1307 | + | |
2380c486 JR |
1308 | + rtsp_exp_policy.max_expected = max_outstanding; |
1309 | + rtsp_exp_policy.timeout = setup_timeout; | |
1310 | + | |
5b1b5d4e | 1311 | + rtsp_buffer = kmalloc(65536, GFP_KERNEL); |
1312 | + if (!rtsp_buffer) | |
1313 | + return -ENOMEM; | |
1314 | + | |
1315 | + /* If no port given, default to standard rtsp port */ | |
1316 | + if (ports[0] == 0) { | |
1317 | + ports[0] = RTSP_PORT; | |
1318 | + } | |
1319 | + | |
1320 | + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { | |
1321 | + hlpr = &rtsp_helpers[i]; | |
1322 | + memset(hlpr, 0, sizeof(struct nf_conntrack_helper)); | |
1323 | + hlpr->tuple.src.l3num = AF_INET; | |
1324 | + hlpr->tuple.src.u.tcp.port = htons(ports[i]); | |
1325 | + hlpr->tuple.dst.protonum = IPPROTO_TCP; | |
1326 | + //hlpr->mask.src.u.tcp.port = 0xFFFF; | |
1327 | + //hlpr->mask.dst.protonum = 0xFF; | |
2380c486 | 1328 | + hlpr->expect_policy = &rtsp_exp_policy; |
5b1b5d4e | 1329 | + hlpr->me = THIS_MODULE; |
1330 | + hlpr->help = help; | |
1331 | + | |
1332 | + tmpname = &rtsp_names[i][0]; | |
1333 | + if (ports[i] == RTSP_PORT) { | |
1334 | + sprintf(tmpname, "rtsp"); | |
1335 | + } else { | |
1336 | + sprintf(tmpname, "rtsp-%d", i); | |
1337 | + } | |
1338 | + hlpr->name = tmpname; | |
1339 | + | |
1340 | + pr_debug("port #%d: %d\n", i, ports[i]); | |
1341 | + | |
1342 | + ret = nf_conntrack_helper_register(hlpr); | |
1343 | + | |
1344 | + if (ret) { | |
1345 | + printk("nf_conntrack_rtsp: ERROR registering port %d\n", ports[i]); | |
1346 | + fini(); | |
1347 | + return -EBUSY; | |
1348 | + } | |
1349 | + num_ports++; | |
1350 | + } | |
1351 | + return 0; | |
1352 | +} | |
1353 | + | |
1354 | +module_init(init); | |
1355 | +module_exit(fini); | |
1356 | + | |
1357 | +EXPORT_SYMBOL(nf_nat_rtsp_hook_expectfn); | |
1358 | + |