Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* NETMAP - static NAT mapping of IP network addresses (1:1). |
2 | * The mapping can be applied to source (POSTROUTING), | |
3 | * destination (PREROUTING), or both (with separate rules). | |
4 | */ | |
5 | ||
6 | /* (C) 2000-2001 Svenning Soerensen <svenning@post5.tele.dk> | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or modify | |
9 | * it under the terms of the GNU General Public License version 2 as | |
10 | * published by the Free Software Foundation. | |
11 | */ | |
12 | ||
13 | #include <linux/config.h> | |
14 | #include <linux/ip.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/netdevice.h> | |
17 | #include <linux/netfilter.h> | |
18 | #include <linux/netfilter_ipv4.h> | |
19 | #include <linux/netfilter_ipv4/ip_nat_rule.h> | |
20 | ||
21 | #define MODULENAME "NETMAP" | |
22 | MODULE_LICENSE("GPL"); | |
23 | MODULE_AUTHOR("Svenning Soerensen <svenning@post5.tele.dk>"); | |
24 | MODULE_DESCRIPTION("iptables 1:1 NAT mapping of IP networks target"); | |
25 | ||
26 | #if 0 | |
27 | #define DEBUGP printk | |
28 | #else | |
29 | #define DEBUGP(format, args...) | |
30 | #endif | |
31 | ||
32 | static int | |
33 | check(const char *tablename, | |
34 | const struct ipt_entry *e, | |
35 | void *targinfo, | |
36 | unsigned int targinfosize, | |
37 | unsigned int hook_mask) | |
38 | { | |
39 | const struct ip_nat_multi_range_compat *mr = targinfo; | |
40 | ||
41 | if (strcmp(tablename, "nat") != 0) { | |
42 | DEBUGP(MODULENAME":check: bad table `%s'.\n", tablename); | |
43 | return 0; | |
44 | } | |
45 | if (targinfosize != IPT_ALIGN(sizeof(*mr))) { | |
46 | DEBUGP(MODULENAME":check: size %u.\n", targinfosize); | |
47 | return 0; | |
48 | } | |
49 | if (hook_mask & ~((1 << NF_IP_PRE_ROUTING) | (1 << NF_IP_POST_ROUTING))) { | |
50 | DEBUGP(MODULENAME":check: bad hooks %x.\n", hook_mask); | |
51 | return 0; | |
52 | } | |
53 | if (!(mr->range[0].flags & IP_NAT_RANGE_MAP_IPS)) { | |
54 | DEBUGP(MODULENAME":check: bad MAP_IPS.\n"); | |
55 | return 0; | |
56 | } | |
57 | if (mr->rangesize != 1) { | |
58 | DEBUGP(MODULENAME":check: bad rangesize %u.\n", mr->rangesize); | |
59 | return 0; | |
60 | } | |
61 | return 1; | |
62 | } | |
63 | ||
64 | static unsigned int | |
65 | target(struct sk_buff **pskb, | |
66 | const struct net_device *in, | |
67 | const struct net_device *out, | |
68 | unsigned int hooknum, | |
69 | const void *targinfo, | |
70 | void *userinfo) | |
71 | { | |
72 | struct ip_conntrack *ct; | |
73 | enum ip_conntrack_info ctinfo; | |
74 | u_int32_t new_ip, netmask; | |
75 | const struct ip_nat_multi_range_compat *mr = targinfo; | |
76 | struct ip_nat_range newrange; | |
77 | ||
78 | IP_NF_ASSERT(hooknum == NF_IP_PRE_ROUTING | |
79 | || hooknum == NF_IP_POST_ROUTING); | |
80 | ct = ip_conntrack_get(*pskb, &ctinfo); | |
81 | ||
82 | netmask = ~(mr->range[0].min_ip ^ mr->range[0].max_ip); | |
83 | ||
84 | if (hooknum == NF_IP_PRE_ROUTING) | |
85 | new_ip = (*pskb)->nh.iph->daddr & ~netmask; | |
86 | else | |
87 | new_ip = (*pskb)->nh.iph->saddr & ~netmask; | |
88 | new_ip |= mr->range[0].min_ip & netmask; | |
89 | ||
90 | newrange = ((struct ip_nat_range) | |
91 | { mr->range[0].flags | IP_NAT_RANGE_MAP_IPS, | |
92 | new_ip, new_ip, | |
93 | mr->range[0].min, mr->range[0].max }); | |
94 | ||
95 | /* Hand modified range to generic setup. */ | |
96 | return ip_nat_setup_info(ct, &newrange, hooknum); | |
97 | } | |
98 | ||
99 | static struct ipt_target target_module = { | |
100 | .name = MODULENAME, | |
101 | .target = target, | |
102 | .checkentry = check, | |
103 | .me = THIS_MODULE | |
104 | }; | |
105 | ||
106 | static int __init init(void) | |
107 | { | |
108 | return ipt_register_target(&target_module); | |
109 | } | |
110 | ||
111 | static void __exit fini(void) | |
112 | { | |
113 | ipt_unregister_target(&target_module); | |
114 | } | |
115 | ||
116 | module_init(init); | |
117 | module_exit(fini); |