d9505e0aa1a1df62a524452db7ebf9c500e104c2
[openwrt.git] / target / linux / generic / patches-3.7 / 604-netfilter_cisco_794x_iphone.patch
1 --- a/include/linux/netfilter/nf_conntrack_sip.h
2 +++ b/include/linux/netfilter/nf_conntrack_sip.h
3 @@ -4,12 +4,15 @@
4  
5  #include <net/netfilter/nf_conntrack_expect.h>
6  
7 +#include <linux/types.h>
8 +
9  #define SIP_PORT       5060
10  #define SIP_TIMEOUT    3600
11  
12  struct nf_ct_sip_master {
13         unsigned int    register_cseq;
14         unsigned int    invite_cseq;
15 +       __be16          forced_dport;
16  };
17  
18  enum sip_expectation_classes {
19 --- a/net/netfilter/nf_nat_sip.c
20 +++ b/net/netfilter/nf_nat_sip.c
21 @@ -95,6 +95,7 @@ static int map_addr(struct sk_buff *skb,
22         enum ip_conntrack_info ctinfo;
23         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
24         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
25 +       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
26         char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
27         unsigned int buflen;
28         union nf_inet_addr newaddr;
29 @@ -107,7 +108,8 @@ static int map_addr(struct sk_buff *skb,
30         } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) &&
31                    ct->tuplehash[dir].tuple.dst.u.udp.port == port) {
32                 newaddr = ct->tuplehash[!dir].tuple.src.u3;
33 -               newport = ct->tuplehash[!dir].tuple.src.u.udp.port;
34 +               newport = ct_sip_info->forced_dport ? ct_sip_info->forced_dport :
35 +                         ct->tuplehash[!dir].tuple.src.u.udp.port;
36         } else
37                 return 1;
38  
39 @@ -144,6 +146,7 @@ static unsigned int nf_nat_sip(struct sk
40         enum ip_conntrack_info ctinfo;
41         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
42         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
43 +       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
44         unsigned int coff, matchoff, matchlen;
45         enum sip_header_types hdr;
46         union nf_inet_addr addr;
47 @@ -258,6 +261,20 @@ next:
48             !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO))
49                 return NF_DROP;
50  
51 +       /* Mangle destination port for Cisco phones, then fix up checksums */
52 +       if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) {
53 +               struct udphdr *uh;
54 +
55 +               if (!skb_make_writable(skb, skb->len))
56 +                       return NF_DROP;
57 +
58 +               uh = (struct udphdr *)(skb->data + ip_hdrlen(skb));
59 +               uh->dest = ct_sip_info->forced_dport;
60 +
61 +               if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, 0, 0, NULL, 0))
62 +                       return NF_DROP;
63 +       }
64 +
65         return NF_ACCEPT;
66  }
67  
68 @@ -311,8 +328,10 @@ static unsigned int nf_nat_sip_expect(st
69         enum ip_conntrack_info ctinfo;
70         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
71         enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
72 +       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
73         union nf_inet_addr newaddr;
74         u_int16_t port;
75 +       __be16 srcport;
76         char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")];
77         unsigned int buflen;
78  
79 @@ -326,8 +345,9 @@ static unsigned int nf_nat_sip_expect(st
80         /* If the signalling port matches the connection's source port in the
81          * original direction, try to use the destination port in the opposite
82          * direction. */
83 -       if (exp->tuple.dst.u.udp.port ==
84 -           ct->tuplehash[dir].tuple.src.u.udp.port)
85 +       srcport = ct_sip_info->forced_dport ? ct_sip_info->forced_dport :
86 +                 ct->tuplehash[dir].tuple.src.u.udp.port;
87 +       if (exp->tuple.dst.u.udp.port == srcport)
88                 port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port);
89         else
90                 port = ntohs(exp->tuple.dst.u.udp.port);
91 --- a/net/netfilter/nf_conntrack_sip.c
92 +++ b/net/netfilter/nf_conntrack_sip.c
93 @@ -1440,8 +1440,25 @@ static int process_sip_request(struct sk
94  {
95         enum ip_conntrack_info ctinfo;
96         struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
97 +       struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct);
98 +       enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
99         unsigned int matchoff, matchlen;
100         unsigned int cseq, i;
101 +       union nf_inet_addr addr;
102 +       __be16 port;
103 +
104 +       /* Many Cisco IP phones use a high source port for SIP requests, but
105 +        * listen for the response on port 5060.  If we are the local
106 +        * router for one of these phones, save the port number from the
107 +        * Via: header so that nf_nat_sip can redirect the responses to
108 +        * the correct port.
109 +        */
110 +       if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
111 +                                   SIP_HDR_VIA_UDP, NULL, &matchoff,
112 +                                   &matchlen, &addr, &port) > 0 &&
113 +           port != ct->tuplehash[dir].tuple.src.u.udp.port &&
114 +           nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3))
115 +               ct_sip_info->forced_dport = port;
116  
117         for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) {
118                 const struct sip_handler *handler;