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