Merge git://1984.lsi.us.es/nf
Pable Neira Ayuso says: ==================== The following five patches contain fixes for 3.6-rc, they are: * Two fixes for message parsing in the SIP conntrack helper, from Patrick McHardy. * One fix for the SIP helper introduced in the user-space cthelper infrastructure, from Patrick McHardy. * fix missing appropriate locking while modifying one conntrack entry from the nfqueue integration code, from myself. * fix possible access to uninitiliazed timer in the nf_conntrack expectation infrastructure, from myself. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
@@ -164,7 +164,7 @@ extern int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr
|
|||||||
unsigned int dataoff, unsigned int datalen,
|
unsigned int dataoff, unsigned int datalen,
|
||||||
const char *name,
|
const char *name,
|
||||||
unsigned int *matchoff, unsigned int *matchlen,
|
unsigned int *matchoff, unsigned int *matchlen,
|
||||||
union nf_inet_addr *addr);
|
union nf_inet_addr *addr, bool delim);
|
||||||
extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
|
extern int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,
|
||||||
unsigned int off, unsigned int datalen,
|
unsigned int off, unsigned int datalen,
|
||||||
const char *name,
|
const char *name,
|
||||||
|
@@ -148,7 +148,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
|
|||||||
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
|
if (ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen,
|
||||||
hdr, NULL, &matchoff, &matchlen,
|
hdr, NULL, &matchoff, &matchlen,
|
||||||
&addr, &port) > 0) {
|
&addr, &port) > 0) {
|
||||||
unsigned int matchend, poff, plen, buflen, n;
|
unsigned int olen, matchend, poff, plen, buflen, n;
|
||||||
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
|
char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")];
|
||||||
|
|
||||||
/* We're only interested in headers related to this
|
/* We're only interested in headers related to this
|
||||||
@@ -163,17 +163,18 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
|
|||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
olen = *datalen;
|
||||||
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
|
if (!map_addr(skb, dataoff, dptr, datalen, matchoff, matchlen,
|
||||||
&addr, port))
|
&addr, port))
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
|
||||||
matchend = matchoff + matchlen;
|
matchend = matchoff + matchlen + *datalen - olen;
|
||||||
|
|
||||||
/* The maddr= parameter (RFC 2361) specifies where to send
|
/* The maddr= parameter (RFC 2361) specifies where to send
|
||||||
* the reply. */
|
* the reply. */
|
||||||
if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
|
if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
|
||||||
"maddr=", &poff, &plen,
|
"maddr=", &poff, &plen,
|
||||||
&addr) > 0 &&
|
&addr, true) > 0 &&
|
||||||
addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
|
addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
|
||||||
addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
|
addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) {
|
||||||
buflen = sprintf(buffer, "%pI4",
|
buflen = sprintf(buffer, "%pI4",
|
||||||
@@ -187,7 +188,7 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, unsigned int dataoff,
|
|||||||
* from which the server received the request. */
|
* from which the server received the request. */
|
||||||
if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
|
if (ct_sip_parse_address_param(ct, *dptr, matchend, *datalen,
|
||||||
"received=", &poff, &plen,
|
"received=", &poff, &plen,
|
||||||
&addr) > 0 &&
|
&addr, false) > 0 &&
|
||||||
addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
|
addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip &&
|
||||||
addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
|
addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) {
|
||||||
buflen = sprintf(buffer, "%pI4",
|
buflen = sprintf(buffer, "%pI4",
|
||||||
|
@@ -361,23 +361,6 @@ static void evict_oldest_expect(struct nf_conn *master,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int refresh_timer(struct nf_conntrack_expect *i)
|
|
||||||
{
|
|
||||||
struct nf_conn_help *master_help = nfct_help(i->master);
|
|
||||||
const struct nf_conntrack_expect_policy *p;
|
|
||||||
|
|
||||||
if (!del_timer(&i->timeout))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
p = &rcu_dereference_protected(
|
|
||||||
master_help->helper,
|
|
||||||
lockdep_is_held(&nf_conntrack_lock)
|
|
||||||
)->expect_policy[i->class];
|
|
||||||
i->timeout.expires = jiffies + p->timeout * HZ;
|
|
||||||
add_timer(&i->timeout);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
||||||
{
|
{
|
||||||
const struct nf_conntrack_expect_policy *p;
|
const struct nf_conntrack_expect_policy *p;
|
||||||
@@ -386,7 +369,7 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
|||||||
struct nf_conn_help *master_help = nfct_help(master);
|
struct nf_conn_help *master_help = nfct_help(master);
|
||||||
struct nf_conntrack_helper *helper;
|
struct nf_conntrack_helper *helper;
|
||||||
struct net *net = nf_ct_exp_net(expect);
|
struct net *net = nf_ct_exp_net(expect);
|
||||||
struct hlist_node *n;
|
struct hlist_node *n, *next;
|
||||||
unsigned int h;
|
unsigned int h;
|
||||||
int ret = 1;
|
int ret = 1;
|
||||||
|
|
||||||
@@ -395,12 +378,12 @@ static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
h = nf_ct_expect_dst_hash(&expect->tuple);
|
h = nf_ct_expect_dst_hash(&expect->tuple);
|
||||||
hlist_for_each_entry(i, n, &net->ct.expect_hash[h], hnode) {
|
hlist_for_each_entry_safe(i, n, next, &net->ct.expect_hash[h], hnode) {
|
||||||
if (expect_matches(i, expect)) {
|
if (expect_matches(i, expect)) {
|
||||||
/* Refresh timer: if it's dying, ignore.. */
|
if (del_timer(&i->timeout)) {
|
||||||
if (refresh_timer(i)) {
|
nf_ct_unlink_expect(i);
|
||||||
ret = 0;
|
nf_ct_expect_put(i);
|
||||||
goto out;
|
break;
|
||||||
}
|
}
|
||||||
} else if (expect_clash(i, expect)) {
|
} else if (expect_clash(i, expect)) {
|
||||||
ret = -EBUSY;
|
ret = -EBUSY;
|
||||||
|
@@ -1896,10 +1896,15 @@ static int
|
|||||||
ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
|
ctnetlink_nfqueue_parse(const struct nlattr *attr, struct nf_conn *ct)
|
||||||
{
|
{
|
||||||
struct nlattr *cda[CTA_MAX+1];
|
struct nlattr *cda[CTA_MAX+1];
|
||||||
|
int ret;
|
||||||
|
|
||||||
nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
|
nla_parse_nested(cda, CTA_MAX, attr, ct_nla_policy);
|
||||||
|
|
||||||
return ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
|
spin_lock_bh(&nf_conntrack_lock);
|
||||||
|
ret = ctnetlink_nfqueue_parse_ct((const struct nlattr **)cda, ct);
|
||||||
|
spin_unlock_bh(&nf_conntrack_lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
|
static struct nfq_ct_hook ctnetlink_nfqueue_hook = {
|
||||||
|
@@ -183,12 +183,12 @@ static int media_len(const struct nf_conn *ct, const char *dptr,
|
|||||||
return len + digits_len(ct, dptr, limit, shift);
|
return len + digits_len(ct, dptr, limit, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_addr(const struct nf_conn *ct, const char *cp,
|
static int sip_parse_addr(const struct nf_conn *ct, const char *cp,
|
||||||
const char **endp, union nf_inet_addr *addr,
|
const char **endp, union nf_inet_addr *addr,
|
||||||
const char *limit)
|
const char *limit, bool delim)
|
||||||
{
|
{
|
||||||
const char *end;
|
const char *end;
|
||||||
int ret = 0;
|
int ret;
|
||||||
|
|
||||||
if (!ct)
|
if (!ct)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -197,16 +197,28 @@ static int parse_addr(const struct nf_conn *ct, const char *cp,
|
|||||||
switch (nf_ct_l3num(ct)) {
|
switch (nf_ct_l3num(ct)) {
|
||||||
case AF_INET:
|
case AF_INET:
|
||||||
ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
|
ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
case AF_INET6:
|
case AF_INET6:
|
||||||
|
if (cp < limit && *cp == '[')
|
||||||
|
cp++;
|
||||||
|
else if (delim)
|
||||||
|
return 0;
|
||||||
|
|
||||||
ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
|
ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (end < limit && *end == ']')
|
||||||
|
end++;
|
||||||
|
else if (delim)
|
||||||
|
return 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BUG();
|
BUG();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == 0 || end == cp)
|
|
||||||
return 0;
|
|
||||||
if (endp)
|
if (endp)
|
||||||
*endp = end;
|
*endp = end;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -219,7 +231,7 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,
|
|||||||
union nf_inet_addr addr;
|
union nf_inet_addr addr;
|
||||||
const char *aux = dptr;
|
const char *aux = dptr;
|
||||||
|
|
||||||
if (!parse_addr(ct, dptr, &dptr, &addr, limit)) {
|
if (!sip_parse_addr(ct, dptr, &dptr, &addr, limit, true)) {
|
||||||
pr_debug("ip: %s parse failed.!\n", dptr);
|
pr_debug("ip: %s parse failed.!\n", dptr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -296,7 +308,7 @@ int ct_sip_parse_request(const struct nf_conn *ct,
|
|||||||
return 0;
|
return 0;
|
||||||
dptr += shift;
|
dptr += shift;
|
||||||
|
|
||||||
if (!parse_addr(ct, dptr, &end, addr, limit))
|
if (!sip_parse_addr(ct, dptr, &end, addr, limit, true))
|
||||||
return -1;
|
return -1;
|
||||||
if (end < limit && *end == ':') {
|
if (end < limit && *end == ':') {
|
||||||
end++;
|
end++;
|
||||||
@@ -550,7 +562,7 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,
|
|||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!parse_addr(ct, dptr + *matchoff, &c, addr, limit))
|
if (!sip_parse_addr(ct, dptr + *matchoff, &c, addr, limit, true))
|
||||||
return -1;
|
return -1;
|
||||||
if (*c == ':') {
|
if (*c == ':') {
|
||||||
c++;
|
c++;
|
||||||
@@ -599,7 +611,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
|
|||||||
unsigned int dataoff, unsigned int datalen,
|
unsigned int dataoff, unsigned int datalen,
|
||||||
const char *name,
|
const char *name,
|
||||||
unsigned int *matchoff, unsigned int *matchlen,
|
unsigned int *matchoff, unsigned int *matchlen,
|
||||||
union nf_inet_addr *addr)
|
union nf_inet_addr *addr, bool delim)
|
||||||
{
|
{
|
||||||
const char *limit = dptr + datalen;
|
const char *limit = dptr + datalen;
|
||||||
const char *start, *end;
|
const char *start, *end;
|
||||||
@@ -613,7 +625,7 @@ int ct_sip_parse_address_param(const struct nf_conn *ct, const char *dptr,
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
start += strlen(name);
|
start += strlen(name);
|
||||||
if (!parse_addr(ct, start, &end, addr, limit))
|
if (!sip_parse_addr(ct, start, &end, addr, limit, delim))
|
||||||
return 0;
|
return 0;
|
||||||
*matchoff = start - dptr;
|
*matchoff = start - dptr;
|
||||||
*matchlen = end - start;
|
*matchlen = end - start;
|
||||||
@@ -675,6 +687,47 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int sdp_parse_addr(const struct nf_conn *ct, const char *cp,
|
||||||
|
const char **endp, union nf_inet_addr *addr,
|
||||||
|
const char *limit)
|
||||||
|
{
|
||||||
|
const char *end;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(addr, 0, sizeof(*addr));
|
||||||
|
switch (nf_ct_l3num(ct)) {
|
||||||
|
case AF_INET:
|
||||||
|
ret = in4_pton(cp, limit - cp, (u8 *)&addr->ip, -1, &end);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
ret = in6_pton(cp, limit - cp, (u8 *)&addr->ip6, -1, &end);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0;
|
||||||
|
if (endp)
|
||||||
|
*endp = end;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip ip address. returns its length. */
|
||||||
|
static int sdp_addr_len(const struct nf_conn *ct, const char *dptr,
|
||||||
|
const char *limit, int *shift)
|
||||||
|
{
|
||||||
|
union nf_inet_addr addr;
|
||||||
|
const char *aux = dptr;
|
||||||
|
|
||||||
|
if (!sdp_parse_addr(ct, dptr, &dptr, &addr, limit)) {
|
||||||
|
pr_debug("ip: %s parse failed.!\n", dptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dptr - aux;
|
||||||
|
}
|
||||||
|
|
||||||
/* SDP header parsing: a SDP session description contains an ordered set of
|
/* SDP header parsing: a SDP session description contains an ordered set of
|
||||||
* headers, starting with a section containing general session parameters,
|
* headers, starting with a section containing general session parameters,
|
||||||
* optionally followed by multiple media descriptions.
|
* optionally followed by multiple media descriptions.
|
||||||
@@ -686,10 +739,10 @@ static int ct_sip_parse_transport(struct nf_conn *ct, const char *dptr,
|
|||||||
*/
|
*/
|
||||||
static const struct sip_header ct_sdp_hdrs[] = {
|
static const struct sip_header ct_sdp_hdrs[] = {
|
||||||
[SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len),
|
[SDP_HDR_VERSION] = SDP_HDR("v=", NULL, digits_len),
|
||||||
[SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", epaddr_len),
|
[SDP_HDR_OWNER_IP4] = SDP_HDR("o=", "IN IP4 ", sdp_addr_len),
|
||||||
[SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", epaddr_len),
|
[SDP_HDR_CONNECTION_IP4] = SDP_HDR("c=", "IN IP4 ", sdp_addr_len),
|
||||||
[SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", epaddr_len),
|
[SDP_HDR_OWNER_IP6] = SDP_HDR("o=", "IN IP6 ", sdp_addr_len),
|
||||||
[SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", epaddr_len),
|
[SDP_HDR_CONNECTION_IP6] = SDP_HDR("c=", "IN IP6 ", sdp_addr_len),
|
||||||
[SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len),
|
[SDP_HDR_MEDIA] = SDP_HDR("m=", NULL, media_len),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -775,7 +828,7 @@ static int ct_sip_parse_sdp_addr(const struct nf_conn *ct, const char *dptr,
|
|||||||
if (ret <= 0)
|
if (ret <= 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (!parse_addr(ct, dptr + *matchoff, NULL, addr,
|
if (!sdp_parse_addr(ct, dptr + *matchoff, NULL, addr,
|
||||||
dptr + *matchoff + *matchlen))
|
dptr + *matchoff + *matchlen))
|
||||||
return -1;
|
return -1;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1515,7 +1568,6 @@ static int sip_help_udp(struct sk_buff *skb, unsigned int protoff,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly;
|
static struct nf_conntrack_helper sip[MAX_PORTS][4] __read_mostly;
|
||||||
static char sip_names[MAX_PORTS][4][sizeof("sip-65535")] __read_mostly;
|
|
||||||
|
|
||||||
static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
|
static const struct nf_conntrack_expect_policy sip_exp_policy[SIP_EXPECT_MAX + 1] = {
|
||||||
[SIP_EXPECT_SIGNALLING] = {
|
[SIP_EXPECT_SIGNALLING] = {
|
||||||
@@ -1585,9 +1637,9 @@ static int __init nf_conntrack_sip_init(void)
|
|||||||
sip[i][j].me = THIS_MODULE;
|
sip[i][j].me = THIS_MODULE;
|
||||||
|
|
||||||
if (ports[i] == SIP_PORT)
|
if (ports[i] == SIP_PORT)
|
||||||
sprintf(sip_names[i][j], "sip");
|
sprintf(sip[i][j].name, "sip");
|
||||||
else
|
else
|
||||||
sprintf(sip_names[i][j], "sip-%u", i);
|
sprintf(sip[i][j].name, "sip-%u", i);
|
||||||
|
|
||||||
pr_debug("port #%u: %u\n", i, ports[i]);
|
pr_debug("port #%u: %u\n", i, ports[i]);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user