[PATCH V7] netfilter: h323: avoid potential attack

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I think hackers chould build a malicious h323 packet to overflow
the pointer p which will panic during the memcpy(addr, p, len)
For example, he may fabricate a very large taddr->ipAddress.ip in
function get_h225_addr.

To avoid above, I add buffer boundary checking both in get addr
functions and set addr functions.

Because the temporary h323 buffer is dynamiclly allocated, I remove
the h323 spin lock in my patch.

Signed-off-by: Zhouyi Zhou <yizhouzhou@xxxxxxxxx>
---
 include/linux/netfilter/nf_conntrack_h323.h |  17 +-
 net/ipv4/netfilter/nf_nat_h323.c            |  33 ++-
 net/netfilter/nf_conntrack_h323_main.c      | 328 +++++++++++++++++-----------
 3 files changed, 244 insertions(+), 134 deletions(-)

diff --git a/include/linux/netfilter/nf_conntrack_h323.h b/include/linux/netfilter/nf_conntrack_h323.h
index 858d9b2..6c6fea1 100644
--- a/include/linux/netfilter/nf_conntrack_h323.h
+++ b/include/linux/netfilter/nf_conntrack_h323.h
@@ -27,11 +27,17 @@ struct nf_ct_h323_master {
 	};
 };
 
+struct h323_ct_state {
+	unsigned char *buf;
+	unsigned char *data;
+	int buflen;
+};
+
 struct nf_conn;
 
 int get_h225_addr(struct nf_conn *ct, unsigned char *data,
 		  TransportAddress *taddr, union nf_inet_addr *addr,
-		  __be16 *port);
+		  __be16 *port, struct h323_ct_state *ctstate);
 void nf_conntrack_h245_expect(struct nf_conn *new,
 			      struct nf_conntrack_expect *this);
 void nf_conntrack_q931_expect(struct nf_conn *new,
@@ -50,12 +56,14 @@ extern int (*set_sig_addr_hook) (struct sk_buff *skb,
 				 struct nf_conn *ct,
 				 enum ip_conntrack_info ctinfo,
 				 unsigned int protoff, unsigned char **data,
-				 TransportAddress *taddr, int count);
+				 TransportAddress *taddr, int count,
+				 struct h323_ct_state *ctstate);
 extern int (*set_ras_addr_hook) (struct sk_buff *skb,
 				 struct nf_conn *ct,
 				 enum ip_conntrack_info ctinfo,
 				 unsigned int protoff, unsigned char **data,
-				 TransportAddress *taddr, int count);
+				 TransportAddress *taddr, int count,
+				 struct h323_ct_state *ctstate);
 extern int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
 				 struct nf_conn *ct,
 				 enum ip_conntrack_info ctinfo,
@@ -90,7 +98,8 @@ extern int (*nat_q931_hook) (struct sk_buff *skb, struct nf_conn *ct,
 			     unsigned int protoff,
 			     unsigned char **data, TransportAddress *taddr,
 			     int idx, __be16 port,
-			     struct nf_conntrack_expect *exp);
+			     struct nf_conntrack_expect *exp,
+			     struct h323_ct_state *ctstate);
 
 #endif
 
diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c
index 574f7eb..5ed2d70 100644
--- a/net/ipv4/netfilter/nf_nat_h323.c
+++ b/net/ipv4/netfilter/nf_nat_h323.c
@@ -33,12 +33,20 @@ static int set_addr(struct sk_buff *skb, unsigned int protoff,
 	} __attribute__ ((__packed__)) buf;
 	const struct tcphdr *th;
 	struct tcphdr _tcph;
