📄 ip_conntrack_helper_h323.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/config.h>#include <linux/module.h>#include <linux/netfilter.h>#include <linux/ip.h>#include <net/tcp.h>#include <linux/netfilter_ipv4/ip_conntrack.h>#include <linux/netfilter_ipv4/ip_conntrack_core.h>#include <linux/netfilter_ipv4/ip_conntrack_helper.h>#include <linux/netfilter_ipv4/ip_conntrack_tuple.h>#include <linux/netfilter_ipv4/ip_conntrack_h323.h>#include <linux/moduleparam.h>#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endif/* Parameters */static unsigned int default_rrq_ttl = 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 = 1;module_param(gkrouted_only, int, 0600);MODULE_PARM_DESC(gkrouted_only, "only accept calls from gatekeeper");/* Hooks for NAT */int (*set_h245_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, H245_TransportAddress * addr, u_int32_t ip, u_int16_t port);int (*set_h225_addr_hook) (struct sk_buff ** pskb, unsigned char **data, int dataoff, TransportAddress * addr, u_int32_t ip, u_int16_t port);int (*set_sig_addr_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress * addr, int count);int (*set_ras_addr_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress * addr, int count);int (*nat_rtp_rtcp_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, H245_TransportAddress * addr, u_int16_t port, u_int16_t rtp_port, struct ip_conntrack_expect * rtp_exp, struct ip_conntrack_expect * rtcp_exp);int (*nat_t120_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, H245_TransportAddress * addr, u_int16_t port, struct ip_conntrack_expect * exp);int (*nat_h245_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, TransportAddress * addr, u_int16_t port, struct ip_conntrack_expect * exp);int (*nat_q931_hook) (struct sk_buff ** pskb, struct ip_conntrack * ct, enum ip_conntrack_info ctinfo, unsigned char **data, TransportAddress * addr, int idx, u_int16_t port, struct ip_conntrack_expect * exp);static DEFINE_SPINLOCK(ip_h323_lock);static char *h323_buffer;/****************************************************************************/static int get_tpkt_data(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int *datalen, int *dataoff){ struct ip_ct_h323_master *info = &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(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_tcph), &_tcph); if (th == NULL) return 0; /* Get TCP data offset */ tcpdataoff = (*pskb)->nh.iph->ihl * 4 + th->doff * 4; /* Get TCP data length */ tcpdatalen = (*pskb)->len - tcpdataoff; if (tcpdatalen <= 0) /* No TCP data */ goto clear_out; if (*data == NULL) { /* first TPKT */ /* Get first TPKT pointer */ tpkt = skb_header_pointer(*pskb, 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) { DEBUGP("ip_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 */ if (net_ratelimit()) printk("ip_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 */ DEBUGP("ip_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("ip_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(unsigned char *data, H245_TransportAddress * addr, u_int32_t * ip, u_int16_t * port){ unsigned char *p; if (addr->choice != eH245_TransportAddress_unicastAddress || addr->unicastAddress.choice != eUnicastAddress_iPAddress) return 0; p = data + addr->unicastAddress.iPAddress.network; *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3])); *port = (p[4] << 8) | (p[5]); return 1;}/****************************************************************************/static int expect_rtp_rtcp(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, H245_TransportAddress * addr){ int dir = CTINFO2DIR(ctinfo); int ret = 0; u_int32_t ip; u_int16_t port; u_int16_t rtp_port; struct ip_conntrack_expect *rtp_exp; struct ip_conntrack_expect *rtcp_exp; /* Read RTP or RTCP address */ if (!get_h245_addr(*data, addr, &ip, &port) || ip != ct->tuplehash[dir].tuple.src.ip || port == 0) return 0; /* RTP port is even */ rtp_port = port & (~1); /* Create expect for RTP */ if ((rtp_exp = ip_conntrack_expect_alloc(ct)) == NULL) return -1; rtp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; rtp_exp->tuple.src.u.udp.port = 0; rtp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; rtp_exp->tuple.dst.u.udp.port = htons(rtp_port); rtp_exp->tuple.dst.protonum = IPPROTO_UDP; rtp_exp->mask.src.ip = 0xFFFFFFFF; rtp_exp->mask.src.u.udp.port = 0; rtp_exp->mask.dst.ip = 0xFFFFFFFF; rtp_exp->mask.dst.u.udp.port = 0xFFFF; rtp_exp->mask.dst.protonum = 0xFF; rtp_exp->flags = 0; /* Create expect for RTCP */ if ((rtcp_exp = ip_conntrack_expect_alloc(ct)) == NULL) { ip_conntrack_expect_put(rtp_exp); return -1; } rtcp_exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; rtcp_exp->tuple.src.u.udp.port = 0; rtcp_exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; rtcp_exp->tuple.dst.u.udp.port = htons(rtp_port + 1); rtcp_exp->tuple.dst.protonum = IPPROTO_UDP; rtcp_exp->mask.src.ip = 0xFFFFFFFF; rtcp_exp->mask.src.u.udp.port = 0; rtcp_exp->mask.dst.ip = 0xFFFFFFFF; rtcp_exp->mask.dst.u.udp.port = 0xFFFF; rtcp_exp->mask.dst.protonum = 0xFF; rtcp_exp->flags = 0; if (ct->tuplehash[dir].tuple.src.ip != ct->tuplehash[!dir].tuple.dst.ip && nat_rtp_rtcp_hook) { /* NAT needed */ ret = nat_rtp_rtcp_hook(pskb, ct, ctinfo, data, dataoff, addr, port, rtp_port, rtp_exp, rtcp_exp); } else { /* Conntrack only */ rtp_exp->expectfn = NULL; rtcp_exp->expectfn = NULL; if (ip_conntrack_expect_related(rtp_exp) == 0) { if (ip_conntrack_expect_related(rtcp_exp) == 0) { DEBUGP("ip_ct_h323: expect RTP " "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(rtp_exp->tuple.src.ip), ntohs(rtp_exp->tuple.src.u.udp.port), NIPQUAD(rtp_exp->tuple.dst.ip), ntohs(rtp_exp->tuple.dst.u.udp.port)); DEBUGP("ip_ct_h323: expect RTCP " "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(rtcp_exp->tuple.src.ip), ntohs(rtcp_exp->tuple.src.u.udp.port), NIPQUAD(rtcp_exp->tuple.dst.ip), ntohs(rtcp_exp->tuple.dst.u.udp.port)); } else { ip_conntrack_unexpect_related(rtp_exp); ret = -1; } } else ret = -1; } ip_conntrack_expect_put(rtp_exp); ip_conntrack_expect_put(rtcp_exp); return ret;}/****************************************************************************/static int expect_t120(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, H245_TransportAddress * addr){ int dir = CTINFO2DIR(ctinfo); int ret = 0; u_int32_t ip; u_int16_t port; struct ip_conntrack_expect *exp = NULL; /* Read T.120 address */ if (!get_h245_addr(*data, addr, &ip, &port) || ip != ct->tuplehash[dir].tuple.src.ip || port == 0) return 0; /* Create expect for T.120 connections */ if ((exp = ip_conntrack_expect_alloc(ct)) == NULL) return -1; exp->tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; exp->tuple.src.u.tcp.port = 0; exp->tuple.dst.ip = ct->tuplehash[!dir].tuple.dst.ip; exp->tuple.dst.u.tcp.port = htons(port); exp->tuple.dst.protonum = IPPROTO_TCP; exp->mask.src.ip = 0xFFFFFFFF; exp->mask.src.u.tcp.port = 0; exp->mask.dst.ip = 0xFFFFFFFF; exp->mask.dst.u.tcp.port = 0xFFFF; exp->mask.dst.protonum = 0xFF; exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple channels */ if (ct->tuplehash[dir].tuple.src.ip != ct->tuplehash[!dir].tuple.dst.ip && nat_t120_hook) { /* NAT needed */ ret = nat_t120_hook(pskb, ct, ctinfo, data, dataoff, addr, port, exp); } else { /* Conntrack only */ exp->expectfn = NULL; if (ip_conntrack_expect_related(exp) == 0) { DEBUGP("ip_ct_h323: expect T.120 " "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", NIPQUAD(exp->tuple.src.ip), ntohs(exp->tuple.src.u.tcp.port), NIPQUAD(exp->tuple.dst.ip), ntohs(exp->tuple.dst.u.tcp.port)); } else ret = -1; } ip_conntrack_expect_put(exp); return ret;}/****************************************************************************/static int process_h245_channel(struct sk_buff **pskb, struct ip_conntrack *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(pskb, ct, ctinfo, data, dataoff, &channel->mediaChannel); if (ret < 0) return -1; } if (channel-> options & eH2250LogicalChannelParameters_mediaControlChannel) { /* RTCP */ ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff, &channel->mediaControlChannel); if (ret < 0) return -1; } return 0;}/****************************************************************************/static int process_olc(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, unsigned char **data, int dataoff, OpenLogicalChannel * olc){ int ret; DEBUGP("ip_ct_h323: OpenLogicalChannel\n"); if (olc->forwardLogicalChannelParameters.multiplexParameters.choice == eOpenLogicalChannel_forwardLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters) { ret = process_h245_channel(pskb, 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(pskb, ct, ctinfo, data, dataoff, &olc-> reverseLogicalChannelParameters. multiplexParameters. h2250LogicalChannelParameters);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -