diff options
author | Patrick McHardy <kaber@trash.net> | 2010-02-11 06:29:38 -0500 |
---|---|---|
committer | Patrick McHardy <kaber@trash.net> | 2010-02-11 06:29:38 -0500 |
commit | 48f8ac26537c1b7b1a2422f5232f45d06c945348 (patch) | |
tree | 352aab0881ef9e449dc86b3dc1da2b4b329ead44 /net | |
parent | 010c0b9f34a4c567b431f8b49a58b7332ed42e47 (diff) |
netfilter: nf_nat_sip: add TCP support
Add support for mangling TCP SIP packets.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 53 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 10 |
2 files changed, 57 insertions, 6 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b232e4040dc6..11b538deaaec 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* SIP extension for UDP NAT alteration. | 1 | /* SIP extension for NAT alteration. |
2 | * | 2 | * |
3 | * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar> | 3 | * (C) 2005 by Christian Hentschel <chentschel@arnet.com.ar> |
4 | * based on RR's ip_nat_ftp.c and other modules. | 4 | * based on RR's ip_nat_ftp.c and other modules. |
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/ip.h> | 15 | #include <linux/ip.h> |
16 | #include <net/ip.h> | 16 | #include <net/ip.h> |
17 | #include <linux/udp.h> | 17 | #include <linux/udp.h> |
18 | #include <linux/tcp.h> | ||
18 | 19 | ||
19 | #include <net/netfilter/nf_nat.h> | 20 | #include <net/netfilter/nf_nat.h> |
20 | #include <net/netfilter/nf_nat_helper.h> | 21 | #include <net/netfilter/nf_nat_helper.h> |
@@ -36,10 +37,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff, | |||
36 | { | 37 | { |
37 | enum ip_conntrack_info ctinfo; | 38 | enum ip_conntrack_info ctinfo; |
38 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 39 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
39 | 40 | struct tcphdr *th; | |
40 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, matchoff, matchlen, | 41 | unsigned int baseoff; |
41 | buffer, buflen)) | 42 | |
42 | return 0; | 43 | if (nf_ct_protonum(ct) == IPPROTO_TCP) { |
44 | th = (struct tcphdr *)(skb->data + ip_hdrlen(skb)); | ||
45 | baseoff = ip_hdrlen(skb) + th->doff * 4; | ||
46 | matchoff += dataoff - baseoff; | ||
47 | |||
48 | if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | ||
49 | matchoff, matchlen, | ||
50 | buffer, buflen, false)) | ||
51 | return 0; | ||
52 | } else { | ||
53 | baseoff = ip_hdrlen(skb) + sizeof(struct udphdr); | ||
54 | matchoff += dataoff - baseoff; | ||
55 | |||
56 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, | ||
57 | matchoff, matchlen, | ||
58 | buffer, buflen)) | ||
59 | return 0; | ||
60 | } | ||
43 | 61 | ||
44 | /* Reload data pointer and adjust datalen value */ | 62 | /* Reload data pointer and adjust datalen value */ |
45 | *dptr = skb->data + dataoff; | 63 | *dptr = skb->data + dataoff; |
@@ -104,6 +122,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
104 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 122 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
105 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 123 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
106 | unsigned int coff, matchoff, matchlen; | 124 | unsigned int coff, matchoff, matchlen; |
125 | enum sip_header_types hdr; | ||
107 | union nf_inet_addr addr; | 126 | union nf_inet_addr addr; |
108 | __be16 port; | 127 | __be16 port; |
109 | int request, in_header; | 128 | int request, in_header; |
@@ -120,9 +139,14 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff, | |||
120 | } else | 139 | } else |
121 | request = 0; | 140 | request = 0; |
122 | 141 | ||
142 | if (nf_ct_protonum(ct) == IPPROTO_TCP) | ||
143 | hdr = SIP_HDR_VIA_TCP; | ||
144 | else | ||
145 | hdr = SIP_HDR_VIA_UDP; | ||
146 | |||
123 | /* Translate topmost Via header and parameters */ | 147 | /* Translate topmost Via header and parameters */ |
124 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | 148 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
125 | SIP_HDR_VIA_UDP, NULL, &matchoff, &matchlen, | 149 | hdr, NULL, &matchoff, &matchlen, |
126 | &addr, &port) > 0) { | 150 | &addr, &port) > 0) { |
127 | unsigned int matchend, poff, plen, buflen, n; | 151 | unsigned int matchend, poff, plen, buflen, n; |
128 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | 152 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; |
@@ -204,9 +228,23 @@ next: | |||
204 | if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) || | 228 | if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) || |
205 | !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO)) | 229 | !map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO)) |
206 | return NF_DROP; | 230 | return NF_DROP; |
231 | |||
207 | return NF_ACCEPT; | 232 | return NF_ACCEPT; |
208 | } | 233 | } |
209 | 234 | ||
235 | static void ip_nat_sip_seq_adjust(struct sk_buff *skb, s16 off) | ||
236 | { | ||
237 | enum ip_conntrack_info ctinfo; | ||
238 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
239 | const struct tcphdr *th; | ||
240 | |||
241 | if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0) | ||
242 | return; | ||
243 | |||
244 | th = (struct tcphdr *)(skb->data + ip_hdrlen(skb)); | ||
245 | nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); | ||
246 | } | ||
247 | |||
210 | /* Handles expected signalling connections and media streams */ | 248 | /* Handles expected signalling connections and media streams */ |
211 | static void ip_nat_sip_expected(struct nf_conn *ct, | 249 | static void ip_nat_sip_expected(struct nf_conn *ct, |
212 | struct nf_conntrack_expect *exp) | 250 | struct nf_conntrack_expect *exp) |
@@ -472,6 +510,7 @@ err1: | |||
472 | static void __exit nf_nat_sip_fini(void) | 510 | static void __exit nf_nat_sip_fini(void) |
473 | { | 511 | { |
474 | rcu_assign_pointer(nf_nat_sip_hook, NULL); | 512 | rcu_assign_pointer(nf_nat_sip_hook, NULL); |
513 | rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, NULL); | ||
475 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); | 514 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); |
476 | rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); | 515 | rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); |
477 | rcu_assign_pointer(nf_nat_sdp_port_hook, NULL); | 516 | rcu_assign_pointer(nf_nat_sdp_port_hook, NULL); |
@@ -483,12 +522,14 @@ static void __exit nf_nat_sip_fini(void) | |||
483 | static int __init nf_nat_sip_init(void) | 522 | static int __init nf_nat_sip_init(void) |
484 | { | 523 | { |
485 | BUG_ON(nf_nat_sip_hook != NULL); | 524 | BUG_ON(nf_nat_sip_hook != NULL); |
525 | BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); | ||
486 | BUG_ON(nf_nat_sip_expect_hook != NULL); | 526 | BUG_ON(nf_nat_sip_expect_hook != NULL); |
487 | BUG_ON(nf_nat_sdp_addr_hook != NULL); | 527 | BUG_ON(nf_nat_sdp_addr_hook != NULL); |
488 | BUG_ON(nf_nat_sdp_port_hook != NULL); | 528 | BUG_ON(nf_nat_sdp_port_hook != NULL); |
489 | BUG_ON(nf_nat_sdp_session_hook != NULL); | 529 | BUG_ON(nf_nat_sdp_session_hook != NULL); |
490 | BUG_ON(nf_nat_sdp_media_hook != NULL); | 530 | BUG_ON(nf_nat_sdp_media_hook != NULL); |
491 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); | 531 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); |
532 | rcu_assign_pointer(nf_nat_sip_seq_adjust_hook, ip_nat_sip_seq_adjust); | ||
492 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); | 533 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); |
493 | rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); | 534 | rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); |
494 | rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port); | 535 | rcu_assign_pointer(nf_nat_sdp_port_hook, ip_nat_sdp_port); |
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 1cc75c5a822b..3bb3aaff76e9 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -56,6 +56,9 @@ unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int dataoff, | |||
56 | unsigned int *datalen) __read_mostly; | 56 | unsigned int *datalen) __read_mostly; |
57 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); | 57 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); |
58 | 58 | ||
59 | void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off) __read_mostly; | ||
60 | EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook); | ||
61 | |||
59 | unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | 62 | unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, |
60 | unsigned int dataoff, | 63 | unsigned int dataoff, |
61 | const char **dptr, | 64 | const char **dptr, |
@@ -1360,6 +1363,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | |||
1360 | const char *dptr, *end; | 1363 | const char *dptr, *end; |
1361 | s16 diff, tdiff = 0; | 1364 | s16 diff, tdiff = 0; |
1362 | int ret; | 1365 | int ret; |
1366 | typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; | ||
1363 | 1367 | ||
1364 | if (ctinfo != IP_CT_ESTABLISHED && | 1368 | if (ctinfo != IP_CT_ESTABLISHED && |
1365 | ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) | 1369 | ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) |
@@ -1415,6 +1419,12 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | |||
1415 | datalen = datalen + diff - msglen; | 1419 | datalen = datalen + diff - msglen; |
1416 | } | 1420 | } |
1417 | 1421 | ||
1422 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { | ||
1423 | nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook); | ||
1424 | if (nf_nat_sip_seq_adjust) | ||
1425 | nf_nat_sip_seq_adjust(skb, tdiff); | ||
1426 | } | ||
1427 | |||
1418 | return ret; | 1428 | return ret; |
1419 | } | 1429 | } |
1420 | 1430 | ||