+	int datalen;
+	struct iphdr *iph = ip_hdr(skb);
 
 	buf.ip = ip;
 	buf.port = port;
 	addroff += dataoff;
 
 	if (ip_hdr(skb)->protocol == IPPROTO_TCP) {
+		th = (void *)iph + iph->ihl * 4;
+		datalen = skb->len - (iph->ihl * 4 + th->doff * 4);
+		/* check offset overflow */
+		if (addroff > datalen)
+			return  -1;
+
 		if (!nf_nat_mangle_tcp_packet(skb, ct, ctinfo,
 					      protoff, addroff, sizeof(buf),
 					      (char *) &buf, sizeof(buf))) {
@@ -53,6 +61,11 @@ static int set_addr(struct sk_buff *skb, unsigned int protoff,
 			return -1;
 		*data = skb->data + ip_hdrlen(skb) + th->doff * 4 + dataoff;
 	} else {
+		datalen = skb->len - (iph->ihl * 4 + sizeof(struct udphdr));
+		/* check offset overflow */
+		if (addroff > datalen)
+			return  -1;
+
 		if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo,
 					      protoff, addroff, sizeof(buf),
 					      (char *) &buf, sizeof(buf))) {
@@ -93,7 +106,8 @@ static int set_h245_addr(struct sk_buff *skb, unsigned protoff,
 static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
 			enum ip_conntrack_info ctinfo,
 			unsigned int protoff, unsigned char **data,
-			TransportAddress *taddr, int count)
+			TransportAddress *taddr, int count,
+			struct h323_ct_state *ctstate)
 {
 	const struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -102,7 +116,8 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
 	union nf_inet_addr addr;
 
 	for (i = 0; i < count; i++) {
-		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port)) {
+		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port,
+				  ctstate)) {
 			if (addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
 			    port == info->sig_port[dir]) {
 				/* GW->GK */
@@ -110,7 +125,7 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
 				/* Fix for Gnomemeeting */
 				if (i > 0 &&
 				    get_h225_addr(ct, *data, &taddr[0],
-						  &addr, &port) &&
+						  &addr, &port, ctstate) &&
 				    (ntohl(addr.ip) & 0xff000000) == 0x7f000000)
 					i = 0;
 
@@ -146,7 +161,8 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct,
 static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
 			enum ip_conntrack_info ctinfo,
 			unsigned int protoff, unsigned char **data,
-			TransportAddress *taddr, int count)
+			TransportAddress *taddr, int count,
+			struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int i;
@@ -154,7 +170,8 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct,
 	union nf_inet_addr addr;
 
 	for (i = 0; i < count; i++) {
-		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
+		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port,
+				  ctstate) &&
 		    addr.ip == ct->tuplehash[dir].tuple.src.u3.ip &&
 		    port == ct->tuplehash[dir].tuple.src.u.udp.port) {
 			pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n",
@@ -424,7 +441,8 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 		    enum ip_conntrack_info ctinfo,
 		    unsigned int protoff, unsigned char **data,
 		    TransportAddress *taddr, int idx,
-		    __be16 port, struct nf_conntrack_expect *exp)
+		    __be16 port, struct nf_conntrack_expect *exp,
+		    struct h323_ct_state *ctstate)
 {
 	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -469,7 +487,8 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct,
 
 		/* Fix for Gnomemeeting */
 		if (idx > 0 &&
-		    get_h225_addr(ct, *data, &taddr[0], &addr, &port) &&
+		    get_h225_addr(ct, *data, &taddr[0], &addr, &port,
+				  ctstate) &&
 		    (ntohl(addr.ip) & 0xff000000) == 0x7f000000) {
 			set_h225_addr(skb, protoff, data, 0, &taddr[0],
 				      &ct->tuplehash[!dir].tuple.dst.u3,
diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c
index 9511af0..19e797f 100644
--- a/net/netfilter/nf_conntrack_h323_main.c
+++ b/net/netfilter/nf_conntrack_h323_main.c
@@ -64,12 +64,14 @@ int (*set_sig_addr_hook) (struct sk_buff *skb,
 			  struct nf_conn *ct,
 			  enum ip_conntrack_info ctinfo,
 			  unsigned int protoff, unsigned char **data,
-			  TransportAddress *taddr, int count) __read_mostly;
+			  TransportAddress *taddr, int count,
+			  struct h323_ct_state *ctstate) __read_mostly;
 int (*set_ras_addr_hook) (struct sk_buff *skb,
 			  struct nf_conn *ct,
 			  enum ip_conntrack_info ctinfo,
 			  unsigned int protoff, unsigned char **data,
-			  TransportAddress *taddr, int count) __read_mostly;
+			  TransportAddress *taddr, int count,
+			  struct h323_ct_state *ctstate) __read_mostly;
 int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,
 			  struct nf_conn *ct,
 			  enum ip_conntrack_info ctinfo,
@@ -105,11 +107,10 @@ int (*nat_q931_hook) (struct sk_buff *skb,
 		      enum ip_conntrack_info ctinfo,
 		      unsigned int protoff,
 		      unsigned char **data, TransportAddress *taddr, int idx,
-		      __be16 port, struct nf_conntrack_expect *exp)
+		      __be16 port, struct nf_conntrack_expect *exp,
+		      struct h323_ct_state *ctstate)
 		      __read_mostly;
 
-static DEFINE_SPINLOCK(nf_h323_lock);
-static char *h323_buffer;
 
 static struct nf_conntrack_helper nf_conntrack_helper_h245;
 static struct nf_conntrack_helper nf_conntrack_helper_q931[];
@@ -118,7 +119,8 @@ static struct nf_conntrack_helper nf_conntrack_helper_ras[];
 /****************************************************************************/
 static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
 			 struct nf_conn *ct, enum ip_conntrack_info ctinfo,
-			 unsigned char **data, int *datalen, int *dataoff)
+			 unsigned char **data, int *datalen, int *dataoff,
+			 struct h323_ct_state *ctstate)
 {
 	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -145,8 +147,15 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
 
 	if (*data == NULL) {	/* first TPKT */
 		/* Get first TPKT pointer */
+		ctstate->buf = kmalloc(tcpdatalen,  GFP_ATOMIC);
+		if (!ctstate->buf)
+			return 0;
+
+		ctstate->buflen = tcpdatalen;
+
 		tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,
-					  h323_buffer);
+					  ctstate->buf);
+		ctstate->data = tpkt;
 		BUG_ON(tpkt == NULL);
 
 		/* Validate TPKT identifier */
@@ -222,7 +231,8 @@ static int get_tpkt_data(struct sk_buff *skb, unsigned int protoff,
 /****************************************************************************/
 static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
 			 H245_TransportAddress *taddr,
-			 union nf_inet_addr *addr, __be16 *port)
+			 union nf_inet_addr *addr, __be16 *port,
+			 struct h323_ct_state *ctstate)
 {
 	const unsigned char *p;
 	int len;
@@ -247,6 +257,11 @@ static int get_h245_addr(struct nf_conn *ct, const unsigned char *data,
 		return 0;
 	}
 
+	/*check pointer overflow */
+	if (p < ctstate->data ||
+	    (p + len + sizeof(__be16)) > ctstate->data + ctstate->buflen)
+		return 0;
+
 	memcpy(addr, p, len);
 	memset((void *)addr + len, 0, sizeof(*addr) - len);
 	memcpy(port, p + len, sizeof(__be16));
@@ -259,7 +274,8 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 			   enum ip_conntrack_info ctinfo,
 			   unsigned int protoff,
 			   unsigned char **data, int dataoff,
-			   H245_TransportAddress *taddr)
+			   H245_TransportAddress *taddr,
+			   struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -271,7 +287,7 @@ static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,
 	typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;
 
 	/* Read RTP or RTCP address */
