Skip to content

Commit

Permalink
netfilter: nf_conntrack_sip: pass data offset to NAT functions
Browse files Browse the repository at this point in the history
When using TCP multiple SIP messages might be present in a single packet.
A following patch will parse them by setting the dptr to the beginning of
each message. The NAT helper needs to reload the dptr value after mangling
the packet however, so it needs to know the offset of the message to the
beginning of the packet.

Signed-off-by: Patrick McHardy <kaber@trash.net>
  • Loading branch information
Patrick McHardy committed Feb 11, 2010
1 parent 54101f4 commit 3b6b9fa
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 92 deletions.
14 changes: 10 additions & 4 deletions include/linux/netfilter/nf_conntrack_sip.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ struct sdp_media_type {
struct sip_handler {
const char *method;
unsigned int len;
int (*request)(struct sk_buff *skb,
int (*request)(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int cseq);
int (*response)(struct sk_buff *skb,
int (*response)(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int cseq, unsigned int code);
};
Expand Down Expand Up @@ -100,33 +100,39 @@ enum sdp_header_types {
};

extern unsigned int (*nf_nat_sip_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen);
extern unsigned int (*nf_nat_sip_expect_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *exp,
unsigned int matchoff,
unsigned int matchlen);
extern unsigned int (*nf_nat_sdp_addr_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
unsigned int sdpoff,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_port_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port);
extern unsigned int (*nf_nat_sdp_session_hook)(struct sk_buff *skb,
const char **dptr,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
unsigned int sdpoff,
const union nf_inet_addr *addr);
extern unsigned int (*nf_nat_sdp_media_hook)(struct sk_buff *skb,
unsigned int dataoff,
const char **dptr,
unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
Expand Down
101 changes: 51 additions & 50 deletions net/ipv4/netfilter/nf_nat_sip.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ MODULE_DESCRIPTION("SIP NAT helper");
MODULE_ALIAS("ip_nat_sip");


static unsigned int mangle_packet(struct sk_buff *skb,
static unsigned int mangle_packet(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int matchoff, unsigned int matchlen,
const char *buffer, unsigned int buflen)
Expand All @@ -42,12 +42,12 @@ static unsigned int mangle_packet(struct sk_buff *skb,
return 0;

/* Reload data pointer and adjust datalen value */
*dptr = skb->data + ip_hdrlen(skb) + sizeof(struct udphdr);
*dptr = skb->data + dataoff;
*datalen += buflen - matchlen;
return 1;
}

static int map_addr(struct sk_buff *skb,
static int map_addr(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int matchoff, unsigned int matchlen,
union nf_inet_addr *addr, __be16 port)
Expand Down Expand Up @@ -76,11 +76,11 @@ static int map_addr(struct sk_buff *skb,

buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport));

return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen);
}

static int map_sip_addr(struct sk_buff *skb,
static int map_sip_addr(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
enum sip_header_types type)
{
Expand All @@ -93,16 +93,17 @@ static int map_sip_addr(struct sk_buff *skb,
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, type, NULL,
&matchoff, &matchlen, &addr, &port) <= 0)
return 1;
return map_addr(skb, dptr, datalen, matchoff, matchlen, &addr, port);
return map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port);
}

static unsigned int ip_nat_sip(struct sk_buff *skb,
static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen)
{
enum ip_conntrack_info ctinfo;
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
unsigned int dataoff, matchoff, matchlen;
unsigned int coff, matchoff, matchlen;
union nf_inet_addr addr;
__be16 port;
int request, in_header;
Expand All @@ -112,7 +113,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
if (ct_sip_parse_request(ct, *dptr, *datalen,
&matchoff, &matchlen,
&addr, &port) > 0 &&
!map_addr(skb, dptr, datalen, matchoff, matchlen,
!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;
request = 1;
Expand All @@ -138,7 +139,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
goto next;
}

if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;

Expand All @@ -153,8 +154,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
buflen = sprintf(buffer, "%pI4",
&ct->tuplehash[!dir].tuple.dst.u3.ip);
if (!mangle_packet(skb, dptr, datalen, poff, plen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
poff, plen, buffer, buflen))
return NF_DROP;
}

Expand All @@ -167,8 +168,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
buflen = sprintf(buffer, "%pI4",
&ct->tuplehash[!dir].tuple.src.u3.ip);
if (!mangle_packet(skb, dptr, datalen, poff, plen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
poff, plen, buffer, buflen))
return NF_DROP;
}

Expand All @@ -181,27 +182,27 @@ static unsigned int ip_nat_sip(struct sk_buff *skb,
htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {
__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
buflen = sprintf(buffer, "%u", ntohs(p));
if (!mangle_packet(skb, dptr, datalen, poff, plen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
poff, plen, buffer, buflen))
return NF_DROP;
}
}

next:
/* Translate Contact headers */
dataoff = 0;
coff = 0;
in_header = 0;
while (ct_sip_parse_header_uri(ct, *dptr, &dataoff, *datalen,
while (ct_sip_parse_header_uri(ct, *dptr, &coff, *datalen,
SIP_HDR_CONTACT, &in_header,
&matchoff, &matchlen,
&addr, &port) > 0) {
if (!map_addr(skb, dptr, datalen, matchoff, matchlen,
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
&addr, port))
return NF_DROP;
}

if (!map_sip_addr(skb, dptr, datalen, SIP_HDR_FROM) ||
!map_sip_addr(skb, dptr, datalen, SIP_HDR_TO))
if (!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_FROM) ||
!map_sip_addr(skb, dataoff, dptr, datalen, SIP_HDR_TO))
return NF_DROP;
return NF_ACCEPT;
}
Expand Down Expand Up @@ -232,7 +233,7 @@ static void ip_nat_sip_expected(struct nf_conn *ct,
}
}

static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
static unsigned int ip_nat_sip_expect(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
struct nf_conntrack_expect *exp,
unsigned int matchoff,
Expand Down Expand Up @@ -279,8 +280,8 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
if (exp->tuple.dst.u3.ip != exp->saved_ip ||
exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) {
buflen = sprintf(buffer, "%pI4:%u", &newip, port);
if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen,
buffer, buflen))
if (!mangle_packet(skb, dataoff, dptr, datalen,
matchoff, matchlen, buffer, buflen))
goto err;
}
return NF_ACCEPT;
Expand All @@ -290,7 +291,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb,
return NF_DROP;
}

