• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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