-	if (!get_h245_addr(ct, *data, taddr, &addr, &port) ||
+	if (!get_h245_addr(ct, *data, taddr, &addr, &port, ctstate) ||
 	    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||
 	    port == 0)
 		return 0;
@@ -334,7 +350,8 @@ static int expect_t120(struct sk_buff *skb,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
 		       unsigned char **data, int dataoff,
-		       H245_TransportAddress *taddr)
+		       H245_TransportAddress *taddr,
+		       struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -344,7 +361,7 @@ static int expect_t120(struct sk_buff *skb,
 	typeof(nat_t120_hook) nat_t120;
 
 	/* Read T.120 address */
-	if (!get_h245_addr(ct, *data, taddr, &addr, &port) ||
+	if (!get_h245_addr(ct, *data, taddr, &addr, &port, ctstate) ||
 	    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||
 	    port == 0)
 		return 0;
@@ -386,14 +403,15 @@ static int process_h245_channel(struct sk_buff *skb,
 				enum ip_conntrack_info ctinfo,
 				unsigned int protoff,
 				unsigned char **data, int dataoff,
-				H2250LogicalChannelParameters *channel)
+				H2250LogicalChannelParameters *channel,
+				struct h323_ct_state *ctstate)
 {
 	int ret;
 
 	if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {
 		/* RTP */
 		ret = expect_rtp_rtcp(skb, ct, ctinfo, protoff, data, dataoff,
-				      &channel->mediaChannel);
+				      &channel->mediaChannel, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -402,7 +420,7 @@ static int process_h245_channel(struct sk_buff *skb,
 	    options & eH2250LogicalChannelParameters_mediaControlChannel) {
 		/* RTCP */
 		ret = expect_rtp_rtcp(skb, ct, ctinfo, protoff, data, dataoff,
-				      &channel->mediaControlChannel);
+				      &channel->mediaControlChannel, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -415,7 +433,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
 		       unsigned char **data, int dataoff,
-		       OpenLogicalChannel *olc)
+		       OpenLogicalChannel *olc,
+		       struct h323_ct_state *ctstate)
 {
 	int ret;
 
@@ -429,7 +448,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
 					   &olc->
 					   forwardLogicalChannelParameters.
 					   multiplexParameters.
-					   h2250LogicalChannelParameters);
+					   h2250LogicalChannelParameters,
+					   ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -448,7 +468,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
 					 &olc->
 					 reverseLogicalChannelParameters.
 					 multiplexParameters.
-					 h2250LogicalChannelParameters);
+					 h2250LogicalChannelParameters,
+					 ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -464,7 +485,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
 	    eNetworkAccessParameters_networkAddress_localAreaAddress) {
 		ret = expect_t120(skb, ct, ctinfo, protoff, data, dataoff,
 				  &olc->separateStack.networkAddress.
-				  localAreaAddress);
+				  localAreaAddress,
+				  ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -476,7 +498,8 @@ static int process_olc(struct sk_buff *skb, struct nf_conn *ct,
 static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
 			enum ip_conntrack_info ctinfo,
 			unsigned int protoff, unsigned char **data, int dataoff,
-			OpenLogicalChannelAck *olca)
+			OpenLogicalChannelAck *olca,
+			struct h323_ct_state *ctstate)
 {
 	H2250LogicalChannelAckParameters *ack;
 	int ret;
@@ -496,7 +519,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
 					   &olca->
 					   reverseLogicalChannelParameters.
 					   multiplexParameters.
-					   h2250LogicalChannelParameters);
+					   h2250LogicalChannelParameters,
+					   ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -513,7 +537,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
 			/* RTP */
 			ret = expect_rtp_rtcp(skb, ct, ctinfo,
 					      protoff, data, dataoff,
-					      &ack->mediaChannel);
+					      &ack->mediaChannel,
+					      ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -523,7 +548,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
 			/* RTCP */
 			ret = expect_rtp_rtcp(skb, ct, ctinfo,
 					      protoff, data, dataoff,
-					      &ack->mediaControlChannel);
+					      &ack->mediaControlChannel,
+					      ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -534,7 +560,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
 		eNetworkAccessParameters_networkAddress_localAreaAddress) {
 		ret = expect_t120(skb, ct, ctinfo, protoff, data, dataoff,
 				  &olca->separateStack.networkAddress.
-				  localAreaAddress);
+				  localAreaAddress,
+				  ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -546,7 +573,8 @@ static int process_olca(struct sk_buff *skb, struct nf_conn *ct,
 static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
 			enum ip_conntrack_info ctinfo,
 			unsigned int protoff, unsigned char **data, int dataoff,
-			MultimediaSystemControlMessage *mscm)
+			MultimediaSystemControlMessage *mscm,
+			struct h323_ct_state *ctstate)
 {
 	switch (mscm->choice) {
 	case eMultimediaSystemControlMessage_request:
@@ -554,7 +582,8 @@ static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
 		    eRequestMessage_openLogicalChannel) {
 			return process_olc(skb, ct, ctinfo,
 					   protoff, data, dataoff,
-					   &mscm->request.openLogicalChannel);
+					   &mscm->request.openLogicalChannel,
+					   ctstate);
 		}
 		pr_debug("nf_ct_h323: H.245 Request %d\n",
 			 mscm->request.choice);
@@ -565,7 +594,8 @@ static int process_h245(struct sk_buff *skb, struct nf_conn *ct,
 			return process_olca(skb, ct, ctinfo,
 					    protoff, data, dataoff,
 					    &mscm->response.
-					    openLogicalChannelAck);
+					    openLogicalChannelAck,
+					    ctstate);
 		}
 		pr_debug("nf_ct_h323: H.245 Response %d\n",
 			 mscm->response.choice);
@@ -587,6 +617,7 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
 	int datalen;
 	int dataoff;
 	int ret;
+	struct h323_ct_state ctstate = {NULL, NULL, 0};
 
 	/* Until there's been traffic both ways, don't look in packets. */
 	if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
@@ -594,11 +625,10 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
 
 	pr_debug("nf_ct_h245: skblen = %u\n", skb->len);
 