static int mangle_content_len(struct sk_buff *skb,
static int mangle_content_len(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen)
{
enum ip_conntrack_info ctinfo;
Expand All @@ -312,12 +313,13 @@ static int mangle_content_len(struct sk_buff *skb,
return 0;

buflen = sprintf(buffer, "%u", c_len);
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen);
}

static int mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
unsigned int dataoff, unsigned int *datalen,
static int mangle_sdp_packet(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int sdpoff,
enum sdp_header_types type,
enum sdp_header_types term,
char *buffer, int buflen)
Expand All @@ -326,16 +328,16 @@ static int mangle_sdp_packet(struct sk_buff *skb, const char **dptr,
struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
unsigned int matchlen, matchoff;

if (ct_sip_get_sdp_header(ct, *dptr, dataoff, *datalen, type, term,
if (ct_sip_get_sdp_header(ct, *dptr, sdpoff, *datalen, type, term,
&matchoff, &matchlen) <= 0)
return -ENOENT;
return mangle_packet(skb, dptr, datalen, matchoff, matchlen,
return mangle_packet(skb, dataoff, dptr, datalen, matchoff, matchlen,
buffer, buflen) ? 0 : -EINVAL;
}

static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int sdpoff,
enum sdp_header_types type,
enum sdp_header_types term,
const union nf_inet_addr *addr)
Expand All @@ -344,16 +346,15 @@ static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr,
unsigned int buflen;

buflen = sprintf(buffer, "%pI4", &addr->ip);
if (mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term,
if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff, type, term,
buffer, buflen))
return 0;

return mangle_content_len(skb, dptr, datalen);
return mangle_content_len(skb, dataoff, dptr, datalen);
}

static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
static unsigned int ip_nat_sdp_port(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int matchoff,
unsigned int matchlen,
u_int16_t port)
Expand All @@ -362,29 +363,29 @@ static unsigned int ip_nat_sdp_port(struct sk_buff *skb,
unsigned int buflen;

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

return mangle_content_len(skb, dptr, datalen);
return mangle_content_len(skb, dataoff, dptr, datalen);
}

static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
unsigned int dataoff,
unsigned int *datalen,
static unsigned int ip_nat_sdp_session(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
unsigned int sdpoff,
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, "%pI4", &addr->ip);
if (mangle_sdp_packet(skb, dptr, dataoff, datalen,
if (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA,
buffer, buflen))
return 0;

switch (mangle_sdp_packet(skb, dptr, dataoff, datalen,
switch (mangle_sdp_packet(skb, dataoff, dptr, datalen, sdpoff,
SDP_HDR_CONNECTION_IP4, SDP_HDR_MEDIA,
buffer, buflen)) {
case 0:
Expand All @@ -401,14 +402,13 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr,
return 0;
}

return mangle_content_len(skb, dptr, datalen);
return mangle_content_len(skb, dataoff, 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_media(struct sk_buff *skb,
const char **dptr,
unsigned int *datalen,
static unsigned int ip_nat_sdp_media(struct sk_buff *skb, unsigned int dataoff,
const char **dptr, unsigned int *datalen,
struct nf_conntrack_expect *rtp_exp,
struct nf_conntrack_expect *rtcp_exp,
unsigned int mediaoff,
Expand Down Expand Up @@ -456,7 +456,8 @@ static unsigned int ip_nat_sdp_media(struct sk_buff *skb,

/* 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))
!ip_nat_sdp_port(skb, dataoff, dptr, datalen,
mediaoff, medialen, port))
goto err2;

return NF_ACCEPT;
Expand Down
Loading

0 comments on commit 3b6b9fa

Please sign in to comment.