www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_nat_amanda.c
1 /* Amanda extension for TCP NAT alteration.
2  * (C) 2002 by Brian J. Murrell <netfilter@interlinx.bc.ca>
3  * based on a copy of HW's ip_nat_irc.c as well as other modules
4  *
5  *      This program is free software; you can redistribute it and/or
6  *      modify it under the terms of the GNU General Public License
7  *      as published by the Free Software Foundation; either version
8  *      2 of the License, or (at your option) any later version.
9  *
10  *      Module load syntax:
11  *      insmod ip_nat_amanda.o
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/module.h>
16 #include <linux/netfilter.h>
17 #include <linux/skbuff.h>
18 #include <linux/ip.h>
19 #include <linux/udp.h>
20 #include <net/tcp.h>
21 #include <net/udp.h>
22
23 #include <linux/netfilter_ipv4.h>
24 #include <linux/netfilter_ipv4/ip_nat.h>
25 #include <linux/netfilter_ipv4/ip_nat_helper.h>
26 #include <linux/netfilter_ipv4/ip_conntrack_helper.h>
27 #include <linux/netfilter_ipv4/ip_conntrack_amanda.h>
28
29
30 MODULE_AUTHOR("Brian J. Murrell <netfilter@interlinx.bc.ca>");
31 MODULE_DESCRIPTION("Amanda NAT helper");
32 MODULE_LICENSE("GPL");
33
34 static unsigned int
35 amanda_nat_expected(struct sk_buff **pskb,
36                     unsigned int hooknum,
37                     struct ip_conntrack *ct,
38                     struct ip_nat_info *info)
39 {
40         struct ip_conntrack *master = master_ct(ct);
41         struct ip_ct_amanda_expect *exp_amanda_info;
42         struct ip_nat_multi_range mr;
43         u_int32_t newip;
44
45         IP_NF_ASSERT(info);
46         IP_NF_ASSERT(master);
47         IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum))));
48
49         if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC)
50                 newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip;
51         else
52                 newip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip;
53
54         mr.rangesize = 1;
55         /* We don't want to manip the per-protocol, just the IPs. */
56         mr.range[0].flags = IP_NAT_RANGE_MAP_IPS;
57         mr.range[0].min_ip = mr.range[0].max_ip = newip;
58
59         if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) {
60                 exp_amanda_info = &ct->master->help.exp_amanda_info;
61                 mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED;
62                 mr.range[0].min = mr.range[0].max
63                         = ((union ip_conntrack_manip_proto)
64                                 { .udp = { htons(exp_amanda_info->port) } });
65         }
66
67         return ip_nat_setup_info(ct, &mr, hooknum);
68 }
69
70 static int amanda_data_fixup(struct ip_conntrack *ct,
71                              struct sk_buff **pskb,
72                              enum ip_conntrack_info ctinfo,
73                              struct ip_conntrack_expect *exp)
74 {
75         struct ip_ct_amanda_expect *exp_amanda_info;
76         struct ip_conntrack_tuple t = exp->tuple;
77         char buffer[sizeof("65535")];
78         u_int16_t port;
79
80         /* Alter conntrack's expectations. */
81         exp_amanda_info = &exp->help.exp_amanda_info;
82         t.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip;
83         for (port = exp_amanda_info->port; port != 0; port++) {
84                 t.dst.u.tcp.port = htons(port);
85                 if (ip_conntrack_change_expect(exp, &t) == 0)
86                         break;
87         }
88         if (port == 0)
89                 return 0;
90
91         sprintf(buffer, "%u", port);
92         return ip_nat_mangle_udp_packet(pskb, ct, ctinfo,
93                                         exp_amanda_info->offset,
94                                         exp_amanda_info->len,
95                                         buffer, strlen(buffer));
96 }
97
98 static unsigned int help(struct ip_conntrack *ct,
99                          struct ip_conntrack_expect *exp,
100                          struct ip_nat_info *info,
101                          enum ip_conntrack_info ctinfo,
102                          unsigned int hooknum,
103                          struct sk_buff **pskb)
104 {
105         int dir = CTINFO2DIR(ctinfo);
106         int ret = NF_ACCEPT;
107
108         /* Only mangle things once: original direction in POST_ROUTING
109            and reply direction on PRE_ROUTING. */
110         if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
111               || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY)))
112                 return NF_ACCEPT;
113
114         /* if this exectation has a "offset" the packet needs to be mangled */
115         if (exp->help.exp_amanda_info.offset != 0)
116                 if (!amanda_data_fixup(ct, pskb, ctinfo, exp))
117                         ret = NF_DROP;
118         exp->help.exp_amanda_info.offset = 0;
119
120         return ret;
121 }
122
123 static struct ip_nat_helper ip_nat_amanda_helper;
124
125 static void __exit fini(void)
126 {
127         ip_nat_helper_unregister(&ip_nat_amanda_helper);
128 }
129
130 static int __init init(void)
131 {
132         struct ip_nat_helper *hlpr = &ip_nat_amanda_helper;
133
134         hlpr->tuple.dst.protonum = IPPROTO_UDP;
135         hlpr->tuple.src.u.udp.port = htons(10080);
136         hlpr->mask.src.u.udp.port = 0xFFFF;
137         hlpr->mask.dst.protonum = 0xFFFF;
138         hlpr->help = help;
139         hlpr->flags = 0;
140         hlpr->me = THIS_MODULE;
141         hlpr->expect = amanda_nat_expected;
142         hlpr->name = "amanda";
143
144         return ip_nat_helper_register(hlpr);
145 }
146
147 NEEDS_CONNTRACK(amanda);
148 module_init(init);
149 module_exit(fini);