Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: nf_conntrack_sip: restrict RTP expect flushing on error to last request

Some Inovaphone PBXs exhibit very stange behaviour: when dialing for
example "123", the device sends INVITE requests for "1", "12" and
"123" back to back. The first requests will elicit error responses
from the receiver, causing the SIP helper to flush the RTP
expectations even though we might still see a positive response.

Note the sequence number of the last INVITE request that contained a
media description and only flush the expectations when receiving a
negative response for that sequence number.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Patrick McHardy and committed by
David S. Miller
ef75d49f 73120964

+14 -9
+1
include/linux/netfilter/nf_conntrack_sip.h
··· 7 7 8 8 struct nf_ct_sip_master { 9 9 unsigned int register_cseq; 10 + unsigned int invite_cseq; 10 11 }; 11 12 12 13 enum sip_expectation_classes {
+13 -9
net/netfilter/nf_conntrack_sip.c
··· 870 870 { 871 871 enum ip_conntrack_info ctinfo; 872 872 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 873 + struct nf_conn_help *help = nfct_help(ct); 873 874 unsigned int matchoff, matchlen; 874 875 unsigned int mediaoff, medialen; 875 876 unsigned int sdpoff; ··· 960 959 if (nf_nat_sdp_session && ct->status & IPS_NAT_MASK) 961 960 ret = nf_nat_sdp_session(skb, dptr, sdpoff, datalen, &rtp_addr); 962 961 962 + if (ret == NF_ACCEPT && i > 0) 963 + help->help.ct_sip_info.invite_cseq = cseq; 964 + 963 965 return ret; 964 966 } 965 967 static int process_invite_response(struct sk_buff *skb, ··· 971 967 { 972 968 enum ip_conntrack_info ctinfo; 973 969 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 970 + struct nf_conn_help *help = nfct_help(ct); 974 971 975 972 if ((code >= 100 && code <= 199) || 976 973 (code >= 200 && code <= 299)) 977 974 return process_sdp(skb, dptr, datalen, cseq); 978 - else { 975 + else if (help->help.ct_sip_info.invite_cseq == cseq) 979 976 flush_expectations(ct, true); 980 - return NF_ACCEPT; 981 - } 977 + return NF_ACCEPT; 982 978 } 983 979 984 980 static int process_update_response(struct sk_buff *skb, ··· 987 983 { 988 984 enum ip_conntrack_info ctinfo; 989 985 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 986 + struct nf_conn_help *help = nfct_help(ct); 990 987 991 988 if ((code >= 100 && code <= 199) || 992 989 (code >= 200 && code <= 299)) 993 990 return process_sdp(skb, dptr, datalen, cseq); 994 - else { 991 + else if (help->help.ct_sip_info.invite_cseq == cseq) 995 992 flush_expectations(ct, true); 996 - return NF_ACCEPT; 997 - } 993 + return NF_ACCEPT; 998 994 } 999 995 1000 996 static int process_prack_response(struct sk_buff *skb, ··· 1003 999 { 1004 1000 enum ip_conntrack_info ctinfo; 1005 1001 struct nf_conn *ct = nf_ct_get(skb, &ctinfo); 1002 + struct nf_conn_help *help = nfct_help(ct); 1006 1003 1007 1004 if ((code >= 100 && code <= 199) || 1008 1005 (code >= 200 && code <= 299)) 1009 1006 return process_sdp(skb, dptr, datalen, cseq); 1010 - else { 1007 + else if (help->help.ct_sip_info.invite_cseq == cseq) 1011 1008 flush_expectations(ct, true); 1012 - return NF_ACCEPT; 1013 - } 1009 + return NF_ACCEPT; 1014 1010 } 1015 1011 1016 1012 static int process_bye_request(struct sk_buff *skb,