iptables branch for 4.2
[iptables.git] / ipset / ipset_ipmap.c
1 /* Copyright 2000-2004 Joakim Axelsson (gozem@linux.nu)
2  *                     Patrick Schaaf (bof@bof.de)
3  *                     Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
4  *
5  * This program is free software; you can redistribute it and/or modify   
6  * it under the terms of the GNU General Public License as published by   
7  * the Free Software Foundation; either version 2 of the License, or      
8  * (at your option) any later version.                                    
9  *                                                                         
10  * This program is distributed in the hope that it will be useful,        
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of         
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
13  * GNU General Public License for more details.                           
14  *                                                                         
15  * You should have received a copy of the GNU General Public License      
16  * along with this program; if not, write to the Free Software            
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #ifndef __always_inline
26 #define __always_inline inline
27 #endif
28 #include <asm/bitops.h>
29
30 #include <linux/netfilter_ipv4/ip_set_ipmap.h>
31 #include "ipset.h"
32
33 #define BUFLEN 30;
34
35 #define OPT_CREATE_FROM    0x01U
36 #define OPT_CREATE_TO      0x02U
37 #define OPT_CREATE_NETWORK 0x04U
38 #define OPT_CREATE_NETMASK 0x08U
39
40 #define OPT_ADDDEL_IP      0x01U
41
42 /* Initialize the create. */
43 void create_init(void *data)
44 {
45         struct ip_set_req_ipmap_create *mydata =
46             (struct ip_set_req_ipmap_create *) data;
47
48         DP("create INIT");
49         mydata->netmask = 0xFFFFFFFF;
50 }
51
52 /* Function which parses command options; returns true if it ate an option */
53 int create_parse(int c, char *argv[], void *data, unsigned *flags)
54 {
55         struct ip_set_req_ipmap_create *mydata =
56             (struct ip_set_req_ipmap_create *) data;
57         unsigned int bits;
58
59         DP("create_parse");
60
61         switch (c) {
62         case '1':
63                 parse_ip(optarg, &mydata->from);
64
65                 *flags |= OPT_CREATE_FROM;
66
67                 DP("--from %x (%s)", mydata->from,
68                    ip_tostring_numeric(mydata->from));
69
70                 break;
71
72         case '2':
73                 parse_ip(optarg, &mydata->to);
74
75                 *flags |= OPT_CREATE_TO;
76
77                 DP("--to %x (%s)", mydata->to,
78                    ip_tostring_numeric(mydata->to));
79
80                 break;
81
82         case '3':
83                 parse_ipandmask(optarg, &mydata->from, &mydata->to);
84
85                 /* Make to the last of from + mask */
86                 if (mydata->to)
87                         mydata->to = mydata->from | ~(mydata->to);
88                 else {
89                         mydata->from = 0x00000000;
90                         mydata->to = 0xFFFFFFFF;
91                 }
92                 *flags |= OPT_CREATE_NETWORK;
93
94                 DP("--network from %x (%s)", 
95                    mydata->from, ip_tostring_numeric(mydata->from));
96                 DP("--network to %x (%s)", 
97                    mydata->to, ip_tostring_numeric(mydata->to));
98
99                 break;
100
101         case '4':
102                 if (string_to_number(optarg, 0, 32, &bits))
103                         exit_error(PARAMETER_PROBLEM, 
104                                   "Invalid netmask `%s' specified", optarg);
105                 
106                 if (bits != 0)
107                         mydata->netmask = 0xFFFFFFFF << (32 - bits);
108
109                 *flags |= OPT_CREATE_NETMASK;
110
111                 DP("--netmask %x", mydata->netmask);
112                 
113                 break;
114
115         default:
116                 return 0;
117         }
118
119         return 1;
120 }
121
122 #define ERRSTRLEN       256
123
124 /* Final check; exit if not ok. */
125 void create_final(void *data, unsigned int flags)
126 {
127         struct ip_set_req_ipmap_create *mydata =
128             (struct ip_set_req_ipmap_create *) data;
129         ip_set_ip_t range;
130         char errstr[ERRSTRLEN];
131
132         if (flags == 0)
133                 exit_error(PARAMETER_PROBLEM,
134                            "Need to specify --from and --to, or --network\n");
135
136         if (flags & OPT_CREATE_NETWORK) {
137                 /* --network */
138                 if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
139                         exit_error(PARAMETER_PROBLEM,
140                                    "Can't specify --from or --to with --network\n");
141         } else {
142                 /* --from --to */
143                 if ((flags & OPT_CREATE_FROM) == 0
144                     || (flags & OPT_CREATE_TO) == 0)
145                         exit_error(PARAMETER_PROBLEM,
146                                    "Need to specify both --from and --to\n");
147         }
148
149         DP("from : %x to: %x diff: %x", 
150            mydata->from, mydata->to,
151            mydata->to - mydata->from);
152
153         if (mydata->from > mydata->to)
154                 exit_error(PARAMETER_PROBLEM,
155                            "From can't be lower than to.\n");
156
157         if (flags & OPT_CREATE_NETMASK) {
158                 unsigned int mask_bits, netmask_bits;
159                 ip_set_ip_t mask;
160                 
161                 if ((mydata->from & mydata->netmask) != mydata->from)
162                         exit_error(PARAMETER_PROBLEM,
163                                    "%s is not a network address according to netmask %d\n",
164                                    ip_tostring_numeric(mydata->from),
165                                    mask_to_bits(mydata->netmask));
166                 
167                 mask = range_to_mask(mydata->from, mydata->to, &mask_bits);
168                 if (!mask
169                     && (mydata->from || mydata->to != 0xFFFFFFFF)) {
170                         strncpy(errstr, ip_tostring_numeric(mydata->from),
171                                 ERRSTRLEN-2);
172                         errstr[ERRSTRLEN-1] = '\0';
173                         exit_error(PARAMETER_PROBLEM,
174                                    "%s-%s is not a full network (%x)\n",
175                                    errstr,
176                                    ip_tostring_numeric(mydata->to), mask);
177                 }
178                 netmask_bits = mask_to_bits(mydata->netmask);
179                 
180                 if (netmask_bits <= mask_bits) {
181                         strncpy(errstr, ip_tostring_numeric(mydata->from),
182                                 ERRSTRLEN-2);
183                         errstr[ERRSTRLEN-1] = '\0';
184                         exit_error(PARAMETER_PROBLEM,
185                                    "%d netmask specifies larger or equal netblock than %s-%s (%d)\n",
186                                    netmask_bits,
187                                    errstr,
188                                    ip_tostring_numeric(mydata->to),
189                                    mask_bits);
190                 }
191                 range = (1<<(netmask_bits - mask_bits)) - 1;
192         } else {
193                 range = mydata->to - mydata->from;
194         }
195         if (range > MAX_RANGE)
196                 exit_error(PARAMETER_PROBLEM,
197                            "Range to large. Max is %d IPs in range\n",
198                            MAX_RANGE+1);
199 }
200
201 /* Create commandline options */
202 static struct option create_opts[] = {
203         {"from", 1, 0, '1'},
204         {"to", 1, 0, '2'},
205         {"network", 1, 0, '3'},
206         {"netmask", 1, 0, '4'},
207         {0}
208 };
209
210 /* Add, del, test parser */
211 ip_set_ip_t adt_parser(unsigned cmd, const char *optarg, void *data)
212 {
213         struct ip_set_req_ipmap *mydata =
214             (struct ip_set_req_ipmap *) data;
215
216         DP("ipmap: %p %p", optarg, data);
217
218         parse_ip(optarg, &mydata->ip);
219         DP("%s", ip_tostring_numeric(mydata->ip));
220
221         return 1;       
222 }
223
224 /*
225  * Print and save
226  */
227
228 void initheader(struct set *set, const void *data)
229 {
230         struct ip_set_req_ipmap_create *header =
231             (struct ip_set_req_ipmap_create *) data;
232         struct ip_set_ipmap *map =
233                 (struct ip_set_ipmap *) set->settype->header;
234                 
235         memset(map, 0, sizeof(struct ip_set_ipmap));
236         map->first_ip = header->from;
237         map->last_ip = header->to;
238         map->netmask = header->netmask;
239
240         if (map->netmask == 0xFFFFFFFF) {
241                 map->hosts = 1;
242                 map->sizeid = map->last_ip - map->first_ip + 1;
243         } else {
244                 unsigned int mask_bits, netmask_bits;
245                 ip_set_ip_t mask;
246         
247                 mask = range_to_mask(header->from, header->to, &mask_bits);
248                 netmask_bits = mask_to_bits(header->netmask);
249
250                 DP("bits: %i %i", mask_bits, netmask_bits);
251                 map->hosts = 2 << (32 - netmask_bits - 1);
252                 map->sizeid = 2 << (netmask_bits - mask_bits - 1);
253         }
254
255         DP("%i %i", map->hosts, map->sizeid );
256 }
257
258 void printheader(struct set *set, unsigned options)
259 {
260         struct ip_set_ipmap *mysetdata =
261             (struct ip_set_ipmap *) set->settype->header;
262
263         printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
264         printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
265         if (mysetdata->netmask == 0xFFFFFFFF)
266                 printf("\n");
267         else
268                 printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
269 }
270
271 void printips_sorted(struct set *set, void *data, size_t len, unsigned options)
272 {
273         struct ip_set_ipmap *mysetdata =
274             (struct ip_set_ipmap *) set->settype->header;
275         ip_set_ip_t id;
276
277         for (id = 0; id < mysetdata->sizeid; id++)
278                 if (test_bit(id, data))
279                         printf("%s\n",
280                                ip_tostring(mysetdata->first_ip
281                                            + id * mysetdata->hosts,
282                                            options));
283 }
284
285 void saveheader(struct set *set, unsigned options)
286 {
287         struct ip_set_ipmap *mysetdata =
288             (struct ip_set_ipmap *) set->settype->header;
289
290         printf("-N %s %s --from %s",
291                set->name, set->settype->typename,
292                ip_tostring(mysetdata->first_ip, options));
293         printf(" --to %s",
294                ip_tostring(mysetdata->last_ip, options));
295         if (mysetdata->netmask == 0xFFFFFFFF)
296                 printf("\n");
297         else
298                 printf(" --netmask %d\n",
299                        mask_to_bits(mysetdata->netmask));
300 }
301
302 void saveips(struct set *set, void *data, size_t len, unsigned options)
303 {
304         struct ip_set_ipmap *mysetdata =
305             (struct ip_set_ipmap *) set->settype->header;
306         ip_set_ip_t id;
307
308         DP("%s", set->name);
309         for (id = 0; id < mysetdata->sizeid; id++)
310                 if (test_bit(id, data))
311                         printf("-A %s %s\n",
312                                set->name,
313                                ip_tostring(mysetdata->first_ip 
314                                            + id * mysetdata->hosts,
315                                            options));
316 }
317
318 void usage(void)
319 {
320         printf
321             ("-N set ipmap --from IP --to IP [--netmask CIDR-netmask]\n"
322              "-N set ipmap --network IP/mask [--netmask CIDR-netmask]\n"
323              "-A set IP\n"
324              "-D set IP\n"
325              "-T set IP\n");
326 }
327
328 static struct settype settype_ipmap = {
329         .typename = SETTYPE_NAME,
330         .protocol_version = IP_SET_PROTOCOL_VERSION,
331
332         /* Create */
333         .create_size = sizeof(struct ip_set_req_ipmap_create),
334         .create_init = &create_init,
335         .create_parse = &create_parse,
336         .create_final = &create_final,
337         .create_opts = create_opts,
338
339         /* Add/del/test */
340         .adt_size = sizeof(struct ip_set_req_ipmap),
341         .adt_parser = &adt_parser,
342
343         /* Printing */
344         .header_size = sizeof(struct ip_set_ipmap),
345         .initheader = &initheader,
346         .printheader = &printheader,
347         .printips = &printips_sorted,   /* We only have sorted version */
348         .printips_sorted = &printips_sorted,
349         .saveheader = &saveheader,
350         .saveips = &saveips,
351         
352         /* Bindings */
353         .bindip_tostring = &binding_ip_tostring,
354         .bindip_parse   = &parse_ip,
355
356         .usage = &usage,
357 };
358
359 void _init(void)
360 {
361         settype_register(&settype_ipmap);
362
363 }