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