📄 nf_conntrack_h323_main.c
字号:
/* * 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 + -