libipt_NETMAP.c revision 1829ed482efbc8b390cc760d012b3a4450494e1a
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 <xtables.h>
11#include <linux/netfilter_ipv4/ip_tables.h>
12#include <linux/netfilter/nf_nat.h>
13
14#define MODULENAME "NETMAP"
15
16static const struct option NETMAP_opts[] = {
17	{ "to", 1, NULL, '1' },
18	{ .name = NULL }
19};
20
21static void NETMAP_help(void)
22{
23	printf(MODULENAME" target options:\n"
24	       "  --%s address[/mask]\n"
25	       "				Network address to map to.\n\n",
26	       NETMAP_opts[0].name);
27}
28
29static u_int32_t
30bits2netmask(int bits)
31{
32	u_int32_t netmask, bm;
33
34	if (bits >= 32 || bits < 0)
35		return(~0);
36	for (netmask = 0, bm = 0x80000000; bits; bits--, bm >>= 1)
37		netmask |= bm;
38	return htonl(netmask);
39}
40
41static int
42netmask2bits(u_int32_t netmask)
43{
44	u_int32_t bm;
45	int bits;
46
47	netmask = ntohl(netmask);
48	for (bits = 0, bm = 0x80000000; netmask & bm; netmask <<= 1)
49		bits++;
50	if (netmask)
51		return -1; /* holes in netmask */
52	return bits;
53}
54
55static void NETMAP_init(struct xt_entry_target *t)
56{
57	struct ip_nat_multi_range *mr = (struct ip_nat_multi_range *)t->data;
58
59	/* Actually, it's 0, but it's ignored at the moment. */
60	mr->rangesize = 1;
61
62}
63
64/* Parses network address */
65static void
66parse_to(char *arg, struct ip_nat_range *range)
67{
68	char *slash;
69	const struct in_addr *ip;
70	u_int32_t netmask;
71	unsigned int bits;
72
73	range->flags |= IP_NAT_RANGE_MAP_IPS;
74	slash = strchr(arg, '/');
75	if (slash)
76		*slash = '\0';
77
78	ip = xtables_numeric_to_ipaddr(arg);
79	if (!ip)
80		xtables_error(PARAMETER_PROBLEM, "Bad IP address \"%s\"\n",
81			   arg);
82	range->min_ip = ip->s_addr;
83	if (slash) {
84		if (strchr(slash+1, '.')) {
85			ip = xtables_numeric_to_ipmask(slash+1);
86			if (!ip)
87				xtables_error(PARAMETER_PROBLEM, "Bad netmask \"%s\"\n",
88					   slash+1);
89			netmask = ip->s_addr;
90		}
91		else {
92			if (!xtables_strtoui(slash+1, NULL, &bits, 0, 32))
93				xtables_error(PARAMETER_PROBLEM, "Bad netmask \"%s\"\n",
94					   slash+1);
95			netmask = bits2netmask(bits);
96		}
97		/* Don't allow /0 (/1 is probably insane, too) */
98		if (netmask == 0)
99			xtables_error(PARAMETER_PROBLEM, "Netmask needed\n");
100	}
101	else
102		netmask = ~0;
103
104	if (range->min_ip & ~netmask) {
105		if (slash)
106			*slash = '/';
107		xtables_error(PARAMETER_PROBLEM, "Bad network address \"%s\"\n",
108			   arg);
109	}
110	range->max_ip = range->min_ip | ~netmask;
111}
112
113static int NETMAP_parse(int c, char **argv, int invert, unsigned int *flags,
114                        const void *entry, struct xt_entry_target **target)
115{
116	struct ip_nat_multi_range *mr
117		= (struct ip_nat_multi_range *)(*target)->data;
118
119	switch (c) {
120	case '1':
121		if (xtables_check_inverse(optarg, &invert, NULL, 0))
122			xtables_error(PARAMETER_PROBLEM,
123				   "Unexpected `!' after --%s", NETMAP_opts[0].name);
124
125		parse_to(optarg, &mr->range[0]);
126		*flags = 1;
127		return 1;
128
129	default:
130		return 0;
131	}
132}
133
134static void NETMAP_check(unsigned int flags)
135{
136	if (!flags)
137		xtables_error(PARAMETER_PROBLEM,
138			   MODULENAME" needs --%s", NETMAP_opts[0].name);
139}
140
141static void NETMAP_print(const void *ip, const struct xt_entry_target *target,
142                         int numeric)
143{
144	struct ip_nat_multi_range *mr
145		= (struct ip_nat_multi_range *)target->data;
146	struct ip_nat_range *r = &mr->range[0];
147	struct in_addr a;
148	int bits;
149
150	a.s_addr = r->min_ip;
151	printf("%s", xtables_ipaddr_to_numeric(&a));
152	a.s_addr = ~(r->min_ip ^ r->max_ip);
153	bits = netmask2bits(a.s_addr);
154	if (bits < 0)
155		printf("/%s", xtables_ipaddr_to_numeric(&a));
156	else
157		printf("/%d", bits);
158}
159
160static void NETMAP_save(const void *ip, const struct xt_entry_target *target)
161{
162	printf("--%s ", NETMAP_opts[0].name);
163	NETMAP_print(ip, target, 0);
164}
165
166static struct xtables_target netmap_tg_reg = {
167	.name		= MODULENAME,
168	.version	= XTABLES_VERSION,
169	.family		= NFPROTO_IPV4,
170	.size		= XT_ALIGN(sizeof(struct ip_nat_multi_range)),
171	.userspacesize	= XT_ALIGN(sizeof(struct ip_nat_multi_range)),
172	.help		= NETMAP_help,
173	.init		= NETMAP_init,
174	.parse		= NETMAP_parse,
175	.final_check	= NETMAP_check,
176	.print		= NETMAP_print,
177	.save		= NETMAP_save,
178	.extra_opts	= NETMAP_opts,
179};
180
181void _init(void)
182{
183	xtables_register_target(&netmap_tg_reg);
184}
185