--- zzzz-none-000/linux-2.6.39.4/net/netfilter/nf_conntrack_sip.c 2011-08-03 19:43:28.000000000 +0000 +++ puma6-atom-6490-729/linux-2.6.39.4/net/netfilter/nf_conntrack_sip.c 2021-11-10 13:38:18.000000000 +0000 @@ -57,6 +57,12 @@ unsigned int *datalen) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_hook); +unsigned int (*nf_not_nat_sip_via_hook)(struct sk_buff *skb, + unsigned int dataoff, + const char **dptr, + unsigned int *datalen) __read_mostly; +EXPORT_SYMBOL_GPL(nf_not_nat_sip_via_hook); + void (*nf_nat_sip_seq_adjust_hook)(struct sk_buff *skb, s16 off) __read_mostly; EXPORT_SYMBOL_GPL(nf_nat_sip_seq_adjust_hook); @@ -1326,6 +1332,7 @@ { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); unsigned int matchoff, matchlen, matchend; unsigned int code, cseq, i; @@ -1352,6 +1359,19 @@ if (*datalen < matchend + handler->len || strnicmp(*dptr + matchend, handler->method, handler->len)) continue; + + /** + * We have to rewrite udp dest port in any case + * when forced_dport is detected + */ + if (!(ct->status & IPS_NAT_MASK) && + help->help.ct_sip_info.forced_dport) { + typeof(nf_not_nat_sip_via_hook) nf_not_nat_via; + nf_not_nat_via = rcu_dereference(nf_not_nat_sip_via_hook); + if (nf_not_nat_via && !nf_not_nat_via(skb, dataoff, dptr, datalen)) + return NF_DROP; + } + return handler->response(skb, dataoff, dptr, datalen, cseq, code); } @@ -1363,8 +1383,25 @@ { enum ip_conntrack_info ctinfo; struct nf_conn *ct = nf_ct_get(skb, &ctinfo); + struct nf_conn_help *help = nfct_help(ct); + enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); unsigned int matchoff, matchlen; unsigned int cseq, i; + union nf_inet_addr addr; + __be16 port; + + /* Many Cisco IP phones use a high source port for SIP requests, but + * listen for the response on port 5060. If we are the local + * router for one of these phones, save the port number from the + * Via: header so that nf_nat_sip can redirect the responses to + * the correct port. + */ + if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, + SIP_HDR_VIA_UDP, NULL, &matchoff, + &matchlen, &addr, &port) > 0 && + port != ct->tuplehash[dir].tuple.src.u.udp.port && + nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3)) + help->help.ct_sip_info.forced_dport = port; for (i = 0; i < ARRAY_SIZE(sip_handlers); i++) { const struct sip_handler *handler;