diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 121 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 142 |
2 files changed, 199 insertions, 64 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 | ||
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 217262e23403..f929add324f3 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -60,13 +60,34 @@ unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb, | |||
60 | unsigned int matchlen) __read_mostly; | 60 | unsigned int matchlen) __read_mostly; |
61 | EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); | 61 | EXPORT_SYMBOL_GPL(nf_nat_sip_expect_hook); |
62 | 62 | ||
63 | unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | 63 | unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb, |
64 | const char **dptr, | 64 | const char **dptr, |
65 | unsigned int *datalen, | 65 | unsigned int dataoff, |
66 | struct nf_conntrack_expect *rtp_exp, | 66 | unsigned int *datalen, |
67 | struct nf_conntrack_expect *rtcp_exp) | 67 | enum sdp_header_types type, |
68 | __read_mostly; | 68 | enum sdp_header_types term, |
69 | EXPORT_SYMBOL_GPL(nf_nat_sdp_hook); | 69 | const union nf_inet_addr *addr) |
70 | __read_mostly; | ||
71 | EXPORT_SYMBOL_GPL(nf_nat_sdp_addr_hook); | ||
72 | |||
73 | unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb, | ||
74 | const char **dptr, | ||
75 | unsigned int dataoff, | ||
76 | unsigned int *datalen, | ||
77 | const union nf_inet_addr *addr) | ||
78 | __read_mostly; | ||
79 | EXPORT_SYMBOL_GPL(nf_nat_sdp_session_hook); | ||
80 | |||
81 | unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb, | ||
82 | const char **dptr, | ||
83 | unsigned int *datalen, | ||
84 | struct nf_conntrack_expect *rtp_exp, | ||
85 | struct nf_conntrack_expect *rtcp_exp, | ||
86 | unsigned int mediaoff, | ||
87 | unsigned int medialen, | ||
88 | union nf_inet_addr *rtp_addr) | ||
89 | __read_mostly; | ||
90 | EXPORT_SYMBOL_GPL(nf_nat_sdp_media_hook); | ||
70 | 91 | ||
71 | static int string_len(const struct nf_conn *ct, const char *dptr, | 92 | static int string_len(const struct nf_conn *ct, const char *dptr, |
72 | const char *limit, int *shift) | 93 | const char *limit, int *shift) |
@@ -613,6 +634,26 @@ int ct_sip_get_sdp_header(const struct nf_conn *ct, const char *dptr, | |||
613 | } | 634 | } |
614 | EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); | 635 | EXPORT_SYMBOL_GPL(ct_sip_get_sdp_header); |
615 | 636 | ||
637 | static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr, | ||
638 | unsigned int dataoff, unsigned int datalen, | ||
639 | enum sdp_header_types type, | ||
640 | enum sdp_header_types term, | ||
641 | unsigned int *matchoff, unsigned int *matchlen, | ||
642 | union nf_inet_addr *addr) | ||
643 | { | ||
644 | int ret; | ||
645 | |||
646 | ret = ct_sip_get_sdp_header(ct, dptr, dataoff, datalen, type, term, | ||
647 | matchoff, matchlen); | ||
648 | if (ret <= 0) | ||
649 | return ret; | ||
650 | |||
651 | if (!parse_addr(ct, dptr + *matchoff, NULL, addr, | ||
652 | dptr + *matchoff + *matchlen)) | ||
653 | return -1; | ||
654 | return 1; | ||
655 | } | ||
656 | |||
616 | static int refresh_signalling_expectation(struct nf_conn *ct, | 657 | static int refresh_signalling_expectation(struct nf_conn *ct, |
617 | union nf_inet_addr *addr, | 658 | union nf_inet_addr *addr, |
618 | __be16 port, | 659 | __be16 port, |
@@ -663,7 +704,8 @@ static void flush_expectations(struct nf_conn *ct, bool media) | |||
663 | 704 | ||
664 | static int set_expected_rtp_rtcp(struct sk_buff *skb, | 705 | static int set_expected_rtp_rtcp(struct sk_buff *skb, |
665 | const char **dptr, unsigned int *datalen, | 706 | const char **dptr, unsigned int *datalen, |
666 | union nf_inet_addr *daddr, __be16 port) | 707 | union nf_inet_addr *daddr, __be16 port, |
708 | unsigned int mediaoff, unsigned int medialen) | ||
667 | { | 709 | { |
668 | struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; | 710 | struct nf_conntrack_expect *exp, *rtp_exp, *rtcp_exp; |
669 | enum ip_conntrack_info ctinfo; | 711 | enum ip_conntrack_info ctinfo; |
@@ -675,7 +717,7 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, | |||
675 | int skip_expect = 0, ret = NF_DROP; | 717 | int skip_expect = 0, ret = NF_DROP; |
676 | u_int16_t base_port; | 718 | u_int16_t base_port; |
677 | __be16 rtp_port, rtcp_port; | 719 | __be16 rtp_port, rtcp_port; |
678 | typeof(nf_nat_sdp_hook) nf_nat_sdp; | 720 | typeof(nf_nat_sdp_media_hook) nf_nat_sdp_media; |
679 | 721 | ||
680 | saddr = NULL; | 722 | saddr = NULL; |
681 | if (sip_direct_media) { | 723 | if (sip_direct_media) { |
@@ -724,9 +766,10 @@ static int set_expected_rtp_rtcp(struct sk_buff *skb, | |||
724 | nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, | 766 | nf_ct_expect_init(rtcp_exp, SIP_EXPECT_AUDIO, family, saddr, daddr, |
725 | IPPROTO_UDP, NULL, &rtcp_port); | 767 | IPPROTO_UDP, NULL, &rtcp_port); |
726 | 768 | ||
727 | nf_nat_sdp = rcu_dereference(nf_nat_sdp_hook); | 769 | nf_nat_sdp_media = rcu_dereference(nf_nat_sdp_media_hook); |
728 | if (nf_nat_sdp && ct->status & IPS_NAT_MASK) | 770 | if (nf_nat_sdp_media && ct->status & IPS_NAT_MASK) |
729 | ret = nf_nat_sdp(skb, dptr, datalen, rtp_exp, rtcp_exp); | 771 | ret = nf_nat_sdp_media(skb, dptr, datalen, rtp_exp, rtcp_exp, |
772 | mediaoff, medialen, daddr); | ||
730 | else { | 773 | else { |
731 | if (nf_ct_expect_related(rtp_exp) == 0) { | 774 | if (nf_ct_expect_related(rtp_exp) == 0) { |
732 | if (nf_ct_expect_related(rtcp_exp) != 0) | 775 | if (nf_ct_expect_related(rtcp_exp) != 0) |
@@ -750,33 +793,78 @@ static int process_sdp(struct sk_buff *skb, | |||
750 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 793 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
751 | int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; | 794 | int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; |
752 | unsigned int matchoff, matchlen; | 795 | unsigned int matchoff, matchlen; |
753 | union nf_inet_addr addr; | 796 | unsigned int mediaoff, medialen; |
797 | unsigned int sdpoff; | ||
798 | unsigned int caddr_len, maddr_len; | ||
799 | union nf_inet_addr caddr, maddr, rtp_addr; | ||
754 | unsigned int port; | 800 | unsigned int port; |
755 | enum sdp_header_types type; | 801 | enum sdp_header_types c_hdr; |
802 | int ret; | ||
803 | typeof(nf_nat_sdp_addr_hook) nf_nat_sdp_addr; | ||
804 | typeof(nf_nat_sdp_session_hook) nf_nat_sdp_session; | ||
756 | 805 | ||
757 | /* Get address and port from SDP packet. */ | 806 | c_hdr = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : |
758 | type = family == AF_INET ? SDP_HDR_CONNECTION_IP4 : | 807 | SDP_HDR_CONNECTION_IP6; |
759 | SDP_HDR_CONNECTION_IP6; | ||
760 | 808 | ||
809 | /* Find beginning of session description */ | ||
761 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | 810 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, |
762 | type, SDP_HDR_UNSPEC, | 811 | SDP_HDR_VERSION, SDP_HDR_UNSPEC, |
763 | &matchoff, &matchlen) <= 0) | 812 | &matchoff, &matchlen) <= 0) |
764 | return NF_ACCEPT; | 813 | return NF_ACCEPT; |
765 | 814 | sdpoff = matchoff; | |
766 | /* We'll drop only if there are parse problems. */ | 815 | |
767 | if (!parse_addr(ct, *dptr + matchoff, NULL, &addr, *dptr + *datalen)) | 816 | /* The connection information is contained in the session description |
768 | return NF_DROP; | 817 | * and/or once per media description. The first media description marks |
769 | 818 | * the end of the session description. */ | |
770 | if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, | 819 | caddr_len = 0; |
820 | if (ct_sip_parse_sdp_addr(ct, *dptr, sdpoff, *datalen, | ||
821 | c_hdr, SDP_HDR_MEDIA, | ||
822 | &matchoff, &matchlen, &caddr) > 0) | ||
823 | caddr_len = matchlen; | ||
824 | |||
825 | if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, | ||
771 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, | 826 | SDP_HDR_MEDIA, SDP_HDR_UNSPEC, |
772 | &matchoff, &matchlen) <= 0) | 827 | &mediaoff, &medialen) <= 0) |
773 | return NF_ACCEPT; | 828 | return NF_ACCEPT; |
774 | 829 | ||
775 | port = simple_strtoul(*dptr + matchoff, NULL, 10); | 830 | port = simple_strtoul(*dptr + mediaoff, NULL, 10); |
776 | if (port < 1024 || port > 65535) | 831 | if (port < 1024 || port > 65535) |
777 | return NF_DROP; | 832 | return NF_DROP; |
778 | 833 | ||
779 | return set_expected_rtp_rtcp(skb, dptr, datalen, &addr, htons(port)); | 834 | /* The media description overrides the session description. */ |
835 | maddr_len = 0; | ||
836 | if (ct_sip_parse_sdp_addr(ct, *dptr, mediaoff, *datalen, | ||
837 | c_hdr, SDP_HDR_MEDIA, | ||
838 | &matchoff, &matchlen, &maddr) > 0) { | ||
839 | maddr_len = matchlen; | ||
840 | memcpy(&rtp_addr, &maddr, sizeof(rtp_addr)); | ||
841 | } else if (caddr_len) | ||
842 | memcpy(&rtp_addr, &caddr, sizeof(rtp_addr)); | ||
843 | else | ||
844 | return NF_DROP; | ||
845 | |||
846 | ret = set_expected_rtp_rtcp(skb, dptr, datalen, &rtp_addr, htons(port), | ||
847 | mediaoff, medialen); | ||
848 | if (ret != NF_ACCEPT) | ||
849 | return ret; | ||
850 | |||
851 | /* Update media connection address if present */ | ||
852 | if (maddr_len) { | ||
853 | nf_nat_sdp_addr = rcu_dereference(nf_nat_sdp_addr_hook); | ||
854 | if (nf_nat_sdp_addr && ct->status & IPS_NAT_MASK) { | ||
855 | ret = nf_nat_sdp_addr(skb, dptr, mediaoff, datalen, | ||
856 | c_hdr, SDP_HDR_MEDIA, &rtp_addr); | ||
857 | if (ret != NF_ACCEPT) | ||
858 | return ret; | ||
859 | } | ||
860 | } | ||
861 | |||
862 | /* Update session connection and owner addresses */ | ||
863 | nf_nat_sdp_session = rcu_dereference(nf_nat_sdp_session_hook); | ||
864 | if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) | ||
865 | ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr); | ||
866 | |||
867 | return ret; | ||
780 | } | 868 | } |
781 | static int process_invite_response(struct sk_buff *skb, | 869 | static int process_invite_response(struct sk_buff *skb, |
782 | const char **dptr, unsigned int *datalen, | 870 | const char **dptr, unsigned int *datalen, |