⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nf_conntrack_h323_main.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * H.323 connection tracking helper * * Copyright (c) 2006 Jing Min Zhao <zhaojingmin@users.sourceforge.net> * * This source code is licensed under General Public License version 2. * * Based on the 'brute force' H.323 connection tracking module by * Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> * * For more information, please see http://nath323.sourceforge.net/ */#include <linux/module.h>#include <linux/moduleparam.h>#include <linux/ctype.h>#include <linux/inet.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/udp.h>#include <linux/tcp.h>#include <linux/skbuff.h>#include <net/route.h>#include <net/ip6_route.h>#include <net/netfilter/nf_conntrack.h>#include <net/netfilter/nf_conntrack_core.h>#include <net/netfilter/nf_conntrack_tuple.h>#include <net/netfilter/nf_conntrack_expect.h>#include <net/netfilter/nf_conntrack_ecache.h>#include <net/netfilter/nf_conntrack_helper.h>#include <linux/netfilter/nf_conntrack_h323.h>/* Parameters */static unsigned int default_rrq_ttl __read_mostly = 300;module_param(default_rrq_ttl, uint, 0600);MODULE_PARM_DESC(default_rrq_ttl, "use this TTL if it's missing in RRQ");static int gkrouted_only __read_mostly = 1;module_param(gkrouted_only, int, 0600);MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");static int callforward_filter __read_mostly = 1;module_param(callforward_filter, bool, 0600);MODULE_PARM_DESC(callforward_filter, "only create call forwarding expectations "				     "if both endpoints are on different sides "				     "(determined by routing information)");/* Hooks for NAT */int (*set_h245_addr_hook) (struct sk_buff *skb,			   unsigned char **data, int dataoff,			   H245_TransportAddress *taddr,			   union nf_conntrack_address *addr, __be16 port)			   __read_mostly;int (*set_h225_addr_hook) (struct sk_buff *skb,			   unsigned char **data, int dataoff,			   TransportAddress *taddr,			   union nf_conntrack_address *addr, __be16 port)			   __read_mostly;int (*set_sig_addr_hook) (struct sk_buff *skb,			  struct nf_conn *ct,			  enum ip_conntrack_info ctinfo,			  unsigned char **data,			  TransportAddress *taddr, int count) __read_mostly;int (*set_ras_addr_hook) (struct sk_buff *skb,			  struct nf_conn *ct,			  enum ip_conntrack_info ctinfo,			  unsigned char **data,			  TransportAddress *taddr, int count) __read_mostly;int (*nat_rtp_rtcp_hook) (struct sk_buff *skb,			  struct nf_conn *ct,			  enum ip_conntrack_info ctinfo,			  unsigned char **data, int dataoff,			  H245_TransportAddress *taddr,			  __be16 port, __be16 rtp_port,			  struct nf_conntrack_expect *rtp_exp,			  struct nf_conntrack_expect *rtcp_exp) __read_mostly;int (*nat_t120_hook) (struct sk_buff *skb,		      struct nf_conn *ct,		      enum ip_conntrack_info ctinfo,		      unsigned char **data, int dataoff,		      H245_TransportAddress *taddr, __be16 port,		      struct nf_conntrack_expect *exp) __read_mostly;int (*nat_h245_hook) (struct sk_buff *skb,		      struct nf_conn *ct,		      enum ip_conntrack_info ctinfo,		      unsigned char **data, int dataoff,		      TransportAddress *taddr, __be16 port,		      struct nf_conntrack_expect *exp) __read_mostly;int (*nat_callforwarding_hook) (struct sk_buff *skb,				struct nf_conn *ct,				enum ip_conntrack_info ctinfo,				unsigned char **data, int dataoff,				TransportAddress *taddr, __be16 port,				struct nf_conntrack_expect *exp) __read_mostly;int (*nat_q931_hook) (struct sk_buff *skb,		      struct nf_conn *ct,		      enum ip_conntrack_info ctinfo,		      unsigned char **data, TransportAddress *taddr, int idx,		      __be16 port, struct nf_conntrack_expect *exp)		      __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[];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){	struct nf_ct_h323_master *info = &nfct_help(ct)->help.ct_h323_info;	int dir = CTINFO2DIR(ctinfo);	struct tcphdr _tcph, *th;	int tcpdatalen;	int tcpdataoff;	unsigned char *tpkt;	int tpktlen;	int tpktoff;	/* Get TCP header */	th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);	if (th == NULL)		return 0;	/* Get TCP data offset */	tcpdataoff = protoff + th->doff * 4;	/* Get TCP data length */	tcpdatalen = skb->len - tcpdataoff;	if (tcpdatalen <= 0)	/* No TCP data */		goto clear_out;	if (*data == NULL) {	/* first TPKT */		/* Get first TPKT pointer */		tpkt = skb_header_pointer(skb, tcpdataoff, tcpdatalen,					  h323_buffer);		BUG_ON(tpkt == NULL);		/* Validate TPKT identifier */		if (tcpdatalen < 4 || tpkt[0] != 0x03 || tpkt[1] != 0) {			/* Netmeeting sends TPKT header and data separately */			if (info->tpkt_len[dir] > 0) {				pr_debug("nf_ct_h323: previous packet "					 "indicated separate TPKT data of %hu "					 "bytes\n", info->tpkt_len[dir]);				if (info->tpkt_len[dir] <= tcpdatalen) {					/* Yes, there was a TPKT header					 * received */					*data = tpkt;					*datalen = info->tpkt_len[dir];					*dataoff = 0;					goto out;				}				/* Fragmented TPKT */				pr_debug("nf_ct_h323: fragmented TPKT\n");				goto clear_out;			}			/* It is not even a TPKT */			return 0;		}		tpktoff = 0;	} else {		/* Next TPKT */		tpktoff = *dataoff + *datalen;		tcpdatalen -= tpktoff;		if (tcpdatalen <= 4)	/* No more TPKT */			goto clear_out;		tpkt = *data + *datalen;		/* Validate TPKT identifier */		if (tpkt[0] != 0x03 || tpkt[1] != 0)			goto clear_out;	}	/* Validate TPKT length */	tpktlen = tpkt[2] * 256 + tpkt[3];	if (tpktlen < 4)		goto clear_out;	if (tpktlen > tcpdatalen) {		if (tcpdatalen == 4) {	/* Separate TPKT header */			/* Netmeeting sends TPKT header and data separately */			pr_debug("nf_ct_h323: separate TPKT header indicates "				 "there will be TPKT data of %hu bytes\n",				 tpktlen - 4);			info->tpkt_len[dir] = tpktlen - 4;			return 0;		}		if (net_ratelimit())			printk("nf_ct_h323: incomplete TPKT (fragmented?)\n");		goto clear_out;	}	/* This is the encapsulated data */	*data = tpkt + 4;	*datalen = tpktlen - 4;	*dataoff = tpktoff + 4;      out:	/* Clear TPKT length */	info->tpkt_len[dir] = 0;	return 1;      clear_out:	info->tpkt_len[dir] = 0;	return 0;}/****************************************************************************/static int get_h245_addr(struct nf_conn *ct, unsigned char *data,			 H245_TransportAddress *taddr,			 union nf_conntrack_address *addr, __be16 *port){	unsigned char *p;	int family = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num;	int len;	if (taddr->choice != eH245_TransportAddress_unicastAddress)		return 0;	switch (taddr->unicastAddress.choice) {	case eUnicastAddress_iPAddress:		if (family != AF_INET)			return 0;		p = data + taddr->unicastAddress.iPAddress.network;		len = 4;		break;	case eUnicastAddress_iP6Address:		if (family != AF_INET6)			return 0;		p = data + taddr->unicastAddress.iP6Address.network;		len = 16;		break;	default:		return 0;	}	memcpy(addr, p, len);	memset((void *)addr + len, 0, sizeof(*addr) - len);	memcpy(port, p + len, sizeof(__be16));	return 1;}/****************************************************************************/static int expect_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct,			   enum ip_conntrack_info ctinfo,			   unsigned char **data, int dataoff,			   H245_TransportAddress *taddr){	int dir = CTINFO2DIR(ctinfo);	int ret = 0;	__be16 port;	__be16 rtp_port, rtcp_port;	union nf_conntrack_address addr;	struct nf_conntrack_expect *rtp_exp;	struct nf_conntrack_expect *rtcp_exp;	typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;	/* Read RTP or RTCP address */	if (!get_h245_addr(ct, *data, taddr, &addr, &port) ||	    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||	    port == 0)		return 0;	/* RTP port is even */	port &= htons(~1);	rtp_port = port;	rtcp_port = htons(ntohs(port) + 1);	/* Create expect for RTP */	if ((rtp_exp = nf_ct_expect_alloc(ct)) == NULL)		return -1;	nf_ct_expect_init(rtp_exp, ct->tuplehash[!dir].tuple.src.l3num,			  &ct->tuplehash[!dir].tuple.src.u3,			  &ct->tuplehash[!dir].tuple.dst.u3,			  IPPROTO_UDP, NULL, &rtp_port);	/* Create expect for RTCP */	if ((rtcp_exp = nf_ct_expect_alloc(ct)) == NULL) {		nf_ct_expect_put(rtp_exp);		return -1;	}	nf_ct_expect_init(rtcp_exp, ct->tuplehash[!dir].tuple.src.l3num,			  &ct->tuplehash[!dir].tuple.src.u3,			  &ct->tuplehash[!dir].tuple.dst.u3,			  IPPROTO_UDP, NULL, &rtcp_port);	if (memcmp(&ct->tuplehash[dir].tuple.src.u3,		   &ct->tuplehash[!dir].tuple.dst.u3,		   sizeof(ct->tuplehash[dir].tuple.src.u3)) &&		   (nat_rtp_rtcp = rcu_dereference(nat_rtp_rtcp_hook)) &&		   ct->status & IPS_NAT_MASK) {		/* NAT needed */		ret = nat_rtp_rtcp(skb, ct, ctinfo, data, dataoff,				   taddr, port, rtp_port, rtp_exp, rtcp_exp);	} else {		/* Conntrack only */		if (nf_ct_expect_related(rtp_exp) == 0) {			if (nf_ct_expect_related(rtcp_exp) == 0) {				pr_debug("nf_ct_h323: expect RTP ");				NF_CT_DUMP_TUPLE(&rtp_exp->tuple);				pr_debug("nf_ct_h323: expect RTCP ");				NF_CT_DUMP_TUPLE(&rtcp_exp->tuple);			} else {				nf_ct_unexpect_related(rtp_exp);				ret = -1;			}		} else			ret = -1;	}	nf_ct_expect_put(rtp_exp);	nf_ct_expect_put(rtcp_exp);	return ret;}/****************************************************************************/static int expect_t120(struct sk_buff *skb,		       struct nf_conn *ct,		       enum ip_conntrack_info ctinfo,		       unsigned char **data, int dataoff,		       H245_TransportAddress *taddr){	int dir = CTINFO2DIR(ctinfo);	int ret = 0;	__be16 port;	union nf_conntrack_address addr;	struct nf_conntrack_expect *exp;	typeof(nat_t120_hook) nat_t120;	/* Read T.120 address */	if (!get_h245_addr(ct, *data, taddr, &addr, &port) ||	    memcmp(&addr, &ct->tuplehash[dir].tuple.src.u3, sizeof(addr)) ||	    port == 0)		return 0;	/* Create expect for T.120 connections */	if ((exp = nf_ct_expect_alloc(ct)) == NULL)		return -1;	nf_ct_expect_init(exp, ct->tuplehash[!dir].tuple.src.l3num,			  &ct->tuplehash[!dir].tuple.src.u3,			  &ct->tuplehash[!dir].tuple.dst.u3,			  IPPROTO_TCP, NULL, &port);	exp->flags = NF_CT_EXPECT_PERMANENT;	/* Accept multiple channels */	if (memcmp(&ct->tuplehash[dir].tuple.src.u3,		   &ct->tuplehash[!dir].tuple.dst.u3,		   sizeof(ct->tuplehash[dir].tuple.src.u3)) &&	    (nat_t120 = rcu_dereference(nat_t120_hook)) &&	    ct->status & IPS_NAT_MASK) {		/* NAT needed */		ret = nat_t120(skb, ct, ctinfo, data, dataoff, taddr,			       port, exp);	} else {		/* Conntrack only */		if (nf_ct_expect_related(exp) == 0) {			pr_debug("nf_ct_h323: expect T.120 ");			NF_CT_DUMP_TUPLE(&exp->tuple);		} else			ret = -1;	}	nf_ct_expect_put(exp);	return ret;}/****************************************************************************/static int process_h245_channel(struct sk_buff *skb,				struct nf_conn *ct,				enum ip_conntrack_info ctinfo,				unsigned char **data, int dataoff,				H2250LogicalChannelParameters *channel){	int ret;	if (channel->options & eH2250LogicalChannelParameters_mediaChannel) {		/* RTP */		ret = expect_rtp_rtcp(skb, ct, ctinfo, data, dataoff,				      &channel->mediaChannel);		if (ret < 0)			return -1;	}	if (channel->	    options & eH2250LogicalChannelParameters_mediaControlChannel) {		/* RTCP */		ret = expect_rtp_rtcp(skb, ct, ctinfo, data, dataoff,				      &channel->mediaControlChannel);		if (ret < 0)			return -1;	}	return 0;}/****************************************************************************/static int process_olc(struct sk_buff *skb, struct nf_conn *ct,		       enum ip_conntrack_info ctinfo,		       unsigned char **data, int dataoff,		       OpenLogicalChannel *olc){	int ret;	pr_debug("nf_ct_h323: OpenLogicalChannel\n");	if (olc->forwardLogicalChannelParameters.multiplexParameters.choice ==	    eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters)	{		ret = process_h245_channel(skb, ct, ctinfo, data, dataoff,					   &olc->					   forwardLogicalChannelParameters.					   multiplexParameters.					   h2250LogicalChannelParameters);		if (ret < 0)			return -1;	}	if ((olc->options &	     eOpenLogicalChannel_reverseLogicalChannelParameters) &&	    (olc->reverseLogicalChannelParameters.options &	     eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters)	    && (olc->reverseLogicalChannelParameters.multiplexParameters.		choice ==		eOpenLogicalChannel_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))	{		ret =		    process_h245_channel(skb, ct, ctinfo, data, dataoff,					 &olc->					 reverseLogicalChannelParameters.					 multiplexParameters.					 h2250LogicalChannelParameters);		if (ret < 0)			return -1;	}	if ((olc->options & eOpenLogicalChannel_separateStack) &&	    olc->forwardLogicalChannelParameters.dataType.choice ==	    eDataType_data &&	    olc->forwardLogicalChannelParameters.dataType.data.application.	    choice == eDataApplicationCapability_application_t120 &&	    olc->forwardLogicalChannelParameters.dataType.data.application.	    t120.choice == eDataProtocolCapability_separateLANStack &&	    olc->separateStack.networkAddress.choice ==	    eNetworkAccessParameters_networkAddress_localAreaAddress) {		ret = expect_t120(skb, ct, ctinfo, data, dataoff,				  &olc->separateStack.networkAddress.				  localAreaAddress);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -