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