diff options
author | Patrick McHardy <kaber@trash.net> | 2008-03-25 23:25:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2008-03-25 23:25:13 -0400 |
commit | 0f32a40fc91a9ebbbf66e826ac2a829ab37d9cf8 (patch) | |
tree | 0c221d19a91fa5ab4d746480438ea0f47031062d /net/ipv4 | |
parent | c978cd3a937141deaf7995b849824af6dacdeae7 (diff) |
[NETFILTER]: nf_conntrack_sip: create signalling expectations
Create expectations for incoming signalling connections when seeing
a REGISTER request. This is needed when the registrar uses a
different source port number for signalling messages and for receiving
incoming calls from other endpoints than the registrar.
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 111 |
1 files changed, 89 insertions, 22 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index b443618a85..4b85e21a2a 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -205,6 +205,91 @@ next: | |||
205 | return NF_ACCEPT; | 205 | return NF_ACCEPT; |
206 | } | 206 | } |
207 | 207 | ||
208 | /* Handles expected signalling connections and media streams */ | ||
209 | static void ip_nat_sip_expected(struct nf_conn *ct, | ||
210 | struct nf_conntrack_expect *exp) | ||
211 | { | ||
212 | struct nf_nat_range range; | ||
213 | |||
214 | /* This must be a fresh one. */ | ||
215 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
216 | |||
217 | /* For DST manip, map port here to where it's expected. */ | ||
218 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
219 | range.min = range.max = exp->saved_proto; | ||
220 | range.min_ip = range.max_ip = exp->saved_ip; | ||
221 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); | ||
222 | |||
223 | /* Change src to where master sends to, but only if the connection | ||
224 | * actually came from the same source. */ | ||
225 | if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == | ||
226 | ct->master->tuplehash[exp->dir].tuple.src.u3.ip) { | ||
227 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
228 | range.min_ip = range.max_ip | ||
229 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
230 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); | ||
231 | } | ||
232 | } | ||
233 | |||
234 | static unsigned int ip_nat_sip_expect(struct sk_buff *skb, | ||
235 | const char **dptr, unsigned int *datalen, | ||
236 | struct nf_conntrack_expect *exp, | ||
237 | unsigned int matchoff, | ||
238 | unsigned int matchlen) | ||
239 | { | ||
240 | enum ip_conntrack_info ctinfo; | ||
241 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
242 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | ||
243 | __be32 newip; | ||
244 | u_int16_t port; | ||
245 | char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; | ||
246 | unsigned buflen; | ||
247 | |||
248 | /* Connection will come from reply */ | ||
249 | if (ct->tuplehash[dir].tuple.src.u3.ip == ct->tuplehash[!dir].tuple.dst.u3.ip) | ||
250 | newip = exp->tuple.dst.u3.ip; | ||
251 | else | ||
252 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | ||
253 | |||
254 | /* If the signalling port matches the connection's source port in the | ||
255 | * original direction, try to use the destination port in the opposite | ||
256 | * direction. */ | ||
257 | if (exp->tuple.dst.u.udp.port == | ||
258 | ct->tuplehash[dir].tuple.src.u.udp.port) | ||
259 | port = ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port); | ||
260 | else | ||
261 | port = ntohs(exp->tuple.dst.u.udp.port); | ||
262 | |||
263 | exp->saved_ip = exp->tuple.dst.u3.ip; | ||
264 | exp->tuple.dst.u3.ip = newip; | ||
265 | exp->saved_proto.udp.port = exp->tuple.dst.u.udp.port; | ||
266 | exp->dir = !dir; | ||
267 | exp->expectfn = ip_nat_sip_expected; | ||
268 | |||
269 | for (; port != 0; port++) { | ||
270 | exp->tuple.dst.u.udp.port = htons(port); | ||
271 | if (nf_ct_expect_related(exp) == 0) | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | if (port == 0) | ||
276 | return NF_DROP; | ||
277 | |||
278 | if (exp->tuple.dst.u3.ip != exp->saved_ip || | ||
279 | exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { | ||
280 | buflen = sprintf(buffer, "%u.%u.%u.%u:%u", | ||
281 | NIPQUAD(newip), port); | ||
282 | if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, | ||
283 | buffer, buflen)) | ||
284 | goto err; | ||
285 | } | ||
286 | return NF_ACCEPT; | ||
287 | |||
288 | err: | ||
289 | nf_ct_unexpect_related(exp); | ||
290 | return NF_DROP; | ||
291 | } | ||
292 | |||
208 | static int mangle_content_len(struct sk_buff *skb, | 293 | static int mangle_content_len(struct sk_buff *skb, |
209 | const char **dptr, unsigned int *datalen) | 294 | const char **dptr, unsigned int *datalen) |
210 | { | 295 | { |
@@ -275,27 +360,6 @@ static unsigned int mangle_sdp(struct sk_buff *skb, | |||
275 | return mangle_content_len(skb, dptr, datalen); | 360 | return mangle_content_len(skb, dptr, datalen); |
276 | } | 361 | } |
277 | 362 | ||
278 | static void ip_nat_sdp_expect(struct nf_conn *ct, | ||
279 | struct nf_conntrack_expect *exp) | ||
280 | { | ||
281 | struct nf_nat_range range; | ||
282 | |||
283 | /* This must be a fresh one. */ | ||
284 | BUG_ON(ct->status & IPS_NAT_DONE_MASK); | ||
285 | |||
286 | /* For DST manip, map port here to where it's expected. */ | ||
287 | range.flags = (IP_NAT_RANGE_MAP_IPS | IP_NAT_RANGE_PROTO_SPECIFIED); | ||
288 | range.min = range.max = exp->saved_proto; | ||
289 | range.min_ip = range.max_ip = exp->saved_ip; | ||
290 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); | ||
291 | |||
292 | /* Change src to where master sends to */ | ||
293 | range.flags = IP_NAT_RANGE_MAP_IPS; | ||
294 | range.min_ip = range.max_ip | ||
295 | = ct->master->tuplehash[!exp->dir].tuple.dst.u3.ip; | ||
296 | nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); | ||
297 | } | ||
298 | |||
299 | /* So, this packet has hit the connection tracking matching code. | 363 | /* So, this packet has hit the connection tracking matching code. |
300 | Mangle it, and change the expectation to match the new version. */ | 364 | Mangle it, and change the expectation to match the new version. */ |
301 | static unsigned int ip_nat_sdp(struct sk_buff *skb, | 365 | static unsigned int ip_nat_sdp(struct sk_buff *skb, |
@@ -322,7 +386,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
322 | 386 | ||
323 | /* When you see the packet, we need to NAT it the same as the | 387 | /* When you see the packet, we need to NAT it the same as the |
324 | this one. */ | 388 | this one. */ |
325 | exp->expectfn = ip_nat_sdp_expect; | 389 | exp->expectfn = ip_nat_sip_expected; |
326 | 390 | ||
327 | /* Try to get same port: if not, try to change it. */ | 391 | /* Try to get same port: if not, try to change it. */ |
328 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { | 392 | for (port = ntohs(exp->saved_proto.udp.port); port != 0; port++) { |
@@ -344,6 +408,7 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
344 | static void __exit nf_nat_sip_fini(void) | 408 | static void __exit nf_nat_sip_fini(void) |
345 | { | 409 | { |
346 | rcu_assign_pointer(nf_nat_sip_hook, NULL); | 410 | rcu_assign_pointer(nf_nat_sip_hook, NULL); |
411 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); | ||
347 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); | 412 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); |
348 | synchronize_rcu(); | 413 | synchronize_rcu(); |
349 | } | 414 | } |
@@ -351,8 +416,10 @@ static void __exit nf_nat_sip_fini(void) | |||
351 | static int __init nf_nat_sip_init(void) | 416 | static int __init nf_nat_sip_init(void) |
352 | { | 417 | { |
353 | BUG_ON(nf_nat_sip_hook != NULL); | 418 | BUG_ON(nf_nat_sip_hook != NULL); |
419 | BUG_ON(nf_nat_sip_expect_hook != NULL); | ||
354 | BUG_ON(nf_nat_sdp_hook != NULL); | 420 | BUG_ON(nf_nat_sdp_hook != NULL); |
355 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); | 421 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); |
422 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); | ||
356 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); | 423 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); |
357 | return 0; | 424 | return 0; |
358 | } | 425 | } |