12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841 |
- /*
- * 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/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>
- #include <linux/ctype.h>
- #include <linux/inet.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");
- static int callforward_filter = 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 ** pskb,
- unsigned char **data, int dataoff,
- H245_TransportAddress * addr,
- __be32 ip, u_int16_t port);
- int (*set_h225_addr_hook) (struct sk_buff ** pskb,
- unsigned char **data, int dataoff,
- TransportAddress * addr,
- __be32 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_callforwarding_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,
- __be32 * 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;
- __be32 ip;
- u_int16_t port;
- u_int16_t rtp_port;
- struct ip_conntrack_expect *rtp_exp;
- struct ip_conntrack_expect *rtcp_exp;
- typeof(nat_rtp_rtcp_hook) nat_rtp_rtcp;
- /* 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 = htonl(0xFFFFFFFF);
- rtp_exp->mask.src.u.udp.port = 0;
- rtp_exp->mask.dst.ip = htonl(0xFFFFFFFF);
- rtp_exp->mask.dst.u.udp.port = htons(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 = htonl(0xFFFFFFFF);
- rtcp_exp->mask.src.u.udp.port = 0;
- rtcp_exp->mask.dst.ip = htonl(0xFFFFFFFF);
- rtcp_exp->mask.dst.u.udp.port = htons(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 = rcu_dereference(nat_rtp_rtcp_hook))) {
- /* NAT needed */
- ret = nat_rtp_rtcp(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;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp = NULL;
- typeof(nat_t120_hook) nat_t120;
- /* 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 = htonl(0xFFFFFFFF);
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(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 = rcu_dereference(nat_t120_hook))) {
- /* NAT needed */
- ret = nat_t120(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);
- 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(pskb, ct, ctinfo, data, dataoff,
- &olc->separateStack.networkAddress.
- localAreaAddress);
- if (ret < 0)
- return -1;
- }
- return 0;
- }
- /****************************************************************************/
- static int process_olca(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- OpenLogicalChannelAck * olca)
- {
- H2250LogicalChannelAckParameters *ack;
- int ret;
- DEBUGP("ip_ct_h323: OpenLogicalChannelAck\n");
- if ((olca->options &
- eOpenLogicalChannelAck_reverseLogicalChannelParameters) &&
- (olca->reverseLogicalChannelParameters.options &
- eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters)
- && (olca->reverseLogicalChannelParameters.multiplexParameters.
- choice ==
- eOpenLogicalChannelAck_reverseLogicalChannelParameters_multiplexParameters_h2250LogicalChannelParameters))
- {
- ret = process_h245_channel(pskb, ct, ctinfo, data, dataoff,
- &olca->
- reverseLogicalChannelParameters.
- multiplexParameters.
- h2250LogicalChannelParameters);
- if (ret < 0)
- return -1;
- }
- if ((olca->options &
- eOpenLogicalChannelAck_forwardMultiplexAckParameters) &&
- (olca->forwardMultiplexAckParameters.choice ==
- eOpenLogicalChannelAck_forwardMultiplexAckParameters_h2250LogicalChannelAckParameters))
- {
- ack = &olca->forwardMultiplexAckParameters.
- h2250LogicalChannelAckParameters;
- if (ack->options &
- eH2250LogicalChannelAckParameters_mediaChannel) {
- /* RTP */
- ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
- &ack->mediaChannel);
- if (ret < 0)
- return -1;
- }
- if (ack->options &
- eH2250LogicalChannelAckParameters_mediaControlChannel) {
- /* RTCP */
- ret = expect_rtp_rtcp(pskb, ct, ctinfo, data, dataoff,
- &ack->mediaControlChannel);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- MultimediaSystemControlMessage * mscm)
- {
- switch (mscm->choice) {
- case eMultimediaSystemControlMessage_request:
- if (mscm->request.choice ==
- eRequestMessage_openLogicalChannel) {
- return process_olc(pskb, ct, ctinfo, data, dataoff,
- &mscm->request.openLogicalChannel);
- }
- DEBUGP("ip_ct_h323: H.245 Request %d\n",
- mscm->request.choice);
- break;
- case eMultimediaSystemControlMessage_response:
- if (mscm->response.choice ==
- eResponseMessage_openLogicalChannelAck) {
- return process_olca(pskb, ct, ctinfo, data, dataoff,
- &mscm->response.
- openLogicalChannelAck);
- }
- DEBUGP("ip_ct_h323: H.245 Response %d\n",
- mscm->response.choice);
- break;
- default:
- DEBUGP("ip_ct_h323: H.245 signal %d\n", mscm->choice);
- break;
- }
- return 0;
- }
- /****************************************************************************/
- static int h245_help(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo)
- {
- static MultimediaSystemControlMessage mscm;
- unsigned char *data = NULL;
- int datalen;
- int dataoff;
- int ret;
- /* Until there's been traffic both ways, don't look in packets. */
- if (ctinfo != IP_CT_ESTABLISHED
- && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
- return NF_ACCEPT;
- }
- DEBUGP("ip_ct_h245: skblen = %u\n", (*pskb)->len);
- spin_lock_bh(&ip_h323_lock);
- /* Process each TPKT */
- while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
- DEBUGP("ip_ct_h245: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
- NIPQUAD((*pskb)->nh.iph->saddr),
- NIPQUAD((*pskb)->nh.iph->daddr), datalen);
- /* Decode H.245 signal */
- ret = DecodeMultimediaSystemControlMessage(data, datalen,
- &mscm);
- if (ret < 0) {
- if (net_ratelimit())
- printk("ip_ct_h245: decoding error: %s\n",
- ret == H323_ERROR_BOUND ?
- "out of bound" : "out of range");
- /* We don't drop when decoding error */
- break;
- }
- /* Process H.245 signal */
- if (process_h245(pskb, ct, ctinfo, &data, dataoff, &mscm) < 0)
- goto drop;
- }
- spin_unlock_bh(&ip_h323_lock);
- return NF_ACCEPT;
- drop:
- spin_unlock_bh(&ip_h323_lock);
- if (net_ratelimit())
- printk("ip_ct_h245: packet dropped\n");
- return NF_DROP;
- }
- /****************************************************************************/
- static struct ip_conntrack_helper ip_conntrack_helper_h245 = {
- .name = "H.245",
- .me = THIS_MODULE,
- .max_expected = H323_RTP_CHANNEL_MAX * 4 + 2 /* T.120 */ ,
- .timeout = 240,
- .tuple = {.dst = {.protonum = IPPROTO_TCP}},
- .mask = {.src = {.u = {0xFFFF}},
- .dst = {.protonum = 0xFF}},
- .help = h245_help
- };
- /****************************************************************************/
- void ip_conntrack_h245_expect(struct ip_conntrack *new,
- struct ip_conntrack_expect *this)
- {
- write_lock_bh(&ip_conntrack_lock);
- new->helper = &ip_conntrack_helper_h245;
- write_unlock_bh(&ip_conntrack_lock);
- }
- /****************************************************************************/
- int get_h225_addr(unsigned char *data, TransportAddress * addr,
- __be32 * ip, u_int16_t * port)
- {
- unsigned char *p;
- if (addr->choice != eTransportAddress_ipAddress)
- return 0;
- p = data + addr->ipAddress.ip;
- *ip = htonl((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]));
- *port = (p[4] << 8) | (p[5]);
- return 1;
- }
- /****************************************************************************/
- static int expect_h245(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- TransportAddress * addr)
- {
- int dir = CTINFO2DIR(ctinfo);
- int ret = 0;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp = NULL;
- typeof(nat_h245_hook) nat_h245;
- /* Read h245Address */
- if (!get_h225_addr(*data, addr, &ip, &port) ||
- ip != ct->tuplehash[dir].tuple.src.ip || port == 0)
- return 0;
- /* Create expect for h245 connection */
- 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 = htonl(0xFFFFFFFF);
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
- exp->flags = 0;
- if (ct->tuplehash[dir].tuple.src.ip !=
- ct->tuplehash[!dir].tuple.dst.ip &&
- (nat_h245 = rcu_dereference(nat_h245_hook))) {
- /* NAT needed */
- ret = nat_h245(pskb, ct, ctinfo, data, dataoff, addr,
- port, exp);
- } else { /* Conntrack only */
- exp->expectfn = ip_conntrack_h245_expect;
- if (ip_conntrack_expect_related(exp) == 0) {
- DEBUGP("ip_ct_q931: expect H.245 "
- "%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;
- }
- /* Forwarding declaration */
- void ip_conntrack_q931_expect(struct ip_conntrack *new,
- struct ip_conntrack_expect *this);
- /****************************************************************************/
- static int expect_callforwarding(struct sk_buff **pskb,
- struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- TransportAddress * addr)
- {
- int dir = CTINFO2DIR(ctinfo);
- int ret = 0;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp = NULL;
- typeof(nat_callforwarding_hook) nat_callforwarding;
- /* Read alternativeAddress */
- if (!get_h225_addr(*data, addr, &ip, &port) || port == 0)
- return 0;
- /* If the calling party is on the same side of the forward-to party,
- * we don't need to track the second call */
- if (callforward_filter) {
- struct rtable *rt1, *rt2;
- struct flowi fl1 = {
- .fl4_dst = ip,
- };
- struct flowi fl2 = {
- .fl4_dst = ct->tuplehash[!dir].tuple.src.ip,
- };
- if (ip_route_output_key(&rt1, &fl1) == 0) {
- if (ip_route_output_key(&rt2, &fl2) == 0) {
- if (rt1->rt_gateway == rt2->rt_gateway &&
- rt1->u.dst.dev == rt2->u.dst.dev)
- ret = 1;
- dst_release(&rt2->u.dst);
- }
- dst_release(&rt1->u.dst);
- }
- if (ret) {
- DEBUGP("ip_ct_q931: Call Forwarding not tracked\n");
- return 0;
- }
- }
- /* Create expect for the second call leg */
- 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 = ip;
- exp->tuple.dst.u.tcp.port = htons(port);
- exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = htonl(0xFFFFFFFF);
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
- exp->flags = 0;
- if (ct->tuplehash[dir].tuple.src.ip !=
- ct->tuplehash[!dir].tuple.dst.ip &&
- (nat_callforwarding = rcu_dereference(nat_callforwarding_hook))) {
- /* Need NAT */
- ret = nat_callforwarding(pskb, ct, ctinfo, data, dataoff,
- addr, port, exp);
- } else { /* Conntrack only */
- exp->expectfn = ip_conntrack_q931_expect;
- if (ip_conntrack_expect_related(exp) == 0) {
- DEBUGP("ip_ct_q931: expect Call Forwarding "
- "%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_setup(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- Setup_UUIE * setup)
- {
- int dir = CTINFO2DIR(ctinfo);
- int ret;
- int i;
- __be32 ip;
- u_int16_t port;
- typeof(set_h225_addr_hook) set_h225_addr;
- DEBUGP("ip_ct_q931: Setup\n");
- if (setup->options & eSetup_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
- &setup->h245Address);
- if (ret < 0)
- return -1;
- }
- set_h225_addr = rcu_dereference(set_h225_addr_hook);
- if ((setup->options & eSetup_UUIE_destCallSignalAddress) &&
- (set_h225_addr) &&
- get_h225_addr(*data, &setup->destCallSignalAddress, &ip, &port) &&
- ip != ct->tuplehash[!dir].tuple.src.ip) {
- DEBUGP("ip_ct_q931: set destCallSignalAddress "
- "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(ip), port,
- NIPQUAD(ct->tuplehash[!dir].tuple.src.ip),
- ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port));
- ret = set_h225_addr(pskb, data, dataoff,
- &setup->destCallSignalAddress,
- ct->tuplehash[!dir].tuple.src.ip,
- ntohs(ct->tuplehash[!dir].tuple.src.
- u.tcp.port));
- if (ret < 0)
- return -1;
- }
- if ((setup->options & eSetup_UUIE_sourceCallSignalAddress) &&
- (set_h225_addr) &&
- get_h225_addr(*data, &setup->sourceCallSignalAddress, &ip, &port)
- && ip != ct->tuplehash[!dir].tuple.dst.ip) {
- DEBUGP("ip_ct_q931: set sourceCallSignalAddress "
- "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n",
- NIPQUAD(ip), port,
- NIPQUAD(ct->tuplehash[!dir].tuple.dst.ip),
- ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port));
- ret = set_h225_addr(pskb, data, dataoff,
- &setup->sourceCallSignalAddress,
- ct->tuplehash[!dir].tuple.dst.ip,
- ntohs(ct->tuplehash[!dir].tuple.dst.
- u.tcp.port));
- if (ret < 0)
- return -1;
- }
- if (setup->options & eSetup_UUIE_fastStart) {
- for (i = 0; i < setup->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &setup->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_callproceeding(struct sk_buff **pskb,
- struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- CallProceeding_UUIE * callproc)
- {
- int ret;
- int i;
- DEBUGP("ip_ct_q931: CallProceeding\n");
- if (callproc->options & eCallProceeding_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
- &callproc->h245Address);
- if (ret < 0)
- return -1;
- }
- if (callproc->options & eCallProceeding_UUIE_fastStart) {
- for (i = 0; i < callproc->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &callproc->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_connect(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- Connect_UUIE * connect)
- {
- int ret;
- int i;
- DEBUGP("ip_ct_q931: Connect\n");
- if (connect->options & eConnect_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
- &connect->h245Address);
- if (ret < 0)
- return -1;
- }
- if (connect->options & eConnect_UUIE_fastStart) {
- for (i = 0; i < connect->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &connect->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_alerting(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- Alerting_UUIE * alert)
- {
- int ret;
- int i;
- DEBUGP("ip_ct_q931: Alerting\n");
- if (alert->options & eAlerting_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
- &alert->h245Address);
- if (ret < 0)
- return -1;
- }
- if (alert->options & eAlerting_UUIE_fastStart) {
- for (i = 0; i < alert->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &alert->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_information(struct sk_buff **pskb,
- struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- Information_UUIE * info)
- {
- int ret;
- int i;
- DEBUGP("ip_ct_q931: Information\n");
- if (info->options & eInformation_UUIE_fastStart) {
- for (i = 0; i < info->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &info->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_facility(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- Facility_UUIE * facility)
- {
- int ret;
- int i;
- DEBUGP("ip_ct_q931: Facility\n");
- if (facility->reason.choice == eFacilityReason_callForwarded) {
- if (facility->options & eFacility_UUIE_alternativeAddress)
- return expect_callforwarding(pskb, ct, ctinfo, data,
- dataoff,
- &facility->
- alternativeAddress);
- return 0;
- }
- if (facility->options & eFacility_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
- &facility->h245Address);
- if (ret < 0)
- return -1;
- }
- if (facility->options & eFacility_UUIE_fastStart) {
- for (i = 0; i < facility->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &facility->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_progress(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff,
- Progress_UUIE * progress)
- {
- int ret;
- int i;
- DEBUGP("ip_ct_q931: Progress\n");
- if (progress->options & eProgress_UUIE_h245Address) {
- ret = expect_h245(pskb, ct, ctinfo, data, dataoff,
- &progress->h245Address);
- if (ret < 0)
- return -1;
- }
- if (progress->options & eProgress_UUIE_fastStart) {
- for (i = 0; i < progress->fastStart.count; i++) {
- ret = process_olc(pskb, ct, ctinfo, data, dataoff,
- &progress->fastStart.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int process_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, int dataoff, Q931 * q931)
- {
- H323_UU_PDU *pdu = &q931->UUIE.h323_uu_pdu;
- int i;
- int ret = 0;
- switch (pdu->h323_message_body.choice) {
- case eH323_UU_PDU_h323_message_body_setup:
- ret = process_setup(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.setup);
- break;
- case eH323_UU_PDU_h323_message_body_callProceeding:
- ret = process_callproceeding(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.
- callProceeding);
- break;
- case eH323_UU_PDU_h323_message_body_connect:
- ret = process_connect(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.connect);
- break;
- case eH323_UU_PDU_h323_message_body_alerting:
- ret = process_alerting(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.alerting);
- break;
- case eH323_UU_PDU_h323_message_body_information:
- ret = process_information(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.
- information);
- break;
- case eH323_UU_PDU_h323_message_body_facility:
- ret = process_facility(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.facility);
- break;
- case eH323_UU_PDU_h323_message_body_progress:
- ret = process_progress(pskb, ct, ctinfo, data, dataoff,
- &pdu->h323_message_body.progress);
- break;
- default:
- DEBUGP("ip_ct_q931: Q.931 signal %d\n",
- pdu->h323_message_body.choice);
- break;
- }
- if (ret < 0)
- return -1;
- if (pdu->options & eH323_UU_PDU_h245Control) {
- for (i = 0; i < pdu->h245Control.count; i++) {
- ret = process_h245(pskb, ct, ctinfo, data, dataoff,
- &pdu->h245Control.item[i]);
- if (ret < 0)
- return -1;
- }
- }
- return 0;
- }
- /****************************************************************************/
- static int q931_help(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo)
- {
- static Q931 q931;
- unsigned char *data = NULL;
- int datalen;
- int dataoff;
- int ret;
- /* Until there's been traffic both ways, don't look in packets. */
- if (ctinfo != IP_CT_ESTABLISHED
- && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) {
- return NF_ACCEPT;
- }
- DEBUGP("ip_ct_q931: skblen = %u\n", (*pskb)->len);
- spin_lock_bh(&ip_h323_lock);
- /* Process each TPKT */
- while (get_tpkt_data(pskb, ct, ctinfo, &data, &datalen, &dataoff)) {
- DEBUGP("ip_ct_q931: TPKT %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
- NIPQUAD((*pskb)->nh.iph->saddr),
- NIPQUAD((*pskb)->nh.iph->daddr), datalen);
- /* Decode Q.931 signal */
- ret = DecodeQ931(data, datalen, &q931);
- if (ret < 0) {
- if (net_ratelimit())
- printk("ip_ct_q931: decoding error: %s\n",
- ret == H323_ERROR_BOUND ?
- "out of bound" : "out of range");
- /* We don't drop when decoding error */
- break;
- }
- /* Process Q.931 signal */
- if (process_q931(pskb, ct, ctinfo, &data, dataoff, &q931) < 0)
- goto drop;
- }
- spin_unlock_bh(&ip_h323_lock);
- return NF_ACCEPT;
- drop:
- spin_unlock_bh(&ip_h323_lock);
- if (net_ratelimit())
- printk("ip_ct_q931: packet dropped\n");
- return NF_DROP;
- }
- /****************************************************************************/
- static struct ip_conntrack_helper ip_conntrack_helper_q931 = {
- .name = "Q.931",
- .me = THIS_MODULE,
- .max_expected = H323_RTP_CHANNEL_MAX * 4 + 4 /* T.120 and H.245 */ ,
- .timeout = 240,
- .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(Q931_PORT)}}},
- .dst = {.protonum = IPPROTO_TCP}},
- .mask = {.src = {.u = {0xFFFF}},
- .dst = {.protonum = 0xFF}},
- .help = q931_help
- };
- /****************************************************************************/
- void ip_conntrack_q931_expect(struct ip_conntrack *new,
- struct ip_conntrack_expect *this)
- {
- write_lock_bh(&ip_conntrack_lock);
- new->helper = &ip_conntrack_helper_q931;
- write_unlock_bh(&ip_conntrack_lock);
- }
- /****************************************************************************/
- static unsigned char *get_udp_data(struct sk_buff **pskb, int *datalen)
- {
- struct udphdr _uh, *uh;
- int dataoff;
- uh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl * 4, sizeof(_uh),
- &_uh);
- if (uh == NULL)
- return NULL;
- dataoff = (*pskb)->nh.iph->ihl * 4 + sizeof(_uh);
- if (dataoff >= (*pskb)->len)
- return NULL;
- *datalen = (*pskb)->len - dataoff;
- return skb_header_pointer(*pskb, dataoff, *datalen, h323_buffer);
- }
- /****************************************************************************/
- static struct ip_conntrack_expect *find_expect(struct ip_conntrack *ct,
- __be32 ip, u_int16_t port)
- {
- struct ip_conntrack_expect *exp;
- struct ip_conntrack_tuple tuple;
- tuple.src.ip = 0;
- tuple.src.u.tcp.port = 0;
- tuple.dst.ip = ip;
- tuple.dst.u.tcp.port = htons(port);
- tuple.dst.protonum = IPPROTO_TCP;
- exp = __ip_conntrack_expect_find(&tuple);
- if (exp && exp->master == ct)
- return exp;
- return NULL;
- }
- /****************************************************************************/
- static int set_expect_timeout(struct ip_conntrack_expect *exp,
- unsigned timeout)
- {
- if (!exp || !del_timer(&exp->timeout))
- return 0;
- exp->timeout.expires = jiffies + timeout * HZ;
- add_timer(&exp->timeout);
- return 1;
- }
- /****************************************************************************/
- static int expect_q931(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data,
- TransportAddress * addr, int count)
- {
- struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
- int dir = CTINFO2DIR(ctinfo);
- int ret = 0;
- int i;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp;
- typeof(nat_q931_hook) nat_q931;
- /* Look for the first related address */
- for (i = 0; i < count; i++) {
- if (get_h225_addr(*data, &addr[i], &ip, &port) &&
- ip == ct->tuplehash[dir].tuple.src.ip && port != 0)
- break;
- }
- if (i >= count) /* Not found */
- return 0;
- /* Create expect for Q.931 */
- if ((exp = ip_conntrack_expect_alloc(ct)) == NULL)
- return -1;
- exp->tuple.src.ip = gkrouted_only ? /* only accept calls from GK? */
- ct->tuplehash[!dir].tuple.src.ip : 0;
- 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 = gkrouted_only ? htonl(0xFFFFFFFF) : 0;
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
- exp->flags = IP_CT_EXPECT_PERMANENT; /* Accept multiple calls */
- nat_q931 = rcu_dereference(nat_q931_hook);
- if (nat_q931) { /* Need NAT */
- ret = nat_q931(pskb, ct, ctinfo, data, addr, i, port, exp);
- } else { /* Conntrack only */
- exp->expectfn = ip_conntrack_q931_expect;
- if (ip_conntrack_expect_related(exp) == 0) {
- DEBUGP("ip_ct_ras: expect Q.931 "
- "%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));
- /* Save port for looking up expect in processing RCF */
- info->sig_port[dir] = port;
- } else
- ret = -1;
- }
- ip_conntrack_expect_put(exp);
- return ret;
- }
- /****************************************************************************/
- static int process_grq(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, GatekeeperRequest * grq)
- {
- typeof(set_ras_addr_hook) set_ras_addr;
- DEBUGP("ip_ct_ras: GRQ\n");
- set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr) /* NATed */
- return set_ras_addr(pskb, ct, ctinfo, data,
- &grq->rasAddress, 1);
- return 0;
- }
- /* Declare before using */
- static void ip_conntrack_ras_expect(struct ip_conntrack *new,
- struct ip_conntrack_expect *this);
- /****************************************************************************/
- static int process_gcf(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, GatekeeperConfirm * gcf)
- {
- int dir = CTINFO2DIR(ctinfo);
- int ret = 0;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp;
- DEBUGP("ip_ct_ras: GCF\n");
- if (!get_h225_addr(*data, &gcf->rasAddress, &ip, &port))
- return 0;
- /* Registration port is the same as discovery port */
- if (ip == ct->tuplehash[dir].tuple.src.ip &&
- port == ntohs(ct->tuplehash[dir].tuple.src.u.udp.port))
- return 0;
- /* Avoid RAS expectation loops. A GCF is never expected. */
- if (test_bit(IPS_EXPECTED_BIT, &ct->status))
- return 0;
- /* Need new expect */
- 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 = ip;
- exp->tuple.dst.u.tcp.port = htons(port);
- exp->tuple.dst.protonum = IPPROTO_UDP;
- exp->mask.src.ip = htonl(0xFFFFFFFF);
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
- exp->flags = 0;
- exp->expectfn = ip_conntrack_ras_expect;
- if (ip_conntrack_expect_related(exp) == 0) {
- DEBUGP("ip_ct_ras: expect RAS "
- "%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_rrq(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, RegistrationRequest * rrq)
- {
- struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
- int ret;
- typeof(set_ras_addr_hook) set_ras_addr;
- DEBUGP("ip_ct_ras: RRQ\n");
- ret = expect_q931(pskb, ct, ctinfo, data,
- rrq->callSignalAddress.item,
- rrq->callSignalAddress.count);
- if (ret < 0)
- return -1;
- set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr) {
- ret = set_ras_addr(pskb, ct, ctinfo, data,
- rrq->rasAddress.item,
- rrq->rasAddress.count);
- if (ret < 0)
- return -1;
- }
- if (rrq->options & eRegistrationRequest_timeToLive) {
- DEBUGP("ip_ct_ras: RRQ TTL = %u seconds\n", rrq->timeToLive);
- info->timeout = rrq->timeToLive;
- } else
- info->timeout = default_rrq_ttl;
- return 0;
- }
- /****************************************************************************/
- static int process_rcf(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, RegistrationConfirm * rcf)
- {
- struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
- int dir = CTINFO2DIR(ctinfo);
- int ret;
- struct ip_conntrack_expect *exp;
- typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("ip_ct_ras: RCF\n");
- set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr) {
- ret = set_sig_addr(pskb, ct, ctinfo, data,
- rcf->callSignalAddress.item,
- rcf->callSignalAddress.count);
- if (ret < 0)
- return -1;
- }
- if (rcf->options & eRegistrationConfirm_timeToLive) {
- DEBUGP("ip_ct_ras: RCF TTL = %u seconds\n", rcf->timeToLive);
- info->timeout = rcf->timeToLive;
- }
- if (info->timeout > 0) {
- DEBUGP
- ("ip_ct_ras: set RAS connection timeout to %u seconds\n",
- info->timeout);
- ip_ct_refresh(ct, *pskb, info->timeout * HZ);
- /* Set expect timeout */
- read_lock_bh(&ip_conntrack_lock);
- exp = find_expect(ct, ct->tuplehash[dir].tuple.dst.ip,
- info->sig_port[!dir]);
- if (exp) {
- DEBUGP("ip_ct_ras: set Q.931 expect "
- "(%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu) "
- "timeout to %u seconds\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),
- info->timeout);
- set_expect_timeout(exp, info->timeout);
- }
- read_unlock_bh(&ip_conntrack_lock);
- }
- return 0;
- }
- /****************************************************************************/
- static int process_urq(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, UnregistrationRequest * urq)
- {
- struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
- int dir = CTINFO2DIR(ctinfo);
- int ret;
- typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("ip_ct_ras: URQ\n");
- set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr) {
- ret = set_sig_addr(pskb, ct, ctinfo, data,
- urq->callSignalAddress.item,
- urq->callSignalAddress.count);
- if (ret < 0)
- return -1;
- }
- /* Clear old expect */
- ip_ct_remove_expectations(ct);
- info->sig_port[dir] = 0;
- info->sig_port[!dir] = 0;
- /* Give it 30 seconds for UCF or URJ */
- ip_ct_refresh(ct, *pskb, 30 * HZ);
- return 0;
- }
- /****************************************************************************/
- static int process_arq(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, AdmissionRequest * arq)
- {
- struct ip_ct_h323_master *info = &ct->help.ct_h323_info;
- int dir = CTINFO2DIR(ctinfo);
- __be32 ip;
- u_int16_t port;
- typeof(set_h225_addr_hook) set_h225_addr;
- DEBUGP("ip_ct_ras: ARQ\n");
- set_h225_addr = rcu_dereference(set_h225_addr_hook);
- if ((arq->options & eAdmissionRequest_destCallSignalAddress) &&
- get_h225_addr(*data, &arq->destCallSignalAddress, &ip, &port) &&
- ip == ct->tuplehash[dir].tuple.src.ip &&
- port == info->sig_port[dir] && set_h225_addr) {
- /* Answering ARQ */
- return set_h225_addr(pskb, data, 0,
- &arq->destCallSignalAddress,
- ct->tuplehash[!dir].tuple.dst.ip,
- info->sig_port[!dir]);
- }
- if ((arq->options & eAdmissionRequest_srcCallSignalAddress) &&
- get_h225_addr(*data, &arq->srcCallSignalAddress, &ip, &port) &&
- ip == ct->tuplehash[dir].tuple.src.ip && set_h225_addr) {
- /* Calling ARQ */
- return set_h225_addr(pskb, data, 0,
- &arq->srcCallSignalAddress,
- ct->tuplehash[!dir].tuple.dst.ip,
- port);
- }
- return 0;
- }
- /****************************************************************************/
- static int process_acf(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, AdmissionConfirm * acf)
- {
- int dir = CTINFO2DIR(ctinfo);
- int ret = 0;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp;
- typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("ip_ct_ras: ACF\n");
- if (!get_h225_addr(*data, &acf->destCallSignalAddress, &ip, &port))
- return 0;
- if (ip == ct->tuplehash[dir].tuple.dst.ip) { /* Answering ACF */
- set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr)
- return set_sig_addr(pskb, ct, ctinfo, data,
- &acf->destCallSignalAddress, 1);
- return 0;
- }
- /* Need new expect */
- 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 = ip;
- exp->tuple.dst.u.tcp.port = htons(port);
- exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = htonl(0xFFFFFFFF);
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
- exp->flags = IP_CT_EXPECT_PERMANENT;
- exp->expectfn = ip_conntrack_q931_expect;
- if (ip_conntrack_expect_related(exp) == 0) {
- DEBUGP("ip_ct_ras: expect Q.931 "
- "%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_lrq(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, LocationRequest * lrq)
- {
- typeof(set_ras_addr_hook) set_ras_addr;
- DEBUGP("ip_ct_ras: LRQ\n");
- set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr)
- return set_ras_addr(pskb, ct, ctinfo, data,
- &lrq->replyAddress, 1);
- return 0;
- }
- /****************************************************************************/
- static int process_lcf(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, LocationConfirm * lcf)
- {
- int dir = CTINFO2DIR(ctinfo);
- int ret = 0;
- __be32 ip;
- u_int16_t port;
- struct ip_conntrack_expect *exp = NULL;
- DEBUGP("ip_ct_ras: LCF\n");
- if (!get_h225_addr(*data, &lcf->callSignalAddress, &ip, &port))
- return 0;
- /* Need new expect for call signal */
- 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 = ip;
- exp->tuple.dst.u.tcp.port = htons(port);
- exp->tuple.dst.protonum = IPPROTO_TCP;
- exp->mask.src.ip = htonl(0xFFFFFFFF);
- exp->mask.src.u.tcp.port = 0;
- exp->mask.dst.ip = htonl(0xFFFFFFFF);
- exp->mask.dst.u.tcp.port = htons(0xFFFF);
- exp->mask.dst.protonum = 0xFF;
- exp->flags = IP_CT_EXPECT_PERMANENT;
- exp->expectfn = ip_conntrack_q931_expect;
- if (ip_conntrack_expect_related(exp) == 0) {
- DEBUGP("ip_ct_ras: expect Q.931 "
- "%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);
- /* Ignore rasAddress */
- return ret;
- }
- /****************************************************************************/
- static int process_irr(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, InfoRequestResponse * irr)
- {
- int ret;
- typeof(set_ras_addr_hook) set_ras_addr;
- typeof(set_sig_addr_hook) set_sig_addr;
- DEBUGP("ip_ct_ras: IRR\n");
- set_ras_addr = rcu_dereference(set_ras_addr_hook);
- if (set_ras_addr) {
- ret = set_ras_addr(pskb, ct, ctinfo, data,
- &irr->rasAddress, 1);
- if (ret < 0)
- return -1;
- }
- set_sig_addr = rcu_dereference(set_sig_addr_hook);
- if (set_sig_addr) {
- ret = set_sig_addr(pskb, ct, ctinfo, data,
- irr->callSignalAddress.item,
- irr->callSignalAddress.count);
- if (ret < 0)
- return -1;
- }
- return 0;
- }
- /****************************************************************************/
- static int process_ras(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo,
- unsigned char **data, RasMessage * ras)
- {
- switch (ras->choice) {
- case eRasMessage_gatekeeperRequest:
- return process_grq(pskb, ct, ctinfo, data,
- &ras->gatekeeperRequest);
- case eRasMessage_gatekeeperConfirm:
- return process_gcf(pskb, ct, ctinfo, data,
- &ras->gatekeeperConfirm);
- case eRasMessage_registrationRequest:
- return process_rrq(pskb, ct, ctinfo, data,
- &ras->registrationRequest);
- case eRasMessage_registrationConfirm:
- return process_rcf(pskb, ct, ctinfo, data,
- &ras->registrationConfirm);
- case eRasMessage_unregistrationRequest:
- return process_urq(pskb, ct, ctinfo, data,
- &ras->unregistrationRequest);
- case eRasMessage_admissionRequest:
- return process_arq(pskb, ct, ctinfo, data,
- &ras->admissionRequest);
- case eRasMessage_admissionConfirm:
- return process_acf(pskb, ct, ctinfo, data,
- &ras->admissionConfirm);
- case eRasMessage_locationRequest:
- return process_lrq(pskb, ct, ctinfo, data,
- &ras->locationRequest);
- case eRasMessage_locationConfirm:
- return process_lcf(pskb, ct, ctinfo, data,
- &ras->locationConfirm);
- case eRasMessage_infoRequestResponse:
- return process_irr(pskb, ct, ctinfo, data,
- &ras->infoRequestResponse);
- default:
- DEBUGP("ip_ct_ras: RAS message %d\n", ras->choice);
- break;
- }
- return 0;
- }
- /****************************************************************************/
- static int ras_help(struct sk_buff **pskb, struct ip_conntrack *ct,
- enum ip_conntrack_info ctinfo)
- {
- static RasMessage ras;
- unsigned char *data;
- int datalen = 0;
- int ret;
- DEBUGP("ip_ct_ras: skblen = %u\n", (*pskb)->len);
- spin_lock_bh(&ip_h323_lock);
- /* Get UDP data */
- data = get_udp_data(pskb, &datalen);
- if (data == NULL)
- goto accept;
- DEBUGP("ip_ct_ras: RAS message %u.%u.%u.%u->%u.%u.%u.%u, len=%d\n",
- NIPQUAD((*pskb)->nh.iph->saddr),
- NIPQUAD((*pskb)->nh.iph->daddr), datalen);
- /* Decode RAS message */
- ret = DecodeRasMessage(data, datalen, &ras);
- if (ret < 0) {
- if (net_ratelimit())
- printk("ip_ct_ras: decoding error: %s\n",
- ret == H323_ERROR_BOUND ?
- "out of bound" : "out of range");
- goto accept;
- }
- /* Process RAS message */
- if (process_ras(pskb, ct, ctinfo, &data, &ras) < 0)
- goto drop;
- accept:
- spin_unlock_bh(&ip_h323_lock);
- return NF_ACCEPT;
- drop:
- spin_unlock_bh(&ip_h323_lock);
- if (net_ratelimit())
- printk("ip_ct_ras: packet dropped\n");
- return NF_DROP;
- }
- /****************************************************************************/
- static struct ip_conntrack_helper ip_conntrack_helper_ras = {
- .name = "RAS",
- .me = THIS_MODULE,
- .max_expected = 32,
- .timeout = 240,
- .tuple = {.src = {.u = {.tcp = {.port = __constant_htons(RAS_PORT)}}},
- .dst = {.protonum = IPPROTO_UDP}},
- .mask = {.src = {.u = {0xFFFE}},
- .dst = {.protonum = 0xFF}},
- .help = ras_help,
- };
- /****************************************************************************/
- static void ip_conntrack_ras_expect(struct ip_conntrack *new,
- struct ip_conntrack_expect *this)
- {
- write_lock_bh(&ip_conntrack_lock);
- new->helper = &ip_conntrack_helper_ras;
- write_unlock_bh(&ip_conntrack_lock);
- }
- /****************************************************************************/
- /* Not __exit - called from init() */
- static void fini(void)
- {
- ip_conntrack_helper_unregister(&ip_conntrack_helper_ras);
- ip_conntrack_helper_unregister(&ip_conntrack_helper_q931);
- kfree(h323_buffer);
- DEBUGP("ip_ct_h323: fini\n");
- }
- /****************************************************************************/
- static int __init init(void)
- {
- int ret;
- h323_buffer = kmalloc(65536, GFP_KERNEL);
- if (!h323_buffer)
- return -ENOMEM;
- if ((ret = ip_conntrack_helper_register(&ip_conntrack_helper_q931)) ||
- (ret = ip_conntrack_helper_register(&ip_conntrack_helper_ras))) {
- fini();
- return ret;
- }
- DEBUGP("ip_ct_h323: init success\n");
- return 0;
- }
- /****************************************************************************/
- module_init(init);
- module_exit(fini);
- EXPORT_SYMBOL_GPL(get_h225_addr);
- EXPORT_SYMBOL_GPL(ip_conntrack_h245_expect);
- EXPORT_SYMBOL_GPL(ip_conntrack_q931_expect);
- EXPORT_SYMBOL_GPL(set_h245_addr_hook);
- EXPORT_SYMBOL_GPL(set_h225_addr_hook);
- EXPORT_SYMBOL_GPL(set_sig_addr_hook);
- EXPORT_SYMBOL_GPL(set_ras_addr_hook);
- EXPORT_SYMBOL_GPL(nat_rtp_rtcp_hook);
- EXPORT_SYMBOL_GPL(nat_t120_hook);
- EXPORT_SYMBOL_GPL(nat_h245_hook);
- EXPORT_SYMBOL_GPL(nat_callforwarding_hook);
- EXPORT_SYMBOL_GPL(nat_q931_hook);
- MODULE_AUTHOR("Jing Min Zhao <zhaojingmin@users.sourceforge.net>");
- MODULE_DESCRIPTION("H.323 connection tracking helper");
- MODULE_LICENSE("GPL");
|