Skip to content

Commit

Permalink
[NETFILTER]: nf_nat_sip: split up SDP mangling
Browse files Browse the repository at this point in the history
The SDP connection addresses may be contained in the payload multiple
times (in the session description and/or once per media description),
currently only the session description is properly updated. Split up
SDP mangling so the function setting up expectations only updates the
media port, update connection addresses from media descriptions while
parsing them and at the end update the session description when the
final addresses are known.

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Patrick McHardy authored and David S. Miller committed Mar 26, 2008
1 parent a9c1d35 commit 4ab9e64
Show file tree
Hide file tree
Showing 3 changed files with 219 additions and 69 deletions.
25 changes: 20 additions & 5 deletions include/linux/netfilter/nf_conntrack_sip.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,26 @@ extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
struct nf_conntrack_expect *exp,
unsigned int matchoff,
unsigned int matchlen);
extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp);
extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp,
unsigned int mediaoff,
unsigned int medialen,
union nf_inet_addr *rtp_addr);

extern int ct_sip_parse_request(const struct nf_conn *ct,
const char *dptr, unsigned int datalen,
Expand Down
121 changes: 84 additions & 37 deletions net/ipv4/netfilter/nf_nat_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -316,78 +316,113 @@ static int mangle_content_len(struct sk_buff *skb,
buffer, buflen);
}

static unsigned mangle_sdp_packet(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
static unsigned mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
unsigned int dataoff, unsigned int *datalen,
enum sdp_header_types type,
enum sdp_header_types term,
char *buffer, int buflen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;

if (ct_sip_get_sdp_header(ct, *dptr, 0, *datalen, type, SDP_HDR_UNSPEC,
if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term,
&matchoff, &matchlen) <= 0)
return 0;
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
buffer, buflen);
}

static unsigned int mangle_sdp(struct sk_buff *skb,
enum ip_conntrack_info ctinfo,
struct nf_conn *ct,
__be32 newip, u_int16_t port,
const char **dptr, unsigned int *datalen)
static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
unsigned int bufflen;
unsigned int buflen;

/* Mangle owner and contact info. */
bufflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip));
if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_OWNER_IP4,
buffer, bufflen))
buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip));
if (!mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term,
buffer, buflen))
return 0;

if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_CONNECTION_IP4,
buffer, bufflen))
return mangle_content_len(skb, dptr, datalen);
}

static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port)
{
char buffer[sizeof("nnnnn")];
unsigned int buflen;

buflen = sprintf(buffer, "%u", port);
if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
buffer, buflen))
return 0;

/* Mangle media port. */
bufflen = sprintf(buffer, "%u", port);
if (!mangle_sdp_packet(skb, dptr, datalen, SDP_HDR_MEDIA,
buffer, bufflen))
return mangle_content_len(skb, dptr, datalen);
}

static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
const union nf_inet_addr *addr)
{
char buffer[sizeof("nnn.nnn.nnn.nnn")];
unsigned int buflen;

/* Mangle session description owner and contact addresses */
buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip));
if (!mangle_sdp_packet(skb, dptr, dataoff, datalen,
SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
buffer, buflen))
return 0;

if (!mangle_sdp_packet(skb, dptr, dataoff, datalen,
SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
buffer, buflen))
return 0;

return mangle_content_len(skb, dptr, datalen);
}

/* So, this packet has hit the connection tracking matching code.
Mangle it, and change the expectation to match the new version. */
static unsigned int ip_nat_sdp(struct sk_buff *skb,
const char **dptr, unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp)
static unsigned int ip_nat_sdp_media(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp,
unsigned int mediaoff,
unsigned int medialen,
union nf_inet_addr *rtp_addr)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
__be32 newip;
u_int16_t port;

/* Connection will come from reply */
if (ct->tuplehash[dir].tuple.src.u3.ip ==
ct->tuplehash[!dir].tuple.dst.u3.ip)
newip = rtp_exp->tuple.dst.u3.ip;
rtp_addr->ip = rtp_exp->tuple.dst.u3.ip;
else
newip = ct->tuplehash[!dir].tuple.dst.u3.ip;
rtp_addr->ip = ct->tuplehash[!dir].tuple.dst.u3.ip;

rtp_exp->saved_ip = rtp_exp->tuple.dst.u3.ip;
rtp_exp->tuple.dst.u3.ip = newip;
rtp_exp->tuple.dst.u3.ip = rtp_addr->ip;
rtp_exp->saved_proto.udp.port = rtp_exp->tuple.dst.u.udp.port;
rtp_exp->dir = !dir;
rtp_exp->expectfn = ip_nat_sip_expected;

rtcp_exp->saved_ip = rtcp_exp->tuple.dst.u3.ip;
rtcp_exp->tuple.dst.u3.ip = newip;
rtcp_exp->tuple.dst.u3.ip = rtp_addr->ip;
rtcp_exp->saved_proto.udp.port = rtcp_exp->tuple.dst.u.udp.port;
rtcp_exp->dir = !dir;
rtcp_exp->expectfn = ip_nat_sip_expected;
Expand All @@ -405,32 +440,44 @@ static unsigned int ip_nat_sdp(struct sk_buff *skb,
}

if (port == 0)
return NF_DROP;
goto err1;

/* Update media port. */
if (rtp_exp->tuple.dst.u.udp.port != rtp_exp->saved_proto.udp.port &&
!ip_nat_sdp_port(skb, dptr, datalen, mediaoff, medialen, port))
goto err2;

if (!mangle_sdp(skb, ctinfo, ct, newip, port, dptr, datalen)) {
nf_ct_unexpect_related(rtp_exp);
nf_ct_unexpect_related(rtcp_exp);
return NF_DROP;
}
return NF_ACCEPT;

err2:
nf_ct_unexpect_related(rtp_exp);
nf_ct_unexpect_related(rtcp_exp);
err1:
return NF_DROP;
}

static void __exit nf_nat_sip_fini(void)
{
rcu_assign_pointer(nf_nat_sip_hook, NULL);
rcu_assign_pointer(nf_nat_sip_expect_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_addr_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_session_hook, NULL);
rcu_assign_pointer(nf_nat_sdp_media_hook, NULL);
synchronize_rcu();
}

static int __init nf_nat_sip_init(void)
{
BUG_ON(nf_nat_sip_hook != NULL);
BUG_ON(nf_nat_sip_expect_hook != NULL);
BUG_ON(nf_nat_sdp_hook != NULL);
BUG_ON(nf_nat_sdp_addr_hook != NULL);
BUG_ON(nf_nat_sdp_session_hook != NULL);
BUG_ON(nf_nat_sdp_media_hook != NULL);
rcu_assign_pointer(nf_nat_sip_hook, ip_nat_sip);
rcu_assign_pointer(nf_nat_sip_expect_hook, ip_nat_sip_expect);
rcu_assign_pointer(nf_nat_sdp_hook, ip_nat_sdp);
rcu_assign_pointer(nf_nat_sdp_addr_hook, ip_nat_sdp_addr);
rcu_assign_pointer(nf_nat_sdp_session_hook, ip_nat_sdp_session);
rcu_assign_pointer(nf_nat_sdp_media_hook, ip_nat_sdp_media);
return 0;
}

Expand Down
Loading

0 comments on commit 4ab9e64

Please sign in to comment.