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