-	spin_lock_bh(&nf_h323_lock);
 
 	/* Process each TPKT */
 	while (get_tpkt_data(skb, protoff, ct, ctinfo,
-			     &data, &datalen, &dataoff)) {
+			     &data, &datalen, &dataoff, &ctstate)) {
 		pr_debug("nf_ct_h245: TPKT len=%d ", datalen);
 		nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
 
@@ -615,15 +645,15 @@ static int h245_help(struct sk_buff *skb, unsigned int protoff,
 
 		/* Process H.245 signal */
 		if (process_h245(skb, ct, ctinfo, protoff,
-				 &data, dataoff, &mscm) < 0)
+				 &data, dataoff, &mscm, &ctstate) < 0)
 			goto drop;
 	}
 
-	spin_unlock_bh(&nf_h323_lock);
+	kfree(ctstate.buf);
 	return NF_ACCEPT;
 
       drop:
-	spin_unlock_bh(&nf_h323_lock);
+	kfree(ctstate.buf);
 	nf_ct_helper_log(skb, ct, "cannot process H.245 message");
 	return NF_DROP;
 }
@@ -647,7 +677,8 @@ static struct nf_conntrack_helper nf_conntrack_helper_h245 __read_mostly = {
 /****************************************************************************/
 int get_h225_addr(struct nf_conn *ct, unsigned char *data,
 		  TransportAddress *taddr,
-		  union nf_inet_addr *addr, __be16 *port)
+		  union nf_inet_addr *addr, __be16 *port,
+		  struct h323_ct_state *ctstate)
 {
 	const unsigned char *p;
 	int len;
@@ -669,6 +700,11 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
 		return 0;
 	}
 
+		/*check pointer overflow */
+	if (p < ctstate->data ||
+	    (p + len + sizeof(__be16)) > ctstate->data + ctstate->buflen)
+		return 0;
+
 	memcpy(addr, p, len);
 	memset((void *)addr + len, 0, sizeof(*addr) - len);
 	memcpy(port, p + len, sizeof(__be16));
