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