1 /* (C) 2001-2002 Magnus Boden <mb@ozaba.mine.nu>
2 * (C) 2006-2012 Patrick McHardy <kaber@trash.net>
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.
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
10 #include <linux/module.h>
11 #include <linux/moduleparam.h>
13 #include <linux/udp.h>
14 #include <linux/netfilter.h>
16 #include <net/netfilter/nf_conntrack.h>
17 #include <net/netfilter/nf_conntrack_tuple.h>
18 #include <net/netfilter/nf_conntrack_expect.h>
19 #include <net/netfilter/nf_conntrack_ecache.h>
20 #include <net/netfilter/nf_conntrack_helper.h>
21 #include <linux/netfilter/nf_conntrack_tftp.h>
23 MODULE_AUTHOR("Magnus Boden <mb@ozaba.mine.nu>");
24 MODULE_DESCRIPTION("TFTP connection tracking helper");
25 MODULE_LICENSE("GPL");
26 MODULE_ALIAS("ip_conntrack_tftp");
27 MODULE_ALIAS_NFCT_HELPER("tftp");
30 static unsigned short ports
[MAX_PORTS
];
31 static unsigned int ports_c
;
32 module_param_array(ports
, ushort
, &ports_c
, 0400);
33 MODULE_PARM_DESC(ports
, "Port numbers of TFTP servers");
35 unsigned int (*nf_nat_tftp_hook
)(struct sk_buff
*skb
,
36 enum ip_conntrack_info ctinfo
,
37 struct nf_conntrack_expect
*exp
) __read_mostly
;
38 EXPORT_SYMBOL_GPL(nf_nat_tftp_hook
);
40 static int tftp_help(struct sk_buff
*skb
,
43 enum ip_conntrack_info ctinfo
)
45 const struct tftphdr
*tfh
;
46 struct tftphdr _tftph
;
47 struct nf_conntrack_expect
*exp
;
48 struct nf_conntrack_tuple
*tuple
;
49 unsigned int ret
= NF_ACCEPT
;
50 typeof(nf_nat_tftp_hook
) nf_nat_tftp
;
52 tfh
= skb_header_pointer(skb
, protoff
+ sizeof(struct udphdr
),
53 sizeof(_tftph
), &_tftph
);
57 switch (ntohs(tfh
->opcode
)) {
58 case TFTP_OPCODE_READ
:
59 case TFTP_OPCODE_WRITE
:
60 /* RRQ and WRQ works the same way */
61 nf_ct_dump_tuple(&ct
->tuplehash
[IP_CT_DIR_ORIGINAL
].tuple
);
62 nf_ct_dump_tuple(&ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
);
64 exp
= nf_ct_expect_alloc(ct
);
66 nf_ct_helper_log(skb
, ct
, "cannot alloc expectation");
69 tuple
= &ct
->tuplehash
[IP_CT_DIR_REPLY
].tuple
;
70 nf_ct_expect_init(exp
, NF_CT_EXPECT_CLASS_DEFAULT
,
72 &tuple
->src
.u3
, &tuple
->dst
.u3
,
73 IPPROTO_UDP
, NULL
, &tuple
->dst
.u
.udp
.port
);
76 nf_ct_dump_tuple(&exp
->tuple
);
78 nf_nat_tftp
= rcu_dereference(nf_nat_tftp_hook
);
79 if (nf_nat_tftp
&& ct
->status
& IPS_NAT_MASK
)
80 ret
= nf_nat_tftp(skb
, ctinfo
, exp
);
81 else if (nf_ct_expect_related(exp
) != 0) {
82 nf_ct_helper_log(skb
, ct
, "cannot add expectation");
85 nf_ct_expect_put(exp
);
87 case TFTP_OPCODE_DATA
:
89 pr_debug("Data/ACK opcode\n");
91 case TFTP_OPCODE_ERROR
:
92 pr_debug("Error opcode\n");
95 pr_debug("Unknown opcode\n");
100 static struct nf_conntrack_helper tftp
[MAX_PORTS
* 2] __read_mostly
;
102 static const struct nf_conntrack_expect_policy tftp_exp_policy
= {
107 static void nf_conntrack_tftp_fini(void)
109 nf_conntrack_helpers_unregister(tftp
, ports_c
* 2);
112 static int __init
nf_conntrack_tftp_init(void)
116 NF_CT_HELPER_BUILD_BUG_ON(0);
119 ports
[ports_c
++] = TFTP_PORT
;
121 for (i
= 0; i
< ports_c
; i
++) {
122 nf_ct_helper_init(&tftp
[2 * i
], AF_INET
, IPPROTO_UDP
, "tftp",
123 TFTP_PORT
, ports
[i
], i
, &tftp_exp_policy
,
124 0, tftp_help
, NULL
, THIS_MODULE
);
125 nf_ct_helper_init(&tftp
[2 * i
+ 1], AF_INET6
, IPPROTO_UDP
, "tftp",
126 TFTP_PORT
, ports
[i
], i
, &tftp_exp_policy
,
127 0, tftp_help
, NULL
, THIS_MODULE
);
130 ret
= nf_conntrack_helpers_register(tftp
, ports_c
* 2);
132 pr_err("failed to register helpers\n");
138 module_init(nf_conntrack_tftp_init
);
139 module_exit(nf_conntrack_tftp_fini
);