@@ -680,7 +716,8 @@ int get_h225_addr(struct nf_conn *ct, unsigned char *data,
 static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff, unsigned char **data, int dataoff,
-		       TransportAddress *taddr)
+		       TransportAddress *taddr,
+		       struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -690,7 +727,7 @@ static int expect_h245(struct sk_buff *skb, struct nf_conn *ct,
 	typeof(nat_h245_hook) nat_h245;
 
 	/* Read h245Address */
-	if (!get_h225_addr(ct, *data, taddr, &addr, &port) ||
+	if (!get_h225_addr(ct, *data, taddr, &addr, &port, ctstate) ||
 	    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||
 	    port == 0)
 		return 0;
@@ -801,7 +838,8 @@ static int expect_callforwarding(struct sk_buff *skb,
 				 enum ip_conntrack_info ctinfo,
 				 unsigned int protoff,
 				 unsigned char **data, int dataoff,
-				 TransportAddress *taddr)
+				 TransportAddress *taddr,
+				 struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -812,7 +850,8 @@ static int expect_callforwarding(struct sk_buff *skb,
 	typeof(nat_callforwarding_hook) nat_callforwarding;
 
 	/* Read alternativeAddress */
-	if (!get_h225_addr(ct, *data, taddr, &addr, &port) || port == 0)
+	if (!get_h225_addr(ct, *data, taddr, &addr, &port, ctstate)
+	    || port == 0)
 		return 0;
 
 	/* If the calling party is on the same side of the forward-to party,
@@ -860,7 +899,7 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int protoff,
 			 unsigned char **data, int dataoff,
-			 Setup_UUIE *setup)
+			 Setup_UUIE *setup, struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret;
@@ -873,7 +912,7 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
 
 	if (setup->options & eSetup_UUIE_h245Address) {
 		ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-				  &setup->h245Address);
+				  &setup->h245Address, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -883,7 +922,7 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
 	    (set_h225_addr) && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK &&
 	    get_h225_addr(ct, *data, &setup->destCallSignalAddress,
-			  &addr, &port) &&
+			  &addr, &port, ctstate) &&
 	    memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) {
 		pr_debug("nf_ct_q931: set destCallSignalAddress %pI6:%hu->%pI6:%hu\n",
 			 &addr, ntohs(port), &ct->tuplehash[!dir].tuple.src.u3,
@@ -900,7 +939,7 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
 	    (set_h225_addr) && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK &&
 	    get_h225_addr(ct, *data, &setup->sourceCallSignalAddress,
-			  &addr, &port) &&
+			  &addr, &port, ctstate) &&
 	    memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) {
 		pr_debug("nf_ct_q931: set sourceCallSignalAddress %pI6:%hu->%pI6:%hu\n",
 			 &addr, ntohs(port), &ct->tuplehash[!dir].tuple.dst.u3,
@@ -917,7 +956,8 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct,
 		for (i = 0; i < setup->fastStart.count; i++) {
 			ret = process_olc(skb, ct, ctinfo,
 					  protoff, data, dataoff,
-					  &setup->fastStart.item[i]);
+					  &setup->fastStart.item[i],
+					  ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -932,7 +972,8 @@ static int process_callproceeding(struct sk_buff *skb,
 				  enum ip_conntrack_info ctinfo,
 				  unsigned int protoff,
 				  unsigned char **data, int dataoff,
-				  CallProceeding_UUIE *callproc)
+				  CallProceeding_UUIE *callproc,
+				  struct h323_ct_state *ctstate)
 {
 	int ret;
 	int i;
@@ -941,7 +982,7 @@ static int process_callproceeding(struct sk_buff *skb,
 
 	if (callproc->options & eCallProceeding_UUIE_h245Address) {
 		ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-				  &callproc->h245Address);
+				  &callproc->h245Address, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -950,7 +991,8 @@ static int process_callproceeding(struct sk_buff *skb,
 		for (i = 0; i < callproc->fastStart.count; i++) {
 			ret = process_olc(skb, ct, ctinfo,
 					  protoff, data, dataoff,
-					  &callproc->fastStart.item[i]);
+					  &callproc->fastStart.item[i],
+					  ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -964,7 +1006,8 @@ static int process_connect(struct sk_buff *skb, struct nf_conn *ct,
 			   enum ip_conntrack_info ctinfo,
 			   unsigned int protoff,
 			   unsigned char **data, int dataoff,
-			   Connect_UUIE *connect)
+			   Connect_UUIE *connect,
+			   struct h323_ct_state *ctstate)
 {
 	int ret;
 	int i;
@@ -973,7 +1016,7 @@ static int process_connect(struct sk_buff *skb, struct nf_conn *ct,
 
 	if (connect->options & eConnect_UUIE_h245Address) {
 		ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-				  &connect->h245Address);
+				  &connect->h245Address, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -982,7 +1025,8 @@ static int process_connect(struct sk_buff *skb, struct nf_conn *ct,
 		for (i = 0; i < connect->fastStart.count; i++) {
 			ret = process_olc(skb, ct, ctinfo,
 					  protoff, data, dataoff,
-					  &connect->fastStart.item[i]);
+					  &connect->fastStart.item[i],
+					  ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -996,7 +1040,7 @@ static int process_alerting(struct sk_buff *skb, struct nf_conn *ct,
 			    enum ip_conntrack_info ctinfo,
 			    unsigned int protoff,
 			    unsigned char **data, int dataoff,
-			    Alerting_UUIE *alert)
+			    Alerting_UUIE *alert, struct h323_ct_state *ctstate)
 {
 	int ret;
 	int i;
@@ -1005,7 +1049,7 @@ static int process_alerting(struct sk_buff *skb, struct nf_conn *ct,
 
 	if (alert->options & eAlerting_UUIE_h245Address) {
 		ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-				  &alert->h245Address);
+				  &alert->h245Address, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1014,7 +1058,8 @@ static int process_alerting(struct sk_buff *skb, struct nf_conn *ct,
 		for (i = 0; i < alert->fastStart.count; i++) {
 			ret = process_olc(skb, ct, ctinfo,
 					  protoff, data, dataoff,
-					  &alert->fastStart.item[i]);
+					  &alert->fastStart.item[i],
+					  ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -1028,7 +1073,8 @@ static int process_facility(struct sk_buff *skb, struct nf_conn *ct,
 			    enum ip_conntrack_info ctinfo,
 			    unsigned int protoff,
 			    unsigned char **data, int dataoff,
-			    Facility_UUIE *facility)
+			    Facility_UUIE *facility,
+			    struct h323_ct_state *ctstate)
 {
 	int ret;
 	int i;
@@ -1040,13 +1086,14 @@ static int process_facility(struct sk_buff *skb, struct nf_conn *ct,
 			return expect_callforwarding(skb, ct, ctinfo,
 						     protoff, data, dataoff,
 						     &facility->
-						     alternativeAddress);
+						     alternativeAddress,
+						     ctstate);
 		return 0;
 	}
 
 	if (facility->options & eFacility_UUIE_h245Address) {
 		ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-				  &facility->h245Address);
+				  &facility->h245Address, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1055,7 +1102,8 @@ static int process_facility(struct sk_buff *skb, struct nf_conn *ct,
 		for (i = 0; i < facility->fastStart.count; i++) {
 			ret = process_olc(skb, ct, ctinfo,
 					  protoff, data, dataoff,
-					  &facility->fastStart.item[i]);
+					  &facility->fastStart.item[i],
+					  ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -1069,7 +1117,8 @@ static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
 			    enum ip_conntrack_info ctinfo,
 			    unsigned int protoff,
 			    unsigned char **data, int dataoff,
-			    Progress_UUIE *progress)
+			    Progress_UUIE *progress,
+			    struct h323_ct_state *ctstate)
 {
 	int ret;
 	int i;
@@ -1078,7 +1127,7 @@ static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
 
 	if (progress->options & eProgress_UUIE_h245Address) {
 		ret = expect_h245(skb, ct, ctinfo, protoff, data, dataoff,
-				  &progress->h245Address);
+				  &progress->h245Address, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1087,7 +1136,8 @@ static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
 		for (i = 0; i < progress->fastStart.count; i++) {
 			ret = process_olc(skb, ct, ctinfo,
 					  protoff, data, dataoff,
-					  &progress->fastStart.item[i]);
+					  &progress->fastStart.item[i],
+					  ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -1100,7 +1150,7 @@ static int process_progress(struct sk_buff *skb, struct nf_conn *ct,
 static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
 			enum ip_conntrack_info ctinfo,
 			unsigned int protoff, unsigned char **data, int dataoff,
-			Q931 *q931)
+			Q931 *q931, struct h323_ct_state *ctstate)
 {
 	H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu;
 	int i;
@@ -1109,29 +1159,35 @@ static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
 	switch (pdu->h323_message_body.choice) {
 	case eH323_UU_PDU_h323_message_body_setup:
 		ret = process_setup(skb, ct, ctinfo, protoff, data, dataoff,
-				    &pdu->h323_message_body.setup);
+				    &pdu->h323_message_body.setup,
+				    ctstate);
 		break;
 	case eH323_UU_PDU_h323_message_body_callProceeding:
 		ret = process_callproceeding(skb, ct, ctinfo,
 					     protoff, data, dataoff,
 					     &pdu->h323_message_body.
-					     callProceeding);
+					     callProceeding,
+					     ctstate);
 		break;
 	case eH323_UU_PDU_h323_message_body_connect:
 		ret = process_connect(skb, ct, ctinfo, protoff, data, dataoff,
-				      &pdu->h323_message_body.connect);
+				      &pdu->h323_message_body.connect,
+				      ctstate);
 		break;
 	case eH323_UU_PDU_h323_message_body_alerting:
 		ret = process_alerting(skb, ct, ctinfo, protoff, data, dataoff,
-				       &pdu->h323_message_body.alerting);
+				       &pdu->h323_message_body.alerting,
+				       ctstate);
 		break;
 	case eH323_UU_PDU_h323_message_body_facility:
 		ret = process_facility(skb, ct, ctinfo, protoff, data, dataoff,
-				       &pdu->h323_message_body.facility);
+				       &pdu->h323_message_body.facility,
+				       ctstate);
 		break;
 	case eH323_UU_PDU_h323_message_body_progress:
 		ret = process_progress(skb, ct, ctinfo, protoff, data, dataoff,
-				       &pdu->h323_message_body.progress);
+				       &pdu->h323_message_body.progress,
+				       ctstate);
 		break;
 	default:
 		pr_debug("nf_ct_q931: Q.931 signal %d\n",
@@ -1146,7 +1202,8 @@ static int process_q931(struct sk_buff *skb, struct nf_conn *ct,
 		for (i = 0; i < pdu->h245Control.count; i++) {
 			ret = process_h245(skb, ct, ctinfo,
 					   protoff, data, dataoff,
-					   &pdu->h245Control.item[i]);
+					   &pdu->h245Control.item[i],
+					   ctstate);
 			if (ret < 0)
 				return -1;
 		}
@@ -1164,6 +1221,7 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
 	int datalen;
 	int dataoff;
 	int ret;
+	struct h323_ct_state ctstate = {NULL, NULL, 0};
 
 	/* Until there's been traffic both ways, don't look in packets. */
 	if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED_REPLY)
@@ -1171,11 +1229,10 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
 
 	pr_debug("nf_ct_q931: skblen = %u\n", skb->len);
 
-	spin_lock_bh(&nf_h323_lock);
 
 	/* Process each TPKT */
 	while (get_tpkt_data(skb, protoff, ct, ctinfo,
-			     &data, &datalen, &dataoff)) {
+			     &data, &datalen, &dataoff, &ctstate)) {
 		pr_debug("nf_ct_q931: TPKT len=%d ", datalen);
 		nf_ct_dump_tuple(&ct->tuplehash[CTINFO2DIR(ctinfo)].tuple);
 
@@ -1191,15 +1248,16 @@ static int q931_help(struct sk_buff *skb, unsigned int protoff,
 
 		/* Process Q.931 signal */
 		if (process_q931(skb, ct, ctinfo, protoff,
-				 &data, dataoff, &q931) < 0)
+				 &data, dataoff, &q931, &ctstate) < 0)
 			goto drop;
 	}
 
