1 /* Shared library add-on to iptables to add static NAT support.
2 Author: Svenning Soerensen <svenning@post5.tele.dk>
3 */
4
5 #include <stdio.h>
6 #include <netdb.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <getopt.h>
10 #include <iptables.h>
11 #include <linux/netfilter_ipv4/ip_tables.h>
12 #include <linux/netfilter_ipv4/ip_nat_rule.h>
13 #include <netinet/in.h>
14
15 #define MODULENAME "NETMAP"
16
17 static struct option opts[] = {
18 { "to", 1, 0, '1' },
19 { 0 }
20 };
21
22 /* Function which prints out usage message. */
23 static void
help(void)24 help(void)
25 {
26 printf(MODULENAME" v%s options:\n"
27 " --%s address[/mask]\n"
28 " Network address to map to.\n\n",
29 IPTABLES_VERSION, opts[0].name);
30 }
31
32 static u_int32_t
bits2netmask(int bits)33 bits2netmask(int bits)
34 {
35 u_int32_t netmask, bm;
36
37 if (bits >= 32 || bits < 0)
38 return(~0);
39 for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
40 netmask |= bm;
41 return htonl(netmask);
42 }
43
44 static int
netmask2bits(u_int32_t netmask)45 netmask2bits(u_int32_t netmask)
46 {
47 u_int32_t bm;
48 int bits;
49
50 netmask = ntohl(netmask);
51 for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
52 bits++;
53 if (netmask)
54 return -1; /* holes in netmask */
55 return bits;
56 }
57
58 /* Initialize the target. */
59 static void
init(struct ipt_entry_target * t,unsigned int * nfcache)60 init(struct ipt_entry_target *t, unsigned int *nfcache)
61 {
62 struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
63
64 /* Actually, it's 0, but it's ignored at the moment. */
65 mr->rangesize = 1;
66
67 }
68
69 /* Parses network address */
70 static void
parse_to(char * arg,struct ip_nat_range * range)71 parse_to(char *arg, struct ip_nat_range *range)
72 {
73 char *slash;
74 struct in_addr *ip;
75 u_int32_t netmask;
76 unsigned int bits;
77
78 range->flags |= IP_NAT_RANGE_MAP_IPS;
79 slash = strchr(arg, '/');
80 if (slash)
81 *slash = '\0';
82
83 ip = dotted_to_addr(arg);
84 if (!ip)
85 exit_error(PARAMETER_PROBLEM, "Bad IP address `%s'\n",
86 arg);
87 range->min_ip = ip->s_addr;
88 if (slash) {
89 if (strchr(slash+1, '.')) {
90 ip = dotted_to_mask(slash+1);
91 if (!ip)
92 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n",
93 slash+1);
94 netmask = ip->s_addr;
95 }
96 else {
97 if (string_to_number(slash+1, 0, 32, &bits) == -1)
98 exit_error(PARAMETER_PROBLEM, "Bad netmask `%s'\n",
99 slash+1);
100 netmask = bits2netmask(bits);
101 }
102 /* Don't allow /0 (/1 is probably insane, too) */
103 if (netmask == 0)
104 exit_error(PARAMETER_PROBLEM, "Netmask needed\n");
105 }
106 else
107 netmask = ~0;
108
109 if (range->min_ip & ~netmask) {
110 if (slash)
111 *slash = '/';
112 exit_error(PARAMETER_PROBLEM, "Bad network address `%s'\n",
113 arg);
114 }
115 range->max_ip = range->min_ip | ~netmask;
116 }
117
118 /* Function which parses command options; returns true if it
119 ate an option */
120 static int
parse(int c,char ** argv,int invert,unsigned int * flags,const struct ipt_entry * entry,struct ipt_entry_target ** target)121 parse(int c, char **argv, int invert, unsigned int *flags,
122 const struct ipt_entry *entry,
123 struct ipt_entry_target **target)
124 {
125 struct ip_nat_multi_range *mr
126 = (struct ip_nat_multi_range *)(*target)->data;
127
128 switch (c) {
129 case '1':
130 if (check_inverse(optarg, &invert, NULL, 0))
131 exit_error(PARAMETER_PROBLEM,
132 "Unexpected `!' after --%s", opts[0].name);
133
134 parse_to(optarg, &mr->range[0]);
135 *flags = 1;
136 return 1;
137
138 default:
139 return 0;
140 }
141 }
142
143 /* Final check; need --to */
final_check(unsigned int flags)144 static void final_check(unsigned int flags)
145 {
146 if (!flags)
147 exit_error(PARAMETER_PROBLEM,
148 MODULENAME" needs --%s", opts[0].name);
149 }
150
151 /* Prints out the targinfo. */
152 static void
print(const struct ipt_ip * ip,const struct ipt_entry_target * target,int numeric)153 print(const struct ipt_ip *ip,
154 const struct ipt_entry_target *target,
155 int numeric)
156 {
157 struct ip_nat_multi_range *mr
158 = (struct ip_nat_multi_range *)target->data;
159 struct ip_nat_range *r = &mr->range[0];
160 struct in_addr a;
161 int bits;
162
163 a.s_addr = r->min_ip;
164 printf("%s", addr_to_dotted(&a));
165 a.s_addr = ~(r->min_ip ^ r->max_ip);
166 bits = netmask2bits(a.s_addr);
167 if (bits < 0)
168 printf("/%s", addr_to_dotted(&a));
169 else
170 printf("/%d", bits);
171 }
172
173 /* Saves the targinfo in parsable form to stdout. */
174 static void
save(const struct ipt_ip * ip,const struct ipt_entry_target * target)175 save(const struct ipt_ip *ip, const struct ipt_entry_target *target)
176 {
177 printf("--%s ", opts[0].name);
178 print(ip, target, 0);
179 }
180
181 static struct iptables_target target_module = {
182 .next = NULL,
183 .name = MODULENAME,
184 .version = IPTABLES_VERSION,
185 .size = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
186 .userspacesize = IPT_ALIGN(sizeof(struct ip_nat_multi_range)),
187 .help = &help,
188 .init = &init,
189 .parse = &parse,
190 .final_check = &final_check,
191 .print = &print,
192 .save = &save,
193 .extra_opts = opts
194 };
195
ipt_NETMAP_init(void)196 void ipt_NETMAP_init(void)
197 {
198 register_target(&target_module);
199 }
200
201