ipset-2.2.8-20051203
[iptables.git] / ipset / ipset_iphash.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/bitops.h>
29 #include <asm/types.h>
30
31 #include <linux/netfilter_ipv4/ip_set_iphash.h>
32 #include <linux/netfilter_ipv4/ip_set_jhash.h>
33
34 #include "ipset.h"
35
36 #define BUFLEN 30;
37
38 #define OPT_CREATE_HASHSIZE     0x01U
39 #define OPT_CREATE_PROBES       0x02U
40 #define OPT_CREATE_RESIZE       0x04U
41 #define OPT_CREATE_NETMASK      0x08U
42
43 /* Initialize the create. */
44 void create_init(void *data)
45 {
46         struct ip_set_req_iphash_create *mydata =
47             (struct ip_set_req_iphash_create *) data;
48
49         DP("create INIT");
50
51         /* Default create parameters */ 
52         mydata->hashsize = 1024;
53         mydata->probes = 8;
54         mydata->resize = 50;
55         
56         mydata->netmask = 0xFFFFFFFF;
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_iphash_create *mydata =
63             (struct ip_set_req_iphash_create *) data;
64         unsigned int bits;
65         ip_set_ip_t value;
66
67         DP("create_parse");
68
69         switch (c) {
70         case '1':
71
72                 if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
73                         exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
74
75                 *flags |= OPT_CREATE_HASHSIZE;
76
77                 DP("--hashsize %u", mydata->hashsize);
78                 
79                 break;
80
81         case '2':
82
83                 if (string_to_number(optarg, 1, 65535, &value))
84                         exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
85
86                 mydata->probes = value;
87                 *flags |= OPT_CREATE_PROBES;
88
89                 DP("--probes %u", mydata->probes);
90                 
91                 break;
92
93         case '3':
94
95                 if (string_to_number(optarg, 0, 65535, &value))
96                         exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
97
98                 mydata->resize = value;
99                 *flags |= OPT_CREATE_RESIZE;
100
101                 DP("--resize %u", mydata->resize);
102                 
103                 break;
104
105         case '4':
106
107                 if (string_to_number(optarg, 0, 32, &bits))
108                         exit_error(PARAMETER_PROBLEM, 
109                                   "Invalid netmask `%s' specified", optarg);
110                 
111                 if (bits != 0)
112                         mydata->netmask = 0xFFFFFFFF << (32 - bits);
113
114                 *flags |= OPT_CREATE_NETMASK;
115
116                 DP("--netmask %x", mydata->netmask);
117                 
118                 break;
119
120         default:
121                 return 0;
122         }
123
124         return 1;
125 }
126
127 /* Final check; exit if not ok. */
128 void create_final(void *data, unsigned int flags)
129 {
130 #ifdef IPSET_DEBUG
131         struct ip_set_req_iphash_create *mydata =
132             (struct ip_set_req_iphash_create *) data;
133
134         DP("hashsize %u probes %u resize %u",
135            mydata->hashsize, mydata->probes, mydata->resize);
136 #endif
137 }
138
139 /* Create commandline options */
140 static struct option create_opts[] = {
141         {"hashsize", 1, 0, '1'},
142         {"probes", 1, 0, '2'},
143         {"resize", 1, 0, '3'},
144         {"netmask", 1, 0, '4'},
145         {0}
146 };
147
148 /* Add, del, test parser */
149 ip_set_ip_t adt_parser(unsigned cmd, const char *optarg, void *data)
150 {
151         struct ip_set_req_iphash *mydata =
152             (struct ip_set_req_iphash *) data;
153
154         parse_ip(optarg, &mydata->ip);
155         if (!mydata->ip)
156                 exit_error(PARAMETER_PROBLEM,
157                            "Zero valued IP address `%s' specified", optarg);
158
159         return mydata->ip;      
160 };
161
162 /*
163  * Print and save
164  */
165
166 void initheader(struct set *set, const void *data)
167 {
168         struct ip_set_req_iphash_create *header =
169             (struct ip_set_req_iphash_create *) data;
170         struct ip_set_iphash *map =
171                 (struct ip_set_iphash *) set->settype->header;
172
173         memset(map, 0, sizeof(struct ip_set_iphash));
174         map->hashsize = header->hashsize;
175         map->probes = header->probes;
176         map->resize = header->resize;
177         map->netmask = header->netmask;
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_iphash *mysetdata =
199             (struct ip_set_iphash *) set->settype->header;
200
201         printf(" hashsize: %u", mysetdata->hashsize);
202         printf(" probes: %u", mysetdata->probes);
203         printf(" resize: %u", mysetdata->resize);
204         if (mysetdata->netmask == 0xFFFFFFFF)
205                 printf("\n");
206         else
207                 printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
208 }
209
210 void printips(struct set *set, void *data, size_t len, unsigned options)
211 {
212         size_t offset = 0;
213         ip_set_ip_t *ip;
214
215         while (offset < len) {
216                 ip = data + offset;
217                 if (*ip)
218                         printf("%s\n", ip_tostring(*ip, options));
219                 offset += sizeof(ip_set_ip_t);
220         }
221 }
222
223 void saveheader(struct set *set, unsigned options)
224 {
225         struct ip_set_iphash *mysetdata =
226             (struct ip_set_iphash *) set->settype->header;
227
228         printf("-N %s %s --hashsize %u --probes %u --resize %u",
229                set->name, set->settype->typename,
230                mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
231         if (mysetdata->netmask == 0xFFFFFFFF)
232                 printf("\n");
233         else
234                 printf(" --netmask %d\n", mask_to_bits(mysetdata->netmask));
235 }
236
237 /* Print save for an IP */
238 void saveips(struct set *set, void *data, size_t len, unsigned options)
239 {
240         size_t offset = 0;
241         ip_set_ip_t *ip;
242
243         while (offset < len) {
244                 ip = data + offset;
245                 if (*ip)
246                         printf("-A %s %s\n", set->name, 
247                                ip_tostring(*ip, options));
248                 offset += sizeof(ip_set_ip_t);
249         }
250 }
251
252 void usage(void)
253 {
254         printf
255             ("-N set iphash [--hashsize hashsize] [--probes probes ]\n"
256              "              [--resize resize] [--netmask CIDR-netmask]\n"
257              "-A set IP\n"
258              "-D set IP\n"
259              "-T set IP\n");
260 }
261
262 static struct settype settype_iphash = {
263         .typename = SETTYPE_NAME,
264         .protocol_version = IP_SET_PROTOCOL_VERSION,
265
266         /* Create */
267         .create_size = sizeof(struct ip_set_req_iphash_create),
268         .create_init = &create_init,
269         .create_parse = &create_parse,
270         .create_final = &create_final,
271         .create_opts = create_opts,
272
273         /* Add/del/test */
274         .adt_size = sizeof(struct ip_set_req_iphash),
275         .adt_parser = &adt_parser,
276
277         /* Printing */
278         .header_size = sizeof(struct ip_set_iphash),
279         .initheader = &initheader,
280         .printheader = &printheader,
281         .printips = &printips,          /* We only have the unsorted version */
282         .printips_sorted = &printips,
283         .saveheader = &saveheader,
284         .saveips = &saveips,
285         
286         /* Bindings */
287         .bindip_tostring = &binding_ip_tostring,
288         .bindip_parse = &parse_ip,
289         
290         .usage = &usage,
291 };
292
293 void _init(void)
294 {
295         settype_register(&settype_iphash);
296
297 }