--- a/net/ipv4/netfilter/Config.in +++ b/net/ipv4/netfilter/Config.in @@ -14,6 +14,7 @@ if [ "$CONFIG_IP_NF_CONNTRACK" != "n" ]; dep_tristate ' Connection tracking flow accounting' CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK dep_tristate ' Connection byte counter support' CONFIG_IP_NF_MATCH_CONNBYTES $CONFIG_IP_NF_CT_ACCT $CONFIG_IP_NF_CONNTRACK $CONFIG_IP_NF_IPTABLES dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + dep_tristate ' MMS protocol support' CONFIG_IP_NF_MMS $CONFIG_IP_NF_CONNTRACK fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then @@ -88,6 +89,13 @@ if [ "$CONFIG_IP_NF_IPTABLES" != "n" ]; define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT fi fi + if [ "$CONFIG_IP_NF_MMS" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_MMS m + else + if [ "$CONFIG_IP_NF_MMS" = "y" ]; then + define_tristate CONFIG_IP_NF_NAT_MMS $CONFIG_IP_NF_NAT + fi + fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then dep_tristate ' Basic SNMP-ALG support (EXPERIMENTAL)' CONFIG_IP_NF_NAT_SNMP_BASIC $CONFIG_IP_NF_NAT fi --- a/net/ipv4/netfilter/Makefile +++ b/net/ipv4/netfilter/Makefile @@ -51,6 +51,10 @@ obj-$(CONFIG_IP_NF_H323) += ip_conntrack ifdef CONFIG_IP_NF_NAT_H323 export-objs += ip_conntrack_h323.o endif +obj-$(CONFIG_IP_NF_MMS) += ip_conntrack_mms.o +ifdef CONFIG_IP_NF_NAT_MMS + export-objs += ip_conntrack_mms.o +endif # NAT helpers obj-$(CONFIG_IP_NF_NAT_AMANDA) += ip_nat_amanda.o @@ -58,6 +62,7 @@ obj-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_t obj-$(CONFIG_IP_NF_NAT_FTP) += ip_nat_ftp.o obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o +obj-$(CONFIG_IP_NF_NAT_MMS) += ip_nat_mms.o # generic IP tables obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o --- /dev/null +++ b/net/ipv4/netfilter/ip_conntrack_mms.c @@ -0,0 +1,292 @@ +/* MMS extension for IP connection tracking + * (C) 2002 by Filip Sneppe + * based on ip_conntrack_ftp.c and ip_conntrack_irc.c + * + * ip_conntrack_mms.c v0.3 2002-09-22 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_conntrack_mms.o ports=port1,port2,...port + * + * Please give the ports of all MMS servers You wish to connect to. + * If you don't specify ports, the default will be TCP port 1755. + * + * More info on MMS protocol, firewalls and NAT: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp + * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp + * + * The SDP project people are reverse-engineering MMS: + * http://get.to/sdp + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +DECLARE_LOCK(ip_mms_lock); +struct module *ip_conntrack_mms = THIS_MODULE; + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_c; +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +#endif + +#define DEBUGP(format, args...) + +#ifdef CONFIG_IP_NF_NAT_NEEDED +EXPORT_SYMBOL(ip_mms_lock); +#endif + +MODULE_AUTHOR("Filip Sneppe "); +MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) connection tracking module"); +MODULE_LICENSE("GPL"); + +/* #define isdigit(c) (c >= '0' && c <= '9') */ + +/* copied from drivers/usb/serial/io_edgeport.c - not perfect but will do the trick */ +static void unicode_to_ascii (char *string, short *unicode, int unicode_size) +{ + int i; + for (i = 0; i < unicode_size; ++i) { + string[i] = (char)(unicode[i]); + } + string[unicode_size] = 0x00; +} + +__inline static int atoi(char *s) +{ + int i=0; + while (isdigit(*s)) { + i = i*10 + *(s++) - '0'; + } + return i; +} + +/* convert ip address string like "192.168.0.10" to unsigned int */ +__inline static u_int32_t asciiiptoi(char *s) +{ + unsigned int i, j, k; + + for(i=k=0; k<3; ++k, ++s, i<<=8) { + i+=atoi(s); + for(j=0; (*(++s) != '.') && (j<3); ++j) + ; + } + i+=atoi(s); + return ntohl(i); +} + +int parse_mms(const char *data, + const unsigned int datalen, + u_int32_t *mms_ip, + u_int16_t *mms_proto, + u_int16_t *mms_port, + char **mms_string_b, + char **mms_string_e, + char **mms_padding_e) +{ + int unicode_size, i; + char tempstring[28]; /* "\\255.255.255.255\UDP\65535" */ + char getlengthstring[28]; + + for(unicode_size=0; + (char) *(data+(MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2)) != (char)0; + unicode_size++) + if ((unicode_size == 28) || (MMS_SRV_UNICODE_STRING_OFFSET+unicode_size*2 >= datalen)) + return -1; /* out of bounds - incomplete packet */ + + unicode_to_ascii(tempstring, (short *)(data+MMS_SRV_UNICODE_STRING_OFFSET), unicode_size); + DEBUGP("ip_conntrack_mms: offset 60: %s\n", (const char *)(tempstring)); + + /* IP address ? */ + *mms_ip = asciiiptoi(tempstring+2); + + i=sprintf(getlengthstring, "%u.%u.%u.%u", HIPQUAD(*mms_ip)); + + /* protocol ? */ + if(strncmp(tempstring+3+i, "TCP", 3)==0) + *mms_proto = IPPROTO_TCP; + else if(strncmp(tempstring+3+i, "UDP", 3)==0) + *mms_proto = IPPROTO_UDP; + + /* port ? */ + *mms_port = atoi(tempstring+7+i); + + /* we store a pointer to the beginning of the "\\a.b.c.d\proto\port" + unicode string, one to the end of the string, and one to the end + of the packet, since we must keep track of the number of bytes + between end of the unicode string and the end of packet (padding) */ + *mms_string_b = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET); + *mms_string_e = (char *)(data + MMS_SRV_UNICODE_STRING_OFFSET + unicode_size * 2); + *mms_padding_e = (char *)(data + datalen); /* looks funny, doesn't it */ + return 0; +} + + +static int help(const struct iphdr *iph, size_t len, + struct ip_conntrack *ct, + enum ip_conntrack_info ctinfo) +{ + /* tcplen not negative guaranteed by ip_conntrack_tcp.c */ + struct tcphdr *tcph = (void *)iph + iph->ihl * 4; + const char *data = (const char *)tcph + tcph->doff * 4; + unsigned int tcplen = len - iph->ihl * 4; + unsigned int datalen = tcplen - tcph->doff * 4; + int dir = CTINFO2DIR(ctinfo); + struct ip_conntrack_expect expect, *exp = &expect; + struct ip_ct_mms_expect *exp_mms_info = &exp->help.exp_mms_info; + + u_int32_t mms_ip; + u_int16_t mms_proto; + char mms_proto_string[8]; + u_int16_t mms_port; + char *mms_string_b, *mms_string_e, *mms_padding_e; + + /* 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) { + DEBUGP("ip_conntrack_mms: Conntrackinfo = %u\n", ctinfo); + return NF_ACCEPT; + } + + /* Not whole TCP header? */ + if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff*4) { + DEBUGP("ip_conntrack_mms: tcplen = %u\n", (unsigned)tcplen); + return NF_ACCEPT; + } + + /* Checksum invalid? Ignore. */ + if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, + csum_partial((char *)tcph, tcplen, 0))) { + DEBUGP("mms_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", + tcph, tcplen, NIPQUAD(iph->saddr), + NIPQUAD(iph->daddr)); + return NF_ACCEPT; + } + + /* Only look at packets with 0x00030002/196610 on bytes 36->39 of TCP payload */ + if( (MMS_SRV_MSG_OFFSET < datalen) && + ((*(u32 *)(data+MMS_SRV_MSG_OFFSET)) == MMS_SRV_MSG_ID)) { + DEBUGP("ip_conntrack_mms: offset 37: %u %u %u %u, datalen:%u\n", + (u8)*(data+36), (u8)*(data+37), + (u8)*(data+38), (u8)*(data+39), + datalen); + if(parse_mms(data, datalen, &mms_ip, &mms_proto, &mms_port, + &mms_string_b, &mms_string_e, &mms_padding_e)) + if(net_ratelimit()) + printk(KERN_WARNING + "ip_conntrack_mms: Unable to parse data payload\n"); + + memset(&expect, 0, sizeof(expect)); + + sprintf(mms_proto_string, "(%u)", mms_proto); + DEBUGP("ip_conntrack_mms: adding %s expectation %u.%u.%u.%u -> %u.%u.%u.%u:%u\n", + mms_proto == IPPROTO_TCP ? "TCP" + : mms_proto == IPPROTO_UDP ? "UDP":mms_proto_string, + NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), + NIPQUAD(mms_ip), + mms_port); + + /* it's possible that the client will just ask the server to tunnel + the stream over the same TCP session (from port 1755): there's + shouldn't be a need to add an expectation in that case, but it + makes NAT packet mangling so much easier */ + LOCK_BH(&ip_mms_lock); + + DEBUGP("ip_conntrack_mms: tcph->seq = %u\n", tcph->seq); + + exp->seq = ntohl(tcph->seq) + (mms_string_b - data); + exp_mms_info->len = (mms_string_e - mms_string_b); + exp_mms_info->padding = (mms_padding_e - mms_string_e); + exp_mms_info->port = mms_port; + + DEBUGP("ip_conntrack_mms: wrote info seq=%u (ofs=%u), len=%d, padding=%u\n", + exp->seq, (mms_string_e - data), exp_mms_info->len, exp_mms_info->padding); + + exp->tuple = ((struct ip_conntrack_tuple) + { { ct->tuplehash[!dir].tuple.src.ip, { 0 } }, + { mms_ip, + { (__u16) ntohs(mms_port) }, + mms_proto } } + ); + exp->mask = ((struct ip_conntrack_tuple) + { { 0xFFFFFFFF, { 0 } }, + { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); + exp->expectfn = NULL; + ip_conntrack_expect_related(ct, &expect); + UNLOCK_BH(&ip_mms_lock); + } + + return NF_ACCEPT; +} + +static struct ip_conntrack_helper mms[MAX_PORTS]; +static char mms_names[MAX_PORTS][10]; + +/* Not __exit: called from init() */ +static void fini(void) +{ + int i; + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("ip_conntrack_mms: unregistering helper for port %d\n", + ports[i]); + ip_conntrack_helper_unregister(&mms[i]); + } +} + +static int __init init(void) +{ + int i, ret; + char *tmpname; + + if (ports[0] == 0) + ports[0] = MMS_PORT; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + memset(&mms[i], 0, sizeof(struct ip_conntrack_helper)); + mms[i].tuple.src.u.tcp.port = htons(ports[i]); + mms[i].tuple.dst.protonum = IPPROTO_TCP; + mms[i].mask.src.u.tcp.port = 0xFFFF; + mms[i].mask.dst.protonum = 0xFFFF; + mms[i].max_expected = 1; + mms[i].timeout = 0; + mms[i].flags = IP_CT_HELPER_F_REUSE_EXPECT; + mms[i].me = THIS_MODULE; + mms[i].help = help; + + tmpname = &mms_names[i][0]; + if (ports[i] == MMS_PORT) + sprintf(tmpname, "mms"); + else + sprintf(tmpname, "mms-%d", ports[i]); + mms[i].name = tmpname; + + DEBUGP("ip_conntrack_mms: registering helper for port %d\n", + ports[i]); + ret = ip_conntrack_helper_register(&mms[i]); + + if (ret) { + fini(); + return ret; + } + ports_c++; + } + return 0; +} + +module_init(init); +module_exit(fini); --- /dev/null +++ b/net/ipv4/netfilter/ip_nat_mms.c @@ -0,0 +1,330 @@ +/* MMS extension for TCP NAT alteration. + * (C) 2002 by Filip Sneppe + * based on ip_nat_ftp.c and ip_nat_irc.c + * + * ip_nat_mms.c v0.3 2002-09-22 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + * Module load syntax: + * insmod ip_nat_mms.o ports=port1,port2,...port + * + * Please give the ports of all MMS servers You wish to connect to. + * If you don't specify ports, the default will be TCP port 1755. + * + * More info on MMS protocol, firewalls and NAT: + * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwmt/html/MMSFirewall.asp + * http://www.microsoft.com/windows/windowsmedia/serve/firewall.asp + * + * The SDP project people are reverse-engineering MMS: + * http://get.to/sdp + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUGP(format, args...) +#define DUMP_BYTES(address, counter) + +#define MAX_PORTS 8 +static int ports[MAX_PORTS]; +static int ports_c = 0; + +#ifdef MODULE_PARM +MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); +#endif + +MODULE_AUTHOR("Filip Sneppe "); +MODULE_DESCRIPTION("Microsoft Windows Media Services (MMS) NAT module"); +MODULE_LICENSE("GPL"); + +DECLARE_LOCK_EXTERN(ip_mms_lock); + + +static int mms_data_fixup(const struct ip_ct_mms_expect *ct_mms_info, + struct ip_conntrack *ct, + struct sk_buff **pskb, + enum ip_conntrack_info ctinfo, + struct ip_conntrack_expect *expect) +{ + u_int32_t newip; + struct ip_conntrack_tuple t; + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + char *data = (char *)tcph + tcph->doff * 4; + int i, j, k, port; + u_int16_t mms_proto; + + u_int32_t *mms_chunkLenLV = (u_int32_t *)(data + MMS_SRV_CHUNKLENLV_OFFSET); + u_int32_t *mms_chunkLenLM = (u_int32_t *)(data + MMS_SRV_CHUNKLENLM_OFFSET); + u_int32_t *mms_messageLength = (u_int32_t *)(data + MMS_SRV_MESSAGELENGTH_OFFSET); + + int zero_padding; + + char buffer[28]; /* "\\255.255.255.255\UDP\65635" * 2 (for unicode) */ + char unicode_buffer[75]; /* 27*2 (unicode) + 20 + 1 */ + char proto_string[6]; + + MUST_BE_LOCKED(&ip_mms_lock); + + /* what was the protocol again ? */ + mms_proto = expect->tuple.dst.protonum; + sprintf(proto_string, "%u", mms_proto); + + DEBUGP("ip_nat_mms: mms_data_fixup: info (seq %u + %u) in %u, proto %s\n", + expect->seq, ct_mms_info->len, ntohl(tcph->seq), + mms_proto == IPPROTO_UDP ? "UDP" + : mms_proto == IPPROTO_TCP ? "TCP":proto_string); + + newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; + + /* Alter conntrack's expectations. */ + t = expect->tuple; + t.dst.ip = newip; + for (port = ct_mms_info->port; port != 0; port++) { + t.dst.u.tcp.port = htons(port); + if (ip_conntrack_change_expect(expect, &t) == 0) { + DEBUGP("ip_nat_mms: mms_data_fixup: using port %d\n", port); + break; + } + } + + if(port == 0) + return 0; + + sprintf(buffer, "\\\\%u.%u.%u.%u\\%s\\%u", + NIPQUAD(newip), + expect->tuple.dst.protonum == IPPROTO_UDP ? "UDP" + : expect->tuple.dst.protonum == IPPROTO_TCP ? "TCP":proto_string, + port); + DEBUGP("ip_nat_mms: new unicode string=%s\n", buffer); + + memset(unicode_buffer, 0, sizeof(char)*75); + + for (i=0; ipadding, ct_mms_info->len); + DEBUGP("ip_nat_mms: mms_data_fixup: offset: %u\n", MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len); + DUMP_BYTES(data+MMS_SRV_UNICODE_STRING_OFFSET, 60); + + /* add end of packet to it */ + for (j=0; jpadding; ++j) { + DEBUGP("ip_nat_mms: mms_data_fixup: i=%u j=%u byte=%u\n", + i, j, (u8)*(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j)); + *(unicode_buffer+i*2+j) = *(data+MMS_SRV_UNICODE_STRING_OFFSET+ct_mms_info->len+j); + } + + /* pad with zeroes at the end ? see explanation of weird math below */ + zero_padding = (8-(strlen(buffer)*2 + ct_mms_info->padding + 4)%8)%8; + for (k=0; k chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", + *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); + + /* explanation, before I forget what I did: + strlen(buffer)*2 + ct_mms_info->padding + 4 must be divisable by 8; + divide by 8 and add 3 to compute the mms_chunkLenLM field, + but note that things may have to be padded with zeroes to align by 8 + bytes, hence we add 7 and divide by 8 to get the correct length */ + *mms_chunkLenLM = (u_int32_t) (3+(strlen(buffer)*2+ct_mms_info->padding+11)/8); + *mms_chunkLenLV = *mms_chunkLenLM+2; + *mms_messageLength = *mms_chunkLenLV*8; + + DEBUGP("ip_nat_mms: modified=> chunkLenLV=%u chunkLenLM=%u messageLength=%u\n", + *mms_chunkLenLV, *mms_chunkLenLM, *mms_messageLength); + + ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, + expect->seq - ntohl(tcph->seq), + ct_mms_info->len + ct_mms_info->padding, unicode_buffer, + strlen(buffer)*2 + ct_mms_info->padding + zero_padding); + DUMP_BYTES(unicode_buffer, 60); + + return 1; +} + +static unsigned int +mms_nat_expected(struct sk_buff **pskb, + unsigned int hooknum, + struct ip_conntrack *ct, + struct ip_nat_info *info) +{ + struct ip_nat_multi_range mr; + u_int32_t newdstip, newsrcip, newip; + + struct ip_conntrack *master = master_ct(ct); + + IP_NF_ASSERT(info); + IP_NF_ASSERT(master); + + IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); + + DEBUGP("ip_nat_mms: mms_nat_expected: We have a connection!\n"); + + newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; + DEBUGP("ip_nat_mms: mms_nat_expected: hook %s: newsrc->newdst %u.%u.%u.%u->%u.%u.%u.%u\n", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???", + NIPQUAD(newsrcip), NIPQUAD(newdstip)); + + if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) + newip = newsrcip; + else + newip = newdstip; + + DEBUGP("ip_nat_mms: mms_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); + + mr.rangesize = 1; + /* We don't want to manip the per-protocol, just the IPs. */ + mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; + mr.range[0].min_ip = mr.range[0].max_ip = newip; + + return ip_nat_setup_info(ct, &mr, hooknum); +} + + +static unsigned int mms_nat_help(struct ip_conntrack *ct, + struct ip_conntrack_expect *exp, + struct ip_nat_info *info, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, + struct sk_buff **pskb) +{ + struct iphdr *iph = (*pskb)->nh.iph; + struct tcphdr *tcph = (void *) iph + iph->ihl * 4; + unsigned int datalen; + int dir; + struct ip_ct_mms_expect *ct_mms_info; + + if (!exp) + DEBUGP("ip_nat_mms: no exp!!"); + + ct_mms_info = &exp->help.exp_mms_info; + + /* Only mangle things once: original direction in POST_ROUTING + and reply direction on PRE_ROUTING. */ + dir = CTINFO2DIR(ctinfo); + if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) + ||(hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { + DEBUGP("ip_nat_mms: mms_nat_help: not touching dir %s at hook %s\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + return NF_ACCEPT; + } + DEBUGP("ip_nat_mms: mms_nat_help: beyond not touching (dir %s at hook %s)\n", + dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", + hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" + : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" + : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); + + datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; + + DEBUGP("ip_nat_mms: mms_nat_help: %u+%u=%u %u %u\n", exp->seq, ct_mms_info->len, + exp->seq + ct_mms_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + + LOCK_BH(&ip_mms_lock); + /* Check wether the whole IP/proto/port pattern is carried in the payload */ + if (between(exp->seq + ct_mms_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen)) { + if (!mms_data_fixup(ct_mms_info, ct, pskb, ctinfo, exp)) { + UNLOCK_BH(&ip_mms_lock); + return NF_DROP; + } + } else { + /* Half a match? This means a partial retransmisison. + It's a cracker being funky. */ + if (net_ratelimit()) { + printk("ip_nat_mms: partial packet %u/%u in %u/%u\n", + exp->seq, ct_mms_info->len, + ntohl(tcph->seq), + ntohl(tcph->seq) + datalen); + } + UNLOCK_BH(&ip_mms_lock); + return NF_DROP; + } + UNLOCK_BH(&ip_mms_lock); + + return NF_ACCEPT; +} + +static struct ip_nat_helper mms[MAX_PORTS]; +static char mms_names[MAX_PORTS][10]; + +/* Not __exit: called from init() */ +static void fini(void) +{ + int i; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + DEBUGP("ip_nat_mms: unregistering helper for port %d\n", ports[i]); + ip_nat_helper_unregister(&mms[i]); + } +} + +static int __init init(void) +{ + int i, ret = 0; + char *tmpname; + + if (ports[0] == 0) + ports[0] = MMS_PORT; + + for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { + + memset(&mms[i], 0, sizeof(struct ip_nat_helper)); + + mms[i].tuple.dst.protonum = IPPROTO_TCP; + mms[i].tuple.src.u.tcp.port = htons(ports[i]); + mms[i].mask.dst.protonum = 0xFFFF; + mms[i].mask.src.u.tcp.port = 0xFFFF; + mms[i].help = mms_nat_help; + mms[i].me = THIS_MODULE; + mms[i].flags = 0; + mms[i].expect = mms_nat_expected; + + tmpname = &mms_names[i][0]; + if (ports[i] == MMS_PORT) + sprintf(tmpname, "mms"); + else + sprintf(tmpname, "mms-%d", i); + mms[i].name = tmpname; + + DEBUGP("ip_nat_mms: register helper for port %d\n", + ports[i]); + ret = ip_nat_helper_register(&mms[i]); + + if (ret) { + printk("ip_nat_mms: error registering " + "helper for port %d\n", ports[i]); + fini(); + return ret; + } + ports_c++; + } + + return ret; +} + +module_init(init); +module_exit(fini); --- a/include/linux/netfilter_ipv4/ip_conntrack.h +++ b/include/linux/netfilter_ipv4/ip_conntrack.h @@ -68,6 +68,7 @@ union ip_conntrack_expect_proto { #include #include #include +#include /* per expectation: application helper private data */ union ip_conntrack_expect_help { @@ -76,6 +77,7 @@ union ip_conntrack_expect_help { struct ip_ct_ftp_expect exp_ftp_info; struct ip_ct_irc_expect exp_irc_info; struct ip_ct_h225_expect exp_h225_info; + struct ip_ct_mms_expect exp_mms_info; #ifdef CONFIG_IP_NF_NAT_NEEDED union { @@ -90,6 +92,7 @@ union ip_conntrack_help { struct ip_ct_ftp_master ct_ftp_info; struct ip_ct_irc_master ct_irc_info; struct ip_ct_h225_master ct_h225_info; + struct ip_ct_mms_master ct_mms_info; }; #ifdef CONFIG_IP_NF_NAT_NEEDED --- /dev/null +++ b/include/linux/netfilter_ipv4/ip_conntrack_mms.h @@ -0,0 +1,31 @@ +#ifndef _IP_CONNTRACK_MMS_H +#define _IP_CONNTRACK_MMS_H +/* MMS tracking. */ + +#ifdef __KERNEL__ +#include + +DECLARE_LOCK_EXTERN(ip_mms_lock); + +#define MMS_PORT 1755 +#define MMS_SRV_MSG_ID 196610 + +#define MMS_SRV_MSG_OFFSET 36 +#define MMS_SRV_UNICODE_STRING_OFFSET 60 +#define MMS_SRV_CHUNKLENLV_OFFSET 16 +#define MMS_SRV_CHUNKLENLM_OFFSET 32 +#define MMS_SRV_MESSAGELENGTH_OFFSET 8 +#endif + +/* This structure is per expected connection */ +struct ip_ct_mms_expect { + u_int32_t len; + u_int32_t padding; + u_int16_t port; +}; + +/* This structure exists only once per master */ +struct ip_ct_mms_master { +}; + +#endif /* _IP_CONNTRACK_MMS_H */