Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu> |
2 | * | |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 as | |
5 | * published by the Free Software Foundation. | |
6 | * | |
7 | * Version: 0.0.7 | |
8 | * | |
9 | * Thu 21 Mar 2002 Harald Welte <laforge@gnumonks.org> | |
10 | * - port to newnat API | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/ip.h> | |
16 | #include <linux/udp.h> | |
17 | ||
18 | #include <linux/netfilter.h> | |
19 | #include <linux/netfilter_ipv4/ip_tables.h> | |
20 | #include <linux/netfilter_ipv4/ip_conntrack_helper.h> | |
21 | #include <linux/netfilter_ipv4/ip_conntrack_tftp.h> | |
22 | #include <linux/moduleparam.h> | |
23 | ||
24 | MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>"); | |
25 | MODULE_DESCRIPTION("tftp connection tracking helper"); | |
26 | MODULE_LICENSE("GPL"); | |
27 | ||
28 | #define MAX_PORTS 8 | |
2fce76af | 29 | static unsigned short ports[MAX_PORTS]; |
1da177e4 | 30 | static int ports_c; |
2fce76af | 31 | module_param_array(ports, ushort, &ports_c, 0400); |
1da177e4 LT |
32 | MODULE_PARM_DESC(ports, "port numbers of tftp servers"); |
33 | ||
34 | #if 0 | |
35 | #define DEBUGP(format, args...) printk("%s:%s:" format, \ | |
36 | __FILE__, __FUNCTION__ , ## args) | |
37 | #else | |
38 | #define DEBUGP(format, args...) | |
39 | #endif | |
40 | ||
41 | unsigned int (*ip_nat_tftp_hook)(struct sk_buff **pskb, | |
42 | enum ip_conntrack_info ctinfo, | |
43 | struct ip_conntrack_expect *exp); | |
44 | EXPORT_SYMBOL_GPL(ip_nat_tftp_hook); | |
45 | ||
46 | static int tftp_help(struct sk_buff **pskb, | |
47 | struct ip_conntrack *ct, | |
48 | enum ip_conntrack_info ctinfo) | |
49 | { | |
50 | struct tftphdr _tftph, *tfh; | |
51 | struct ip_conntrack_expect *exp; | |
52 | unsigned int ret = NF_ACCEPT; | |
53 | ||
54 | tfh = skb_header_pointer(*pskb, | |
55 | (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr), | |
56 | sizeof(_tftph), &_tftph); | |
57 | if (tfh == NULL) | |
58 | return NF_ACCEPT; | |
59 | ||
60 | switch (ntohs(tfh->opcode)) { | |
61 | /* RRQ and WRQ works the same way */ | |
62 | case TFTP_OPCODE_READ: | |
63 | case TFTP_OPCODE_WRITE: | |
64 | DEBUGP(""); | |
65 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
66 | DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); | |
67 | ||
4acdbdbe | 68 | exp = ip_conntrack_expect_alloc(ct); |
1da177e4 LT |
69 | if (exp == NULL) |
70 | return NF_DROP; | |
71 | ||
72 | exp->tuple = ct->tuplehash[IP_CT_DIR_REPLY].tuple; | |
73 | exp->mask.src.ip = 0xffffffff; | |
6f169300 | 74 | exp->mask.src.u.udp.port = 0; |
1da177e4 LT |
75 | exp->mask.dst.ip = 0xffffffff; |
76 | exp->mask.dst.u.udp.port = 0xffff; | |
77 | exp->mask.dst.protonum = 0xff; | |
78 | exp->expectfn = NULL; | |
2248bcfc | 79 | exp->flags = 0; |
1da177e4 LT |
80 | |
81 | DEBUGP("expect: "); | |
82 | DUMP_TUPLE(&exp->tuple); | |
83 | DUMP_TUPLE(&exp->mask); | |
84 | if (ip_nat_tftp_hook) | |
85 | ret = ip_nat_tftp_hook(pskb, ctinfo, exp); | |
4acdbdbe | 86 | else if (ip_conntrack_expect_related(exp) != 0) |
1da177e4 | 87 | ret = NF_DROP; |
4acdbdbe | 88 | ip_conntrack_expect_put(exp); |
1da177e4 LT |
89 | break; |
90 | case TFTP_OPCODE_DATA: | |
91 | case TFTP_OPCODE_ACK: | |
92 | DEBUGP("Data/ACK opcode\n"); | |
93 | break; | |
94 | case TFTP_OPCODE_ERROR: | |
95 | DEBUGP("Error opcode\n"); | |
96 | break; | |
97 | default: | |
98 | DEBUGP("Unknown opcode\n"); | |
99 | } | |
100 | return NF_ACCEPT; | |
101 | } | |
102 | ||
103 | static struct ip_conntrack_helper tftp[MAX_PORTS]; | |
5cb30640 | 104 | static char tftp_names[MAX_PORTS][sizeof("tftp-65535")]; |
1da177e4 | 105 | |
65b4b4e8 | 106 | static void ip_conntrack_tftp_fini(void) |
1da177e4 LT |
107 | { |
108 | int i; | |
109 | ||
110 | for (i = 0 ; i < ports_c; i++) { | |
111 | DEBUGP("unregistering helper for port %d\n", | |
112 | ports[i]); | |
113 | ip_conntrack_helper_unregister(&tftp[i]); | |
114 | } | |
115 | } | |
116 | ||
65b4b4e8 | 117 | static int __init ip_conntrack_tftp_init(void) |
1da177e4 LT |
118 | { |
119 | int i, ret; | |
120 | char *tmpname; | |
121 | ||
122 | if (ports_c == 0) | |
123 | ports[ports_c++] = TFTP_PORT; | |
124 | ||
125 | for (i = 0; i < ports_c; i++) { | |
126 | /* Create helper structure */ | |
127 | memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); | |
128 | ||
129 | tftp[i].tuple.dst.protonum = IPPROTO_UDP; | |
130 | tftp[i].tuple.src.u.udp.port = htons(ports[i]); | |
131 | tftp[i].mask.dst.protonum = 0xFF; | |
132 | tftp[i].mask.src.u.udp.port = 0xFFFF; | |
133 | tftp[i].max_expected = 1; | |
134 | tftp[i].timeout = 5 * 60; /* 5 minutes */ | |
135 | tftp[i].me = THIS_MODULE; | |
136 | tftp[i].help = tftp_help; | |
137 | ||
138 | tmpname = &tftp_names[i][0]; | |
139 | if (ports[i] == TFTP_PORT) | |
140 | sprintf(tmpname, "tftp"); | |
141 | else | |
142 | sprintf(tmpname, "tftp-%d", i); | |
143 | tftp[i].name = tmpname; | |
144 | ||
145 | DEBUGP("port #%d: %d\n", i, ports[i]); | |
146 | ||
147 | ret=ip_conntrack_helper_register(&tftp[i]); | |
148 | if (ret) { | |
149 | printk("ERROR registering helper for port %d\n", | |
150 | ports[i]); | |
65b4b4e8 | 151 | ip_conntrack_tftp_fini(); |
1da177e4 LT |
152 | return(ret); |
153 | } | |
154 | } | |
155 | return(0); | |
156 | } | |
157 | ||
65b4b4e8 AM |
158 | module_init(ip_conntrack_tftp_init); |
159 | module_exit(ip_conntrack_tftp_fini); |