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