-	spin_unlock_bh(&nf_h323_lock);
+	kfree(ctstate.buf);
 	return NF_ACCEPT;
 
       drop:
-	spin_unlock_bh(&nf_h323_lock);
+	kfree(ctstate.buf);
+
 	nf_ct_helper_log(skb, ct, "cannot process Q.931 message");
 	return NF_DROP;
 }
@@ -1235,7 +1293,7 @@ static struct nf_conntrack_helper nf_conntrack_helper_q931[] __read_mostly = {
 
 /****************************************************************************/
 static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
-				   int *datalen)
+				   int *datalen, struct h323_ct_state *ctstate)
 {
 	const struct udphdr *uh;
 	struct udphdr _uh;
@@ -1248,7 +1306,15 @@ static unsigned char *get_udp_data(struct sk_buff *skb, unsigned int protoff,
 	if (dataoff >= skb->len)
 		return NULL;
 	*datalen = skb->len - dataoff;
-	return skb_header_pointer(skb, dataoff, *datalen, h323_buffer);
+
+	ctstate->buf = kmalloc(*datalen, GFP_ATOMIC);
+	if (!ctstate->buf)
+		return NULL;
+
+	ctstate->buflen = *datalen;
+	ctstate->data = skb_header_pointer(skb, dataoff, *datalen,
+					   ctstate->buf);
+	return ctstate->data;
 }
 
 /****************************************************************************/
@@ -1289,7 +1355,8 @@ static int set_expect_timeout(struct nf_conntrack_expect *exp,
 static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff, unsigned char **data,
-		       TransportAddress *taddr, int count)
+		       TransportAddress *taddr, int count,
+		       struct h323_ct_state *ctstate)
 {
 	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -1302,7 +1369,8 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 
 	/* Look for the first related address */
 	for (i = 0; i < count; i++) {
-		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) &&
+		if (get_h225_addr(ct, *data, &taddr[i], &addr, &port,
+				  ctstate) &&
 		    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3,
 			   sizeof(addr)) == 0 && port != 0)
 			break;
@@ -1326,7 +1394,7 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 	if (nat_q931 && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK) {	/* Need NAT */
 		ret = nat_q931(skb, ct, ctinfo, protoff, data,
-			       taddr, i, port, exp);
+			       taddr, i, port, exp, ctstate);
 	} else {		/* Conntrack only */
 		if (nf_ct_expect_related(exp) == 0) {
 			pr_debug("nf_ct_ras: expect Q.931 ");
@@ -1347,7 +1415,8 @@ static int expect_q931(struct sk_buff *skb, struct nf_conn *ct,
 static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, GatekeeperRequest *grq)
+		       unsigned char **data, GatekeeperRequest *grq,
+		       struct h323_ct_state *ctstate)
 {
 	typeof(set_ras_addr_hook) set_ras_addr;
 
@@ -1357,7 +1426,7 @@ static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
 	if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK)	/* NATed */
 		return set_ras_addr(skb, ct, ctinfo, protoff, data,
-				    &grq->rasAddress, 1);
+				    &grq->rasAddress, 1, ctstate);
 	return 0;
 }
 
@@ -1365,7 +1434,8 @@ static int process_grq(struct sk_buff *skb, struct nf_conn *ct,
 static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, GatekeeperConfirm *gcf)
+		       unsigned char **data, GatekeeperConfirm *gcf,
+		       struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -1375,7 +1445,7 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
 
 	pr_debug("nf_ct_ras: GCF\n");
 
-	if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port))
+	if (!get_h225_addr(ct, *data, &gcf->rasAddress, &addr, &port, ctstate))
 		return 0;
 
 	/* Registration port is the same as discovery port */
