diff options
Diffstat (limited to 'net/ipv4')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 121 |
1 files changed, 84 insertions, 37 deletions
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index f73ab4883b75..4429069d9b42 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -316,45 +316,77 @@ static int mangle_content_len(struct sk_buff *skb, | |||
316 | buffer, buflen); | 316 | buffer, buflen); |
317 | } | 317 | } |
318 | 318 | ||
319 | static unsigned mangle_sdp_packet(struct sk_buff *skb, | 319 | static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr, |
320 | const char **dptr, unsigned int *datalen, | 320 | unsigned int dataoff, unsigned int *datalen, |
321 | enum sdp_header_types type, | 321 | enum sdp_header_types type, |
322 | enum sdp_header_types term, | ||
322 | char *buffer, int buflen) | 323 | char *buffer, int buflen) |
323 | { | 324 | { |
324 | enum ip_conntrack_info ctinfo; | 325 | enum ip_conntrack_info ctinfo; |
325 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 326 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
326 | unsigned int matchlen, matchoff; | 327 | unsigned int matchlen, matchoff; |
327 | 328 | ||
328 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC, | 329 | if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term, |
329 | &matchoff, &matchlen) <= 0) | 330 | &matchoff, &matchlen) <= 0) |
330 | return 0; | 331 | return 0; |
331 | return mangle_packet(skb, dptr, datalen, matchoff, matchlen, | 332 | return mangle_packet(skb, dptr, datalen, matchoff, matchlen, |
332 | buffer, buflen); | 333 | buffer, buflen); |
333 | } | 334 | } |
334 | 335 | ||
335 | static unsigned int mangle_sdp(struct sk_buff *skb, | 336 | static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, |
336 | enum ip_conntrack_info ctinfo, | 337 | unsigned int dataoff, |
337 | struct nf_conn *ct, | 338 | unsigned int *datalen, |
338 | __be32 newip, u_int16_t port, | 339 | enum sdp_header_types type, |
339 | const char **dptr, unsigned int *datalen) | 340 | enum sdp_header_types term, |
341 | const union nf_inet_addr *addr) | ||
340 | { | 342 | { |
341 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; | 343 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; |
342 | unsigned int bufflen; | 344 | unsigned int buflen; |
343 | 345 | ||
344 | /* Mangle owner and contact info. */ | 346 | buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip)); |
345 | bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); | 347 | if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, |
346 | if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4, | 348 | buffer, buflen)) |
347 | buffer, bufflen)) | ||
348 | return 0; | 349 | return 0; |
349 | 350 | ||
350 | if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4, | 351 | return mangle_content_len(skb, dptr, datalen); |
351 | buffer, bufflen)) | 352 | } |
353 | |||
354 | static unsigned int ip_nat_sdp_port(struct sk_buff *skb, | ||
355 | const char **dptr, | ||
356 | unsigned int *datalen, | ||
357 | unsigned int matchoff, | ||
358 | unsigned int matchlen, | ||
359 | u_int16_t port) | ||
360 | { | ||
361 | char buffer[sizeof("nnnnn")]; | ||
362 | unsigned int buflen; | ||
363 | |||
364 | buflen = sprintf(buffer, "%u", port); | ||
365 | if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, | ||
366 | buffer, buflen)) | ||
352 | return 0; | 367 | return 0; |
353 | 368 | ||
354 | /* Mangle media port. */ | 369 | return mangle_content_len(skb, dptr, datalen); |
355 | bufflen = sprintf(buffer, "%u", port); | 370 | } |
356 | if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA, | 371 | |
357 | buffer, bufflen)) | 372 | static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, |
373 | unsigned int dataoff, | ||
374 | unsigned int *datalen, | ||
375 | const union nf_inet_addr *addr) | ||
376 | { | ||
377 | char buffer[sizeof("nnn.nnn.nnn.nnn")]; | ||
378 | unsigned int buflen; | ||
379 | |||
380 | /* Mangle session description owner and contact addresses */ | ||
381 | buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip)); | ||
382 | if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, | ||
383 | SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, | ||
384 | buffer, buflen)) | ||
385 | return 0; | ||
386 | |||
387 | if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, | ||
388 | SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA, | ||
389 | buffer, buflen)) | ||
358 | return 0; | 390 | return 0; |
359 | 391 | ||
360 | return mangle_content_len(skb, dptr, datalen); | 392 | return mangle_content_len(skb, dptr, datalen); |
@@ -362,32 +394,35 @@ static unsigned int mangle_sdp(struct sk_buff *skb, | |||
362 | 394 | ||
363 | /* So, this packet has hit the connection tracking matching code. | 395 | /* So, this packet has hit the connection tracking matching code. |
364 | Mangle it, and change the expectation to match the new version. */ | 396 | Mangle it, and change the expectation to match the new version. */ |
365 | static unsigned int ip_nat_sdp(struct sk_buff *skb, | 397 | static unsigned int ip_nat_sdp_media(struct sk_buff *skb, |
366 | const char **dptr, unsigned int *datalen, | 398 | const char **dptr, |
367 | struct nf_conntrack_expect *rtp_exp, | 399 | unsigned int *datalen, |
368 | struct nf_conntrack_expect *rtcp_exp) | 400 | struct nf_conntrack_expect *rtp_exp, |
401 | struct nf_conntrack_expect *rtcp_exp, | ||
402 | unsigned int mediaoff, | ||
403 | unsigned int medialen, | ||
404 | union nf_inet_addr *rtp_addr) | ||
369 | { | 405 | { |
370 | enum ip_conntrack_info ctinfo; | 406 | enum ip_conntrack_info ctinfo; |
371 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 407 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
372 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 408 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
373 | __be32 newip; | ||
374 | u_int16_t port; | 409 | u_int16_t port; |
375 | 410 | ||
376 | /* Connection will come from reply */ | 411 | /* Connection will come from reply */ |
377 | if (ct->tuplehash[dir].tuple.src.u3.ip == | 412 | if (ct->tuplehash[dir].tuple.src.u3.ip == |
378 | ct->tuplehash[!dir].tuple.dst.u3.ip) | 413 | ct->tuplehash[!dir].tuple.dst.u3.ip) |
379 | newip = rtp_exp->tuple.dst.u3.ip; | 414 | rtp_addr->ip = rtp_exp->tuple.dst.u3.ip; |
380 | else | 415 | else |
381 | newip = ct->tuplehash[!dir].tuple.dst.u3.ip; | 416 | rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip; |
382 | 417 | ||
383 | rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; | 418 | rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip; |
384 | rtp_exp->tuple.dst.u3.ip = newip; | 419 | rtp_exp->tuple.dst.u3.ip = rtp_addr->ip; |
385 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; | 420 | rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port; |
386 | rtp_exp->dir = !dir; | 421 | rtp_exp->dir = !dir; |
387 | rtp_exp->expectfn = ip_nat_sip_expected; | 422 | rtp_exp->expectfn = ip_nat_sip_expected; |
388 | 423 | ||
389 | rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; | 424 | rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip; |
390 | rtcp_exp->tuple.dst.u3.ip = newip; | 425 | rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip; |
391 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; | 426 | rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port; |
392 | rtcp_exp->dir = !dir; | 427 | rtcp_exp->dir = !dir; |
393 | rtcp_exp->expectfn = ip_nat_sip_expected; | 428 | rtcp_exp->expectfn = ip_nat_sip_expected; |
@@ -405,21 +440,29 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb, | |||
405 | } | 440 | } |
406 | 441 | ||
407 | if (port == 0) | 442 | if (port == 0) |
408 | return NF_DROP; | 443 | goto err1; |
444 | |||
445 | /* Update media port. */ | ||
446 | if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port && | ||
447 | !ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port)) | ||
448 | goto err2; | ||
409 | 449 | ||
410 | if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) { | ||
411 | nf_ct_unexpect_related(rtp_exp); | ||
412 | nf_ct_unexpect_related(rtcp_exp); | ||
413 | return NF_DROP; | ||
414 | } | ||
415 | return NF_ACCEPT; | 450 | return NF_ACCEPT; |
451 | |||
452 | err2: | ||
453 | nf_ct_unexpect_related(rtp_exp); | ||
454 | nf_ct_unexpect_related(rtcp_exp); | ||
455 | err1: | ||
456 | return NF_DROP; | ||
416 | } | 457 | } |
417 | 458 | ||
418 | static void __exit nf_nat_sip_fini(void) | 459 | static void __exit nf_nat_sip_fini(void) |
419 | { | 460 | { |
420 | rcu_assign_pointer(nf_nat_sip_hook, NULL); | 461 | rcu_assign_pointer(nf_nat_sip_hook, NULL); |
421 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); | 462 | rcu_assign_pointer(nf_nat_sip_expect_hook, NULL); |
422 | rcu_assign_pointer(nf_nat_sdp_hook, NULL); | 463 | rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL); |
464 | rcu_assign_pointer(nf_nat_sdp_session_hook, NULL); | ||
465 | rcu_assign_pointer(nf_nat_sdp_media_hook, NULL); | ||
423 | synchronize_rcu(); | 466 | synchronize_rcu(); |
424 | } | 467 | } |
425 | 468 | ||
@@ -427,10 +470,14 @@ static int __init nf_nat_sip_init(void) | |||
427 | { | 470 | { |
428 | BUG_ON(nf_nat_sip_hook != NULL); | 471 | BUG_ON(nf_nat_sip_hook != NULL); |
429 | BUG_ON(nf_nat_sip_expect_hook != NULL); | 472 | BUG_ON(nf_nat_sip_expect_hook != NULL); |
430 | BUG_ON(nf_nat_sdp_hook != NULL); | 473 | BUG_ON(nf_nat_sdp_addr_hook != NULL); |
474 | BUG_ON(nf_nat_sdp_session_hook != NULL); | ||
475 | BUG_ON(nf_nat_sdp_media_hook != NULL); | ||
431 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); | 476 | rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip); |
432 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); | 477 | rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect); |
433 | rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp); | 478 | rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr); |
479 | rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session); | ||
480 | rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media); | ||
434 | return 0; | 481 | return 0; |
435 | } | 482 | } |
436 | 483 | ||