Commit 7266507d89991fa1e989283e4e032c6d9357fe26
Committed by
Pablo Neira Ayuso
1 parent
247fa82be1
Exists in
master
and in
20 other branches
netfilter: nf_ct_sip: support Cisco 7941/7945 IP phones
Most SIP devices use a source port of 5060/udp on SIP requests, so the response automatically comes back to port 5060: phone_ip:5060 -> proxy_ip:5060 REGISTER proxy_ip:5060 -> phone_ip:5060 100 Trying The newer Cisco IP phones, however, use a randomly chosen high source port for the SIP request but expect the response on port 5060: phone_ip:49173 -> proxy_ip:5060 REGISTER proxy_ip:5060 -> phone_ip:5060 100 Trying Standard Linux NAT, with or without nf_nat_sip, will send the reply back to port 49173, not 5060: phone_ip:49173 -> proxy_ip:5060 REGISTER proxy_ip:5060 -> phone_ip:49173 100 Trying But the phone is not listening on 49173, so it will never see the reply. This patch modifies nf_*_sip to work around this quirk by extracting the SIP response port from the Via: header, iff the source IP in the packet header matches the source IP in the SIP request. Signed-off-by: Kevin Cernekee <cernekee@gmail.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: Patrick McHardy <kaber@trash.net> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Showing 3 changed files with 44 additions and 3 deletions Inline Diff
include/linux/netfilter/nf_conntrack_sip.h
1 | #ifndef __NF_CONNTRACK_SIP_H__ | 1 | #ifndef __NF_CONNTRACK_SIP_H__ |
2 | #define __NF_CONNTRACK_SIP_H__ | 2 | #define __NF_CONNTRACK_SIP_H__ |
3 | #ifdef __KERNEL__ | 3 | #ifdef __KERNEL__ |
4 | 4 | ||
5 | #include <net/netfilter/nf_conntrack_expect.h> | 5 | #include <net/netfilter/nf_conntrack_expect.h> |
6 | 6 | ||
7 | #include <linux/types.h> | ||
8 | |||
7 | #define SIP_PORT 5060 | 9 | #define SIP_PORT 5060 |
8 | #define SIP_TIMEOUT 3600 | 10 | #define SIP_TIMEOUT 3600 |
9 | 11 | ||
10 | struct nf_ct_sip_master { | 12 | struct nf_ct_sip_master { |
11 | unsigned int register_cseq; | 13 | unsigned int register_cseq; |
12 | unsigned int invite_cseq; | 14 | unsigned int invite_cseq; |
15 | __be16 forced_dport; | ||
13 | }; | 16 | }; |
14 | 17 | ||
15 | enum sip_expectation_classes { | 18 | enum sip_expectation_classes { |
16 | SIP_EXPECT_SIGNALLING, | 19 | SIP_EXPECT_SIGNALLING, |
17 | SIP_EXPECT_AUDIO, | 20 | SIP_EXPECT_AUDIO, |
18 | SIP_EXPECT_VIDEO, | 21 | SIP_EXPECT_VIDEO, |
19 | SIP_EXPECT_IMAGE, | 22 | SIP_EXPECT_IMAGE, |
20 | __SIP_EXPECT_MAX | 23 | __SIP_EXPECT_MAX |
21 | }; | 24 | }; |
22 | #define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) | 25 | #define SIP_EXPECT_MAX (__SIP_EXPECT_MAX - 1) |
23 | 26 | ||
24 | struct sdp_media_type { | 27 | struct sdp_media_type { |
25 | const char *name; | 28 | const char *name; |
26 | unsigned int len; | 29 | unsigned int len; |
27 | enum sip_expectation_classes class; | 30 | enum sip_expectation_classes class; |
28 | }; | 31 | }; |
29 | 32 | ||
30 | #define SDP_MEDIA_TYPE(__name, __class) \ | 33 | #define SDP_MEDIA_TYPE(__name, __class) \ |
31 | { \ | 34 | { \ |
32 | .name = (__name), \ | 35 | .name = (__name), \ |
33 | .len = sizeof(__name) - 1, \ | 36 | .len = sizeof(__name) - 1, \ |
34 | .class = (__class), \ | 37 | .class = (__class), \ |
35 | } | 38 | } |
36 | 39 | ||
37 | struct sip_handler { | 40 | struct sip_handler { |
38 | const char *method; | 41 | const char *method; |
39 | unsigned int len; | 42 | unsigned int len; |
40 | int (*request)(struct sk_buff *skb, unsigned int protoff, | 43 | int (*request)(struct sk_buff *skb, unsigned int protoff, |
41 | unsigned int dataoff, | 44 | unsigned int dataoff, |
42 | const char **dptr, unsigned int *datalen, | 45 | const char **dptr, unsigned int *datalen, |
43 | unsigned int cseq); | 46 | unsigned int cseq); |
44 | int (*response)(struct sk_buff *skb, unsigned int protoff, | 47 | int (*response)(struct sk_buff *skb, unsigned int protoff, |
45 | unsigned int dataoff, | 48 | unsigned int dataoff, |
46 | const char **dptr, unsigned int *datalen, | 49 | const char **dptr, unsigned int *datalen, |
47 | unsigned int cseq, unsigned int code); | 50 | unsigned int cseq, unsigned int code); |
48 | }; | 51 | }; |
49 | 52 | ||
50 | #define SIP_HANDLER(__method, __request, __response) \ | 53 | #define SIP_HANDLER(__method, __request, __response) \ |
51 | { \ | 54 | { \ |
52 | .method = (__method), \ | 55 | .method = (__method), \ |
53 | .len = sizeof(__method) - 1, \ | 56 | .len = sizeof(__method) - 1, \ |
54 | .request = (__request), \ | 57 | .request = (__request), \ |
55 | .response = (__response), \ | 58 | .response = (__response), \ |
56 | } | 59 | } |
57 | 60 | ||
58 | struct sip_header { | 61 | struct sip_header { |
59 | const char *name; | 62 | const char *name; |
60 | const char *cname; | 63 | const char *cname; |
61 | const char *search; | 64 | const char *search; |
62 | unsigned int len; | 65 | unsigned int len; |
63 | unsigned int clen; | 66 | unsigned int clen; |
64 | unsigned int slen; | 67 | unsigned int slen; |
65 | int (*match_len)(const struct nf_conn *ct, | 68 | int (*match_len)(const struct nf_conn *ct, |
66 | const char *dptr, const char *limit, | 69 | const char *dptr, const char *limit, |
67 | int *shift); | 70 | int *shift); |
68 | }; | 71 | }; |
69 | 72 | ||
70 | #define __SIP_HDR(__name, __cname, __search, __match) \ | 73 | #define __SIP_HDR(__name, __cname, __search, __match) \ |
71 | { \ | 74 | { \ |
72 | .name = (__name), \ | 75 | .name = (__name), \ |
73 | .len = sizeof(__name) - 1, \ | 76 | .len = sizeof(__name) - 1, \ |
74 | .cname = (__cname), \ | 77 | .cname = (__cname), \ |
75 | .clen = (__cname) ? sizeof(__cname) - 1 : 0, \ | 78 | .clen = (__cname) ? sizeof(__cname) - 1 : 0, \ |
76 | .search = (__search), \ | 79 | .search = (__search), \ |
77 | .slen = (__search) ? sizeof(__search) - 1 : 0, \ | 80 | .slen = (__search) ? sizeof(__search) - 1 : 0, \ |
78 | .match_len = (__match), \ | 81 | .match_len = (__match), \ |
79 | } | 82 | } |
80 | 83 | ||
81 | #define SIP_HDR(__name, __cname, __search, __match) \ | 84 | #define SIP_HDR(__name, __cname, __search, __match) \ |
82 | __SIP_HDR(__name, __cname, __search, __match) | 85 | __SIP_HDR(__name, __cname, __search, __match) |
83 | 86 | ||
84 | #define SDP_HDR(__name, __search, __match) \ | 87 | #define SDP_HDR(__name, __search, __match) \ |
85 | __SIP_HDR(__name, NULL, __search, __match) | 88 | __SIP_HDR(__name, NULL, __search, __match) |
86 | 89 | ||
87 | enum sip_header_types { | 90 | enum sip_header_types { |
88 | SIP_HDR_CSEQ, | 91 | SIP_HDR_CSEQ, |
89 | SIP_HDR_FROM, | 92 | SIP_HDR_FROM, |
90 | SIP_HDR_TO, | 93 | SIP_HDR_TO, |
91 | SIP_HDR_CONTACT, | 94 | SIP_HDR_CONTACT, |
92 | SIP_HDR_VIA_UDP, | 95 | SIP_HDR_VIA_UDP, |
93 | SIP_HDR_VIA_TCP, | 96 | SIP_HDR_VIA_TCP, |
94 | SIP_HDR_EXPIRES, | 97 | SIP_HDR_EXPIRES, |
95 | SIP_HDR_CONTENT_LENGTH, | 98 | SIP_HDR_CONTENT_LENGTH, |
96 | SIP_HDR_CALL_ID, | 99 | SIP_HDR_CALL_ID, |
97 | }; | 100 | }; |
98 | 101 | ||
99 | enum sdp_header_types { | 102 | enum sdp_header_types { |
100 | SDP_HDR_UNSPEC, | 103 | SDP_HDR_UNSPEC, |
101 | SDP_HDR_VERSION, | 104 | SDP_HDR_VERSION, |
102 | SDP_HDR_OWNER, | 105 | SDP_HDR_OWNER, |
103 | SDP_HDR_CONNECTION, | 106 | SDP_HDR_CONNECTION, |
104 | SDP_HDR_MEDIA, | 107 | SDP_HDR_MEDIA, |
105 | }; | 108 | }; |
106 | 109 | ||
107 | extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, | 110 | extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, |
108 | unsigned int protoff, | 111 | unsigned int protoff, |
109 | unsigned int dataoff, | 112 | unsigned int dataoff, |
110 | const char **dptr, | 113 | const char **dptr, |
111 | unsigned int *datalen); | 114 | unsigned int *datalen); |
112 | extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, | 115 | extern void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, |
113 | unsigned int protoff, s16 off); | 116 | unsigned int protoff, s16 off); |
114 | extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | 117 | extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, |
115 | unsigned int protoff, | 118 | unsigned int protoff, |
116 | unsigned int dataoff, | 119 | unsigned int dataoff, |
117 | const char **dptr, | 120 | const char **dptr, |
118 | unsigned int *datalen, | 121 | unsigned int *datalen, |
119 | struct nf_conntrack_expect *exp, | 122 | struct nf_conntrack_expect *exp, |
120 | unsigned int matchoff, | 123 | unsigned int matchoff, |
121 | unsigned int matchlen); | 124 | unsigned int matchlen); |
122 | extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, | 125 | extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, |
123 | unsigned int protoff, | 126 | unsigned int protoff, |
124 | unsigned int dataoff, | 127 | unsigned int dataoff, |
125 | const char **dptr, | 128 | const char **dptr, |
126 | unsigned int *datalen, | 129 | unsigned int *datalen, |
127 | unsigned int sdpoff, | 130 | unsigned int sdpoff, |
128 | enum sdp_header_types type, | 131 | enum sdp_header_types type, |
129 | enum sdp_header_types term, | 132 | enum sdp_header_types term, |
130 | const union nf_inet_addr *addr); | 133 | const union nf_inet_addr *addr); |
131 | extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, | 134 | extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, |
132 | unsigned int protoff, | 135 | unsigned int protoff, |
133 | unsigned int dataoff, | 136 | unsigned int dataoff, |
134 | const char **dptr, | 137 | const char **dptr, |
135 | unsigned int *datalen, | 138 | unsigned int *datalen, |
136 | unsigned int matchoff, | 139 | unsigned int matchoff, |
137 | unsigned int matchlen, | 140 | unsigned int matchlen, |
138 | u_int16_t port); | 141 | u_int16_t port); |
139 | extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, | 142 | extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, |
140 | unsigned int protoff, | 143 | unsigned int protoff, |
141 | unsigned int dataoff, | 144 | unsigned int dataoff, |
142 | const char **dptr, | 145 | const char **dptr, |
143 | unsigned int *datalen, | 146 | unsigned int *datalen, |
144 | unsigned int sdpoff, | 147 | unsigned int sdpoff, |
145 | const union nf_inet_addr *addr); | 148 | const union nf_inet_addr *addr); |
146 | extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, | 149 | extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, |
147 | unsigned int protoff, | 150 | unsigned int protoff, |
148 | unsigned int dataoff, | 151 | unsigned int dataoff, |
149 | const char **dptr, | 152 | const char **dptr, |
150 | unsigned int *datalen, | 153 | unsigned int *datalen, |
151 | struct nf_conntrack_expect *rtp_exp, | 154 | struct nf_conntrack_expect *rtp_exp, |
152 | struct nf_conntrack_expect *rtcp_exp, | 155 | struct nf_conntrack_expect *rtcp_exp, |
153 | unsigned int mediaoff, | 156 | unsigned int mediaoff, |
154 | unsigned int medialen, | 157 | unsigned int medialen, |
155 | union nf_inet_addr *rtp_addr); | 158 | union nf_inet_addr *rtp_addr); |
156 | 159 | ||
157 | extern int ct_sip_parse_request(const struct nf_conn *ct, | 160 | extern int ct_sip_parse_request(const struct nf_conn *ct, |
158 | const char *dptr, unsigned int datalen, | 161 | const char *dptr, unsigned int datalen, |
159 | unsigned int *matchoff, unsigned int *matchlen, | 162 | unsigned int *matchoff, unsigned int *matchlen, |
160 | union nf_inet_addr *addr, __be16 *port); | 163 | union nf_inet_addr *addr, __be16 *port); |
161 | extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, | 164 | extern int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, |
162 | unsigned int dataoff, unsigned int datalen, | 165 | unsigned int dataoff, unsigned int datalen, |
163 | enum sip_header_types type, | 166 | enum sip_header_types type, |
164 | unsigned int *matchoff, unsigned int *matchlen); | 167 | unsigned int *matchoff, unsigned int *matchlen); |
165 | extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, | 168 | extern int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, |
166 | unsigned int *dataoff, unsigned int datalen, | 169 | unsigned int *dataoff, unsigned int datalen, |
167 | enum sip_header_types type, int *in_header, | 170 | enum sip_header_types type, int *in_header, |
168 | unsigned int *matchoff, unsigned int *matchlen, | 171 | unsigned int *matchoff, unsigned int *matchlen, |
169 | union nf_inet_addr *addr, __be16 *port); | 172 | union nf_inet_addr *addr, __be16 *port); |
170 | extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, | 173 | extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, |
171 | unsigned int dataoff, unsigned int datalen, | 174 | unsigned int dataoff, unsigned int datalen, |
172 | const char *name, | 175 | const char *name, |
173 | unsigned int *matchoff, unsigned int *matchlen, | 176 | unsigned int *matchoff, unsigned int *matchlen, |
174 | union nf_inet_addr *addr, bool delim); | 177 | union nf_inet_addr *addr, bool delim); |
175 | extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, | 178 | extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, |
176 | unsigned int off, unsigned int datalen, | 179 | unsigned int off, unsigned int datalen, |
177 | const char *name, | 180 | const char *name, |
178 | unsigned int *matchoff, unsigned int *matchen, | 181 | unsigned int *matchoff, unsigned int *matchen, |
179 | unsigned int *val); | 182 | unsigned int *val); |
180 | 183 | ||
181 | extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, | 184 | extern int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, |
182 | unsigned int dataoff, unsigned int datalen, | 185 | unsigned int dataoff, unsigned int datalen, |
183 | enum sdp_header_types type, | 186 | enum sdp_header_types type, |
184 | enum sdp_header_types term, | 187 | enum sdp_header_types term, |
185 | unsigned int *matchoff, unsigned int *matchlen); | 188 | unsigned int *matchoff, unsigned int *matchlen); |
186 | 189 | ||
187 | #endif /* __KERNEL__ */ | 190 | #endif /* __KERNEL__ */ |
188 | #endif /* __NF_CONNTRACK_SIP_H__ */ | 191 | #endif /* __NF_CONNTRACK_SIP_H__ */ |
189 | 192 |
net/netfilter/nf_conntrack_sip.c
1 | /* SIP extension for IP connection tracking. | 1 | /* SIP extension for IP connection tracking. |
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_conntrack_ftp.c and other modules. | 4 | * based on RR's ip_conntrack_ftp.c and other modules. |
5 | * (C) 2007 United Security Providers | 5 | * (C) 2007 United Security Providers |
6 | * (C) 2007, 2008 Patrick McHardy <kaber@trash.net> | 6 | * (C) 2007, 2008 Patrick McHardy <kaber@trash.net> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/ctype.h> | 14 | #include <linux/ctype.h> |
15 | #include <linux/skbuff.h> | 15 | #include <linux/skbuff.h> |
16 | #include <linux/inet.h> | 16 | #include <linux/inet.h> |
17 | #include <linux/in.h> | 17 | #include <linux/in.h> |
18 | #include <linux/udp.h> | 18 | #include <linux/udp.h> |
19 | #include <linux/tcp.h> | 19 | #include <linux/tcp.h> |
20 | #include <linux/netfilter.h> | 20 | #include <linux/netfilter.h> |
21 | 21 | ||
22 | #include <net/netfilter/nf_conntrack.h> | 22 | #include <net/netfilter/nf_conntrack.h> |
23 | #include <net/netfilter/nf_conntrack_core.h> | 23 | #include <net/netfilter/nf_conntrack_core.h> |
24 | #include <net/netfilter/nf_conntrack_expect.h> | 24 | #include <net/netfilter/nf_conntrack_expect.h> |
25 | #include <net/netfilter/nf_conntrack_helper.h> | 25 | #include <net/netfilter/nf_conntrack_helper.h> |
26 | #include <net/netfilter/nf_conntrack_zones.h> | 26 | #include <net/netfilter/nf_conntrack_zones.h> |
27 | #include <linux/netfilter/nf_conntrack_sip.h> | 27 | #include <linux/netfilter/nf_conntrack_sip.h> |
28 | 28 | ||
29 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
30 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); | 30 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); |
31 | MODULE_DESCRIPTION("SIP connection tracking helper"); | 31 | MODULE_DESCRIPTION("SIP connection tracking helper"); |
32 | MODULE_ALIAS("ip_conntrack_sip"); | 32 | MODULE_ALIAS("ip_conntrack_sip"); |
33 | MODULE_ALIAS_NFCT_HELPER("sip"); | 33 | MODULE_ALIAS_NFCT_HELPER("sip"); |
34 | 34 | ||
35 | #define MAX_PORTS 8 | 35 | #define MAX_PORTS 8 |
36 | static unsigned short ports[MAX_PORTS]; | 36 | static unsigned short ports[MAX_PORTS]; |
37 | static unsigned int ports_c; | 37 | static unsigned int ports_c; |
38 | module_param_array(ports, ushort, &ports_c, 0400); | 38 | module_param_array(ports, ushort, &ports_c, 0400); |
39 | MODULE_PARM_DESC(ports, "port numbers of SIP servers"); | 39 | MODULE_PARM_DESC(ports, "port numbers of SIP servers"); |
40 | 40 | ||
41 | static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; | 41 | static unsigned int sip_timeout __read_mostly = SIP_TIMEOUT; |
42 | module_param(sip_timeout, uint, 0600); | 42 | module_param(sip_timeout, uint, 0600); |
43 | MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); | 43 | MODULE_PARM_DESC(sip_timeout, "timeout for the master SIP session"); |
44 | 44 | ||
45 | static int sip_direct_signalling __read_mostly = 1; | 45 | static int sip_direct_signalling __read_mostly = 1; |
46 | module_param(sip_direct_signalling, int, 0600); | 46 | module_param(sip_direct_signalling, int, 0600); |
47 | MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " | 47 | MODULE_PARM_DESC(sip_direct_signalling, "expect incoming calls from registrar " |
48 | "only (default 1)"); | 48 | "only (default 1)"); |
49 | 49 | ||
50 | static int sip_direct_media __read_mostly = 1; | 50 | static int sip_direct_media __read_mostly = 1; |
51 | module_param(sip_direct_media, int, 0600); | 51 | module_param(sip_direct_media, int, 0600); |
52 | MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " | 52 | MODULE_PARM_DESC(sip_direct_media, "Expect Media streams between signalling " |
53 | "endpoints only (default 1)"); | 53 | "endpoints only (default 1)"); |
54 | 54 | ||
55 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int protoff, | 55 | unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb, unsigned int protoff, |
56 | unsigned int dataoff, const char **dptr, | 56 | unsigned int dataoff, const char **dptr, |
57 | unsigned int *datalen) __read_mostly; | 57 | unsigned int *datalen) __read_mostly; |
58 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); | 58 | EXPORT_SYMBOL_GPL(nf_nat_sip_hook); |
59 | 59 | ||
60 | void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, unsigned int protoff, | 60 | void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, unsigned int protoff, |
61 | s16 off) __read_mostly; | 61 | s16 off) __read_mostly; |
62 | EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook); | 62 | EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook); |
63 | 63 | ||
64 | unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | 64 | unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, |
65 | unsigned int protoff, | 65 | unsigned int protoff, |
66 | unsigned int dataoff, | 66 | unsigned int dataoff, |
67 | const char **dptr, | 67 | const char **dptr, |
68 | unsigned int *datalen, | 68 | unsigned int *datalen, |
69 | struct nf_conntrack_expect *exp, | 69 | struct nf_conntrack_expect *exp, |
70 | unsigned int matchoff, | 70 | unsigned int matchoff, |
71 | unsigned int matchlen) __read_mostly; | 71 | unsigned int matchlen) __read_mostly; |
72 | EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); | 72 | EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); |
73 | 73 | ||
74 | unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, unsigned int protoff, | 74 | unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, unsigned int protoff, |
75 | unsigned int dataoff, | 75 | unsigned int dataoff, |
76 | const char **dptr, | 76 | const char **dptr, |
77 | unsigned int *datalen, | 77 | unsigned int *datalen, |
78 | unsigned int sdpoff, | 78 | unsigned int sdpoff, |
79 | enum sdp_header_types type, | 79 | enum sdp_header_types type, |
80 | enum sdp_header_types term, | 80 | enum sdp_header_types term, |
81 | const union nf_inet_addr *addr) | 81 | const union nf_inet_addr *addr) |
82 | __read_mostly; | 82 | __read_mostly; |
83 | EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); | 83 | EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); |
84 | 84 | ||
85 | unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, unsigned int protoff, | 85 | unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb, unsigned int protoff, |
86 | unsigned int dataoff, | 86 | unsigned int dataoff, |
87 | const char **dptr, | 87 | const char **dptr, |
88 | unsigned int *datalen, | 88 | unsigned int *datalen, |
89 | unsigned int matchoff, | 89 | unsigned int matchoff, |
90 | unsigned int matchlen, | 90 | unsigned int matchlen, |
91 | u_int16_t port) __read_mostly; | 91 | u_int16_t port) __read_mostly; |
92 | EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); | 92 | EXPORT_SYMBOL_GPL(nf_nat_sdp_port_hook); |
93 | 93 | ||
94 | unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, | 94 | unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, |
95 | unsigned int protoff, | 95 | unsigned int protoff, |
96 | unsigned int dataoff, | 96 | unsigned int dataoff, |
97 | const char **dptr, | 97 | const char **dptr, |
98 | unsigned int *datalen, | 98 | unsigned int *datalen, |
99 | unsigned int sdpoff, | 99 | unsigned int sdpoff, |
100 | const union nf_inet_addr *addr) | 100 | const union nf_inet_addr *addr) |
101 | __read_mostly; | 101 | __read_mostly; |
102 | EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); | 102 | EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); |
103 | 103 | ||
104 | unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, unsigned int protoff, | 104 | unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, unsigned int protoff, |
105 | unsigned int dataoff, | 105 | unsigned int dataoff, |
106 | const char **dptr, | 106 | const char **dptr, |
107 | unsigned int *datalen, | 107 | unsigned int *datalen, |
108 | struct nf_conntrack_expect *rtp_exp, | 108 | struct nf_conntrack_expect *rtp_exp, |
109 | struct nf_conntrack_expect *rtcp_exp, | 109 | struct nf_conntrack_expect *rtcp_exp, |
110 | unsigned int mediaoff, | 110 | unsigned int mediaoff, |
111 | unsigned int medialen, | 111 | unsigned int medialen, |
112 | union nf_inet_addr *rtp_addr) | 112 | union nf_inet_addr *rtp_addr) |
113 | __read_mostly; | 113 | __read_mostly; |
114 | EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook); | 114 | EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook); |
115 | 115 | ||
116 | static int string_len(const struct nf_conn *ct, const char *dptr, | 116 | static int string_len(const struct nf_conn *ct, const char *dptr, |
117 | const char *limit, int *shift) | 117 | const char *limit, int *shift) |
118 | { | 118 | { |
119 | int len = 0; | 119 | int len = 0; |
120 | 120 | ||
121 | while (dptr < limit && isalpha(*dptr)) { | 121 | while (dptr < limit && isalpha(*dptr)) { |
122 | dptr++; | 122 | dptr++; |
123 | len++; | 123 | len++; |
124 | } | 124 | } |
125 | return len; | 125 | return len; |
126 | } | 126 | } |
127 | 127 | ||
128 | static int digits_len(const struct nf_conn *ct, const char *dptr, | 128 | static int digits_len(const struct nf_conn *ct, const char *dptr, |
129 | const char *limit, int *shift) | 129 | const char *limit, int *shift) |
130 | { | 130 | { |
131 | int len = 0; | 131 | int len = 0; |
132 | while (dptr < limit && isdigit(*dptr)) { | 132 | while (dptr < limit && isdigit(*dptr)) { |
133 | dptr++; | 133 | dptr++; |
134 | len++; | 134 | len++; |
135 | } | 135 | } |
136 | return len; | 136 | return len; |
137 | } | 137 | } |
138 | 138 | ||
139 | static int iswordc(const char c) | 139 | static int iswordc(const char c) |
140 | { | 140 | { |
141 | if (isalnum(c) || c == '!' || c == '"' || c == '%' || | 141 | if (isalnum(c) || c == '!' || c == '"' || c == '%' || |
142 | (c >= '(' && c <= '/') || c == ':' || c == '<' || c == '>' || | 142 | (c >= '(' && c <= '/') || c == ':' || c == '<' || c == '>' || |
143 | c == '?' || (c >= '[' && c <= ']') || c == '_' || c == '`' || | 143 | c == '?' || (c >= '[' && c <= ']') || c == '_' || c == '`' || |
144 | c == '{' || c == '}' || c == '~') | 144 | c == '{' || c == '}' || c == '~') |
145 | return 1; | 145 | return 1; |
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | static int word_len(const char *dptr, const char *limit) | 149 | static int word_len(const char *dptr, const char *limit) |
150 | { | 150 | { |
151 | int len = 0; | 151 | int len = 0; |
152 | while (dptr < limit && iswordc(*dptr)) { | 152 | while (dptr < limit && iswordc(*dptr)) { |
153 | dptr++; | 153 | dptr++; |
154 | len++; | 154 | len++; |
155 | } | 155 | } |
156 | return len; | 156 | return len; |
157 | } | 157 | } |
158 | 158 | ||
159 | static int callid_len(const struct nf_conn *ct, const char *dptr, | 159 | static int callid_len(const struct nf_conn *ct, const char *dptr, |
160 | const char *limit, int *shift) | 160 | const char *limit, int *shift) |
161 | { | 161 | { |
162 | int len, domain_len; | 162 | int len, domain_len; |
163 | 163 | ||
164 | len = word_len(dptr, limit); | 164 | len = word_len(dptr, limit); |
165 | dptr += len; | 165 | dptr += len; |
166 | if (!len || dptr == limit || *dptr != '@') | 166 | if (!len || dptr == limit || *dptr != '@') |
167 | return len; | 167 | return len; |
168 | dptr++; | 168 | dptr++; |
169 | len++; | 169 | len++; |
170 | 170 | ||
171 | domain_len = word_len(dptr, limit); | 171 | domain_len = word_len(dptr, limit); |
172 | if (!domain_len) | 172 | if (!domain_len) |
173 | return 0; | 173 | return 0; |
174 | return len + domain_len; | 174 | return len + domain_len; |
175 | } | 175 | } |
176 | 176 | ||
177 | /* get media type + port length */ | 177 | /* get media type + port length */ |
178 | static int media_len(const struct nf_conn *ct, const char *dptr, | 178 | static int media_len(const struct nf_conn *ct, const char *dptr, |
179 | const char *limit, int *shift) | 179 | const char *limit, int *shift) |
180 | { | 180 | { |
181 | int len = string_len(ct, dptr, limit, shift); | 181 | int len = string_len(ct, dptr, limit, shift); |
182 | 182 | ||
183 | dptr += len; | 183 | dptr += len; |
184 | if (dptr >= limit || *dptr != ' ') | 184 | if (dptr >= limit || *dptr != ' ') |
185 | return 0; | 185 | return 0; |
186 | len++; | 186 | len++; |
187 | dptr++; | 187 | dptr++; |
188 | 188 | ||
189 | return len + digits_len(ct, dptr, limit, shift); | 189 | return len + digits_len(ct, dptr, limit, shift); |
190 | } | 190 | } |
191 | 191 | ||
192 | static int sip_parse_addr(const struct nf_conn *ct, const char *cp, | 192 | static int sip_parse_addr(const struct nf_conn *ct, const char *cp, |
193 | const char **endp, union nf_inet_addr *addr, | 193 | const char **endp, union nf_inet_addr *addr, |
194 | const char *limit, bool delim) | 194 | const char *limit, bool delim) |
195 | { | 195 | { |
196 | const char *end; | 196 | const char *end; |
197 | int ret; | 197 | int ret; |
198 | 198 | ||
199 | if (!ct) | 199 | if (!ct) |
200 | return 0; | 200 | return 0; |
201 | 201 | ||
202 | memset(addr, 0, sizeof(*addr)); | 202 | memset(addr, 0, sizeof(*addr)); |
203 | switch (nf_ct_l3num(ct)) { | 203 | switch (nf_ct_l3num(ct)) { |
204 | case AF_INET: | 204 | case AF_INET: |
205 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); | 205 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); |
206 | if (ret == 0) | 206 | if (ret == 0) |
207 | return 0; | 207 | return 0; |
208 | break; | 208 | break; |
209 | case AF_INET6: | 209 | case AF_INET6: |
210 | if (cp < limit && *cp == '[') | 210 | if (cp < limit && *cp == '[') |
211 | cp++; | 211 | cp++; |
212 | else if (delim) | 212 | else if (delim) |
213 | return 0; | 213 | return 0; |
214 | 214 | ||
215 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); | 215 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); |
216 | if (ret == 0) | 216 | if (ret == 0) |
217 | return 0; | 217 | return 0; |
218 | 218 | ||
219 | if (end < limit && *end == ']') | 219 | if (end < limit && *end == ']') |
220 | end++; | 220 | end++; |
221 | else if (delim) | 221 | else if (delim) |
222 | return 0; | 222 | return 0; |
223 | break; | 223 | break; |
224 | default: | 224 | default: |
225 | BUG(); | 225 | BUG(); |
226 | } | 226 | } |
227 | 227 | ||
228 | if (endp) | 228 | if (endp) |
229 | *endp = end; | 229 | *endp = end; |
230 | return 1; | 230 | return 1; |
231 | } | 231 | } |
232 | 232 | ||
233 | /* skip ip address. returns its length. */ | 233 | /* skip ip address. returns its length. */ |
234 | static int epaddr_len(const struct nf_conn *ct, const char *dptr, | 234 | static int epaddr_len(const struct nf_conn *ct, const char *dptr, |
235 | const char *limit, int *shift) | 235 | const char *limit, int *shift) |
236 | { | 236 | { |
237 | union nf_inet_addr addr; | 237 | union nf_inet_addr addr; |
238 | const char *aux = dptr; | 238 | const char *aux = dptr; |
239 | 239 | ||
240 | if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) { | 240 | if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) { |
241 | pr_debug("ip: %s parse failed.!\n", dptr); | 241 | pr_debug("ip: %s parse failed.!\n", dptr); |
242 | return 0; | 242 | return 0; |
243 | } | 243 | } |
244 | 244 | ||
245 | /* Port number */ | 245 | /* Port number */ |
246 | if (*dptr == ':') { | 246 | if (*dptr == ':') { |
247 | dptr++; | 247 | dptr++; |
248 | dptr += digits_len(ct, dptr, limit, shift); | 248 | dptr += digits_len(ct, dptr, limit, shift); |
249 | } | 249 | } |
250 | return dptr - aux; | 250 | return dptr - aux; |
251 | } | 251 | } |
252 | 252 | ||
253 | /* get address length, skiping user info. */ | 253 | /* get address length, skiping user info. */ |
254 | static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, | 254 | static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, |
255 | const char *limit, int *shift) | 255 | const char *limit, int *shift) |
256 | { | 256 | { |
257 | const char *start = dptr; | 257 | const char *start = dptr; |
258 | int s = *shift; | 258 | int s = *shift; |
259 | 259 | ||
260 | /* Search for @, but stop at the end of the line. | 260 | /* Search for @, but stop at the end of the line. |
261 | * We are inside a sip: URI, so we don't need to worry about | 261 | * We are inside a sip: URI, so we don't need to worry about |
262 | * continuation lines. */ | 262 | * continuation lines. */ |
263 | while (dptr < limit && | 263 | while (dptr < limit && |
264 | *dptr != '@' && *dptr != '\r' && *dptr != '\n') { | 264 | *dptr != '@' && *dptr != '\r' && *dptr != '\n') { |
265 | (*shift)++; | 265 | (*shift)++; |
266 | dptr++; | 266 | dptr++; |
267 | } | 267 | } |
268 | 268 | ||
269 | if (dptr < limit && *dptr == '@') { | 269 | if (dptr < limit && *dptr == '@') { |
270 | dptr++; | 270 | dptr++; |
271 | (*shift)++; | 271 | (*shift)++; |
272 | } else { | 272 | } else { |
273 | dptr = start; | 273 | dptr = start; |
274 | *shift = s; | 274 | *shift = s; |
275 | } | 275 | } |
276 | 276 | ||
277 | return epaddr_len(ct, dptr, limit, shift); | 277 | return epaddr_len(ct, dptr, limit, shift); |
278 | } | 278 | } |
279 | 279 | ||
280 | /* Parse a SIP request line of the form: | 280 | /* Parse a SIP request line of the form: |
281 | * | 281 | * |
282 | * Request-Line = Method SP Request-URI SP SIP-Version CRLF | 282 | * Request-Line = Method SP Request-URI SP SIP-Version CRLF |
283 | * | 283 | * |
284 | * and return the offset and length of the address contained in the Request-URI. | 284 | * and return the offset and length of the address contained in the Request-URI. |
285 | */ | 285 | */ |
286 | int ct_sip_parse_request(const struct nf_conn *ct, | 286 | int ct_sip_parse_request(const struct nf_conn *ct, |
287 | const char *dptr, unsigned int datalen, | 287 | const char *dptr, unsigned int datalen, |
288 | unsigned int *matchoff, unsigned int *matchlen, | 288 | unsigned int *matchoff, unsigned int *matchlen, |
289 | union nf_inet_addr *addr, __be16 *port) | 289 | union nf_inet_addr *addr, __be16 *port) |
290 | { | 290 | { |
291 | const char *start = dptr, *limit = dptr + datalen, *end; | 291 | const char *start = dptr, *limit = dptr + datalen, *end; |
292 | unsigned int mlen; | 292 | unsigned int mlen; |
293 | unsigned int p; | 293 | unsigned int p; |
294 | int shift = 0; | 294 | int shift = 0; |
295 | 295 | ||
296 | /* Skip method and following whitespace */ | 296 | /* Skip method and following whitespace */ |
297 | mlen = string_len(ct, dptr, limit, NULL); | 297 | mlen = string_len(ct, dptr, limit, NULL); |
298 | if (!mlen) | 298 | if (!mlen) |
299 | return 0; | 299 | return 0; |
300 | dptr += mlen; | 300 | dptr += mlen; |
301 | if (++dptr >= limit) | 301 | if (++dptr >= limit) |
302 | return 0; | 302 | return 0; |
303 | 303 | ||
304 | /* Find SIP URI */ | 304 | /* Find SIP URI */ |
305 | for (; dptr < limit - strlen("sip:"); dptr++) { | 305 | for (; dptr < limit - strlen("sip:"); dptr++) { |
306 | if (*dptr == '\r' || *dptr == '\n') | 306 | if (*dptr == '\r' || *dptr == '\n') |
307 | return -1; | 307 | return -1; |
308 | if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) { | 308 | if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) { |
309 | dptr += strlen("sip:"); | 309 | dptr += strlen("sip:"); |
310 | break; | 310 | break; |
311 | } | 311 | } |
312 | } | 312 | } |
313 | if (!skp_epaddr_len(ct, dptr, limit, &shift)) | 313 | if (!skp_epaddr_len(ct, dptr, limit, &shift)) |
314 | return 0; | 314 | return 0; |
315 | dptr += shift; | 315 | dptr += shift; |
316 | 316 | ||
317 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) | 317 | if (!sip_parse_addr(ct, dptr, &end, addr, limit, true)) |
318 | return -1; | 318 | return -1; |
319 | if (end < limit && *end == ':') { | 319 | if (end < limit && *end == ':') { |
320 | end++; | 320 | end++; |
321 | p = simple_strtoul(end, (char **)&end, 10); | 321 | p = simple_strtoul(end, (char **)&end, 10); |
322 | if (p < 1024 || p > 65535) | 322 | if (p < 1024 || p > 65535) |
323 | return -1; | 323 | return -1; |
324 | *port = htons(p); | 324 | *port = htons(p); |
325 | } else | 325 | } else |
326 | *port = htons(SIP_PORT); | 326 | *port = htons(SIP_PORT); |
327 | 327 | ||
328 | if (end == dptr) | 328 | if (end == dptr) |
329 | return 0; | 329 | return 0; |
330 | *matchoff = dptr - start; | 330 | *matchoff = dptr - start; |
331 | *matchlen = end - dptr; | 331 | *matchlen = end - dptr; |
332 | return 1; | 332 | return 1; |
333 | } | 333 | } |
334 | EXPORT_SYMBOL_GPL(ct_sip_parse_request); | 334 | EXPORT_SYMBOL_GPL(ct_sip_parse_request); |
335 | 335 | ||
336 | /* SIP header parsing: SIP headers are located at the beginning of a line, but | 336 | /* SIP header parsing: SIP headers are located at the beginning of a line, but |
337 | * may span several lines, in which case the continuation lines begin with a | 337 | * may span several lines, in which case the continuation lines begin with a |
338 | * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or | 338 | * whitespace character. RFC 2543 allows lines to be terminated with CR, LF or |
339 | * CRLF, RFC 3261 allows only CRLF, we support both. | 339 | * CRLF, RFC 3261 allows only CRLF, we support both. |
340 | * | 340 | * |
341 | * Headers are followed by (optionally) whitespace, a colon, again (optionally) | 341 | * Headers are followed by (optionally) whitespace, a colon, again (optionally) |
342 | * whitespace and the values. Whitespace in this context means any amount of | 342 | * whitespace and the values. Whitespace in this context means any amount of |
343 | * tabs, spaces and continuation lines, which are treated as a single whitespace | 343 | * tabs, spaces and continuation lines, which are treated as a single whitespace |
344 | * character. | 344 | * character. |
345 | * | 345 | * |
346 | * Some headers may appear multiple times. A comma separated list of values is | 346 | * Some headers may appear multiple times. A comma separated list of values is |
347 | * equivalent to multiple headers. | 347 | * equivalent to multiple headers. |
348 | */ | 348 | */ |
349 | static const struct sip_header ct_sip_hdrs[] = { | 349 | static const struct sip_header ct_sip_hdrs[] = { |
350 | [SIP_HDR_CSEQ] = SIP_HDR("CSeq", NULL, NULL, digits_len), | 350 | [SIP_HDR_CSEQ] = SIP_HDR("CSeq", NULL, NULL, digits_len), |
351 | [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), | 351 | [SIP_HDR_FROM] = SIP_HDR("From", "f", "sip:", skp_epaddr_len), |
352 | [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), | 352 | [SIP_HDR_TO] = SIP_HDR("To", "t", "sip:", skp_epaddr_len), |
353 | [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), | 353 | [SIP_HDR_CONTACT] = SIP_HDR("Contact", "m", "sip:", skp_epaddr_len), |
354 | [SIP_HDR_VIA_UDP] = SIP_HDR("Via", "v", "UDP ", epaddr_len), | 354 | [SIP_HDR_VIA_UDP] = SIP_HDR("Via", "v", "UDP ", epaddr_len), |
355 | [SIP_HDR_VIA_TCP] = SIP_HDR("Via", "v", "TCP ", epaddr_len), | 355 | [SIP_HDR_VIA_TCP] = SIP_HDR("Via", "v", "TCP ", epaddr_len), |
356 | [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), | 356 | [SIP_HDR_EXPIRES] = SIP_HDR("Expires", NULL, NULL, digits_len), |
357 | [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), | 357 | [SIP_HDR_CONTENT_LENGTH] = SIP_HDR("Content-Length", "l", NULL, digits_len), |
358 | [SIP_HDR_CALL_ID] = SIP_HDR("Call-Id", "i", NULL, callid_len), | 358 | [SIP_HDR_CALL_ID] = SIP_HDR("Call-Id", "i", NULL, callid_len), |
359 | }; | 359 | }; |
360 | 360 | ||
361 | static const char *sip_follow_continuation(const char *dptr, const char *limit) | 361 | static const char *sip_follow_continuation(const char *dptr, const char *limit) |
362 | { | 362 | { |
363 | /* Walk past newline */ | 363 | /* Walk past newline */ |
364 | if (++dptr >= limit) | 364 | if (++dptr >= limit) |
365 | return NULL; | 365 | return NULL; |
366 | 366 | ||
367 | /* Skip '\n' in CR LF */ | 367 | /* Skip '\n' in CR LF */ |
368 | if (*(dptr - 1) == '\r' && *dptr == '\n') { | 368 | if (*(dptr - 1) == '\r' && *dptr == '\n') { |
369 | if (++dptr >= limit) | 369 | if (++dptr >= limit) |
370 | return NULL; | 370 | return NULL; |
371 | } | 371 | } |
372 | 372 | ||
373 | /* Continuation line? */ | 373 | /* Continuation line? */ |
374 | if (*dptr != ' ' && *dptr != '\t') | 374 | if (*dptr != ' ' && *dptr != '\t') |
375 | return NULL; | 375 | return NULL; |
376 | 376 | ||
377 | /* skip leading whitespace */ | 377 | /* skip leading whitespace */ |
378 | for (; dptr < limit; dptr++) { | 378 | for (; dptr < limit; dptr++) { |
379 | if (*dptr != ' ' && *dptr != '\t') | 379 | if (*dptr != ' ' && *dptr != '\t') |
380 | break; | 380 | break; |
381 | } | 381 | } |
382 | return dptr; | 382 | return dptr; |
383 | } | 383 | } |
384 | 384 | ||
385 | static const char *sip_skip_whitespace(const char *dptr, const char *limit) | 385 | static const char *sip_skip_whitespace(const char *dptr, const char *limit) |
386 | { | 386 | { |
387 | for (; dptr < limit; dptr++) { | 387 | for (; dptr < limit; dptr++) { |
388 | if (*dptr == ' ') | 388 | if (*dptr == ' ') |
389 | continue; | 389 | continue; |
390 | if (*dptr != '\r' && *dptr != '\n') | 390 | if (*dptr != '\r' && *dptr != '\n') |
391 | break; | 391 | break; |
392 | dptr = sip_follow_continuation(dptr, limit); | 392 | dptr = sip_follow_continuation(dptr, limit); |
393 | if (dptr == NULL) | 393 | if (dptr == NULL) |
394 | return NULL; | 394 | return NULL; |
395 | } | 395 | } |
396 | return dptr; | 396 | return dptr; |
397 | } | 397 | } |
398 | 398 | ||
399 | /* Search within a SIP header value, dealing with continuation lines */ | 399 | /* Search within a SIP header value, dealing with continuation lines */ |
400 | static const char *ct_sip_header_search(const char *dptr, const char *limit, | 400 | static const char *ct_sip_header_search(const char *dptr, const char *limit, |
401 | const char *needle, unsigned int len) | 401 | const char *needle, unsigned int len) |
402 | { | 402 | { |
403 | for (limit -= len; dptr < limit; dptr++) { | 403 | for (limit -= len; dptr < limit; dptr++) { |
404 | if (*dptr == '\r' || *dptr == '\n') { | 404 | if (*dptr == '\r' || *dptr == '\n') { |
405 | dptr = sip_follow_continuation(dptr, limit); | 405 | dptr = sip_follow_continuation(dptr, limit); |
406 | if (dptr == NULL) | 406 | if (dptr == NULL) |
407 | break; | 407 | break; |
408 | continue; | 408 | continue; |
409 | } | 409 | } |
410 | 410 | ||
411 | if (strnicmp(dptr, needle, len) == 0) | 411 | if (strnicmp(dptr, needle, len) == 0) |
412 | return dptr; | 412 | return dptr; |
413 | } | 413 | } |
414 | return NULL; | 414 | return NULL; |
415 | } | 415 | } |
416 | 416 | ||
417 | int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, | 417 | int ct_sip_get_header(const struct nf_conn *ct, const char *dptr, |
418 | unsigned int dataoff, unsigned int datalen, | 418 | unsigned int dataoff, unsigned int datalen, |
419 | enum sip_header_types type, | 419 | enum sip_header_types type, |
420 | unsigned int *matchoff, unsigned int *matchlen) | 420 | unsigned int *matchoff, unsigned int *matchlen) |
421 | { | 421 | { |
422 | const struct sip_header *hdr = &ct_sip_hdrs[type]; | 422 | const struct sip_header *hdr = &ct_sip_hdrs[type]; |
423 | const char *start = dptr, *limit = dptr + datalen; | 423 | const char *start = dptr, *limit = dptr + datalen; |
424 | int shift = 0; | 424 | int shift = 0; |
425 | 425 | ||
426 | for (dptr += dataoff; dptr < limit; dptr++) { | 426 | for (dptr += dataoff; dptr < limit; dptr++) { |
427 | /* Find beginning of line */ | 427 | /* Find beginning of line */ |
428 | if (*dptr != '\r' && *dptr != '\n') | 428 | if (*dptr != '\r' && *dptr != '\n') |
429 | continue; | 429 | continue; |
430 | if (++dptr >= limit) | 430 | if (++dptr >= limit) |
431 | break; | 431 | break; |
432 | if (*(dptr - 1) == '\r' && *dptr == '\n') { | 432 | if (*(dptr - 1) == '\r' && *dptr == '\n') { |
433 | if (++dptr >= limit) | 433 | if (++dptr >= limit) |
434 | break; | 434 | break; |
435 | } | 435 | } |
436 | 436 | ||
437 | /* Skip continuation lines */ | 437 | /* Skip continuation lines */ |
438 | if (*dptr == ' ' || *dptr == '\t') | 438 | if (*dptr == ' ' || *dptr == '\t') |
439 | continue; | 439 | continue; |
440 | 440 | ||
441 | /* Find header. Compact headers must be followed by a | 441 | /* Find header. Compact headers must be followed by a |
442 | * non-alphabetic character to avoid mismatches. */ | 442 | * non-alphabetic character to avoid mismatches. */ |
443 | if (limit - dptr >= hdr->len && | 443 | if (limit - dptr >= hdr->len && |
444 | strnicmp(dptr, hdr->name, hdr->len) == 0) | 444 | strnicmp(dptr, hdr->name, hdr->len) == 0) |
445 | dptr += hdr->len; | 445 | dptr += hdr->len; |
446 | else if (hdr->cname && limit - dptr >= hdr->clen + 1 && | 446 | else if (hdr->cname && limit - dptr >= hdr->clen + 1 && |
447 | strnicmp(dptr, hdr->cname, hdr->clen) == 0 && | 447 | strnicmp(dptr, hdr->cname, hdr->clen) == 0 && |
448 | !isalpha(*(dptr + hdr->clen))) | 448 | !isalpha(*(dptr + hdr->clen))) |
449 | dptr += hdr->clen; | 449 | dptr += hdr->clen; |
450 | else | 450 | else |
451 | continue; | 451 | continue; |
452 | 452 | ||
453 | /* Find and skip colon */ | 453 | /* Find and skip colon */ |
454 | dptr = sip_skip_whitespace(dptr, limit); | 454 | dptr = sip_skip_whitespace(dptr, limit); |
455 | if (dptr == NULL) | 455 | if (dptr == NULL) |
456 | break; | 456 | break; |
457 | if (*dptr != ':' || ++dptr >= limit) | 457 | if (*dptr != ':' || ++dptr >= limit) |
458 | break; | 458 | break; |
459 | 459 | ||
460 | /* Skip whitespace after colon */ | 460 | /* Skip whitespace after colon */ |
461 | dptr = sip_skip_whitespace(dptr, limit); | 461 | dptr = sip_skip_whitespace(dptr, limit); |
462 | if (dptr == NULL) | 462 | if (dptr == NULL) |
463 | break; | 463 | break; |
464 | 464 | ||
465 | *matchoff = dptr - start; | 465 | *matchoff = dptr - start; |
466 | if (hdr->search) { | 466 | if (hdr->search) { |
467 | dptr = ct_sip_header_search(dptr, limit, hdr->search, | 467 | dptr = ct_sip_header_search(dptr, limit, hdr->search, |
468 | hdr->slen); | 468 | hdr->slen); |
469 | if (!dptr) | 469 | if (!dptr) |
470 | return -1; | 470 | return -1; |
471 | dptr += hdr->slen; | 471 | dptr += hdr->slen; |
472 | } | 472 | } |
473 | 473 | ||
474 | *matchlen = hdr->match_len(ct, dptr, limit, &shift); | 474 | *matchlen = hdr->match_len(ct, dptr, limit, &shift); |
475 | if (!*matchlen) | 475 | if (!*matchlen) |
476 | return -1; | 476 | return -1; |
477 | *matchoff = dptr - start + shift; | 477 | *matchoff = dptr - start + shift; |
478 | return 1; | 478 | return 1; |
479 | } | 479 | } |
480 | return 0; | 480 | return 0; |
481 | } | 481 | } |
482 | EXPORT_SYMBOL_GPL(ct_sip_get_header); | 482 | EXPORT_SYMBOL_GPL(ct_sip_get_header); |
483 | 483 | ||
484 | /* Get next header field in a list of comma separated values */ | 484 | /* Get next header field in a list of comma separated values */ |
485 | static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr, | 485 | static int ct_sip_next_header(const struct nf_conn *ct, const char *dptr, |
486 | unsigned int dataoff, unsigned int datalen, | 486 | unsigned int dataoff, unsigned int datalen, |
487 | enum sip_header_types type, | 487 | enum sip_header_types type, |
488 | unsigned int *matchoff, unsigned int *matchlen) | 488 | unsigned int *matchoff, unsigned int *matchlen) |
489 | { | 489 | { |
490 | const struct sip_header *hdr = &ct_sip_hdrs[type]; | 490 | const struct sip_header *hdr = &ct_sip_hdrs[type]; |
491 | const char *start = dptr, *limit = dptr + datalen; | 491 | const char *start = dptr, *limit = dptr + datalen; |
492 | int shift = 0; | 492 | int shift = 0; |
493 | 493 | ||
494 | dptr += dataoff; | 494 | dptr += dataoff; |
495 | 495 | ||
496 | dptr = ct_sip_header_search(dptr, limit, ",", strlen(",")); | 496 | dptr = ct_sip_header_search(dptr, limit, ",", strlen(",")); |
497 | if (!dptr) | 497 | if (!dptr) |
498 | return 0; | 498 | return 0; |
499 | 499 | ||
500 | dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen); | 500 | dptr = ct_sip_header_search(dptr, limit, hdr->search, hdr->slen); |
501 | if (!dptr) | 501 | if (!dptr) |
502 | return 0; | 502 | return 0; |
503 | dptr += hdr->slen; | 503 | dptr += hdr->slen; |
504 | 504 | ||
505 | *matchoff = dptr - start; | 505 | *matchoff = dptr - start; |
506 | *matchlen = hdr->match_len(ct, dptr, limit, &shift); | 506 | *matchlen = hdr->match_len(ct, dptr, limit, &shift); |
507 | if (!*matchlen) | 507 | if (!*matchlen) |
508 | return -1; | 508 | return -1; |
509 | *matchoff += shift; | 509 | *matchoff += shift; |
510 | return 1; | 510 | return 1; |
511 | } | 511 | } |
512 | 512 | ||
513 | /* Walk through headers until a parsable one is found or no header of the | 513 | /* Walk through headers until a parsable one is found or no header of the |
514 | * given type is left. */ | 514 | * given type is left. */ |
515 | static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr, | 515 | static int ct_sip_walk_headers(const struct nf_conn *ct, const char *dptr, |
516 | unsigned int dataoff, unsigned int datalen, | 516 | unsigned int dataoff, unsigned int datalen, |
517 | enum sip_header_types type, int *in_header, | 517 | enum sip_header_types type, int *in_header, |
518 | unsigned int *matchoff, unsigned int *matchlen) | 518 | unsigned int *matchoff, unsigned int *matchlen) |
519 | { | 519 | { |
520 | int ret; | 520 | int ret; |
521 | 521 | ||
522 | if (in_header && *in_header) { | 522 | if (in_header && *in_header) { |
523 | while (1) { | 523 | while (1) { |
524 | ret = ct_sip_next_header(ct, dptr, dataoff, datalen, | 524 | ret = ct_sip_next_header(ct, dptr, dataoff, datalen, |
525 | type, matchoff, matchlen); | 525 | type, matchoff, matchlen); |
526 | if (ret > 0) | 526 | if (ret > 0) |
527 | return ret; | 527 | return ret; |
528 | if (ret == 0) | 528 | if (ret == 0) |
529 | break; | 529 | break; |
530 | dataoff += *matchoff; | 530 | dataoff += *matchoff; |
531 | } | 531 | } |
532 | *in_header = 0; | 532 | *in_header = 0; |
533 | } | 533 | } |
534 | 534 | ||
535 | while (1) { | 535 | while (1) { |
536 | ret = ct_sip_get_header(ct, dptr, dataoff, datalen, | 536 | ret = ct_sip_get_header(ct, dptr, dataoff, datalen, |
537 | type, matchoff, matchlen); | 537 | type, matchoff, matchlen); |
538 | if (ret > 0) | 538 | if (ret > 0) |
539 | break; | 539 | break; |
540 | if (ret == 0) | 540 | if (ret == 0) |
541 | return ret; | 541 | return ret; |
542 | dataoff += *matchoff; | 542 | dataoff += *matchoff; |
543 | } | 543 | } |
544 | 544 | ||
545 | if (in_header) | 545 | if (in_header) |
546 | *in_header = 1; | 546 | *in_header = 1; |
547 | return 1; | 547 | return 1; |
548 | } | 548 | } |
549 | 549 | ||
550 | /* Locate a SIP header, parse the URI and return the offset and length of | 550 | /* Locate a SIP header, parse the URI and return the offset and length of |
551 | * the address as well as the address and port themselves. A stream of | 551 | * the address as well as the address and port themselves. A stream of |
552 | * headers can be parsed by handing in a non-NULL datalen and in_header | 552 | * headers can be parsed by handing in a non-NULL datalen and in_header |
553 | * pointer. | 553 | * pointer. |
554 | */ | 554 | */ |
555 | int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, | 555 | int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, |
556 | unsigned int *dataoff, unsigned int datalen, | 556 | unsigned int *dataoff, unsigned int datalen, |
557 | enum sip_header_types type, int *in_header, | 557 | enum sip_header_types type, int *in_header, |
558 | unsigned int *matchoff, unsigned int *matchlen, | 558 | unsigned int *matchoff, unsigned int *matchlen, |
559 | union nf_inet_addr *addr, __be16 *port) | 559 | union nf_inet_addr *addr, __be16 *port) |
560 | { | 560 | { |
561 | const char *c, *limit = dptr + datalen; | 561 | const char *c, *limit = dptr + datalen; |
562 | unsigned int p; | 562 | unsigned int p; |
563 | int ret; | 563 | int ret; |
564 | 564 | ||
565 | ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, | 565 | ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen, |
566 | type, in_header, matchoff, matchlen); | 566 | type, in_header, matchoff, matchlen); |
567 | WARN_ON(ret < 0); | 567 | WARN_ON(ret < 0); |
568 | if (ret == 0) | 568 | if (ret == 0) |
569 | return ret; | 569 | return ret; |
570 | 570 | ||
571 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) | 571 | if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true)) |
572 | return -1; | 572 | return -1; |
573 | if (*c == ':') { | 573 | if (*c == ':') { |
574 | c++; | 574 | c++; |
575 | p = simple_strtoul(c, (char **)&c, 10); | 575 | p = simple_strtoul(c, (char **)&c, 10); |
576 | if (p < 1024 || p > 65535) | 576 | if (p < 1024 || p > 65535) |
577 | return -1; | 577 | return -1; |
578 | *port = htons(p); | 578 | *port = htons(p); |
579 | } else | 579 | } else |
580 | *port = htons(SIP_PORT); | 580 | *port = htons(SIP_PORT); |
581 | 581 | ||
582 | if (dataoff) | 582 | if (dataoff) |
583 | *dataoff = c - dptr; | 583 | *dataoff = c - dptr; |
584 | return 1; | 584 | return 1; |
585 | } | 585 | } |
586 | EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); | 586 | EXPORT_SYMBOL_GPL(ct_sip_parse_header_uri); |
587 | 587 | ||
588 | static int ct_sip_parse_param(const struct nf_conn *ct, const char *dptr, | 588 | static int ct_sip_parse_param(const struct nf_conn *ct, const char *dptr, |
589 | unsigned int dataoff, unsigned int datalen, | 589 | unsigned int dataoff, unsigned int datalen, |
590 | const char *name, | 590 | const char *name, |
591 | unsigned int *matchoff, unsigned int *matchlen) | 591 | unsigned int *matchoff, unsigned int *matchlen) |
592 | { | 592 | { |
593 | const char *limit = dptr + datalen; | 593 | const char *limit = dptr + datalen; |
594 | const char *start; | 594 | const char *start; |
595 | const char *end; | 595 | const char *end; |
596 | 596 | ||
597 | limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); | 597 | limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); |
598 | if (!limit) | 598 | if (!limit) |
599 | limit = dptr + datalen; | 599 | limit = dptr + datalen; |
600 | 600 | ||
601 | start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); | 601 | start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); |
602 | if (!start) | 602 | if (!start) |
603 | return 0; | 603 | return 0; |
604 | start += strlen(name); | 604 | start += strlen(name); |
605 | 605 | ||
606 | end = ct_sip_header_search(start, limit, ";", strlen(";")); | 606 | end = ct_sip_header_search(start, limit, ";", strlen(";")); |
607 | if (!end) | 607 | if (!end) |
608 | end = limit; | 608 | end = limit; |
609 | 609 | ||
610 | *matchoff = start - dptr; | 610 | *matchoff = start - dptr; |
611 | *matchlen = end - start; | 611 | *matchlen = end - start; |
612 | return 1; | 612 | return 1; |
613 | } | 613 | } |
614 | 614 | ||
615 | /* Parse address from header parameter and return address, offset and length */ | 615 | /* Parse address from header parameter and return address, offset and length */ |
616 | int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, | 616 | int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr, |
617 | unsigned int dataoff, unsigned int datalen, | 617 | unsigned int dataoff, unsigned int datalen, |
618 | const char *name, | 618 | const char *name, |
619 | unsigned int *matchoff, unsigned int *matchlen, | 619 | unsigned int *matchoff, unsigned int *matchlen, |
620 | union nf_inet_addr *addr, bool delim) | 620 | union nf_inet_addr *addr, bool delim) |
621 | { | 621 | { |
622 | const char *limit = dptr + datalen; | 622 | const char *limit = dptr + datalen; |
623 | const char *start, *end; | 623 | const char *start, *end; |
624 | 624 | ||
625 | limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); | 625 | limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); |
626 | if (!limit) | 626 | if (!limit) |
627 | limit = dptr + datalen; | 627 | limit = dptr + datalen; |
628 | 628 | ||
629 | start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); | 629 | start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); |
630 | if (!start) | 630 | if (!start) |
631 | return 0; | 631 | return 0; |
632 | 632 | ||
633 | start += strlen(name); | 633 | start += strlen(name); |
634 | if (!sip_parse_addr(ct, start, &end, addr, limit, delim)) | 634 | if (!sip_parse_addr(ct, start, &end, addr, limit, delim)) |
635 | return 0; | 635 | return 0; |
636 | *matchoff = start - dptr; | 636 | *matchoff = start - dptr; |
637 | *matchlen = end - start; | 637 | *matchlen = end - start; |
638 | return 1; | 638 | return 1; |
639 | } | 639 | } |
640 | EXPORT_SYMBOL_GPL(ct_sip_parse_address_param); | 640 | EXPORT_SYMBOL_GPL(ct_sip_parse_address_param); |
641 | 641 | ||
642 | /* Parse numerical header parameter and return value, offset and length */ | 642 | /* Parse numerical header parameter and return value, offset and length */ |
643 | int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, | 643 | int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr, |
644 | unsigned int dataoff, unsigned int datalen, | 644 | unsigned int dataoff, unsigned int datalen, |
645 | const char *name, | 645 | const char *name, |
646 | unsigned int *matchoff, unsigned int *matchlen, | 646 | unsigned int *matchoff, unsigned int *matchlen, |
647 | unsigned int *val) | 647 | unsigned int *val) |
648 | { | 648 | { |
649 | const char *limit = dptr + datalen; | 649 | const char *limit = dptr + datalen; |
650 | const char *start; | 650 | const char *start; |
651 | char *end; | 651 | char *end; |
652 | 652 | ||
653 | limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); | 653 | limit = ct_sip_header_search(dptr + dataoff, limit, ",", strlen(",")); |
654 | if (!limit) | 654 | if (!limit) |
655 | limit = dptr + datalen; | 655 | limit = dptr + datalen; |
656 | 656 | ||
657 | start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); | 657 | start = ct_sip_header_search(dptr + dataoff, limit, name, strlen(name)); |
658 | if (!start) | 658 | if (!start) |
659 | return 0; | 659 | return 0; |
660 | 660 | ||
661 | start += strlen(name); | 661 | start += strlen(name); |
662 | *val = simple_strtoul(start, &end, 0); | 662 | *val = simple_strtoul(start, &end, 0); |
663 | if (start == end) | 663 | if (start == end) |
664 | return 0; | 664 | return 0; |
665 | if (matchoff && matchlen) { | 665 | if (matchoff && matchlen) { |
666 | *matchoff = start - dptr; | 666 | *matchoff = start - dptr; |
667 | *matchlen = end - start; | 667 | *matchlen = end - start; |
668 | } | 668 | } |
669 | return 1; | 669 | return 1; |
670 | } | 670 | } |
671 | EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param); | 671 | EXPORT_SYMBOL_GPL(ct_sip_parse_numerical_param); |
672 | 672 | ||
673 | static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, | 673 | static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr, |
674 | unsigned int dataoff, unsigned int datalen, | 674 | unsigned int dataoff, unsigned int datalen, |
675 | u8 *proto) | 675 | u8 *proto) |
676 | { | 676 | { |
677 | unsigned int matchoff, matchlen; | 677 | unsigned int matchoff, matchlen; |
678 | 678 | ||
679 | if (ct_sip_parse_param(ct, dptr, dataoff, datalen, "transport=", | 679 | if (ct_sip_parse_param(ct, dptr, dataoff, datalen, "transport=", |
680 | &matchoff, &matchlen)) { | 680 | &matchoff, &matchlen)) { |
681 | if (!strnicmp(dptr + matchoff, "TCP", strlen("TCP"))) | 681 | if (!strnicmp(dptr + matchoff, "TCP", strlen("TCP"))) |
682 | *proto = IPPROTO_TCP; | 682 | *proto = IPPROTO_TCP; |
683 | else if (!strnicmp(dptr + matchoff, "UDP", strlen("UDP"))) | 683 | else if (!strnicmp(dptr + matchoff, "UDP", strlen("UDP"))) |
684 | *proto = IPPROTO_UDP; | 684 | *proto = IPPROTO_UDP; |
685 | else | 685 | else |
686 | return 0; | 686 | return 0; |
687 | 687 | ||
688 | if (*proto != nf_ct_protonum(ct)) | 688 | if (*proto != nf_ct_protonum(ct)) |
689 | return 0; | 689 | return 0; |
690 | } else | 690 | } else |
691 | *proto = nf_ct_protonum(ct); | 691 | *proto = nf_ct_protonum(ct); |
692 | 692 | ||
693 | return 1; | 693 | return 1; |
694 | } | 694 | } |
695 | 695 | ||
696 | static int sdp_parse_addr(const struct nf_conn *ct, const char *cp, | 696 | static int sdp_parse_addr(const struct nf_conn *ct, const char *cp, |
697 | const char **endp, union nf_inet_addr *addr, | 697 | const char **endp, union nf_inet_addr *addr, |
698 | const char *limit) | 698 | const char *limit) |
699 | { | 699 | { |
700 | const char *end; | 700 | const char *end; |
701 | int ret; | 701 | int ret; |
702 | 702 | ||
703 | memset(addr, 0, sizeof(*addr)); | 703 | memset(addr, 0, sizeof(*addr)); |
704 | switch (nf_ct_l3num(ct)) { | 704 | switch (nf_ct_l3num(ct)) { |
705 | case AF_INET: | 705 | case AF_INET: |
706 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); | 706 | ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end); |
707 | break; | 707 | break; |
708 | case AF_INET6: | 708 | case AF_INET6: |
709 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); | 709 | ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end); |
710 | break; | 710 | break; |
711 | default: | 711 | default: |
712 | BUG(); | 712 | BUG(); |
713 | } | 713 | } |
714 | 714 | ||
715 | if (ret == 0) | 715 | if (ret == 0) |
716 | return 0; | 716 | return 0; |
717 | if (endp) | 717 | if (endp) |
718 | *endp = end; | 718 | *endp = end; |
719 | return 1; | 719 | return 1; |
720 | } | 720 | } |
721 | 721 | ||
722 | /* skip ip address. returns its length. */ | 722 | /* skip ip address. returns its length. */ |
723 | static int sdp_addr_len(const struct nf_conn *ct, const char *dptr, | 723 | static int sdp_addr_len(const struct nf_conn *ct, const char *dptr, |
724 | const char *limit, int *shift) | 724 | const char *limit, int *shift) |
725 | { | 725 | { |
726 | union nf_inet_addr addr; | 726 | union nf_inet_addr addr; |
727 | const char *aux = dptr; | 727 | const char *aux = dptr; |
728 | 728 | ||
729 | if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) { | 729 | if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) { |
730 | pr_debug("ip: %s parse failed.!\n", dptr); | 730 | pr_debug("ip: %s parse failed.!\n", dptr); |
731 | return 0; | 731 | return 0; |
732 | } | 732 | } |
733 | 733 | ||
734 | return dptr - aux; | 734 | return dptr - aux; |
735 | } | 735 | } |
736 | 736 | ||
737 | /* SDP header parsing: a SDP session description contains an ordered set of | 737 | /* SDP header parsing: a SDP session description contains an ordered set of |
738 | * headers, starting with a section containing general session parameters, | 738 | * headers, starting with a section containing general session parameters, |
739 | * optionally followed by multiple media descriptions. | 739 | * optionally followed by multiple media descriptions. |
740 | * | 740 | * |
741 | * SDP headers always start at the beginning of a line. According to RFC 2327: | 741 | * SDP headers always start at the beginning of a line. According to RFC 2327: |
742 | * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should | 742 | * "The sequence CRLF (0x0d0a) is used to end a record, although parsers should |
743 | * be tolerant and also accept records terminated with a single newline | 743 | * be tolerant and also accept records terminated with a single newline |
744 | * character". We handle both cases. | 744 | * character". We handle both cases. |
745 | */ | 745 | */ |
746 | static const struct sip_header ct_sdp_hdrs_v4[] = { | 746 | static const struct sip_header ct_sdp_hdrs_v4[] = { |
747 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), | 747 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), |
748 | [SDP_HDR_OWNER] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len), | 748 | [SDP_HDR_OWNER] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len), |
749 | [SDP_HDR_CONNECTION] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len), | 749 | [SDP_HDR_CONNECTION] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len), |
750 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), | 750 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), |
751 | }; | 751 | }; |
752 | 752 | ||
753 | static const struct sip_header ct_sdp_hdrs_v6[] = { | 753 | static const struct sip_header ct_sdp_hdrs_v6[] = { |
754 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), | 754 | [SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len), |
755 | [SDP_HDR_OWNER] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len), | 755 | [SDP_HDR_OWNER] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len), |
756 | [SDP_HDR_CONNECTION] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len), | 756 | [SDP_HDR_CONNECTION] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len), |
757 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), | 757 | [SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len), |
758 | }; | 758 | }; |
759 | 759 | ||
760 | /* Linear string search within SDP header values */ | 760 | /* Linear string search within SDP header values */ |
761 | static const char *ct_sdp_header_search(const char *dptr, const char *limit, | 761 | static const char *ct_sdp_header_search(const char *dptr, const char *limit, |
762 | const char *needle, unsigned int len) | 762 | const char *needle, unsigned int len) |
763 | { | 763 | { |
764 | for (limit -= len; dptr < limit; dptr++) { | 764 | for (limit -= len; dptr < limit; dptr++) { |
765 | if (*dptr == '\r' || *dptr == '\n') | 765 | if (*dptr == '\r' || *dptr == '\n') |
766 | break; | 766 | break; |
767 | if (strncmp(dptr, needle, len) == 0) | 767 | if (strncmp(dptr, needle, len) == 0) |
768 | return dptr; | 768 | return dptr; |
769 | } | 769 | } |
770 | return NULL; | 770 | return NULL; |
771 | } | 771 | } |
772 | 772 | ||
773 | /* Locate a SDP header (optionally a substring within the header value), | 773 | /* Locate a SDP header (optionally a substring within the header value), |
774 | * optionally stopping at the first occurrence of the term header, parse | 774 | * optionally stopping at the first occurrence of the term header, parse |
775 | * it and return the offset and length of the data we're interested in. | 775 | * it and return the offset and length of the data we're interested in. |
776 | */ | 776 | */ |
777 | int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, | 777 | int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, |
778 | unsigned int dataoff, unsigned int datalen, | 778 | unsigned int dataoff, unsigned int datalen, |
779 | enum sdp_header_types type, | 779 | enum sdp_header_types type, |
780 | enum sdp_header_types term, | 780 | enum sdp_header_types term, |
781 | unsigned int *matchoff, unsigned int *matchlen) | 781 | unsigned int *matchoff, unsigned int *matchlen) |
782 | { | 782 | { |
783 | const struct sip_header *hdrs, *hdr, *thdr; | 783 | const struct sip_header *hdrs, *hdr, *thdr; |
784 | const char *start = dptr, *limit = dptr + datalen; | 784 | const char *start = dptr, *limit = dptr + datalen; |
785 | int shift = 0; | 785 | int shift = 0; |
786 | 786 | ||
787 | hdrs = nf_ct_l3num(ct) == NFPROTO_IPV4 ? ct_sdp_hdrs_v4 : ct_sdp_hdrs_v6; | 787 | hdrs = nf_ct_l3num(ct) == NFPROTO_IPV4 ? ct_sdp_hdrs_v4 : ct_sdp_hdrs_v6; |
788 | hdr = &hdrs[type]; | 788 | hdr = &hdrs[type]; |
789 | thdr = &hdrs[term]; | 789 | thdr = &hdrs[term]; |
790 | 790 | ||
791 | for (dptr += dataoff; dptr < limit; dptr++) { | 791 | for (dptr += dataoff; dptr < limit; dptr++) { |
792 | /* Find beginning of line */ | 792 | /* Find beginning of line */ |
793 | if (*dptr != '\r' && *dptr != '\n') | 793 | if (*dptr != '\r' && *dptr != '\n') |
794 | continue; | 794 | continue; |
795 | if (++dptr >= limit) | 795 | if (++dptr >= limit) |
796 | break; | 796 | break; |
797 | if (*(dptr - 1) == '\r' && *dptr == '\n') { | 797 | if (*(dptr - 1) == '\r' && *dptr == '\n') { |
798 | if (++dptr >= limit) | 798 | if (++dptr >= limit) |
799 | break; | 799 | break; |
800 | } | 800 | } |
801 | 801 | ||
802 | if (term != SDP_HDR_UNSPEC && | 802 | if (term != SDP_HDR_UNSPEC && |
803 | limit - dptr >= thdr->len && | 803 | limit - dptr >= thdr->len && |
804 | strnicmp(dptr, thdr->name, thdr->len) == 0) | 804 | strnicmp(dptr, thdr->name, thdr->len) == 0) |
805 | break; | 805 | break; |
806 | else if (limit - dptr >= hdr->len && | 806 | else if (limit - dptr >= hdr->len && |
807 | strnicmp(dptr, hdr->name, hdr->len) == 0) | 807 | strnicmp(dptr, hdr->name, hdr->len) == 0) |
808 | dptr += hdr->len; | 808 | dptr += hdr->len; |
809 | else | 809 | else |
810 | continue; | 810 | continue; |
811 | 811 | ||
812 | *matchoff = dptr - start; | 812 | *matchoff = dptr - start; |
813 | if (hdr->search) { | 813 | if (hdr->search) { |
814 | dptr = ct_sdp_header_search(dptr, limit, hdr->search, | 814 | dptr = ct_sdp_header_search(dptr, limit, hdr->search, |
815 | hdr->slen); | 815 | hdr->slen); |
816 | if (!dptr) | 816 | if (!dptr) |
817 | return -1; | 817 | return -1; |
818 | dptr += hdr->slen; | 818 | dptr += hdr->slen; |
819 | } | 819 | } |
820 | 820 | ||
821 | *matchlen = hdr->match_len(ct, dptr, limit, &shift); | 821 | *matchlen = hdr->match_len(ct, dptr, limit, &shift); |
822 | if (!*matchlen) | 822 | if (!*matchlen) |
823 | return -1; | 823 | return -1; |
824 | *matchoff = dptr - start + shift; | 824 | *matchoff = dptr - start + shift; |
825 | return 1; | 825 | return 1; |
826 | } | 826 | } |
827 | return 0; | 827 | return 0; |
828 | } | 828 | } |
829 | EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); | 829 | EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); |
830 | 830 | ||
831 | static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, | 831 | static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, |
832 | unsigned int dataoff, unsigned int datalen, | 832 | unsigned int dataoff, unsigned int datalen, |
833 | enum sdp_header_types type, | 833 | enum sdp_header_types type, |
834 | enum sdp_header_types term, | 834 | enum sdp_header_types term, |
835 | unsigned int *matchoff, unsigned int *matchlen, | 835 | unsigned int *matchoff, unsigned int *matchlen, |
836 | union nf_inet_addr *addr) | 836 | union nf_inet_addr *addr) |
837 | { | 837 | { |
838 | int ret; | 838 | int ret; |
839 | 839 | ||
840 | ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term, | 840 | ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term, |
841 | matchoff, matchlen); | 841 | matchoff, matchlen); |
842 | if (ret <= 0) | 842 | if (ret <= 0) |
843 | return ret; | 843 | return ret; |
844 | 844 | ||
845 | if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr, | 845 | if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr, |
846 | dptr + *matchoff + *matchlen)) | 846 | dptr + *matchoff + *matchlen)) |
847 | return -1; | 847 | return -1; |
848 | return 1; | 848 | return 1; |
849 | } | 849 | } |
850 | 850 | ||
851 | static int refresh_signalling_expectation(struct nf_conn *ct, | 851 | static int refresh_signalling_expectation(struct nf_conn *ct, |
852 | union nf_inet_addr *addr, | 852 | union nf_inet_addr *addr, |
853 | u8 proto, __be16 port, | 853 | u8 proto, __be16 port, |
854 | unsigned int expires) | 854 | unsigned int expires) |
855 | { | 855 | { |
856 | struct nf_conn_help *help = nfct_help(ct); | 856 | struct nf_conn_help *help = nfct_help(ct); |
857 | struct nf_conntrack_expect *exp; | 857 | struct nf_conntrack_expect *exp; |
858 | struct hlist_node *n, *next; | 858 | struct hlist_node *n, *next; |
859 | int found = 0; | 859 | int found = 0; |
860 | 860 | ||
861 | spin_lock_bh(&nf_conntrack_lock); | 861 | spin_lock_bh(&nf_conntrack_lock); |
862 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { | 862 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { |
863 | if (exp->class != SIP_EXPECT_SIGNALLING || | 863 | if (exp->class != SIP_EXPECT_SIGNALLING || |
864 | !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || | 864 | !nf_inet_addr_cmp(&exp->tuple.dst.u3, addr) || |
865 | exp->tuple.dst.protonum != proto || | 865 | exp->tuple.dst.protonum != proto || |
866 | exp->tuple.dst.u.udp.port != port) | 866 | exp->tuple.dst.u.udp.port != port) |
867 | continue; | 867 | continue; |
868 | if (!del_timer(&exp->timeout)) | 868 | if (!del_timer(&exp->timeout)) |
869 | continue; | 869 | continue; |
870 | exp->flags &= ~NF_CT_EXPECT_INACTIVE; | 870 | exp->flags &= ~NF_CT_EXPECT_INACTIVE; |
871 | exp->timeout.expires = jiffies + expires * HZ; | 871 | exp->timeout.expires = jiffies + expires * HZ; |
872 | add_timer(&exp->timeout); | 872 | add_timer(&exp->timeout); |
873 | found = 1; | 873 | found = 1; |
874 | break; | 874 | break; |
875 | } | 875 | } |
876 | spin_unlock_bh(&nf_conntrack_lock); | 876 | spin_unlock_bh(&nf_conntrack_lock); |
877 | return found; | 877 | return found; |
878 | } | 878 | } |
879 | 879 | ||
880 | static void flush_expectations(struct nf_conn *ct, bool media) | 880 | static void flush_expectations(struct nf_conn *ct, bool media) |
881 | { | 881 | { |
882 | struct nf_conn_help *help = nfct_help(ct); | 882 | struct nf_conn_help *help = nfct_help(ct); |
883 | struct nf_conntrack_expect *exp; | 883 | struct nf_conntrack_expect *exp; |
884 | struct hlist_node *n, *next; | 884 | struct hlist_node *n, *next; |
885 | 885 | ||
886 | spin_lock_bh(&nf_conntrack_lock); | 886 | spin_lock_bh(&nf_conntrack_lock); |
887 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { | 887 | hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) { |
888 | if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) | 888 | if ((exp->class != SIP_EXPECT_SIGNALLING) ^ media) |
889 | continue; | 889 | continue; |
890 | if (!del_timer(&exp->timeout)) | 890 | if (!del_timer(&exp->timeout)) |
891 | continue; | 891 | continue; |
892 | nf_ct_unlink_expect(exp); | 892 | nf_ct_unlink_expect(exp); |
893 | nf_ct_expect_put(exp); | 893 | nf_ct_expect_put(exp); |
894 | if (!media) | 894 | if (!media) |
895 | break; | 895 | break; |
896 | } | 896 | } |
897 | spin_unlock_bh(&nf_conntrack_lock); | 897 | spin_unlock_bh(&nf_conntrack_lock); |
898 | } | 898 | } |
899 | 899 | ||
900 | static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, | 900 | static int set_expected_rtp_rtcp(struct sk_buff *skb, unsigned int protoff, |
901 | unsigned int dataoff, | 901 | unsigned int dataoff, |
902 | const char **dptr, unsigned int *datalen, | 902 | const char **dptr, unsigned int *datalen, |
903 | union nf_inet_addr *daddr, __be16 port, | 903 | union nf_inet_addr *daddr, __be16 port, |
904 | enum sip_expectation_classes class, | 904 | enum sip_expectation_classes class, |
905 | unsigned int mediaoff, unsigned int medialen) | 905 | unsigned int mediaoff, unsigned int medialen) |
906 | { | 906 | { |
907 | struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; | 907 | struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; |
908 | enum ip_conntrack_info ctinfo; | 908 | enum ip_conntrack_info ctinfo; |
909 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 909 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
910 | struct net *net = nf_ct_net(ct); | 910 | struct net *net = nf_ct_net(ct); |
911 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 911 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
912 | union nf_inet_addr *saddr; | 912 | union nf_inet_addr *saddr; |
913 | struct nf_conntrack_tuple tuple; | 913 | struct nf_conntrack_tuple tuple; |
914 | int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; | 914 | int direct_rtp = 0, skip_expect = 0, ret = NF_DROP; |
915 | u_int16_t base_port; | 915 | u_int16_t base_port; |
916 | __be16 rtp_port, rtcp_port; | 916 | __be16 rtp_port, rtcp_port; |
917 | typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port; | 917 | typeof(nf_nat_sdp_port_hook) nf_nat_sdp_port; |
918 | typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; | 918 | typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; |
919 | 919 | ||
920 | saddr = NULL; | 920 | saddr = NULL; |
921 | if (sip_direct_media) { | 921 | if (sip_direct_media) { |
922 | if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3)) | 922 | if (!nf_inet_addr_cmp(daddr, &ct->tuplehash[dir].tuple.src.u3)) |
923 | return NF_ACCEPT; | 923 | return NF_ACCEPT; |
924 | saddr = &ct->tuplehash[!dir].tuple.src.u3; | 924 | saddr = &ct->tuplehash[!dir].tuple.src.u3; |
925 | } | 925 | } |
926 | 926 | ||
927 | /* We need to check whether the registration exists before attempting | 927 | /* We need to check whether the registration exists before attempting |
928 | * to register it since we can see the same media description multiple | 928 | * to register it since we can see the same media description multiple |
929 | * times on different connections in case multiple endpoints receive | 929 | * times on different connections in case multiple endpoints receive |
930 | * the same call. | 930 | * the same call. |
931 | * | 931 | * |
932 | * RTP optimization: if we find a matching media channel expectation | 932 | * RTP optimization: if we find a matching media channel expectation |
933 | * and both the expectation and this connection are SNATed, we assume | 933 | * and both the expectation and this connection are SNATed, we assume |
934 | * both sides can reach each other directly and use the final | 934 | * both sides can reach each other directly and use the final |
935 | * destination address from the expectation. We still need to keep | 935 | * destination address from the expectation. We still need to keep |
936 | * the NATed expectations for media that might arrive from the | 936 | * the NATed expectations for media that might arrive from the |
937 | * outside, and additionally need to expect the direct RTP stream | 937 | * outside, and additionally need to expect the direct RTP stream |
938 | * in case it passes through us even without NAT. | 938 | * in case it passes through us even without NAT. |
939 | */ | 939 | */ |
940 | memset(&tuple, 0, sizeof(tuple)); | 940 | memset(&tuple, 0, sizeof(tuple)); |
941 | if (saddr) | 941 | if (saddr) |
942 | tuple.src.u3 = *saddr; | 942 | tuple.src.u3 = *saddr; |
943 | tuple.src.l3num = nf_ct_l3num(ct); | 943 | tuple.src.l3num = nf_ct_l3num(ct); |
944 | tuple.dst.protonum = IPPROTO_UDP; | 944 | tuple.dst.protonum = IPPROTO_UDP; |
945 | tuple.dst.u3 = *daddr; | 945 | tuple.dst.u3 = *daddr; |
946 | tuple.dst.u.udp.port = port; | 946 | tuple.dst.u.udp.port = port; |
947 | 947 | ||
948 | rcu_read_lock(); | 948 | rcu_read_lock(); |
949 | do { | 949 | do { |
950 | exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); | 950 | exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple); |
951 | 951 | ||
952 | if (!exp || exp->master == ct || | 952 | if (!exp || exp->master == ct || |
953 | nfct_help(exp->master)->helper != nfct_help(ct)->helper || | 953 | nfct_help(exp->master)->helper != nfct_help(ct)->helper || |
954 | exp->class != class) | 954 | exp->class != class) |
955 | break; | 955 | break; |
956 | #ifdef CONFIG_NF_NAT_NEEDED | 956 | #ifdef CONFIG_NF_NAT_NEEDED |
957 | if (!direct_rtp && | 957 | if (!direct_rtp && |
958 | (!nf_inet_addr_cmp(&exp->saved_addr, &exp->tuple.dst.u3) || | 958 | (!nf_inet_addr_cmp(&exp->saved_addr, &exp->tuple.dst.u3) || |
959 | exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) && | 959 | exp->saved_proto.udp.port != exp->tuple.dst.u.udp.port) && |
960 | ct->status & IPS_NAT_MASK) { | 960 | ct->status & IPS_NAT_MASK) { |
961 | *daddr = exp->saved_addr; | 961 | *daddr = exp->saved_addr; |
962 | tuple.dst.u3 = exp->saved_addr; | 962 | tuple.dst.u3 = exp->saved_addr; |
963 | tuple.dst.u.udp.port = exp->saved_proto.udp.port; | 963 | tuple.dst.u.udp.port = exp->saved_proto.udp.port; |
964 | direct_rtp = 1; | 964 | direct_rtp = 1; |
965 | } else | 965 | } else |
966 | #endif | 966 | #endif |
967 | skip_expect = 1; | 967 | skip_expect = 1; |
968 | } while (!skip_expect); | 968 | } while (!skip_expect); |
969 | rcu_read_unlock(); | 969 | rcu_read_unlock(); |
970 | 970 | ||
971 | base_port = ntohs(tuple.dst.u.udp.port) & ~1; | 971 | base_port = ntohs(tuple.dst.u.udp.port) & ~1; |
972 | rtp_port = htons(base_port); | 972 | rtp_port = htons(base_port); |
973 | rtcp_port = htons(base_port + 1); | 973 | rtcp_port = htons(base_port + 1); |
974 | 974 | ||
975 | if (direct_rtp) { | 975 | if (direct_rtp) { |
976 | nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook); | 976 | nf_nat_sdp_port = rcu_dereference(nf_nat_sdp_port_hook); |
977 | if (nf_nat_sdp_port && | 977 | if (nf_nat_sdp_port && |
978 | !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen, | 978 | !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen, |
979 | mediaoff, medialen, ntohs(rtp_port))) | 979 | mediaoff, medialen, ntohs(rtp_port))) |
980 | goto err1; | 980 | goto err1; |
981 | } | 981 | } |
982 | 982 | ||
983 | if (skip_expect) | 983 | if (skip_expect) |
984 | return NF_ACCEPT; | 984 | return NF_ACCEPT; |
985 | 985 | ||
986 | rtp_exp = nf_ct_expect_alloc(ct); | 986 | rtp_exp = nf_ct_expect_alloc(ct); |
987 | if (rtp_exp == NULL) | 987 | if (rtp_exp == NULL) |
988 | goto err1; | 988 | goto err1; |
989 | nf_ct_expect_init(rtp_exp, class, nf_ct_l3num(ct), saddr, daddr, | 989 | nf_ct_expect_init(rtp_exp, class, nf_ct_l3num(ct), saddr, daddr, |
990 | IPPROTO_UDP, NULL, &rtp_port); | 990 | IPPROTO_UDP, NULL, &rtp_port); |
991 | 991 | ||
992 | rtcp_exp = nf_ct_expect_alloc(ct); | 992 | rtcp_exp = nf_ct_expect_alloc(ct); |
993 | if (rtcp_exp == NULL) | 993 | if (rtcp_exp == NULL) |
994 | goto err2; | 994 | goto err2; |
995 | nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr, | 995 | nf_ct_expect_init(rtcp_exp, class, nf_ct_l3num(ct), saddr, daddr, |
996 | IPPROTO_UDP, NULL, &rtcp_port); | 996 | IPPROTO_UDP, NULL, &rtcp_port); |
997 | 997 | ||
998 | nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); | 998 | nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); |
999 | if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp) | 999 | if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK && !direct_rtp) |
1000 | ret = nf_nat_sdp_media(skb, protoff, dataoff, dptr, datalen, | 1000 | ret = nf_nat_sdp_media(skb, protoff, dataoff, dptr, datalen, |
1001 | rtp_exp, rtcp_exp, | 1001 | rtp_exp, rtcp_exp, |
1002 | mediaoff, medialen, daddr); | 1002 | mediaoff, medialen, daddr); |
1003 | else { | 1003 | else { |
1004 | if (nf_ct_expect_related(rtp_exp) == 0) { | 1004 | if (nf_ct_expect_related(rtp_exp) == 0) { |
1005 | if (nf_ct_expect_related(rtcp_exp) != 0) | 1005 | if (nf_ct_expect_related(rtcp_exp) != 0) |
1006 | nf_ct_unexpect_related(rtp_exp); | 1006 | nf_ct_unexpect_related(rtp_exp); |
1007 | else | 1007 | else |
1008 | ret = NF_ACCEPT; | 1008 | ret = NF_ACCEPT; |
1009 | } | 1009 | } |
1010 | } | 1010 | } |
1011 | nf_ct_expect_put(rtcp_exp); | 1011 | nf_ct_expect_put(rtcp_exp); |
1012 | err2: | 1012 | err2: |
1013 | nf_ct_expect_put(rtp_exp); | 1013 | nf_ct_expect_put(rtp_exp); |
1014 | err1: | 1014 | err1: |
1015 | return ret; | 1015 | return ret; |
1016 | } | 1016 | } |
1017 | 1017 | ||
1018 | static const struct sdp_media_type sdp_media_types[] = { | 1018 | static const struct sdp_media_type sdp_media_types[] = { |
1019 | SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO), | 1019 | SDP_MEDIA_TYPE("audio ", SIP_EXPECT_AUDIO), |
1020 | SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO), | 1020 | SDP_MEDIA_TYPE("video ", SIP_EXPECT_VIDEO), |
1021 | SDP_MEDIA_TYPE("image ", SIP_EXPECT_IMAGE), | 1021 | SDP_MEDIA_TYPE("image ", SIP_EXPECT_IMAGE), |
1022 | }; | 1022 | }; |
1023 | 1023 | ||
1024 | static const struct sdp_media_type *sdp_media_type(const char *dptr, | 1024 | static const struct sdp_media_type *sdp_media_type(const char *dptr, |
1025 | unsigned int matchoff, | 1025 | unsigned int matchoff, |
1026 | unsigned int matchlen) | 1026 | unsigned int matchlen) |
1027 | { | 1027 | { |
1028 | const struct sdp_media_type *t; | 1028 | const struct sdp_media_type *t; |
1029 | unsigned int i; | 1029 | unsigned int i; |
1030 | 1030 | ||
1031 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) { | 1031 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); i++) { |
1032 | t = &sdp_media_types[i]; | 1032 | t = &sdp_media_types[i]; |
1033 | if (matchlen < t->len || | 1033 | if (matchlen < t->len || |
1034 | strncmp(dptr + matchoff, t->name, t->len)) | 1034 | strncmp(dptr + matchoff, t->name, t->len)) |
1035 | continue; | 1035 | continue; |
1036 | return t; | 1036 | return t; |
1037 | } | 1037 | } |
1038 | return NULL; | 1038 | return NULL; |
1039 | } | 1039 | } |
1040 | 1040 | ||
1041 | static int process_sdp(struct sk_buff *skb, unsigned int protoff, | 1041 | static int process_sdp(struct sk_buff *skb, unsigned int protoff, |
1042 | unsigned int dataoff, | 1042 | unsigned int dataoff, |
1043 | const char **dptr, unsigned int *datalen, | 1043 | const char **dptr, unsigned int *datalen, |
1044 | unsigned int cseq) | 1044 | unsigned int cseq) |
1045 | { | 1045 | { |
1046 | enum ip_conntrack_info ctinfo; | 1046 | enum ip_conntrack_info ctinfo; |
1047 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1047 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1048 | unsigned int matchoff, matchlen; | 1048 | unsigned int matchoff, matchlen; |
1049 | unsigned int mediaoff, medialen; | 1049 | unsigned int mediaoff, medialen; |
1050 | unsigned int sdpoff; | 1050 | unsigned int sdpoff; |
1051 | unsigned int caddr_len, maddr_len; | 1051 | unsigned int caddr_len, maddr_len; |
1052 | unsigned int i; | 1052 | unsigned int i; |
1053 | union nf_inet_addr caddr, maddr, rtp_addr; | 1053 | union nf_inet_addr caddr, maddr, rtp_addr; |
1054 | unsigned int port; | 1054 | unsigned int port; |
1055 | const struct sdp_media_type *t; | 1055 | const struct sdp_media_type *t; |
1056 | int ret = NF_ACCEPT; | 1056 | int ret = NF_ACCEPT; |
1057 | typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; | 1057 | typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; |
1058 | typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; | 1058 | typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; |
1059 | 1059 | ||
1060 | nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); | 1060 | nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); |
1061 | 1061 | ||
1062 | /* Find beginning of session description */ | 1062 | /* Find beginning of session description */ |
1063 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | 1063 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, |
1064 | SDP_HDR_VERSION, SDP_HDR_UNSPEC, | 1064 | SDP_HDR_VERSION, SDP_HDR_UNSPEC, |
1065 | &matchoff, &matchlen) <= 0) | 1065 | &matchoff, &matchlen) <= 0) |
1066 | return NF_ACCEPT; | 1066 | return NF_ACCEPT; |
1067 | sdpoff = matchoff; | 1067 | sdpoff = matchoff; |
1068 | 1068 | ||
1069 | /* The connection information is contained in the session description | 1069 | /* The connection information is contained in the session description |
1070 | * and/or once per media description. The first media description marks | 1070 | * and/or once per media description. The first media description marks |
1071 | * the end of the session description. */ | 1071 | * the end of the session description. */ |
1072 | caddr_len = 0; | 1072 | caddr_len = 0; |
1073 | if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen, | 1073 | if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen, |
1074 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, | 1074 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, |
1075 | &matchoff, &matchlen, &caddr) > 0) | 1075 | &matchoff, &matchlen, &caddr) > 0) |
1076 | caddr_len = matchlen; | 1076 | caddr_len = matchlen; |
1077 | 1077 | ||
1078 | mediaoff = sdpoff; | 1078 | mediaoff = sdpoff; |
1079 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { | 1079 | for (i = 0; i < ARRAY_SIZE(sdp_media_types); ) { |
1080 | if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, | 1080 | if (ct_sip_get_sdp_header(ct, *dptr, mediaoff, *datalen, |
1081 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, | 1081 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, |
1082 | &mediaoff, &medialen) <= 0) | 1082 | &mediaoff, &medialen) <= 0) |
1083 | break; | 1083 | break; |
1084 | 1084 | ||
1085 | /* Get media type and port number. A media port value of zero | 1085 | /* Get media type and port number. A media port value of zero |
1086 | * indicates an inactive stream. */ | 1086 | * indicates an inactive stream. */ |
1087 | t = sdp_media_type(*dptr, mediaoff, medialen); | 1087 | t = sdp_media_type(*dptr, mediaoff, medialen); |
1088 | if (!t) { | 1088 | if (!t) { |
1089 | mediaoff += medialen; | 1089 | mediaoff += medialen; |
1090 | continue; | 1090 | continue; |
1091 | } | 1091 | } |
1092 | mediaoff += t->len; | 1092 | mediaoff += t->len; |
1093 | medialen -= t->len; | 1093 | medialen -= t->len; |
1094 | 1094 | ||
1095 | port = simple_strtoul(*dptr + mediaoff, NULL, 10); | 1095 | port = simple_strtoul(*dptr + mediaoff, NULL, 10); |
1096 | if (port == 0) | 1096 | if (port == 0) |
1097 | continue; | 1097 | continue; |
1098 | if (port < 1024 || port > 65535) | 1098 | if (port < 1024 || port > 65535) |
1099 | return NF_DROP; | 1099 | return NF_DROP; |
1100 | 1100 | ||
1101 | /* The media description overrides the session description. */ | 1101 | /* The media description overrides the session description. */ |
1102 | maddr_len = 0; | 1102 | maddr_len = 0; |
1103 | if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, | 1103 | if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, |
1104 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, | 1104 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, |
1105 | &matchoff, &matchlen, &maddr) > 0) { | 1105 | &matchoff, &matchlen, &maddr) > 0) { |
1106 | maddr_len = matchlen; | 1106 | maddr_len = matchlen; |
1107 | memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); | 1107 | memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); |
1108 | } else if (caddr_len) | 1108 | } else if (caddr_len) |
1109 | memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); | 1109 | memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); |
1110 | else | 1110 | else |
1111 | return NF_DROP; | 1111 | return NF_DROP; |
1112 | 1112 | ||
1113 | ret = set_expected_rtp_rtcp(skb, protoff, dataoff, | 1113 | ret = set_expected_rtp_rtcp(skb, protoff, dataoff, |
1114 | dptr, datalen, | 1114 | dptr, datalen, |
1115 | &rtp_addr, htons(port), t->class, | 1115 | &rtp_addr, htons(port), t->class, |
1116 | mediaoff, medialen); | 1116 | mediaoff, medialen); |
1117 | if (ret != NF_ACCEPT) | 1117 | if (ret != NF_ACCEPT) |
1118 | return ret; | 1118 | return ret; |
1119 | 1119 | ||
1120 | /* Update media connection address if present */ | 1120 | /* Update media connection address if present */ |
1121 | if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { | 1121 | if (maddr_len && nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { |
1122 | ret = nf_nat_sdp_addr(skb, protoff, dataoff, | 1122 | ret = nf_nat_sdp_addr(skb, protoff, dataoff, |
1123 | dptr, datalen, mediaoff, | 1123 | dptr, datalen, mediaoff, |
1124 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, | 1124 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, |
1125 | &rtp_addr); | 1125 | &rtp_addr); |
1126 | if (ret != NF_ACCEPT) | 1126 | if (ret != NF_ACCEPT) |
1127 | return ret; | 1127 | return ret; |
1128 | } | 1128 | } |
1129 | i++; | 1129 | i++; |
1130 | } | 1130 | } |
1131 | 1131 | ||
1132 | /* Update session connection and owner addresses */ | 1132 | /* Update session connection and owner addresses */ |
1133 | nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); | 1133 | nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); |
1134 | if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) | 1134 | if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) |
1135 | ret = nf_nat_sdp_session(skb, protoff, dataoff, | 1135 | ret = nf_nat_sdp_session(skb, protoff, dataoff, |
1136 | dptr, datalen, sdpoff, &rtp_addr); | 1136 | dptr, datalen, sdpoff, &rtp_addr); |
1137 | 1137 | ||
1138 | return ret; | 1138 | return ret; |
1139 | } | 1139 | } |
1140 | static int process_invite_response(struct sk_buff *skb, unsigned int protoff, | 1140 | static int process_invite_response(struct sk_buff *skb, unsigned int protoff, |
1141 | unsigned int dataoff, | 1141 | unsigned int dataoff, |
1142 | const char **dptr, unsigned int *datalen, | 1142 | const char **dptr, unsigned int *datalen, |
1143 | unsigned int cseq, unsigned int code) | 1143 | unsigned int cseq, unsigned int code) |
1144 | { | 1144 | { |
1145 | enum ip_conntrack_info ctinfo; | 1145 | enum ip_conntrack_info ctinfo; |
1146 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1146 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1147 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | 1147 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
1148 | 1148 | ||
1149 | if ((code >= 100 && code <= 199) || | 1149 | if ((code >= 100 && code <= 199) || |
1150 | (code >= 200 && code <= 299)) | 1150 | (code >= 200 && code <= 299)) |
1151 | return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); | 1151 | return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); |
1152 | else if (ct_sip_info->invite_cseq == cseq) | 1152 | else if (ct_sip_info->invite_cseq == cseq) |
1153 | flush_expectations(ct, true); | 1153 | flush_expectations(ct, true); |
1154 | return NF_ACCEPT; | 1154 | return NF_ACCEPT; |
1155 | } | 1155 | } |
1156 | 1156 | ||
1157 | static int process_update_response(struct sk_buff *skb, unsigned int protoff, | 1157 | static int process_update_response(struct sk_buff *skb, unsigned int protoff, |
1158 | unsigned int dataoff, | 1158 | unsigned int dataoff, |
1159 | const char **dptr, unsigned int *datalen, | 1159 | const char **dptr, unsigned int *datalen, |
1160 | unsigned int cseq, unsigned int code) | 1160 | unsigned int cseq, unsigned int code) |
1161 | { | 1161 | { |
1162 | enum ip_conntrack_info ctinfo; | 1162 | enum ip_conntrack_info ctinfo; |
1163 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1163 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1164 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | 1164 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
1165 | 1165 | ||
1166 | if ((code >= 100 && code <= 199) || | 1166 | if ((code >= 100 && code <= 199) || |
1167 | (code >= 200 && code <= 299)) | 1167 | (code >= 200 && code <= 299)) |
1168 | return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); | 1168 | return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); |
1169 | else if (ct_sip_info->invite_cseq == cseq) | 1169 | else if (ct_sip_info->invite_cseq == cseq) |
1170 | flush_expectations(ct, true); | 1170 | flush_expectations(ct, true); |
1171 | return NF_ACCEPT; | 1171 | return NF_ACCEPT; |
1172 | } | 1172 | } |
1173 | 1173 | ||
1174 | static int process_prack_response(struct sk_buff *skb, unsigned int protoff, | 1174 | static int process_prack_response(struct sk_buff *skb, unsigned int protoff, |
1175 | unsigned int dataoff, | 1175 | unsigned int dataoff, |
1176 | const char **dptr, unsigned int *datalen, | 1176 | const char **dptr, unsigned int *datalen, |
1177 | unsigned int cseq, unsigned int code) | 1177 | unsigned int cseq, unsigned int code) |
1178 | { | 1178 | { |
1179 | enum ip_conntrack_info ctinfo; | 1179 | enum ip_conntrack_info ctinfo; |
1180 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1180 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1181 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | 1181 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
1182 | 1182 | ||
1183 | if ((code >= 100 && code <= 199) || | 1183 | if ((code >= 100 && code <= 199) || |
1184 | (code >= 200 && code <= 299)) | 1184 | (code >= 200 && code <= 299)) |
1185 | return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); | 1185 | return process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); |
1186 | else if (ct_sip_info->invite_cseq == cseq) | 1186 | else if (ct_sip_info->invite_cseq == cseq) |
1187 | flush_expectations(ct, true); | 1187 | flush_expectations(ct, true); |
1188 | return NF_ACCEPT; | 1188 | return NF_ACCEPT; |
1189 | } | 1189 | } |
1190 | 1190 | ||
1191 | static int process_invite_request(struct sk_buff *skb, unsigned int protoff, | 1191 | static int process_invite_request(struct sk_buff *skb, unsigned int protoff, |
1192 | unsigned int dataoff, | 1192 | unsigned int dataoff, |
1193 | const char **dptr, unsigned int *datalen, | 1193 | const char **dptr, unsigned int *datalen, |
1194 | unsigned int cseq) | 1194 | unsigned int cseq) |
1195 | { | 1195 | { |
1196 | enum ip_conntrack_info ctinfo; | 1196 | enum ip_conntrack_info ctinfo; |
1197 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1197 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1198 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | 1198 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
1199 | unsigned int ret; | 1199 | unsigned int ret; |
1200 | 1200 | ||
1201 | flush_expectations(ct, true); | 1201 | flush_expectations(ct, true); |
1202 | ret = process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); | 1202 | ret = process_sdp(skb, protoff, dataoff, dptr, datalen, cseq); |
1203 | if (ret == NF_ACCEPT) | 1203 | if (ret == NF_ACCEPT) |
1204 | ct_sip_info->invite_cseq = cseq; | 1204 | ct_sip_info->invite_cseq = cseq; |
1205 | return ret; | 1205 | return ret; |
1206 | } | 1206 | } |
1207 | 1207 | ||
1208 | static int process_bye_request(struct sk_buff *skb, unsigned int protoff, | 1208 | static int process_bye_request(struct sk_buff *skb, unsigned int protoff, |
1209 | unsigned int dataoff, | 1209 | unsigned int dataoff, |
1210 | const char **dptr, unsigned int *datalen, | 1210 | const char **dptr, unsigned int *datalen, |
1211 | unsigned int cseq) | 1211 | unsigned int cseq) |
1212 | { | 1212 | { |
1213 | enum ip_conntrack_info ctinfo; | 1213 | enum ip_conntrack_info ctinfo; |
1214 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1214 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1215 | 1215 | ||
1216 | flush_expectations(ct, true); | 1216 | flush_expectations(ct, true); |
1217 | return NF_ACCEPT; | 1217 | return NF_ACCEPT; |
1218 | } | 1218 | } |
1219 | 1219 | ||
1220 | /* Parse a REGISTER request and create a permanent expectation for incoming | 1220 | /* Parse a REGISTER request and create a permanent expectation for incoming |
1221 | * signalling connections. The expectation is marked inactive and is activated | 1221 | * signalling connections. The expectation is marked inactive and is activated |
1222 | * when receiving a response indicating success from the registrar. | 1222 | * when receiving a response indicating success from the registrar. |
1223 | */ | 1223 | */ |
1224 | static int process_register_request(struct sk_buff *skb, unsigned int protoff, | 1224 | static int process_register_request(struct sk_buff *skb, unsigned int protoff, |
1225 | unsigned int dataoff, | 1225 | unsigned int dataoff, |
1226 | const char **dptr, unsigned int *datalen, | 1226 | const char **dptr, unsigned int *datalen, |
1227 | unsigned int cseq) | 1227 | unsigned int cseq) |
1228 | { | 1228 | { |
1229 | enum ip_conntrack_info ctinfo; | 1229 | enum ip_conntrack_info ctinfo; |
1230 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1230 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1231 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | 1231 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
1232 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 1232 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
1233 | unsigned int matchoff, matchlen; | 1233 | unsigned int matchoff, matchlen; |
1234 | struct nf_conntrack_expect *exp; | 1234 | struct nf_conntrack_expect *exp; |
1235 | union nf_inet_addr *saddr, daddr; | 1235 | union nf_inet_addr *saddr, daddr; |
1236 | __be16 port; | 1236 | __be16 port; |
1237 | u8 proto; | 1237 | u8 proto; |
1238 | unsigned int expires = 0; | 1238 | unsigned int expires = 0; |
1239 | int ret; | 1239 | int ret; |
1240 | typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; | 1240 | typeof(nf_nat_sip_expect_hook) nf_nat_sip_expect; |
1241 | 1241 | ||
1242 | /* Expected connections can not register again. */ | 1242 | /* Expected connections can not register again. */ |
1243 | if (ct->status & IPS_EXPECTED) | 1243 | if (ct->status & IPS_EXPECTED) |
1244 | return NF_ACCEPT; | 1244 | return NF_ACCEPT; |
1245 | 1245 | ||
1246 | /* We must check the expiration time: a value of zero signals the | 1246 | /* We must check the expiration time: a value of zero signals the |
1247 | * registrar to release the binding. We'll remove our expectation | 1247 | * registrar to release the binding. We'll remove our expectation |
1248 | * when receiving the new bindings in the response, but we don't | 1248 | * when receiving the new bindings in the response, but we don't |
1249 | * want to create new ones. | 1249 | * want to create new ones. |
1250 | * | 1250 | * |
1251 | * The expiration time may be contained in Expires: header, the | 1251 | * The expiration time may be contained in Expires: header, the |
1252 | * Contact: header parameters or the URI parameters. | 1252 | * Contact: header parameters or the URI parameters. |
1253 | */ | 1253 | */ |
1254 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, | 1254 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, |
1255 | &matchoff, &matchlen) > 0) | 1255 | &matchoff, &matchlen) > 0) |
1256 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); | 1256 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); |
1257 | 1257 | ||
1258 | ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | 1258 | ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
1259 | SIP_HDR_CONTACT, NULL, | 1259 | SIP_HDR_CONTACT, NULL, |
1260 | &matchoff, &matchlen, &daddr, &port); | 1260 | &matchoff, &matchlen, &daddr, &port); |
1261 | if (ret < 0) | 1261 | if (ret < 0) |
1262 | return NF_DROP; | 1262 | return NF_DROP; |
1263 | else if (ret == 0) | 1263 | else if (ret == 0) |
1264 | return NF_ACCEPT; | 1264 | return NF_ACCEPT; |
1265 | 1265 | ||
1266 | /* We don't support third-party registrations */ | 1266 | /* We don't support third-party registrations */ |
1267 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) | 1267 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, &daddr)) |
1268 | return NF_ACCEPT; | 1268 | return NF_ACCEPT; |
1269 | 1269 | ||
1270 | if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, *datalen, | 1270 | if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, *datalen, |
1271 | &proto) == 0) | 1271 | &proto) == 0) |
1272 | return NF_ACCEPT; | 1272 | return NF_ACCEPT; |
1273 | 1273 | ||
1274 | if (ct_sip_parse_numerical_param(ct, *dptr, | 1274 | if (ct_sip_parse_numerical_param(ct, *dptr, |
1275 | matchoff + matchlen, *datalen, | 1275 | matchoff + matchlen, *datalen, |
1276 | "expires=", NULL, NULL, &expires) < 0) | 1276 | "expires=", NULL, NULL, &expires) < 0) |
1277 | return NF_DROP; | 1277 | return NF_DROP; |
1278 | 1278 | ||
1279 | if (expires == 0) { | 1279 | if (expires == 0) { |
1280 | ret = NF_ACCEPT; | 1280 | ret = NF_ACCEPT; |
1281 | goto store_cseq; | 1281 | goto store_cseq; |
1282 | } | 1282 | } |
1283 | 1283 | ||
1284 | exp = nf_ct_expect_alloc(ct); | 1284 | exp = nf_ct_expect_alloc(ct); |
1285 | if (!exp) | 1285 | if (!exp) |
1286 | return NF_DROP; | 1286 | return NF_DROP; |
1287 | 1287 | ||
1288 | saddr = NULL; | 1288 | saddr = NULL; |
1289 | if (sip_direct_signalling) | 1289 | if (sip_direct_signalling) |
1290 | saddr = &ct->tuplehash[!dir].tuple.src.u3; | 1290 | saddr = &ct->tuplehash[!dir].tuple.src.u3; |
1291 | 1291 | ||
1292 | nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), | 1292 | nf_ct_expect_init(exp, SIP_EXPECT_SIGNALLING, nf_ct_l3num(ct), |
1293 | saddr, &daddr, proto, NULL, &port); | 1293 | saddr, &daddr, proto, NULL, &port); |
1294 | exp->timeout.expires = sip_timeout * HZ; | 1294 | exp->timeout.expires = sip_timeout * HZ; |
1295 | exp->helper = nfct_help(ct)->helper; | 1295 | exp->helper = nfct_help(ct)->helper; |
1296 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; | 1296 | exp->flags = NF_CT_EXPECT_PERMANENT | NF_CT_EXPECT_INACTIVE; |
1297 | 1297 | ||
1298 | nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); | 1298 | nf_nat_sip_expect = rcu_dereference(nf_nat_sip_expect_hook); |
1299 | if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) | 1299 | if (nf_nat_sip_expect && ct->status & IPS_NAT_MASK) |
1300 | ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen, | 1300 | ret = nf_nat_sip_expect(skb, protoff, dataoff, dptr, datalen, |
1301 | exp, matchoff, matchlen); | 1301 | exp, matchoff, matchlen); |
1302 | else { | 1302 | else { |
1303 | if (nf_ct_expect_related(exp) != 0) | 1303 | if (nf_ct_expect_related(exp) != 0) |
1304 | ret = NF_DROP; | 1304 | ret = NF_DROP; |
1305 | else | 1305 | else |
1306 | ret = NF_ACCEPT; | 1306 | ret = NF_ACCEPT; |
1307 | } | 1307 | } |
1308 | nf_ct_expect_put(exp); | 1308 | nf_ct_expect_put(exp); |
1309 | 1309 | ||
1310 | store_cseq: | 1310 | store_cseq: |
1311 | if (ret == NF_ACCEPT) | 1311 | if (ret == NF_ACCEPT) |
1312 | ct_sip_info->register_cseq = cseq; | 1312 | ct_sip_info->register_cseq = cseq; |
1313 | return ret; | 1313 | return ret; |
1314 | } | 1314 | } |
1315 | 1315 | ||
1316 | static int process_register_response(struct sk_buff *skb, unsigned int protoff, | 1316 | static int process_register_response(struct sk_buff *skb, unsigned int protoff, |
1317 | unsigned int dataoff, | 1317 | unsigned int dataoff, |
1318 | const char **dptr, unsigned int *datalen, | 1318 | const char **dptr, unsigned int *datalen, |
1319 | unsigned int cseq, unsigned int code) | 1319 | unsigned int cseq, unsigned int code) |
1320 | { | 1320 | { |
1321 | enum ip_conntrack_info ctinfo; | 1321 | enum ip_conntrack_info ctinfo; |
1322 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1322 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1323 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | 1323 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); |
1324 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 1324 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
1325 | union nf_inet_addr addr; | 1325 | union nf_inet_addr addr; |
1326 | __be16 port; | 1326 | __be16 port; |
1327 | u8 proto; | 1327 | u8 proto; |
1328 | unsigned int matchoff, matchlen, coff = 0; | 1328 | unsigned int matchoff, matchlen, coff = 0; |
1329 | unsigned int expires = 0; | 1329 | unsigned int expires = 0; |
1330 | int in_contact = 0, ret; | 1330 | int in_contact = 0, ret; |
1331 | 1331 | ||
1332 | /* According to RFC 3261, "UAs MUST NOT send a new registration until | 1332 | /* According to RFC 3261, "UAs MUST NOT send a new registration until |
1333 | * they have received a final response from the registrar for the | 1333 | * they have received a final response from the registrar for the |
1334 | * previous one or the previous REGISTER request has timed out". | 1334 | * previous one or the previous REGISTER request has timed out". |
1335 | * | 1335 | * |
1336 | * However, some servers fail to detect retransmissions and send late | 1336 | * However, some servers fail to detect retransmissions and send late |
1337 | * responses, so we store the sequence number of the last valid | 1337 | * responses, so we store the sequence number of the last valid |
1338 | * request and compare it here. | 1338 | * request and compare it here. |
1339 | */ | 1339 | */ |
1340 | if (ct_sip_info->register_cseq != cseq) | 1340 | if (ct_sip_info->register_cseq != cseq) |
1341 | return NF_ACCEPT; | 1341 | return NF_ACCEPT; |
1342 | 1342 | ||
1343 | if (code >= 100 && code <= 199) | 1343 | if (code >= 100 && code <= 199) |
1344 | return NF_ACCEPT; | 1344 | return NF_ACCEPT; |
1345 | if (code < 200 || code > 299) | 1345 | if (code < 200 || code > 299) |
1346 | goto flush; | 1346 | goto flush; |
1347 | 1347 | ||
1348 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, | 1348 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_EXPIRES, |
1349 | &matchoff, &matchlen) > 0) | 1349 | &matchoff, &matchlen) > 0) |
1350 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); | 1350 | expires = simple_strtoul(*dptr + matchoff, NULL, 10); |
1351 | 1351 | ||
1352 | while (1) { | 1352 | while (1) { |
1353 | unsigned int c_expires = expires; | 1353 | unsigned int c_expires = expires; |
1354 | 1354 | ||
1355 | ret = ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, | 1355 | ret = ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, |
1356 | SIP_HDR_CONTACT, &in_contact, | 1356 | SIP_HDR_CONTACT, &in_contact, |
1357 | &matchoff, &matchlen, | 1357 | &matchoff, &matchlen, |
1358 | &addr, &port); | 1358 | &addr, &port); |
1359 | if (ret < 0) | 1359 | if (ret < 0) |
1360 | return NF_DROP; | 1360 | return NF_DROP; |
1361 | else if (ret == 0) | 1361 | else if (ret == 0) |
1362 | break; | 1362 | break; |
1363 | 1363 | ||
1364 | /* We don't support third-party registrations */ | 1364 | /* We don't support third-party registrations */ |
1365 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) | 1365 | if (!nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, &addr)) |
1366 | continue; | 1366 | continue; |
1367 | 1367 | ||
1368 | if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, | 1368 | if (ct_sip_parse_transport(ct, *dptr, matchoff + matchlen, |
1369 | *datalen, &proto) == 0) | 1369 | *datalen, &proto) == 0) |
1370 | continue; | 1370 | continue; |
1371 | 1371 | ||
1372 | ret = ct_sip_parse_numerical_param(ct, *dptr, | 1372 | ret = ct_sip_parse_numerical_param(ct, *dptr, |
1373 | matchoff + matchlen, | 1373 | matchoff + matchlen, |
1374 | *datalen, "expires=", | 1374 | *datalen, "expires=", |
1375 | NULL, NULL, &c_expires); | 1375 | NULL, NULL, &c_expires); |
1376 | if (ret < 0) | 1376 | if (ret < 0) |
1377 | return NF_DROP; | 1377 | return NF_DROP; |
1378 | if (c_expires == 0) | 1378 | if (c_expires == 0) |
1379 | break; | 1379 | break; |
1380 | if (refresh_signalling_expectation(ct, &addr, proto, port, | 1380 | if (refresh_signalling_expectation(ct, &addr, proto, port, |
1381 | c_expires)) | 1381 | c_expires)) |
1382 | return NF_ACCEPT; | 1382 | return NF_ACCEPT; |
1383 | } | 1383 | } |
1384 | 1384 | ||
1385 | flush: | 1385 | flush: |
1386 | flush_expectations(ct, false); | 1386 | flush_expectations(ct, false); |
1387 | return NF_ACCEPT; | 1387 | return NF_ACCEPT; |
1388 | } | 1388 | } |
1389 | 1389 | ||
1390 | static const struct sip_handler sip_handlers[] = { | 1390 | static const struct sip_handler sip_handlers[] = { |
1391 | SIP_HANDLER("INVITE", process_invite_request, process_invite_response), | 1391 | SIP_HANDLER("INVITE", process_invite_request, process_invite_response), |
1392 | SIP_HANDLER("UPDATE", process_sdp, process_update_response), | 1392 | SIP_HANDLER("UPDATE", process_sdp, process_update_response), |
1393 | SIP_HANDLER("ACK", process_sdp, NULL), | 1393 | SIP_HANDLER("ACK", process_sdp, NULL), |
1394 | SIP_HANDLER("PRACK", process_sdp, process_prack_response), | 1394 | SIP_HANDLER("PRACK", process_sdp, process_prack_response), |
1395 | SIP_HANDLER("BYE", process_bye_request, NULL), | 1395 | SIP_HANDLER("BYE", process_bye_request, NULL), |
1396 | SIP_HANDLER("REGISTER", process_register_request, process_register_response), | 1396 | SIP_HANDLER("REGISTER", process_register_request, process_register_response), |
1397 | }; | 1397 | }; |
1398 | 1398 | ||
1399 | static int process_sip_response(struct sk_buff *skb, unsigned int protoff, | 1399 | static int process_sip_response(struct sk_buff *skb, unsigned int protoff, |
1400 | unsigned int dataoff, | 1400 | unsigned int dataoff, |
1401 | const char **dptr, unsigned int *datalen) | 1401 | const char **dptr, unsigned int *datalen) |
1402 | { | 1402 | { |
1403 | enum ip_conntrack_info ctinfo; | 1403 | enum ip_conntrack_info ctinfo; |
1404 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1404 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1405 | unsigned int matchoff, matchlen, matchend; | 1405 | unsigned int matchoff, matchlen, matchend; |
1406 | unsigned int code, cseq, i; | 1406 | unsigned int code, cseq, i; |
1407 | 1407 | ||
1408 | if (*datalen < strlen("SIP/2.0 200")) | 1408 | if (*datalen < strlen("SIP/2.0 200")) |
1409 | return NF_ACCEPT; | 1409 | return NF_ACCEPT; |
1410 | code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); | 1410 | code = simple_strtoul(*dptr + strlen("SIP/2.0 "), NULL, 10); |
1411 | if (!code) | 1411 | if (!code) |
1412 | return NF_DROP; | 1412 | return NF_DROP; |
1413 | 1413 | ||
1414 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, | 1414 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, |
1415 | &matchoff, &matchlen) <= 0) | 1415 | &matchoff, &matchlen) <= 0) |
1416 | return NF_DROP; | 1416 | return NF_DROP; |
1417 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | 1417 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); |
1418 | if (!cseq) | 1418 | if (!cseq) |
1419 | return NF_DROP; | 1419 | return NF_DROP; |
1420 | matchend = matchoff + matchlen + 1; | 1420 | matchend = matchoff + matchlen + 1; |
1421 | 1421 | ||
1422 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { | 1422 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { |
1423 | const struct sip_handler *handler; | 1423 | const struct sip_handler *handler; |
1424 | 1424 | ||
1425 | handler = &sip_handlers[i]; | 1425 | handler = &sip_handlers[i]; |
1426 | if (handler->response == NULL) | 1426 | if (handler->response == NULL) |
1427 | continue; | 1427 | continue; |
1428 | if (*datalen < matchend + handler->len || | 1428 | if (*datalen < matchend + handler->len || |
1429 | strnicmp(*dptr + matchend, handler->method, handler->len)) | 1429 | strnicmp(*dptr + matchend, handler->method, handler->len)) |
1430 | continue; | 1430 | continue; |
1431 | return handler->response(skb, protoff, dataoff, dptr, datalen, | 1431 | return handler->response(skb, protoff, dataoff, dptr, datalen, |
1432 | cseq, code); | 1432 | cseq, code); |
1433 | } | 1433 | } |
1434 | return NF_ACCEPT; | 1434 | return NF_ACCEPT; |
1435 | } | 1435 | } |
1436 | 1436 | ||
1437 | static int process_sip_request(struct sk_buff *skb, unsigned int protoff, | 1437 | static int process_sip_request(struct sk_buff *skb, unsigned int protoff, |
1438 | unsigned int dataoff, | 1438 | unsigned int dataoff, |
1439 | const char **dptr, unsigned int *datalen) | 1439 | const char **dptr, unsigned int *datalen) |
1440 | { | 1440 | { |
1441 | enum ip_conntrack_info ctinfo; | 1441 | enum ip_conntrack_info ctinfo; |
1442 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 1442 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
1443 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
1444 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
1443 | unsigned int matchoff, matchlen; | 1445 | unsigned int matchoff, matchlen; |
1444 | unsigned int cseq, i; | 1446 | unsigned int cseq, i; |
1447 | union nf_inet_addr addr; | ||
1448 | __be16 port; | ||
1449 | |||
1450 | /* Many Cisco IP phones use a high source port for SIP requests, but | ||
1451 | * listen for the response on port 5060. If we are the local | ||
1452 | * router for one of these phones, save the port number from the | ||
1453 | * Via: header so that nf_nat_sip can redirect the responses to | ||
1454 | * the correct port. | ||
1455 | */ | ||
1456 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | ||
1457 | SIP_HDR_VIA_UDP, NULL, &matchoff, | ||
1458 | &matchlen, &addr, &port) > 0 && | ||
1459 | port != ct->tuplehash[dir].tuple.src.u.udp.port && | ||
1460 | nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3)) | ||
1461 | ct_sip_info->forced_dport = port; | ||
1445 | 1462 | ||
1446 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { | 1463 | for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { |
1447 | const struct sip_handler *handler; | 1464 | const struct sip_handler *handler; |
1448 | 1465 | ||
1449 | handler = &sip_handlers[i]; | 1466 | handler = &sip_handlers[i]; |
1450 | if (handler->request == NULL) | 1467 | if (handler->request == NULL) |
1451 | continue; | 1468 | continue; |
1452 | if (*datalen < handler->len || | 1469 | if (*datalen < handler->len || |
1453 | strnicmp(*dptr, handler->method, handler->len)) | 1470 | strnicmp(*dptr, handler->method, handler->len)) |
1454 | continue; | 1471 | continue; |
1455 | 1472 | ||
1456 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, | 1473 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CSEQ, |
1457 | &matchoff, &matchlen) <= 0) | 1474 | &matchoff, &matchlen) <= 0) |
1458 | return NF_DROP; | 1475 | return NF_DROP; |
1459 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); | 1476 | cseq = simple_strtoul(*dptr + matchoff, NULL, 10); |
1460 | if (!cseq) | 1477 | if (!cseq) |
1461 | return NF_DROP; | 1478 | return NF_DROP; |
1462 | 1479 | ||
1463 | return handler->request(skb, protoff, dataoff, dptr, datalen, | 1480 | return handler->request(skb, protoff, dataoff, dptr, datalen, |
1464 | cseq); | 1481 | cseq); |
1465 | } | 1482 | } |
1466 | return NF_ACCEPT; | 1483 | return NF_ACCEPT; |
1467 | } | 1484 | } |
1468 | 1485 | ||
1469 | static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct, | 1486 | static int process_sip_msg(struct sk_buff *skb, struct nf_conn *ct, |
1470 | unsigned int protoff, unsigned int dataoff, | 1487 | unsigned int protoff, unsigned int dataoff, |
1471 | const char **dptr, unsigned int *datalen) | 1488 | const char **dptr, unsigned int *datalen) |
1472 | { | 1489 | { |
1473 | typeof(nf_nat_sip_hook) nf_nat_sip; | 1490 | typeof(nf_nat_sip_hook) nf_nat_sip; |
1474 | int ret; | 1491 | int ret; |
1475 | 1492 | ||
1476 | if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) | 1493 | if (strnicmp(*dptr, "SIP/2.0 ", strlen("SIP/2.0 ")) != 0) |
1477 | ret = process_sip_request(skb, protoff, dataoff, dptr, datalen); | 1494 | ret = process_sip_request(skb, protoff, dataoff, dptr, datalen); |
1478 | else | 1495 | else |
1479 | ret = process_sip_response(skb, protoff, dataoff, dptr, datalen); | 1496 | ret = process_sip_response(skb, protoff, dataoff, dptr, datalen); |
1480 | 1497 | ||
1481 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { | 1498 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { |
1482 | nf_nat_sip = rcu_dereference(nf_nat_sip_hook); | 1499 | nf_nat_sip = rcu_dereference(nf_nat_sip_hook); |
1483 | if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff, | 1500 | if (nf_nat_sip && !nf_nat_sip(skb, protoff, dataoff, |
1484 | dptr, datalen)) | 1501 | dptr, datalen)) |
1485 | ret = NF_DROP; | 1502 | ret = NF_DROP; |
1486 | } | 1503 | } |
1487 | 1504 | ||
1488 | return ret; | 1505 | return ret; |
1489 | } | 1506 | } |
1490 | 1507 | ||
1491 | static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, | 1508 | static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, |
1492 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) | 1509 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) |
1493 | { | 1510 | { |
1494 | struct tcphdr *th, _tcph; | 1511 | struct tcphdr *th, _tcph; |
1495 | unsigned int dataoff, datalen; | 1512 | unsigned int dataoff, datalen; |
1496 | unsigned int matchoff, matchlen, clen; | 1513 | unsigned int matchoff, matchlen, clen; |
1497 | unsigned int msglen, origlen; | 1514 | unsigned int msglen, origlen; |
1498 | const char *dptr, *end; | 1515 | const char *dptr, *end; |
1499 | s16 diff, tdiff = 0; | 1516 | s16 diff, tdiff = 0; |
1500 | int ret = NF_ACCEPT; | 1517 | int ret = NF_ACCEPT; |
1501 | bool term; | 1518 | bool term; |
1502 | typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; | 1519 | typeof(nf_nat_sip_seq_adjust_hook) nf_nat_sip_seq_adjust; |
1503 | 1520 | ||
1504 | if (ctinfo != IP_CT_ESTABLISHED && | 1521 | if (ctinfo != IP_CT_ESTABLISHED && |
1505 | ctinfo != IP_CT_ESTABLISHED_REPLY) | 1522 | ctinfo != IP_CT_ESTABLISHED_REPLY) |
1506 | return NF_ACCEPT; | 1523 | return NF_ACCEPT; |
1507 | 1524 | ||
1508 | /* No Data ? */ | 1525 | /* No Data ? */ |
1509 | th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); | 1526 | th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph); |
1510 | if (th == NULL) | 1527 | if (th == NULL) |
1511 | return NF_ACCEPT; | 1528 | return NF_ACCEPT; |
1512 | dataoff = protoff + th->doff * 4; | 1529 | dataoff = protoff + th->doff * 4; |
1513 | if (dataoff >= skb->len) | 1530 | if (dataoff >= skb->len) |
1514 | return NF_ACCEPT; | 1531 | return NF_ACCEPT; |
1515 | 1532 | ||
1516 | nf_ct_refresh(ct, skb, sip_timeout * HZ); | 1533 | nf_ct_refresh(ct, skb, sip_timeout * HZ); |
1517 | 1534 | ||
1518 | if (unlikely(skb_linearize(skb))) | 1535 | if (unlikely(skb_linearize(skb))) |
1519 | return NF_DROP; | 1536 | return NF_DROP; |
1520 | 1537 | ||
1521 | dptr = skb->data + dataoff; | 1538 | dptr = skb->data + dataoff; |
1522 | datalen = skb->len - dataoff; | 1539 | datalen = skb->len - dataoff; |
1523 | if (datalen < strlen("SIP/2.0 200")) | 1540 | if (datalen < strlen("SIP/2.0 200")) |
1524 | return NF_ACCEPT; | 1541 | return NF_ACCEPT; |
1525 | 1542 | ||
1526 | while (1) { | 1543 | while (1) { |
1527 | if (ct_sip_get_header(ct, dptr, 0, datalen, | 1544 | if (ct_sip_get_header(ct, dptr, 0, datalen, |
1528 | SIP_HDR_CONTENT_LENGTH, | 1545 | SIP_HDR_CONTENT_LENGTH, |
1529 | &matchoff, &matchlen) <= 0) | 1546 | &matchoff, &matchlen) <= 0) |
1530 | break; | 1547 | break; |
1531 | 1548 | ||
1532 | clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); | 1549 | clen = simple_strtoul(dptr + matchoff, (char **)&end, 10); |
1533 | if (dptr + matchoff == end) | 1550 | if (dptr + matchoff == end) |
1534 | break; | 1551 | break; |
1535 | 1552 | ||
1536 | term = false; | 1553 | term = false; |
1537 | for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) { | 1554 | for (; end + strlen("\r\n\r\n") <= dptr + datalen; end++) { |
1538 | if (end[0] == '\r' && end[1] == '\n' && | 1555 | if (end[0] == '\r' && end[1] == '\n' && |
1539 | end[2] == '\r' && end[3] == '\n') { | 1556 | end[2] == '\r' && end[3] == '\n') { |
1540 | term = true; | 1557 | term = true; |
1541 | break; | 1558 | break; |
1542 | } | 1559 | } |
1543 | } | 1560 | } |
1544 | if (!term) | 1561 | if (!term) |
1545 | break; | 1562 | break; |
1546 | end += strlen("\r\n\r\n") + clen; | 1563 | end += strlen("\r\n\r\n") + clen; |
1547 | 1564 | ||
1548 | msglen = origlen = end - dptr; | 1565 | msglen = origlen = end - dptr; |
1549 | if (msglen > datalen) | 1566 | if (msglen > datalen) |
1550 | return NF_DROP; | 1567 | return NF_DROP; |
1551 | 1568 | ||
1552 | ret = process_sip_msg(skb, ct, protoff, dataoff, | 1569 | ret = process_sip_msg(skb, ct, protoff, dataoff, |
1553 | &dptr, &msglen); | 1570 | &dptr, &msglen); |
1554 | if (ret != NF_ACCEPT) | 1571 | if (ret != NF_ACCEPT) |
1555 | break; | 1572 | break; |
1556 | diff = msglen - origlen; | 1573 | diff = msglen - origlen; |
1557 | tdiff += diff; | 1574 | tdiff += diff; |
1558 | 1575 | ||
1559 | dataoff += msglen; | 1576 | dataoff += msglen; |
1560 | dptr += msglen; | 1577 | dptr += msglen; |
1561 | datalen = datalen + diff - msglen; | 1578 | datalen = datalen + diff - msglen; |
1562 | } | 1579 | } |
1563 | 1580 | ||
1564 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { | 1581 | if (ret == NF_ACCEPT && ct->status & IPS_NAT_MASK) { |
1565 | nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook); | 1582 | nf_nat_sip_seq_adjust = rcu_dereference(nf_nat_sip_seq_adjust_hook); |
1566 | if (nf_nat_sip_seq_adjust) | 1583 | if (nf_nat_sip_seq_adjust) |
1567 | nf_nat_sip_seq_adjust(skb, protoff, tdiff); | 1584 | nf_nat_sip_seq_adjust(skb, protoff, tdiff); |
1568 | } | 1585 | } |
1569 | 1586 | ||
1570 | return ret; | 1587 | return ret; |
1571 | } | 1588 | } |
1572 | 1589 | ||
1573 | static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, | 1590 | static int sip_help_udp(struct sk_buff *skb, unsigned int protoff, |
1574 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) | 1591 | struct nf_conn *ct, enum ip_conntrack_info ctinfo) |
1575 | { | 1592 | { |
1576 | unsigned int dataoff, datalen; | 1593 | unsigned int dataoff, datalen; |
1577 | const char *dptr; | 1594 | const char *dptr; |
1578 | 1595 | ||
1579 | /* No Data ? */ | 1596 | /* No Data ? */ |
1580 | dataoff = protoff + sizeof(struct udphdr); | 1597 | dataoff = protoff + sizeof(struct udphdr); |
1581 | if (dataoff >= skb->len) | 1598 | if (dataoff >= skb->len) |
1582 | return NF_ACCEPT; | 1599 | return NF_ACCEPT; |
1583 | 1600 | ||
1584 | nf_ct_refresh(ct, skb, sip_timeout * HZ); | 1601 | nf_ct_refresh(ct, skb, sip_timeout * HZ); |
1585 | 1602 | ||
1586 | if (unlikely(skb_linearize(skb))) | 1603 | if (unlikely(skb_linearize(skb))) |
1587 | return NF_DROP; | 1604 | return NF_DROP; |
1588 | 1605 | ||
1589 | dptr = skb->data + dataoff; | 1606 | dptr = skb->data + dataoff; |
1590 | datalen = skb->len - dataoff; | 1607 | datalen = skb->len - dataoff; |
1591 | if (datalen < strlen("SIP/2.0 200")) | 1608 | if (datalen < strlen("SIP/2.0 200")) |
1592 | return NF_ACCEPT; | 1609 | return NF_ACCEPT; |
1593 | 1610 | ||
1594 | return process_sip_msg(skb, ct, protoff, dataoff, &dptr, &datalen); | 1611 | return process_sip_msg(skb, ct, protoff, dataoff, &dptr, &datalen); |
1595 | } | 1612 | } |
1596 | 1613 | ||
1597 | static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; | 1614 | static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly; |
1598 | 1615 | ||
1599 | static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { | 1616 | static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = { |
1600 | [SIP_EXPECT_SIGNALLING] = { | 1617 | [SIP_EXPECT_SIGNALLING] = { |
1601 | .name = "signalling", | 1618 | .name = "signalling", |
1602 | .max_expected = 1, | 1619 | .max_expected = 1, |
1603 | .timeout = 3 * 60, | 1620 | .timeout = 3 * 60, |
1604 | }, | 1621 | }, |
1605 | [SIP_EXPECT_AUDIO] = { | 1622 | [SIP_EXPECT_AUDIO] = { |
1606 | .name = "audio", | 1623 | .name = "audio", |
1607 | .max_expected = 2 * IP_CT_DIR_MAX, | 1624 | .max_expected = 2 * IP_CT_DIR_MAX, |
1608 | .timeout = 3 * 60, | 1625 | .timeout = 3 * 60, |
1609 | }, | 1626 | }, |
1610 | [SIP_EXPECT_VIDEO] = { | 1627 | [SIP_EXPECT_VIDEO] = { |
1611 | .name = "video", | 1628 | .name = "video", |
1612 | .max_expected = 2 * IP_CT_DIR_MAX, | 1629 | .max_expected = 2 * IP_CT_DIR_MAX, |
1613 | .timeout = 3 * 60, | 1630 | .timeout = 3 * 60, |
1614 | }, | 1631 | }, |
1615 | [SIP_EXPECT_IMAGE] = { | 1632 | [SIP_EXPECT_IMAGE] = { |
1616 | .name = "image", | 1633 | .name = "image", |
1617 | .max_expected = IP_CT_DIR_MAX, | 1634 | .max_expected = IP_CT_DIR_MAX, |
1618 | .timeout = 3 * 60, | 1635 | .timeout = 3 * 60, |
1619 | }, | 1636 | }, |
1620 | }; | 1637 | }; |
1621 | 1638 | ||
1622 | static void nf_conntrack_sip_fini(void) | 1639 | static void nf_conntrack_sip_fini(void) |
1623 | { | 1640 | { |
1624 | int i, j; | 1641 | int i, j; |
1625 | 1642 | ||
1626 | for (i = 0; i < ports_c; i++) { | 1643 | for (i = 0; i < ports_c; i++) { |
1627 | for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { | 1644 | for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { |
1628 | if (sip[i][j].me == NULL) | 1645 | if (sip[i][j].me == NULL) |
1629 | continue; | 1646 | continue; |
1630 | nf_conntrack_helper_unregister(&sip[i][j]); | 1647 | nf_conntrack_helper_unregister(&sip[i][j]); |
1631 | } | 1648 | } |
1632 | } | 1649 | } |
1633 | } | 1650 | } |
1634 | 1651 | ||
1635 | static int __init nf_conntrack_sip_init(void) | 1652 | static int __init nf_conntrack_sip_init(void) |
1636 | { | 1653 | { |
1637 | int i, j, ret; | 1654 | int i, j, ret; |
1638 | 1655 | ||
1639 | if (ports_c == 0) | 1656 | if (ports_c == 0) |
1640 | ports[ports_c++] = SIP_PORT; | 1657 | ports[ports_c++] = SIP_PORT; |
1641 | 1658 | ||
1642 | for (i = 0; i < ports_c; i++) { | 1659 | for (i = 0; i < ports_c; i++) { |
1643 | memset(&sip[i], 0, sizeof(sip[i])); | 1660 | memset(&sip[i], 0, sizeof(sip[i])); |
1644 | 1661 | ||
1645 | sip[i][0].tuple.src.l3num = AF_INET; | 1662 | sip[i][0].tuple.src.l3num = AF_INET; |
1646 | sip[i][0].tuple.dst.protonum = IPPROTO_UDP; | 1663 | sip[i][0].tuple.dst.protonum = IPPROTO_UDP; |
1647 | sip[i][0].help = sip_help_udp; | 1664 | sip[i][0].help = sip_help_udp; |
1648 | sip[i][1].tuple.src.l3num = AF_INET; | 1665 | sip[i][1].tuple.src.l3num = AF_INET; |
1649 | sip[i][1].tuple.dst.protonum = IPPROTO_TCP; | 1666 | sip[i][1].tuple.dst.protonum = IPPROTO_TCP; |
1650 | sip[i][1].help = sip_help_tcp; | 1667 | sip[i][1].help = sip_help_tcp; |
1651 | 1668 | ||
1652 | sip[i][2].tuple.src.l3num = AF_INET6; | 1669 | sip[i][2].tuple.src.l3num = AF_INET6; |
1653 | sip[i][2].tuple.dst.protonum = IPPROTO_UDP; | 1670 | sip[i][2].tuple.dst.protonum = IPPROTO_UDP; |
1654 | sip[i][2].help = sip_help_udp; | 1671 | sip[i][2].help = sip_help_udp; |
1655 | sip[i][3].tuple.src.l3num = AF_INET6; | 1672 | sip[i][3].tuple.src.l3num = AF_INET6; |
1656 | sip[i][3].tuple.dst.protonum = IPPROTO_TCP; | 1673 | sip[i][3].tuple.dst.protonum = IPPROTO_TCP; |
1657 | sip[i][3].help = sip_help_tcp; | 1674 | sip[i][3].help = sip_help_tcp; |
1658 | 1675 | ||
1659 | for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { | 1676 | for (j = 0; j < ARRAY_SIZE(sip[i]); j++) { |
1660 | sip[i][j].data_len = sizeof(struct nf_ct_sip_master); | 1677 | sip[i][j].data_len = sizeof(struct nf_ct_sip_master); |
1661 | sip[i][j].tuple.src.u.udp.port = htons(ports[i]); | 1678 | sip[i][j].tuple.src.u.udp.port = htons(ports[i]); |
1662 | sip[i][j].expect_policy = sip_exp_policy; | 1679 | sip[i][j].expect_policy = sip_exp_policy; |
1663 | sip[i][j].expect_class_max = SIP_EXPECT_MAX; | 1680 | sip[i][j].expect_class_max = SIP_EXPECT_MAX; |
1664 | sip[i][j].me = THIS_MODULE; | 1681 | sip[i][j].me = THIS_MODULE; |
1665 | 1682 | ||
1666 | if (ports[i] == SIP_PORT) | 1683 | if (ports[i] == SIP_PORT) |
1667 | sprintf(sip[i][j].name, "sip"); | 1684 | sprintf(sip[i][j].name, "sip"); |
1668 | else | 1685 | else |
1669 | sprintf(sip[i][j].name, "sip-%u", i); | 1686 | sprintf(sip[i][j].name, "sip-%u", i); |
1670 | 1687 | ||
1671 | pr_debug("port #%u: %u\n", i, ports[i]); | 1688 | pr_debug("port #%u: %u\n", i, ports[i]); |
1672 | 1689 | ||
1673 | ret = nf_conntrack_helper_register(&sip[i][j]); | 1690 | ret = nf_conntrack_helper_register(&sip[i][j]); |
1674 | if (ret) { | 1691 | if (ret) { |
1675 | printk(KERN_ERR "nf_ct_sip: failed to register" | 1692 | printk(KERN_ERR "nf_ct_sip: failed to register" |
1676 | " helper for pf: %u port: %u\n", | 1693 | " helper for pf: %u port: %u\n", |
1677 | sip[i][j].tuple.src.l3num, ports[i]); | 1694 | sip[i][j].tuple.src.l3num, ports[i]); |
1678 | nf_conntrack_sip_fini(); | 1695 | nf_conntrack_sip_fini(); |
1679 | return ret; | 1696 | return ret; |
1680 | } | 1697 | } |
1681 | } | 1698 | } |
1682 | } | 1699 | } |
1683 | return 0; | 1700 | return 0; |
1684 | } | 1701 | } |
1685 | 1702 | ||
1686 | module_init(nf_conntrack_sip_init); | 1703 | module_init(nf_conntrack_sip_init); |
1687 | module_exit(nf_conntrack_sip_fini); | 1704 | module_exit(nf_conntrack_sip_fini); |
1688 | 1705 |
net/netfilter/nf_nat_sip.c
1 | /* SIP extension for 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. |
5 | * (C) 2007 United Security Providers | 5 | * (C) 2007 United Security Providers |
6 | * (C) 2007, 2008, 2011, 2012 Patrick McHardy <kaber@trash.net> | 6 | * (C) 2007, 2008, 2011, 2012 Patrick McHardy <kaber@trash.net> |
7 | * | 7 | * |
8 | * This program is free software; you can redistribute it and/or modify | 8 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 9 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 10 | * published by the Free Software Foundation. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
15 | #include <linux/inet.h> | 15 | #include <linux/inet.h> |
16 | #include <linux/udp.h> | 16 | #include <linux/udp.h> |
17 | #include <linux/tcp.h> | 17 | #include <linux/tcp.h> |
18 | 18 | ||
19 | #include <net/netfilter/nf_nat.h> | 19 | #include <net/netfilter/nf_nat.h> |
20 | #include <net/netfilter/nf_nat_helper.h> | 20 | #include <net/netfilter/nf_nat_helper.h> |
21 | #include <net/netfilter/nf_conntrack_helper.h> | 21 | #include <net/netfilter/nf_conntrack_helper.h> |
22 | #include <net/netfilter/nf_conntrack_expect.h> | 22 | #include <net/netfilter/nf_conntrack_expect.h> |
23 | #include <linux/netfilter/nf_conntrack_sip.h> | 23 | #include <linux/netfilter/nf_conntrack_sip.h> |
24 | 24 | ||
25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
26 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); | 26 | MODULE_AUTHOR("Christian Hentschel <chentschel@arnet.com.ar>"); |
27 | MODULE_DESCRIPTION("SIP NAT helper"); | 27 | MODULE_DESCRIPTION("SIP NAT helper"); |
28 | MODULE_ALIAS("ip_nat_sip"); | 28 | MODULE_ALIAS("ip_nat_sip"); |
29 | 29 | ||
30 | 30 | ||
31 | static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, | 31 | static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, |
32 | unsigned int dataoff, | 32 | unsigned int dataoff, |
33 | const char **dptr, unsigned int *datalen, | 33 | const char **dptr, unsigned int *datalen, |
34 | unsigned int matchoff, unsigned int matchlen, | 34 | unsigned int matchoff, unsigned int matchlen, |
35 | const char *buffer, unsigned int buflen) | 35 | const char *buffer, unsigned int buflen) |
36 | { | 36 | { |
37 | enum ip_conntrack_info ctinfo; | 37 | enum ip_conntrack_info ctinfo; |
38 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 38 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
39 | struct tcphdr *th; | 39 | struct tcphdr *th; |
40 | unsigned int baseoff; | 40 | unsigned int baseoff; |
41 | 41 | ||
42 | if (nf_ct_protonum(ct) == IPPROTO_TCP) { | 42 | if (nf_ct_protonum(ct) == IPPROTO_TCP) { |
43 | th = (struct tcphdr *)(skb->data + protoff); | 43 | th = (struct tcphdr *)(skb->data + protoff); |
44 | baseoff = protoff + th->doff * 4; | 44 | baseoff = protoff + th->doff * 4; |
45 | matchoff += dataoff - baseoff; | 45 | matchoff += dataoff - baseoff; |
46 | 46 | ||
47 | if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, | 47 | if (!__nf_nat_mangle_tcp_packet(skb, ct, ctinfo, |
48 | protoff, matchoff, matchlen, | 48 | protoff, matchoff, matchlen, |
49 | buffer, buflen, false)) | 49 | buffer, buflen, false)) |
50 | return 0; | 50 | return 0; |
51 | } else { | 51 | } else { |
52 | baseoff = protoff + sizeof(struct udphdr); | 52 | baseoff = protoff + sizeof(struct udphdr); |
53 | matchoff += dataoff - baseoff; | 53 | matchoff += dataoff - baseoff; |
54 | 54 | ||
55 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, | 55 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, |
56 | protoff, matchoff, matchlen, | 56 | protoff, matchoff, matchlen, |
57 | buffer, buflen)) | 57 | buffer, buflen)) |
58 | return 0; | 58 | return 0; |
59 | } | 59 | } |
60 | 60 | ||
61 | /* Reload data pointer and adjust datalen value */ | 61 | /* Reload data pointer and adjust datalen value */ |
62 | *dptr = skb->data + dataoff; | 62 | *dptr = skb->data + dataoff; |
63 | *datalen += buflen - matchlen; | 63 | *datalen += buflen - matchlen; |
64 | return 1; | 64 | return 1; |
65 | } | 65 | } |
66 | 66 | ||
67 | static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, | 67 | static int sip_sprintf_addr(const struct nf_conn *ct, char *buffer, |
68 | const union nf_inet_addr *addr, bool delim) | 68 | const union nf_inet_addr *addr, bool delim) |
69 | { | 69 | { |
70 | if (nf_ct_l3num(ct) == NFPROTO_IPV4) | 70 | if (nf_ct_l3num(ct) == NFPROTO_IPV4) |
71 | return sprintf(buffer, "%pI4", &addr->ip); | 71 | return sprintf(buffer, "%pI4", &addr->ip); |
72 | else { | 72 | else { |
73 | if (delim) | 73 | if (delim) |
74 | return sprintf(buffer, "[%pI6c]", &addr->ip6); | 74 | return sprintf(buffer, "[%pI6c]", &addr->ip6); |
75 | else | 75 | else |
76 | return sprintf(buffer, "%pI6c", &addr->ip6); | 76 | return sprintf(buffer, "%pI6c", &addr->ip6); |
77 | } | 77 | } |
78 | } | 78 | } |
79 | 79 | ||
80 | static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, | 80 | static int sip_sprintf_addr_port(const struct nf_conn *ct, char *buffer, |
81 | const union nf_inet_addr *addr, u16 port) | 81 | const union nf_inet_addr *addr, u16 port) |
82 | { | 82 | { |
83 | if (nf_ct_l3num(ct) == NFPROTO_IPV4) | 83 | if (nf_ct_l3num(ct) == NFPROTO_IPV4) |
84 | return sprintf(buffer, "%pI4:%u", &addr->ip, port); | 84 | return sprintf(buffer, "%pI4:%u", &addr->ip, port); |
85 | else | 85 | else |
86 | return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); | 86 | return sprintf(buffer, "[%pI6c]:%u", &addr->ip6, port); |
87 | } | 87 | } |
88 | 88 | ||
89 | static int map_addr(struct sk_buff *skb, unsigned int protoff, | 89 | static int map_addr(struct sk_buff *skb, unsigned int protoff, |
90 | unsigned int dataoff, | 90 | unsigned int dataoff, |
91 | const char **dptr, unsigned int *datalen, | 91 | const char **dptr, unsigned int *datalen, |
92 | unsigned int matchoff, unsigned int matchlen, | 92 | unsigned int matchoff, unsigned int matchlen, |
93 | union nf_inet_addr *addr, __be16 port) | 93 | union nf_inet_addr *addr, __be16 port) |
94 | { | 94 | { |
95 | enum ip_conntrack_info ctinfo; | 95 | enum ip_conntrack_info ctinfo; |
96 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 96 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
97 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 97 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
98 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
98 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; | 99 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
99 | unsigned int buflen; | 100 | unsigned int buflen; |
100 | union nf_inet_addr newaddr; | 101 | union nf_inet_addr newaddr; |
101 | __be16 newport; | 102 | __be16 newport; |
102 | 103 | ||
103 | if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) && | 104 | if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, addr) && |
104 | ct->tuplehash[dir].tuple.src.u.udp.port == port) { | 105 | ct->tuplehash[dir].tuple.src.u.udp.port == port) { |
105 | newaddr = ct->tuplehash[!dir].tuple.dst.u3; | 106 | newaddr = ct->tuplehash[!dir].tuple.dst.u3; |
106 | newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; | 107 | newport = ct->tuplehash[!dir].tuple.dst.u.udp.port; |
107 | } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) && | 108 | } else if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.dst.u3, addr) && |
108 | ct->tuplehash[dir].tuple.dst.u.udp.port == port) { | 109 | ct->tuplehash[dir].tuple.dst.u.udp.port == port) { |
109 | newaddr = ct->tuplehash[!dir].tuple.src.u3; | 110 | newaddr = ct->tuplehash[!dir].tuple.src.u3; |
110 | newport = ct->tuplehash[!dir].tuple.src.u.udp.port; | 111 | newport = ct_sip_info->forced_dport ? : |
112 | ct->tuplehash[!dir].tuple.src.u.udp.port; | ||
111 | } else | 113 | } else |
112 | return 1; | 114 | return 1; |
113 | 115 | ||
114 | if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) | 116 | if (nf_inet_addr_cmp(&newaddr, addr) && newport == port) |
115 | return 1; | 117 | return 1; |
116 | 118 | ||
117 | buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); | 119 | buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, ntohs(newport)); |
118 | return mangle_packet(skb, protoff, dataoff, dptr, datalen, | 120 | return mangle_packet(skb, protoff, dataoff, dptr, datalen, |
119 | matchoff, matchlen, buffer, buflen); | 121 | matchoff, matchlen, buffer, buflen); |
120 | } | 122 | } |
121 | 123 | ||
122 | static int map_sip_addr(struct sk_buff *skb, unsigned int protoff, | 124 | static int map_sip_addr(struct sk_buff *skb, unsigned int protoff, |
123 | unsigned int dataoff, | 125 | unsigned int dataoff, |
124 | const char **dptr, unsigned int *datalen, | 126 | const char **dptr, unsigned int *datalen, |
125 | enum sip_header_types type) | 127 | enum sip_header_types type) |
126 | { | 128 | { |
127 | enum ip_conntrack_info ctinfo; | 129 | enum ip_conntrack_info ctinfo; |
128 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 130 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
129 | unsigned int matchlen, matchoff; | 131 | unsigned int matchlen, matchoff; |
130 | union nf_inet_addr addr; | 132 | union nf_inet_addr addr; |
131 | __be16 port; | 133 | __be16 port; |
132 | 134 | ||
133 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, | 135 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL, |
134 | &matchoff, &matchlen, &addr, &port) <= 0) | 136 | &matchoff, &matchlen, &addr, &port) <= 0) |
135 | return 1; | 137 | return 1; |
136 | return map_addr(skb, protoff, dataoff, dptr, datalen, | 138 | return map_addr(skb, protoff, dataoff, dptr, datalen, |
137 | matchoff, matchlen, &addr, port); | 139 | matchoff, matchlen, &addr, port); |
138 | } | 140 | } |
139 | 141 | ||
140 | static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, | 142 | static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, |
141 | unsigned int dataoff, | 143 | unsigned int dataoff, |
142 | const char **dptr, unsigned int *datalen) | 144 | const char **dptr, unsigned int *datalen) |
143 | { | 145 | { |
144 | enum ip_conntrack_info ctinfo; | 146 | enum ip_conntrack_info ctinfo; |
145 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 147 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
146 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 148 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
149 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
147 | unsigned int coff, matchoff, matchlen; | 150 | unsigned int coff, matchoff, matchlen; |
148 | enum sip_header_types hdr; | 151 | enum sip_header_types hdr; |
149 | union nf_inet_addr addr; | 152 | union nf_inet_addr addr; |
150 | __be16 port; | 153 | __be16 port; |
151 | int request, in_header; | 154 | int request, in_header; |
152 | 155 | ||
153 | /* Basic rules: requests and responses. */ | 156 | /* Basic rules: requests and responses. */ |
154 | if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { | 157 | if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { |
155 | if (ct_sip_parse_request(ct, *dptr, *datalen, | 158 | if (ct_sip_parse_request(ct, *dptr, *datalen, |
156 | &matchoff, &matchlen, | 159 | &matchoff, &matchlen, |
157 | &addr, &port) > 0 && | 160 | &addr, &port) > 0 && |
158 | !map_addr(skb, protoff, dataoff, dptr, datalen, | 161 | !map_addr(skb, protoff, dataoff, dptr, datalen, |
159 | matchoff, matchlen, &addr, port)) | 162 | matchoff, matchlen, &addr, port)) |
160 | return NF_DROP; | 163 | return NF_DROP; |
161 | request = 1; | 164 | request = 1; |
162 | } else | 165 | } else |
163 | request = 0; | 166 | request = 0; |
164 | 167 | ||
165 | if (nf_ct_protonum(ct) == IPPROTO_TCP) | 168 | if (nf_ct_protonum(ct) == IPPROTO_TCP) |
166 | hdr = SIP_HDR_VIA_TCP; | 169 | hdr = SIP_HDR_VIA_TCP; |
167 | else | 170 | else |
168 | hdr = SIP_HDR_VIA_UDP; | 171 | hdr = SIP_HDR_VIA_UDP; |
169 | 172 | ||
170 | /* Translate topmost Via header and parameters */ | 173 | /* Translate topmost Via header and parameters */ |
171 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, | 174 | if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, |
172 | hdr, NULL, &matchoff, &matchlen, | 175 | hdr, NULL, &matchoff, &matchlen, |
173 | &addr, &port) > 0) { | 176 | &addr, &port) > 0) { |
174 | unsigned int olen, matchend, poff, plen, buflen, n; | 177 | unsigned int olen, matchend, poff, plen, buflen, n; |
175 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; | 178 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
176 | 179 | ||
177 | /* We're only interested in headers related to this | 180 | /* We're only interested in headers related to this |
178 | * connection */ | 181 | * connection */ |
179 | if (request) { | 182 | if (request) { |
180 | if (!nf_inet_addr_cmp(&addr, | 183 | if (!nf_inet_addr_cmp(&addr, |
181 | &ct->tuplehash[dir].tuple.src.u3) || | 184 | &ct->tuplehash[dir].tuple.src.u3) || |
182 | port != ct->tuplehash[dir].tuple.src.u.udp.port) | 185 | port != ct->tuplehash[dir].tuple.src.u.udp.port) |
183 | goto next; | 186 | goto next; |
184 | } else { | 187 | } else { |
185 | if (!nf_inet_addr_cmp(&addr, | 188 | if (!nf_inet_addr_cmp(&addr, |
186 | &ct->tuplehash[dir].tuple.dst.u3) || | 189 | &ct->tuplehash[dir].tuple.dst.u3) || |
187 | port != ct->tuplehash[dir].tuple.dst.u.udp.port) | 190 | port != ct->tuplehash[dir].tuple.dst.u.udp.port) |
188 | goto next; | 191 | goto next; |
189 | } | 192 | } |
190 | 193 | ||
191 | olen = *datalen; | 194 | olen = *datalen; |
192 | if (!map_addr(skb, protoff, dataoff, dptr, datalen, | 195 | if (!map_addr(skb, protoff, dataoff, dptr, datalen, |
193 | matchoff, matchlen, &addr, port)) | 196 | matchoff, matchlen, &addr, port)) |
194 | return NF_DROP; | 197 | return NF_DROP; |
195 | 198 | ||
196 | matchend = matchoff + matchlen + *datalen - olen; | 199 | matchend = matchoff + matchlen + *datalen - olen; |
197 | 200 | ||
198 | /* The maddr= parameter (RFC 2361) specifies where to send | 201 | /* The maddr= parameter (RFC 2361) specifies where to send |
199 | * the reply. */ | 202 | * the reply. */ |
200 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, | 203 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
201 | "maddr=", &poff, &plen, | 204 | "maddr=", &poff, &plen, |
202 | &addr, true) > 0 && | 205 | &addr, true) > 0 && |
203 | nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && | 206 | nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && |
204 | !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { | 207 | !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { |
205 | buflen = sip_sprintf_addr(ct, buffer, | 208 | buflen = sip_sprintf_addr(ct, buffer, |
206 | &ct->tuplehash[!dir].tuple.dst.u3, | 209 | &ct->tuplehash[!dir].tuple.dst.u3, |
207 | true); | 210 | true); |
208 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, | 211 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
209 | poff, plen, buffer, buflen)) | 212 | poff, plen, buffer, buflen)) |
210 | return NF_DROP; | 213 | return NF_DROP; |
211 | } | 214 | } |
212 | 215 | ||
213 | /* The received= parameter (RFC 2361) contains the address | 216 | /* The received= parameter (RFC 2361) contains the address |
214 | * from which the server received the request. */ | 217 | * from which the server received the request. */ |
215 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, | 218 | if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen, |
216 | "received=", &poff, &plen, | 219 | "received=", &poff, &plen, |
217 | &addr, false) > 0 && | 220 | &addr, false) > 0 && |
218 | nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && | 221 | nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && |
219 | !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { | 222 | !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { |
220 | buflen = sip_sprintf_addr(ct, buffer, | 223 | buflen = sip_sprintf_addr(ct, buffer, |
221 | &ct->tuplehash[!dir].tuple.src.u3, | 224 | &ct->tuplehash[!dir].tuple.src.u3, |
222 | false); | 225 | false); |
223 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, | 226 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
224 | poff, plen, buffer, buflen)) | 227 | poff, plen, buffer, buflen)) |
225 | return NF_DROP; | 228 | return NF_DROP; |
226 | } | 229 | } |
227 | 230 | ||
228 | /* The rport= parameter (RFC 3581) contains the port number | 231 | /* The rport= parameter (RFC 3581) contains the port number |
229 | * from which the server received the request. */ | 232 | * from which the server received the request. */ |
230 | if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, | 233 | if (ct_sip_parse_numerical_param(ct, *dptr, matchend, *datalen, |
231 | "rport=", &poff, &plen, | 234 | "rport=", &poff, &plen, |
232 | &n) > 0 && | 235 | &n) > 0 && |
233 | htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && | 236 | htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && |
234 | htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { | 237 | htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) { |
235 | __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; | 238 | __be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; |
236 | buflen = sprintf(buffer, "%u", ntohs(p)); | 239 | buflen = sprintf(buffer, "%u", ntohs(p)); |
237 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, | 240 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
238 | poff, plen, buffer, buflen)) | 241 | poff, plen, buffer, buflen)) |
239 | return NF_DROP; | 242 | return NF_DROP; |
240 | } | 243 | } |
241 | } | 244 | } |
242 | 245 | ||
243 | next: | 246 | next: |
244 | /* Translate Contact headers */ | 247 | /* Translate Contact headers */ |
245 | coff = 0; | 248 | coff = 0; |
246 | in_header = 0; | 249 | in_header = 0; |
247 | while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, | 250 | while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen, |
248 | SIP_HDR_CONTACT, &in_header, | 251 | SIP_HDR_CONTACT, &in_header, |
249 | &matchoff, &matchlen, | 252 | &matchoff, &matchlen, |
250 | &addr, &port) > 0) { | 253 | &addr, &port) > 0) { |
251 | if (!map_addr(skb, protoff, dataoff, dptr, datalen, | 254 | if (!map_addr(skb, protoff, dataoff, dptr, datalen, |
252 | matchoff, matchlen, | 255 | matchoff, matchlen, |
253 | &addr, port)) | 256 | &addr, port)) |
254 | return NF_DROP; | 257 | return NF_DROP; |
255 | } | 258 | } |
256 | 259 | ||
257 | if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) || | 260 | if (!map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_FROM) || |
258 | !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) | 261 | !map_sip_addr(skb, protoff, dataoff, dptr, datalen, SIP_HDR_TO)) |
259 | return NF_DROP; | 262 | return NF_DROP; |
260 | 263 | ||
264 | /* Mangle destination port for Cisco phones, then fix up checksums */ | ||
265 | if (dir == IP_CT_DIR_REPLY && ct_sip_info->forced_dport) { | ||
266 | struct udphdr *uh; | ||
267 | |||
268 | if (!skb_make_writable(skb, skb->len)) | ||
269 | return NF_DROP; | ||
270 | |||
271 | uh = (void *)skb->data + protoff; | ||
272 | uh->dest = ct_sip_info->forced_dport; | ||
273 | |||
274 | if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff, | ||
275 | 0, 0, NULL, 0)) | ||
276 | return NF_DROP; | ||
277 | } | ||
278 | |||
261 | return NF_ACCEPT; | 279 | return NF_ACCEPT; |
262 | } | 280 | } |
263 | 281 | ||
264 | static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff, | 282 | static void nf_nat_sip_seq_adjust(struct sk_buff *skb, unsigned int protoff, |
265 | s16 off) | 283 | s16 off) |
266 | { | 284 | { |
267 | enum ip_conntrack_info ctinfo; | 285 | enum ip_conntrack_info ctinfo; |
268 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 286 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
269 | const struct tcphdr *th; | 287 | const struct tcphdr *th; |
270 | 288 | ||
271 | if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0) | 289 | if (nf_ct_protonum(ct) != IPPROTO_TCP || off == 0) |
272 | return; | 290 | return; |
273 | 291 | ||
274 | th = (struct tcphdr *)(skb->data + protoff); | 292 | th = (struct tcphdr *)(skb->data + protoff); |
275 | nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); | 293 | nf_nat_set_seq_adjust(ct, ctinfo, th->seq, off); |
276 | } | 294 | } |
277 | 295 | ||
278 | /* Handles expected signalling connections and media streams */ | 296 | /* Handles expected signalling connections and media streams */ |
279 | static void nf_nat_sip_expected(struct nf_conn *ct, | 297 | static void nf_nat_sip_expected(struct nf_conn *ct, |
280 | struct nf_conntrack_expect *exp) | 298 | struct nf_conntrack_expect *exp) |
281 | { | 299 | { |
282 | struct nf_nat_range range; | 300 | struct nf_nat_range range; |
283 | 301 | ||
284 | /* This must be a fresh one. */ | 302 | /* This must be a fresh one. */ |
285 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | 303 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); |
286 | 304 | ||
287 | /* For DST manip, map port here to where it's expected. */ | 305 | /* For DST manip, map port here to where it's expected. */ |
288 | range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); | 306 | range.flags = (NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED); |
289 | range.min_proto = range.max_proto = exp->saved_proto; | 307 | range.min_proto = range.max_proto = exp->saved_proto; |
290 | range.min_addr = range.max_addr = exp->saved_addr; | 308 | range.min_addr = range.max_addr = exp->saved_addr; |
291 | nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); | 309 | nf_nat_setup_info(ct, &range, NF_NAT_MANIP_DST); |
292 | 310 | ||
293 | /* Change src to where master sends to, but only if the connection | 311 | /* Change src to where master sends to, but only if the connection |
294 | * actually came from the same source. */ | 312 | * actually came from the same source. */ |
295 | if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, | 313 | if (nf_inet_addr_cmp(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3, |
296 | &ct->master->tuplehash[exp->dir].tuple.src.u3)) { | 314 | &ct->master->tuplehash[exp->dir].tuple.src.u3)) { |
297 | range.flags = NF_NAT_RANGE_MAP_IPS; | 315 | range.flags = NF_NAT_RANGE_MAP_IPS; |
298 | range.min_addr = range.max_addr | 316 | range.min_addr = range.max_addr |
299 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3; | 317 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3; |
300 | nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); | 318 | nf_nat_setup_info(ct, &range, NF_NAT_MANIP_SRC); |
301 | } | 319 | } |
302 | } | 320 | } |
303 | 321 | ||
304 | static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, | 322 | static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff, |
305 | unsigned int dataoff, | 323 | unsigned int dataoff, |
306 | const char **dptr, unsigned int *datalen, | 324 | const char **dptr, unsigned int *datalen, |
307 | struct nf_conntrack_expect *exp, | 325 | struct nf_conntrack_expect *exp, |
308 | unsigned int matchoff, | 326 | unsigned int matchoff, |
309 | unsigned int matchlen) | 327 | unsigned int matchlen) |
310 | { | 328 | { |
311 | enum ip_conntrack_info ctinfo; | 329 | enum ip_conntrack_info ctinfo; |
312 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 330 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
313 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 331 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
332 | struct nf_ct_sip_master *ct_sip_info = nfct_help_data(ct); | ||
314 | union nf_inet_addr newaddr; | 333 | union nf_inet_addr newaddr; |
315 | u_int16_t port; | 334 | u_int16_t port; |
335 | __be16 srcport; | ||
316 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; | 336 | char buffer[INET6_ADDRSTRLEN + sizeof("[]:nnnnn")]; |
317 | unsigned int buflen; | 337 | unsigned int buflen; |
318 | 338 | ||
319 | /* Connection will come from reply */ | 339 | /* Connection will come from reply */ |
320 | if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | 340 | if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, |
321 | &ct->tuplehash[!dir].tuple.dst.u3)) | 341 | &ct->tuplehash[!dir].tuple.dst.u3)) |
322 | newaddr = exp->tuple.dst.u3; | 342 | newaddr = exp->tuple.dst.u3; |
323 | else | 343 | else |
324 | newaddr = ct->tuplehash[!dir].tuple.dst.u3; | 344 | newaddr = ct->tuplehash[!dir].tuple.dst.u3; |
325 | 345 | ||
326 | /* If the signalling port matches the connection's source port in the | 346 | /* If the signalling port matches the connection's source port in the |
327 | * original direction, try to use the destination port in the opposite | 347 | * original direction, try to use the destination port in the opposite |
328 | * direction. */ | 348 | * direction. */ |
329 | if (exp->tuple.dst.u.udp.port == | 349 | srcport = ct_sip_info->forced_dport ? : |
330 | ct->tuplehash[dir].tuple.src.u.udp.port) | 350 | ct->tuplehash[dir].tuple.src.u.udp.port; |
351 | if (exp->tuple.dst.u.udp.port == srcport) | ||
331 | port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); | 352 | port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); |
332 | else | 353 | else |
333 | port = ntohs(exp->tuple.dst.u.udp.port); | 354 | port = ntohs(exp->tuple.dst.u.udp.port); |
334 | 355 | ||
335 | exp->saved_addr = exp->tuple.dst.u3; | 356 | exp->saved_addr = exp->tuple.dst.u3; |
336 | exp->tuple.dst.u3 = newaddr; | 357 | exp->tuple.dst.u3 = newaddr; |
337 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; | 358 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; |
338 | exp->dir = !dir; | 359 | exp->dir = !dir; |
339 | exp->expectfn = nf_nat_sip_expected; | 360 | exp->expectfn = nf_nat_sip_expected; |
340 | 361 | ||
341 | for (; port != 0; port++) { | 362 | for (; port != 0; port++) { |
342 | int ret; | 363 | int ret; |
343 | 364 | ||
344 | exp->tuple.dst.u.udp.port = htons(port); | 365 | exp->tuple.dst.u.udp.port = htons(port); |
345 | ret = nf_ct_expect_related(exp); | 366 | ret = nf_ct_expect_related(exp); |
346 | if (ret == 0) | 367 | if (ret == 0) |
347 | break; | 368 | break; |
348 | else if (ret != -EBUSY) { | 369 | else if (ret != -EBUSY) { |
349 | port = 0; | 370 | port = 0; |
350 | break; | 371 | break; |
351 | } | 372 | } |
352 | } | 373 | } |
353 | 374 | ||
354 | if (port == 0) | 375 | if (port == 0) |
355 | return NF_DROP; | 376 | return NF_DROP; |
356 | 377 | ||
357 | if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || | 378 | if (!nf_inet_addr_cmp(&exp->tuple.dst.u3, &exp->saved_addr) || |
358 | exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { | 379 | exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { |
359 | buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); | 380 | buflen = sip_sprintf_addr_port(ct, buffer, &newaddr, port); |
360 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, | 381 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
361 | matchoff, matchlen, buffer, buflen)) | 382 | matchoff, matchlen, buffer, buflen)) |
362 | goto err; | 383 | goto err; |
363 | } | 384 | } |
364 | return NF_ACCEPT; | 385 | return NF_ACCEPT; |
365 | 386 | ||
366 | err: | 387 | err: |
367 | nf_ct_unexpect_related(exp); | 388 | nf_ct_unexpect_related(exp); |
368 | return NF_DROP; | 389 | return NF_DROP; |
369 | } | 390 | } |
370 | 391 | ||
371 | static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, | 392 | static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, |
372 | unsigned int dataoff, | 393 | unsigned int dataoff, |
373 | const char **dptr, unsigned int *datalen) | 394 | const char **dptr, unsigned int *datalen) |
374 | { | 395 | { |
375 | enum ip_conntrack_info ctinfo; | 396 | enum ip_conntrack_info ctinfo; |
376 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 397 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
377 | unsigned int matchoff, matchlen; | 398 | unsigned int matchoff, matchlen; |
378 | char buffer[sizeof("65536")]; | 399 | char buffer[sizeof("65536")]; |
379 | int buflen, c_len; | 400 | int buflen, c_len; |
380 | 401 | ||
381 | /* Get actual SDP length */ | 402 | /* Get actual SDP length */ |
382 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | 403 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, |
383 | SDP_HDR_VERSION, SDP_HDR_UNSPEC, | 404 | SDP_HDR_VERSION, SDP_HDR_UNSPEC, |
384 | &matchoff, &matchlen) <= 0) | 405 | &matchoff, &matchlen) <= 0) |
385 | return 0; | 406 | return 0; |
386 | c_len = *datalen - matchoff + strlen("v="); | 407 | c_len = *datalen - matchoff + strlen("v="); |
387 | 408 | ||
388 | /* Now, update SDP length */ | 409 | /* Now, update SDP length */ |
389 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, | 410 | if (ct_sip_get_header(ct, *dptr, 0, *datalen, SIP_HDR_CONTENT_LENGTH, |
390 | &matchoff, &matchlen) <= 0) | 411 | &matchoff, &matchlen) <= 0) |
391 | return 0; | 412 | return 0; |
392 | 413 | ||
393 | buflen = sprintf(buffer, "%u", c_len); | 414 | buflen = sprintf(buffer, "%u", c_len); |
394 | return mangle_packet(skb, protoff, dataoff, dptr, datalen, | 415 | return mangle_packet(skb, protoff, dataoff, dptr, datalen, |
395 | matchoff, matchlen, buffer, buflen); | 416 | matchoff, matchlen, buffer, buflen); |
396 | } | 417 | } |
397 | 418 | ||
398 | static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff, | 419 | static int mangle_sdp_packet(struct sk_buff *skb, unsigned int protoff, |
399 | unsigned int dataoff, | 420 | unsigned int dataoff, |
400 | const char **dptr, unsigned int *datalen, | 421 | const char **dptr, unsigned int *datalen, |
401 | unsigned int sdpoff, | 422 | unsigned int sdpoff, |
402 | enum sdp_header_types type, | 423 | enum sdp_header_types type, |
403 | enum sdp_header_types term, | 424 | enum sdp_header_types term, |
404 | char *buffer, int buflen) | 425 | char *buffer, int buflen) |
405 | { | 426 | { |
406 | enum ip_conntrack_info ctinfo; | 427 | enum ip_conntrack_info ctinfo; |
407 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 428 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
408 | unsigned int matchlen, matchoff; | 429 | unsigned int matchlen, matchoff; |
409 | 430 | ||
410 | if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term, | 431 | if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term, |
411 | &matchoff, &matchlen) <= 0) | 432 | &matchoff, &matchlen) <= 0) |
412 | return -ENOENT; | 433 | return -ENOENT; |
413 | return mangle_packet(skb, protoff, dataoff, dptr, datalen, | 434 | return mangle_packet(skb, protoff, dataoff, dptr, datalen, |
414 | matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL; | 435 | matchoff, matchlen, buffer, buflen) ? 0 : -EINVAL; |
415 | } | 436 | } |
416 | 437 | ||
417 | static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, | 438 | static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff, |
418 | unsigned int dataoff, | 439 | unsigned int dataoff, |
419 | const char **dptr, unsigned int *datalen, | 440 | const char **dptr, unsigned int *datalen, |
420 | unsigned int sdpoff, | 441 | unsigned int sdpoff, |
421 | enum sdp_header_types type, | 442 | enum sdp_header_types type, |
422 | enum sdp_header_types term, | 443 | enum sdp_header_types term, |
423 | const union nf_inet_addr *addr) | 444 | const union nf_inet_addr *addr) |
424 | { | 445 | { |
425 | enum ip_conntrack_info ctinfo; | 446 | enum ip_conntrack_info ctinfo; |
426 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 447 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
427 | char buffer[INET6_ADDRSTRLEN]; | 448 | char buffer[INET6_ADDRSTRLEN]; |
428 | unsigned int buflen; | 449 | unsigned int buflen; |
429 | 450 | ||
430 | buflen = sip_sprintf_addr(ct, buffer, addr, false); | 451 | buflen = sip_sprintf_addr(ct, buffer, addr, false); |
431 | if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, | 452 | if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, |
432 | sdpoff, type, term, buffer, buflen)) | 453 | sdpoff, type, term, buffer, buflen)) |
433 | return 0; | 454 | return 0; |
434 | 455 | ||
435 | return mangle_content_len(skb, protoff, dataoff, dptr, datalen); | 456 | return mangle_content_len(skb, protoff, dataoff, dptr, datalen); |
436 | } | 457 | } |
437 | 458 | ||
438 | static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, | 459 | static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff, |
439 | unsigned int dataoff, | 460 | unsigned int dataoff, |
440 | const char **dptr, unsigned int *datalen, | 461 | const char **dptr, unsigned int *datalen, |
441 | unsigned int matchoff, | 462 | unsigned int matchoff, |
442 | unsigned int matchlen, | 463 | unsigned int matchlen, |
443 | u_int16_t port) | 464 | u_int16_t port) |
444 | { | 465 | { |
445 | char buffer[sizeof("nnnnn")]; | 466 | char buffer[sizeof("nnnnn")]; |
446 | unsigned int buflen; | 467 | unsigned int buflen; |
447 | 468 | ||
448 | buflen = sprintf(buffer, "%u", port); | 469 | buflen = sprintf(buffer, "%u", port); |
449 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, | 470 | if (!mangle_packet(skb, protoff, dataoff, dptr, datalen, |
450 | matchoff, matchlen, buffer, buflen)) | 471 | matchoff, matchlen, buffer, buflen)) |
451 | return 0; | 472 | return 0; |
452 | 473 | ||
453 | return mangle_content_len(skb, protoff, dataoff, dptr, datalen); | 474 | return mangle_content_len(skb, protoff, dataoff, dptr, datalen); |
454 | } | 475 | } |
455 | 476 | ||
456 | static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff, | 477 | static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoff, |
457 | unsigned int dataoff, | 478 | unsigned int dataoff, |
458 | const char **dptr, unsigned int *datalen, | 479 | const char **dptr, unsigned int *datalen, |
459 | unsigned int sdpoff, | 480 | unsigned int sdpoff, |
460 | const union nf_inet_addr *addr) | 481 | const union nf_inet_addr *addr) |
461 | { | 482 | { |
462 | enum ip_conntrack_info ctinfo; | 483 | enum ip_conntrack_info ctinfo; |
463 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 484 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
464 | char buffer[INET6_ADDRSTRLEN]; | 485 | char buffer[INET6_ADDRSTRLEN]; |
465 | unsigned int buflen; | 486 | unsigned int buflen; |
466 | 487 | ||
467 | /* Mangle session description owner and contact addresses */ | 488 | /* Mangle session description owner and contact addresses */ |
468 | buflen = sip_sprintf_addr(ct, buffer, addr, false); | 489 | buflen = sip_sprintf_addr(ct, buffer, addr, false); |
469 | if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, | 490 | if (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, |
470 | SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) | 491 | SDP_HDR_OWNER, SDP_HDR_MEDIA, buffer, buflen)) |
471 | return 0; | 492 | return 0; |
472 | 493 | ||
473 | switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, | 494 | switch (mangle_sdp_packet(skb, protoff, dataoff, dptr, datalen, sdpoff, |
474 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, | 495 | SDP_HDR_CONNECTION, SDP_HDR_MEDIA, |
475 | buffer, buflen)) { | 496 | buffer, buflen)) { |
476 | case 0: | 497 | case 0: |
477 | /* | 498 | /* |
478 | * RFC 2327: | 499 | * RFC 2327: |
479 | * | 500 | * |
480 | * Session description | 501 | * Session description |
481 | * | 502 | * |
482 | * c=* (connection information - not required if included in all media) | 503 | * c=* (connection information - not required if included in all media) |
483 | */ | 504 | */ |
484 | case -ENOENT: | 505 | case -ENOENT: |
485 | break; | 506 | break; |
486 | default: | 507 | default: |
487 | return 0; | 508 | return 0; |
488 | } | 509 | } |
489 | 510 | ||
490 | return mangle_content_len(skb, protoff, dataoff, dptr, datalen); | 511 | return mangle_content_len(skb, protoff, dataoff, dptr, datalen); |
491 | } | 512 | } |
492 | 513 | ||
493 | /* So, this packet has hit the connection tracking matching code. | 514 | /* So, this packet has hit the connection tracking matching code. |
494 | Mangle it, and change the expectation to match the new version. */ | 515 | Mangle it, and change the expectation to match the new version. */ |
495 | static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff, | 516 | static unsigned int nf_nat_sdp_media(struct sk_buff *skb, unsigned int protoff, |
496 | unsigned int dataoff, | 517 | unsigned int dataoff, |
497 | const char **dptr, unsigned int *datalen, | 518 | const char **dptr, unsigned int *datalen, |
498 | struct nf_conntrack_expect *rtp_exp, | 519 | struct nf_conntrack_expect *rtp_exp, |
499 | struct nf_conntrack_expect *rtcp_exp, | 520 | struct nf_conntrack_expect *rtcp_exp, |
500 | unsigned int mediaoff, | 521 | unsigned int mediaoff, |
501 | unsigned int medialen, | 522 | unsigned int medialen, |
502 | union nf_inet_addr *rtp_addr) | 523 | union nf_inet_addr *rtp_addr) |
503 | { | 524 | { |
504 | enum ip_conntrack_info ctinfo; | 525 | enum ip_conntrack_info ctinfo; |
505 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 526 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
506 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 527 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
507 | u_int16_t port; | 528 | u_int16_t port; |
508 | 529 | ||
509 | /* Connection will come from reply */ | 530 | /* Connection will come from reply */ |
510 | if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, | 531 | if (nf_inet_addr_cmp(&ct->tuplehash[dir].tuple.src.u3, |
511 | &ct->tuplehash[!dir].tuple.dst.u3)) | 532 | &ct->tuplehash[!dir].tuple.dst.u3)) |
512 | *rtp_addr = rtp_exp->tuple.dst.u3; | 533 | *rtp_addr = rtp_exp->tuple.dst.u3; |
513 | else | 534 | else |
514 | *rtp_addr = ct->tuplehash[!dir].tuple.dst.u3; | 535 | *rtp_addr = ct->tuplehash[!dir].tuple.dst.u3; |
515 | 536 | ||
516 | rtp_exp->saved_addr = rtp_exp->tuple.dst.u3; | 537 | rtp_exp->saved_addr = rtp_exp->tuple.dst.u3; |
517 | rtp_exp->tuple.dst.u3 = *rtp_addr; | 538 | rtp_exp->tuple.dst.u3 = *rtp_addr; |
518 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | 539 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; |
519 | rtp_exp->dir = !dir; | 540 | rtp_exp->dir = !dir; |
520 | rtp_exp->expectfn = nf_nat_sip_expected; | 541 | rtp_exp->expectfn = nf_nat_sip_expected; |
521 | 542 | ||
522 | rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3; | 543 | rtcp_exp->saved_addr = rtcp_exp->tuple.dst.u3; |
523 | rtcp_exp->tuple.dst.u3 = *rtp_addr; | 544 | rtcp_exp->tuple.dst.u3 = *rtp_addr; |
524 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | 545 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; |
525 | rtcp_exp->dir = !dir; | 546 | rtcp_exp->dir = !dir; |
526 | rtcp_exp->expectfn = nf_nat_sip_expected; | 547 | rtcp_exp->expectfn = nf_nat_sip_expected; |
527 | 548 | ||
528 | /* Try to get same pair of ports: if not, try to change them. */ | 549 | /* Try to get same pair of ports: if not, try to change them. */ |
529 | for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); | 550 | for (port = ntohs(rtp_exp->tuple.dst.u.udp.port); |
530 | port != 0; port += 2) { | 551 | port != 0; port += 2) { |
531 | int ret; | 552 | int ret; |
532 | 553 | ||
533 | rtp_exp->tuple.dst.u.udp.port = htons(port); | 554 | rtp_exp->tuple.dst.u.udp.port = htons(port); |
534 | ret = nf_ct_expect_related(rtp_exp); | 555 | ret = nf_ct_expect_related(rtp_exp); |
535 | if (ret == -EBUSY) | 556 | if (ret == -EBUSY) |
536 | continue; | 557 | continue; |
537 | else if (ret < 0) { | 558 | else if (ret < 0) { |
538 | port = 0; | 559 | port = 0; |
539 | break; | 560 | break; |
540 | } | 561 | } |
541 | rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); | 562 | rtcp_exp->tuple.dst.u.udp.port = htons(port + 1); |
542 | ret = nf_ct_expect_related(rtcp_exp); | 563 | ret = nf_ct_expect_related(rtcp_exp); |
543 | if (ret == 0) | 564 | if (ret == 0) |
544 | break; | 565 | break; |
545 | else if (ret == -EBUSY) { | 566 | else if (ret == -EBUSY) { |
546 | nf_ct_unexpect_related(rtp_exp); | 567 | nf_ct_unexpect_related(rtp_exp); |
547 | continue; | 568 | continue; |
548 | } else if (ret < 0) { | 569 | } else if (ret < 0) { |
549 | nf_ct_unexpect_related(rtp_exp); | 570 | nf_ct_unexpect_related(rtp_exp); |
550 | port = 0; | 571 | port = 0; |
551 | break; | 572 | break; |
552 | } | 573 | } |
553 | } | 574 | } |
554 | 575 | ||
555 | if (port == 0) | 576 | if (port == 0) |
556 | goto err1; | 577 | goto err1; |
557 | 578 | ||
558 | /* Update media port. */ | 579 | /* Update media port. */ |
559 | if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && | 580 | if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && |
560 | !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen, | 581 | !nf_nat_sdp_port(skb, protoff, dataoff, dptr, datalen, |
561 | mediaoff, medialen, port)) | 582 | mediaoff, medialen, port)) |
562 | goto err2; | 583 | goto err2; |
563 | 584 | ||
564 | return NF_ACCEPT; | 585 | return NF_ACCEPT; |
565 | 586 | ||
566 | err2: | 587 | err2: |
567 | nf_ct_unexpect_related(rtp_exp); | 588 | nf_ct_unexpect_related(rtp_exp); |
568 | nf_ct_unexpect_related(rtcp_exp); | 589 | nf_ct_unexpect_related(rtcp_exp); |
569 | err1: | 590 | err1: |
570 | return NF_DROP; | 591 | return NF_DROP; |
571 | } | 592 | } |
572 | 593 | ||
573 | static struct nf_ct_helper_expectfn sip_nat = { | 594 | static struct nf_ct_helper_expectfn sip_nat = { |
574 | .name = "sip", | 595 | .name = "sip", |
575 | .expectfn = nf_nat_sip_expected, | 596 | .expectfn = nf_nat_sip_expected, |
576 | }; | 597 | }; |
577 | 598 | ||
578 | static void __exit nf_nat_sip_fini(void) | 599 | static void __exit nf_nat_sip_fini(void) |
579 | { | 600 | { |
580 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); | 601 | RCU_INIT_POINTER(nf_nat_sip_hook, NULL); |
581 | RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL); | 602 | RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, NULL); |
582 | RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL); | 603 | RCU_INIT_POINTER(nf_nat_sip_expect_hook, NULL); |
583 | RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL); | 604 | RCU_INIT_POINTER(nf_nat_sdp_addr_hook, NULL); |
584 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); | 605 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, NULL); |
585 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); | 606 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, NULL); |
586 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); | 607 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, NULL); |
587 | nf_ct_helper_expectfn_unregister(&sip_nat); | 608 | nf_ct_helper_expectfn_unregister(&sip_nat); |
588 | synchronize_rcu(); | 609 | synchronize_rcu(); |
589 | } | 610 | } |
590 | 611 | ||
591 | static int __init nf_nat_sip_init(void) | 612 | static int __init nf_nat_sip_init(void) |
592 | { | 613 | { |
593 | BUG_ON(nf_nat_sip_hook != NULL); | 614 | BUG_ON(nf_nat_sip_hook != NULL); |
594 | BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); | 615 | BUG_ON(nf_nat_sip_seq_adjust_hook != NULL); |
595 | BUG_ON(nf_nat_sip_expect_hook != NULL); | 616 | BUG_ON(nf_nat_sip_expect_hook != NULL); |
596 | BUG_ON(nf_nat_sdp_addr_hook != NULL); | 617 | BUG_ON(nf_nat_sdp_addr_hook != NULL); |
597 | BUG_ON(nf_nat_sdp_port_hook != NULL); | 618 | BUG_ON(nf_nat_sdp_port_hook != NULL); |
598 | BUG_ON(nf_nat_sdp_session_hook != NULL); | 619 | BUG_ON(nf_nat_sdp_session_hook != NULL); |
599 | BUG_ON(nf_nat_sdp_media_hook != NULL); | 620 | BUG_ON(nf_nat_sdp_media_hook != NULL); |
600 | RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip); | 621 | RCU_INIT_POINTER(nf_nat_sip_hook, nf_nat_sip); |
601 | RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust); | 622 | RCU_INIT_POINTER(nf_nat_sip_seq_adjust_hook, nf_nat_sip_seq_adjust); |
602 | RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect); | 623 | RCU_INIT_POINTER(nf_nat_sip_expect_hook, nf_nat_sip_expect); |
603 | RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr); | 624 | RCU_INIT_POINTER(nf_nat_sdp_addr_hook, nf_nat_sdp_addr); |
604 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port); | 625 | RCU_INIT_POINTER(nf_nat_sdp_port_hook, nf_nat_sdp_port); |
605 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session); | 626 | RCU_INIT_POINTER(nf_nat_sdp_session_hook, nf_nat_sdp_session); |
606 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media); | 627 | RCU_INIT_POINTER(nf_nat_sdp_media_hook, nf_nat_sdp_media); |
607 | nf_ct_helper_expectfn_register(&sip_nat); | 628 | nf_ct_helper_expectfn_register(&sip_nat); |
608 | return 0; | 629 | return 0; |
609 | } | 630 | } |
610 | 631 | ||
611 | module_init(nf_nat_sip_init); | 632 | module_init(nf_nat_sip_init); |
612 | module_exit(nf_nat_sip_fini); | 633 | module_exit(nf_nat_sip_fini); |
613 | 634 |