@@ -1410,7 +1480,8 @@ static int process_gcf(struct sk_buff *skb, struct nf_conn *ct,
 static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, RegistrationRequest *rrq)
+		       unsigned char **data, RegistrationRequest *rrq,
+		       struct h323_ct_state *ctstate)
 {
 	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int ret;
@@ -1420,7 +1491,8 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
 
 	ret = expect_q931(skb, ct, ctinfo, protoff, data,
 			  rrq->callSignalAddress.item,
-			  rrq->callSignalAddress.count);
+			  rrq->callSignalAddress.count,
+			  ctstate);
 	if (ret < 0)
 		return -1;
 
@@ -1429,7 +1501,8 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
 	    ct->status & IPS_NAT_MASK) {
 		ret = set_ras_addr(skb, ct, ctinfo, protoff, data,
 				   rrq->rasAddress.item,
-				   rrq->rasAddress.count);
+				   rrq->rasAddress.count,
+				   ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1447,7 +1520,8 @@ static int process_rrq(struct sk_buff *skb, struct nf_conn *ct,
 static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, RegistrationConfirm *rcf)
+		       unsigned char **data, RegistrationConfirm *rcf,
+		       struct h323_ct_state *ctstate)
 {
 	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -1461,8 +1535,9 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
 	if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK) {
 		ret = set_sig_addr(skb, ct, ctinfo, protoff, data,
-					rcf->callSignalAddress.item,
-					rcf->callSignalAddress.count);
+				   rcf->callSignalAddress.item,
+				   rcf->callSignalAddress.count,
+				   ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1498,7 +1573,8 @@ static int process_rcf(struct sk_buff *skb, struct nf_conn *ct,
 static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, UnregistrationRequest *urq)
+		       unsigned char **data, UnregistrationRequest *urq,
+		       struct h323_ct_state *ctstate)
 {
 	struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -1512,7 +1588,8 @@ static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
 	    ct->status & IPS_NAT_MASK) {
 		ret = set_sig_addr(skb, ct, ctinfo, protoff, data,
 				   urq->callSignalAddress.item,
-				   urq->callSignalAddress.count);
+				   urq->callSignalAddress.count,
+				   ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1532,7 +1609,8 @@ static int process_urq(struct sk_buff *skb, struct nf_conn *ct,
 static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, AdmissionRequest *arq)
+		       unsigned char **data, AdmissionRequest *arq,
+		       struct h323_ct_state *ctstate)
 {
 	const struct nf_ct_h323_master *info = nfct_help_data(ct);
 	int dir = CTINFO2DIR(ctinfo);
@@ -1545,7 +1623,7 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
 	set_h225_addr = rcu_dereference(set_h225_addr_hook);
 	if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
 	    get_h225_addr(ct, *data, &arq->destCallSignalAddress,
-			  &addr, &port) &&
+			  &addr, &port, ctstate) &&
 	    !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
 	    port == info->sig_port[dir] &&
 	    nf_ct_l3num(ct) == NFPROTO_IPV4 &&
@@ -1559,7 +1637,7 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
 
 	if ((arq->options & eAdmissionRequest_srcCallSignalAddress) &&
 	    get_h225_addr(ct, *data, &arq->srcCallSignalAddress,
-			  &addr, &port) &&
+			  &addr, &port, ctstate) &&
 	    !memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) &&
 	    set_h225_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK) {
@@ -1577,7 +1655,8 @@ static int process_arq(struct sk_buff *skb, struct nf_conn *ct,
 static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, AdmissionConfirm *acf)
+		       unsigned char **data, AdmissionConfirm *acf,
+		       struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -1589,7 +1668,7 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
 	pr_debug("nf_ct_ras: ACF\n");
 
 	if (!get_h225_addr(ct, *data, &acf->destCallSignalAddress,
-			   &addr, &port))
+			   &addr, &port, ctstate))
 		return 0;
 
 	if (!memcmp(&addr, &ct->tuplehash[dir].tuple.dst.u3, sizeof(addr))) {
@@ -1598,7 +1677,8 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
 		if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 		    ct->status & IPS_NAT_MASK)
 			return set_sig_addr(skb, ct, ctinfo, protoff, data,
-					    &acf->destCallSignalAddress, 1);
+					    &acf->destCallSignalAddress, 1,
+					    ctstate);
 		return 0;
 	}
 
@@ -1626,7 +1706,8 @@ static int process_acf(struct sk_buff *skb, struct nf_conn *ct,
 static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, LocationRequest *lrq)
+		       unsigned char **data, LocationRequest *lrq,
+		       struct h323_ct_state *ctstate)
 {
 	typeof(set_ras_addr_hook) set_ras_addr;
 
@@ -1636,7 +1717,8 @@ static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
 	if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK)
 		return set_ras_addr(skb, ct, ctinfo, protoff, data,
-				    &lrq->replyAddress, 1);
+				    &lrq->replyAddress, 1,
+				    ctstate);
 	return 0;
 }
 
@@ -1644,7 +1726,8 @@ static int process_lrq(struct sk_buff *skb, struct nf_conn *ct,
 static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, LocationConfirm *lcf)
+		       unsigned char **data, LocationConfirm *lcf,
+		       struct h323_ct_state *ctstate)
 {
 	int dir = CTINFO2DIR(ctinfo);
 	int ret = 0;
@@ -1655,7 +1738,7 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
 	pr_debug("nf_ct_ras: LCF\n");
 
 	if (!get_h225_addr(ct, *data, &lcf->callSignalAddress,
-			   &addr, &port))
+			   &addr, &port, ctstate))
 		return 0;
 
 	/* Need new expect for call signal */
@@ -1684,7 +1767,8 @@ static int process_lcf(struct sk_buff *skb, struct nf_conn *ct,
 static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, InfoRequestResponse *irr)
