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 | |
29 | static int ports[MAX_PORTS]; | |
30 | static int ports_c; | |
31 | module_param_array(ports, int, &ports_c, 0400); | |
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; | |
74 | exp->mask.dst.ip = 0xffffffff; | |
75 | exp->mask.dst.u.udp.port = 0xffff; | |
76 | exp->mask.dst.protonum = 0xff; | |
77 | exp->expectfn = NULL; | |
1da177e4 LT |
78 | |
79 | DEBUGP("expect: "); | |
80 | DUMP_TUPLE(&exp->tuple); | |
81 | DUMP_TUPLE(&exp->mask); | |
82 | if (ip_nat_tftp_hook) | |
83 | ret = ip_nat_tftp_hook(pskb, ctinfo, exp); | |
4acdbdbe | 84 | else if (ip_conntrack_expect_related(exp) != 0) |
1da177e4 | 85 | ret = NF_DROP; |
4acdbdbe | 86 | ip_conntrack_expect_put(exp); |
1da177e4 LT |
87 | break; |
88 | case TFTP_OPCODE_DATA: | |
89 | case TFTP_OPCODE_ACK: | |
90 | DEBUGP("Data/ACK opcode\n"); | |
91 | break; | |
92 | case TFTP_OPCODE_ERROR: | |
93 | DEBUGP("Error opcode\n"); | |
94 | break; | |
95 | default: | |
96 | DEBUGP("Unknown opcode\n"); | |
97 | } | |
98 | return NF_ACCEPT; | |
99 | } | |
100 | ||
101 | static struct ip_conntrack_helper tftp[MAX_PORTS]; | |
102 | static char tftp_names[MAX_PORTS][10]; | |
103 | ||
104 | static void fini(void) | |
105 | { | |
106 | int i; | |
107 | ||
108 | for (i = 0 ; i < ports_c; i++) { | |
109 | DEBUGP("unregistering helper for port %d\n", | |
110 | ports[i]); | |
111 | ip_conntrack_helper_unregister(&tftp[i]); | |
112 | } | |
113 | } | |
114 | ||
115 | static int __init init(void) | |
116 | { | |
117 | int i, ret; | |
118 | char *tmpname; | |
119 | ||
120 | if (ports_c == 0) | |
121 | ports[ports_c++] = TFTP_PORT; | |
122 | ||
123 | for (i = 0; i < ports_c; i++) { | |
124 | /* Create helper structure */ | |
125 | memset(&tftp[i], 0, sizeof(struct ip_conntrack_helper)); | |
126 | ||
127 | tftp[i].tuple.dst.protonum = IPPROTO_UDP; | |
128 | tftp[i].tuple.src.u.udp.port = htons(ports[i]); | |
129 | tftp[i].mask.dst.protonum = 0xFF; | |
130 | tftp[i].mask.src.u.udp.port = 0xFFFF; | |
131 | tftp[i].max_expected = 1; | |
132 | tftp[i].timeout = 5 * 60; /* 5 minutes */ | |
133 | tftp[i].me = THIS_MODULE; | |
134 | tftp[i].help = tftp_help; | |
135 | ||
136 | tmpname = &tftp_names[i][0]; | |
137 | if (ports[i] == TFTP_PORT) | |
138 | sprintf(tmpname, "tftp"); | |
139 | else | |
140 | sprintf(tmpname, "tftp-%d", i); | |
141 | tftp[i].name = tmpname; | |
142 | ||
143 | DEBUGP("port #%d: %d\n", i, ports[i]); | |
144 | ||
145 | ret=ip_conntrack_helper_register(&tftp[i]); | |
146 | if (ret) { | |
147 | printk("ERROR registering helper for port %d\n", | |
148 | ports[i]); | |
149 | fini(); | |
150 | return(ret); | |
151 | } | |
152 | } | |
153 | return(0); | |
154 | } | |
155 | ||
156 | module_init(init); | |
157 | module_exit(fini); |