/* (C) 2001-2002 Magnus Boden * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Version: 0.0.7 * * Thu 21 Mar 2002 Harald Welte * - port to newnat API * */ #include #include #include #include #include #include #include #include MODULE_AUTHOR("Magnus Boden "); MODULE_DESCRIPTION("tftp connection tracking helper"); MODULE_LICENSE("GPL"); #define MAX_PORTS 8 static unsigned short ports[MAX_PORTS]; static int ports_c; module_param_array(ports, ushort, &ports_c, 0400); MODULE_PARM_DESC(ports, "port numbers of tftp servers"); #if 0 #define DEBUGP(format, args...) printk("%s:%s:" format, \ __FILE__, __FUNCTION__ , ## args) #else #define DEBUGP(format, args...) #endif unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb, enum ip_conntrack_info ctinfo, struct ip_conntrack_expect *exp); EXPORT_SYMBOL_GPL(ip_nat_tftp_hook); static int tftp_help(struct sk_buff **pskb, struct ip_conntrack *ct, enum ip_conntrack_info ctinfo) { struct tftphdr _tftph, *tfh; struct ip_conntrack_expect *exp; unsigned int ret = NF_ACCEPT; tfh = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), sizeof(_tftph), &_tftph); if (tfh == NULL) return NF_ACCEPT; switch (ntohs(tfh->opcode)) { /* RRQ and WRQ works the same way */ case TFTP_OPCODE_READ: case TFTP_OPCODE_WRITE: DEBUGP(""); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); exp = ip_conntrack_expect_alloc(ct); if (exp == NULL) return NF_DROP; exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; exp->mask.src.ip = 0xffffffff; exp->mask.src.u.udp.port = 0; exp->mask.dst.ip = 0xffffffff; exp->mask.dst.u.udp.port = 0xffff; exp->mask.dst.protonum = 0xff; exp->expectfn = NULL; exp->flags = 0; DEBUGP("expect: "); DUMP_TUPLE(&exp->tuple); DUMP_TUPLE(&exp->mask); if (ip_nat_tftp_hook) ret = ip_nat_tftp_hook(pskb, ctinfo, exp); else if (ip_conntrack_expect_related(exp) != 0) ret = NF_DROP; ip_conntrack_expect_put(exp); break; case TFTP_OPCODE_DATA: case TFTP_OPCODE_ACK: DEBUGP("Data/ACK opcode\n"); break; case TFTP_OPCODE_ERROR: DEBUGP("Error opcode\n"); break; default: DEBUGP("Unknown opcode\n"); } return NF_ACCEPT; } static struct ip_conntrack_helper tftp[MAX_PORTS]; static char tftp_names[MAX_PORTS][sizeof("tftp-65535")]; static void ip_conntrack_tftp_fini(void) { int i; for (i = 0 ; i < ports_c; i++) { DEBUGP("unregistering helper for port %d\n", ports[i]); ip_conntrack_helper_unregister(&tftp[i]); } } static int __init ip_conntrack_tftp_init(void) { int i, ret; char *tmpname; if (ports_c == 0) ports[ports_c++] = TFTP_PORT; for (i = 0; i < ports_c; i++) { /* Create helper structure */ memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); tftp[i].tuple.dst.protonum = IPPROTO_UDP; tftp[i].tuple.src.u.udp.port = htons(ports[i]); tftp[i].mask.dst.protonum = 0xFF; tftp[i].mask.src.u.udp.port = 0xFFFF; tftp[i].max_expected = 1; tftp[i].timeout = 5 * 60; /* 5 minutes */ tftp[i].me = THIS_MODULE; tftp[i].help = tftp_help; tmpname = &tftp_names[i][0]; if (ports[i] == TFTP_PORT) sprintf(tmpname, "tftp"); else sprintf(tmpname, "tftp-%d", i); tftp[i].name = tmpname; DEBUGP("port #%d: %d\n", i, ports[i]); ret=ip_conntrack_helper_register(&tftp[i]); if (ret) { printk("ERROR registering helper for port %d\n", ports[i]); ip_conntrack_tftp_fini(); return(ret); } } return(0); } module_init(ip_conntrack_tftp_init); module_exit(ip_conntrack_tftp_fini);