+		       unsigned char **data, InfoRequestResponse *irr,
+		       struct h323_ct_state *ctstate)
 {
 	int ret;
 	typeof(set_ras_addr_hook) set_ras_addr;
@@ -1696,7 +1780,7 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
 	if (set_ras_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK) {
 		ret = set_ras_addr(skb, ct, ctinfo, protoff, data,
-				   &irr->rasAddress, 1);
+				   &irr->rasAddress, 1, ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1705,8 +1789,9 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
 	if (set_sig_addr && nf_ct_l3num(ct) == NFPROTO_IPV4 &&
 	    ct->status & IPS_NAT_MASK) {
 		ret = set_sig_addr(skb, ct, ctinfo, protoff, data,
-					irr->callSignalAddress.item,
-					irr->callSignalAddress.count);
+				   irr->callSignalAddress.item,
+				   irr->callSignalAddress.count,
+				   ctstate);
 		if (ret < 0)
 			return -1;
 	}
@@ -1718,39 +1803,40 @@ static int process_irr(struct sk_buff *skb, struct nf_conn *ct,
 static int process_ras(struct sk_buff *skb, struct nf_conn *ct,
 		       enum ip_conntrack_info ctinfo,
 		       unsigned int protoff,
-		       unsigned char **data, RasMessage *ras)
+		       unsigned char **data, RasMessage *ras,
+		       struct h323_ct_state *ctstate)
 {
 	switch (ras->choice) {
 	case eRasMessage_gatekeeperRequest:
 		return process_grq(skb, ct, ctinfo, protoff, data,
-				   &ras->gatekeeperRequest);
+				   &ras->gatekeeperRequest, ctstate);
 	case eRasMessage_gatekeeperConfirm:
 		return process_gcf(skb, ct, ctinfo, protoff, data,
-				   &ras->gatekeeperConfirm);
+				   &ras->gatekeeperConfirm, ctstate);
 	case eRasMessage_registrationRequest:
 		return process_rrq(skb, ct, ctinfo, protoff, data,
-				   &ras->registrationRequest);
+				   &ras->registrationRequest, ctstate);
 	case eRasMessage_registrationConfirm:
 		return process_rcf(skb, ct, ctinfo, protoff, data,
-				   &ras->registrationConfirm);
+				   &ras->registrationConfirm, ctstate);
 	case eRasMessage_unregistrationRequest:
 		return process_urq(skb, ct, ctinfo, protoff, data,
-				   &ras->unregistrationRequest);
+				   &ras->unregistrationRequest, ctstate);
 	case eRasMessage_admissionRequest:
 		return process_arq(skb, ct, ctinfo, protoff, data,
-				   &ras->admissionRequest);
+				   &ras->admissionRequest, ctstate);
 	case eRasMessage_admissionConfirm:
 		return process_acf(skb, ct, ctinfo, protoff, data,
-				   &ras->admissionConfirm);
+				   &ras->admissionConfirm, ctstate);
 	case eRasMessage_locationRequest:
 		return process_lrq(skb, ct, ctinfo, protoff, data,
-				   &ras->locationRequest);
+				   &ras->locationRequest, ctstate);
 	case eRasMessage_locationConfirm:
 		return process_lcf(skb, ct, ctinfo, protoff, data,
-				   &ras->locationConfirm);
+				   &ras->locationConfirm, ctstate);
 	case eRasMessage_infoRequestResponse:
 		return process_irr(skb, ct, ctinfo, protoff, data,
-				   &ras->infoRequestResponse);
+				   &ras->infoRequestResponse, ctstate);
 	default:
 		pr_debug("nf_ct_ras: RAS message %d\n", ras->choice);
 		break;
@@ -1767,13 +1853,13 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
 	unsigned char *data;
 	int datalen = 0;
 	int ret;
+	struct h323_ct_state ctstate = {NULL, NULL, 0};
 
 	pr_debug("nf_ct_ras: skblen = %u\n", skb->len);
 
-	spin_lock_bh(&nf_h323_lock);
 
 	/* Get UDP data */
-	data = get_udp_data(skb, protoff, &datalen);
+	data = get_udp_data(skb, protoff, &datalen, &ctstate);
 	if (data == NULL)
 		goto accept;
 	pr_debug("nf_ct_ras: RAS message len=%d ", datalen);
@@ -1789,15 +1875,16 @@ static int ras_help(struct sk_buff *skb, unsigned int protoff,
 	}
 
 	/* Process RAS message */
-	if (process_ras(skb, ct, ctinfo, protoff, &data, &ras) < 0)
+	if (process_ras(skb, ct, ctinfo, protoff, &data, &ras,
+			&ctstate) < 0)
 		goto drop;
 
       accept:
-	spin_unlock_bh(&nf_h323_lock);
+	kfree(ctstate.buf);
 	return NF_ACCEPT;
 
       drop:
-	spin_unlock_bh(&nf_h323_lock);
+	kfree(ctstate.buf);
 	nf_ct_helper_log(skb, ct, "cannot process RAS message");
 	return NF_DROP;
 }
@@ -1839,7 +1926,6 @@ static void __exit nf_conntrack_h323_fini(void)
 	nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[1]);
 	nf_conntrack_helper_unregister(&nf_conntrack_helper_q931[0]);
 	nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
-	kfree(h323_buffer);
 	pr_debug("nf_ct_h323: fini\n");
 }
 
@@ -1848,9 +1934,6 @@ static int __init nf_conntrack_h323_init(void)
 {
 	int ret;
 
-	h323_buffer = kmalloc(65536, GFP_KERNEL);
-	if (!h323_buffer)
-		return -ENOMEM;
 	ret = nf_conntrack_helper_register(&nf_conntrack_helper_h245);
 	if (ret < 0)
 		goto err1;
@@ -1878,7 +1961,6 @@ err3:
 err2:
 	nf_conntrack_helper_unregister(&nf_conntrack_helper_h245);
 err1:
-	kfree(h323_buffer);
 	return ret;
 }
 
-- 
2.5.0


--
To unsubscribe from this list: send the line "unsubscribe netfilter-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux