Blame view

net/netfilter/nf_conntrack_tftp.c 4.1 KB
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
1
2
3
4
5
6
7
8
9
10
11
  /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
   *
   * 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.
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/in.h>
  #include <linux/udp.h>
1863f0965   Yasuyuki Kozakai   [NETFILTER]: nf_c...
12
  #include <linux/netfilter.h>
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
13
14
15
16
17
18
19
20
21
22
23
24
  
  #include <net/netfilter/nf_conntrack.h>
  #include <net/netfilter/nf_conntrack_tuple.h>
  #include <net/netfilter/nf_conntrack_expect.h>
  #include <net/netfilter/nf_conntrack_ecache.h>
  #include <net/netfilter/nf_conntrack_helper.h>
  #include <linux/netfilter/nf_conntrack_tftp.h>
  
  MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
  MODULE_DESCRIPTION("TFTP connection tracking helper");
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("ip_conntrack_tftp");
4dc06f963   Pablo Neira Ayuso   netfilter: nf_con...
25
  MODULE_ALIAS_NFCT_HELPER("tftp");
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
26
27
28
  
  #define MAX_PORTS 8
  static unsigned short ports[MAX_PORTS];
2f0d2f103   Stephen Hemminger   [NETFILTER]: conn...
29
  static unsigned int ports_c;
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
30
31
  module_param_array(ports, ushort, &ports_c, 0400);
  MODULE_PARM_DESC(ports, "Port numbers of TFTP servers");
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
32
  unsigned int (*nf_nat_tftp_hook)(struct sk_buff *skb,
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
33
34
35
  				 enum ip_conntrack_info ctinfo,
  				 struct nf_conntrack_expect *exp) __read_mostly;
  EXPORT_SYMBOL_GPL(nf_nat_tftp_hook);
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
36
  static int tftp_help(struct sk_buff *skb,
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
37
38
39
40
  		     unsigned int protoff,
  		     struct nf_conn *ct,
  		     enum ip_conntrack_info ctinfo)
  {
de24b4ebb   Jan Engelhardt   [NETFILTER]: nf_{...
41
42
  	const struct tftphdr *tfh;
  	struct tftphdr _tftph;
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
43
44
45
  	struct nf_conntrack_expect *exp;
  	struct nf_conntrack_tuple *tuple;
  	unsigned int ret = NF_ACCEPT;
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
46
  	typeof(nf_nat_tftp_hook) nf_nat_tftp;
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
47
  	tfh = skb_header_pointer(skb, protoff + sizeof(struct udphdr),
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
48
49
50
51
52
53
54
55
  				 sizeof(_tftph), &_tftph);
  	if (tfh == NULL)
  		return NF_ACCEPT;
  
  	switch (ntohs(tfh->opcode)) {
  	case TFTP_OPCODE_READ:
  	case TFTP_OPCODE_WRITE:
  		/* RRQ and WRQ works the same way */
3c9fba656   Jan Engelhardt   [NETFILTER]: nf_c...
56
57
  		nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);
  		nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_REPLY].tuple);
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
58

6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
59
  		exp = nf_ct_expect_alloc(ct);
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
60
61
62
  		if (exp == NULL)
  			return NF_DROP;
  		tuple = &ct->tuplehash[IP_CT_DIR_REPLY].tuple;
5e8fbe2ac   Patrick McHardy   [NETFILTER]: nf_c...
63
64
  		nf_ct_expect_init(exp, NF_CT_EXPECT_CLASS_DEFAULT,
  				  nf_ct_l3num(ct),
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
65
  				  &tuple->src.u3, &tuple->dst.u3,
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
66
  				  IPPROTO_UDP, NULL, &tuple->dst.u.udp.port);
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
67

0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
68
  		pr_debug("expect: ");
3c9fba656   Jan Engelhardt   [NETFILTER]: nf_c...
69
  		nf_ct_dump_tuple(&exp->tuple);
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
70
71
72
  
  		nf_nat_tftp = rcu_dereference(nf_nat_tftp_hook);
  		if (nf_nat_tftp && ct->status & IPS_NAT_MASK)
3db05fea5   Herbert Xu   [NETFILTER]: Repl...
73
  			ret = nf_nat_tftp(skb, ctinfo, exp);
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
74
  		else if (nf_ct_expect_related(exp) != 0)
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
75
  			ret = NF_DROP;
6823645d6   Patrick McHardy   [NETFILTER]: nf_c...
76
  		nf_ct_expect_put(exp);
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
77
78
79
  		break;
  	case TFTP_OPCODE_DATA:
  	case TFTP_OPCODE_ACK:
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
80
81
  		pr_debug("Data/ACK opcode
  ");
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
82
83
  		break;
  	case TFTP_OPCODE_ERROR:
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
84
85
  		pr_debug("Error opcode
  ");
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
86
87
  		break;
  	default:
0d53778e8   Patrick McHardy   [NETFILTER]: Conv...
88
89
  		pr_debug("Unknown opcode
  ");
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
90
91
92
93
94
95
  	}
  	return ret;
  }
  
  static struct nf_conntrack_helper tftp[MAX_PORTS][2] __read_mostly;
  static char tftp_names[MAX_PORTS][2][sizeof("tftp-65535")] __read_mostly;
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
96
97
98
99
  static const struct nf_conntrack_expect_policy tftp_exp_policy = {
  	.max_expected	= 1,
  	.timeout	= 5 * 60,
  };
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  static void nf_conntrack_tftp_fini(void)
  {
  	int i, j;
  
  	for (i = 0; i < ports_c; i++) {
  		for (j = 0; j < 2; j++)
  			nf_conntrack_helper_unregister(&tftp[i][j]);
  	}
  }
  
  static int __init nf_conntrack_tftp_init(void)
  {
  	int i, j, ret;
  	char *tmpname;
  
  	if (ports_c == 0)
  		ports[ports_c++] = TFTP_PORT;
  
  	for (i = 0; i < ports_c; i++) {
  		memset(&tftp[i], 0, sizeof(tftp[i]));
  
  		tftp[i][0].tuple.src.l3num = AF_INET;
  		tftp[i][1].tuple.src.l3num = AF_INET6;
  		for (j = 0; j < 2; j++) {
  			tftp[i][j].tuple.dst.protonum = IPPROTO_UDP;
  			tftp[i][j].tuple.src.u.udp.port = htons(ports[i]);
6002f266b   Patrick McHardy   [NETFILTER]: nf_c...
126
  			tftp[i][j].expect_policy = &tftp_exp_policy;
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
127
128
129
130
131
132
133
134
135
136
137
138
  			tftp[i][j].me = THIS_MODULE;
  			tftp[i][j].help = tftp_help;
  
  			tmpname = &tftp_names[i][j][0];
  			if (ports[i] == TFTP_PORT)
  				sprintf(tmpname, "tftp");
  			else
  				sprintf(tmpname, "tftp-%u", i);
  			tftp[i][j].name = tmpname;
  
  			ret = nf_conntrack_helper_register(&tftp[i][j]);
  			if (ret) {
654d0fbdc   Stephen Hemminger   netfilter: cleanu...
139
140
141
  				printk(KERN_ERR "nf_ct_tftp: failed to register"
  				       " helper for pf: %u port: %u
  ",
a536df35b   Patrick McHardy   [NETFILTER]: nf_c...
142
143
144
145
146
147
148
149
150
151
152
  					tftp[i][j].tuple.src.l3num, ports[i]);
  				nf_conntrack_tftp_fini();
  				return ret;
  			}
  		}
  	}
  	return 0;
  }
  
  module_init(nf_conntrack_tftp_init);
  module_exit(nf_conntrack_tftp_fini);