OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / ipset / ipset_ipportnethash.c
1 /* Copyright 2008 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 <limits.h>                     /* UINT_MAX */
19 #include <stdio.h>                      /* *printf */
20 #include <string.h>                     /* mem*, str* */
21
22 #include "ipset.h"
23
24 #include <linux/netfilter_ipv4/ip_set_ipportnethash.h>
25
26 #define OPT_CREATE_HASHSIZE     0x01U
27 #define OPT_CREATE_PROBES       0x02U
28 #define OPT_CREATE_RESIZE       0x04U
29 #define OPT_CREATE_NETWORK      0x08U
30 #define OPT_CREATE_FROM         0x10U
31 #define OPT_CREATE_TO           0x20U
32
33 /* Initialize the create. */
34 static void
35 ipportnethash_create_init(void *data)
36 {
37         struct ip_set_req_ipportnethash_create *mydata = data;
38
39         DP("create INIT");
40
41         /* Default create parameters */ 
42         mydata->hashsize = 1024;
43         mydata->probes = 8;
44         mydata->resize = 50;
45 }
46
47 /* Function which parses command options; returns true if it ate an option */
48 static int
49 ipportnethash_create_parse(int c, char *argv[] UNUSED, void *data,
50                            unsigned *flags)
51 {
52         struct ip_set_req_ipportnethash_create *mydata = data;
53         ip_set_ip_t value;
54
55         DP("create_parse");
56
57         switch (c) {
58         case '1':
59
60                 if (string_to_number(optarg, 1, UINT_MAX - 1, &mydata->hashsize))
61                         exit_error(PARAMETER_PROBLEM, "Invalid hashsize `%s' specified", optarg);
62
63                 *flags |= OPT_CREATE_HASHSIZE;
64
65                 DP("--hashsize %u", mydata->hashsize);
66                 
67                 break;
68
69         case '2':
70
71                 if (string_to_number(optarg, 1, 65535, &value))
72                         exit_error(PARAMETER_PROBLEM, "Invalid probes `%s' specified", optarg);
73
74                 mydata->probes = value;
75                 *flags |= OPT_CREATE_PROBES;
76
77                 DP("--probes %u", mydata->probes);
78                 
79                 break;
80
81         case '3':
82
83                 if (string_to_number(optarg, 0, 65535, &value))
84                         exit_error(PARAMETER_PROBLEM, "Invalid resize `%s' specified", optarg);
85
86                 mydata->resize = value;
87                 *flags |= OPT_CREATE_RESIZE;
88
89                 DP("--resize %u", mydata->resize);
90                 
91                 break;
92
93         case '4':
94                 parse_ip(optarg, &mydata->from);
95
96                 *flags |= OPT_CREATE_FROM;
97
98                 DP("--from %x (%s)", mydata->from,
99                    ip_tostring_numeric(mydata->from));
100
101                 break;
102
103         case '5':
104                 parse_ip(optarg, &mydata->to);
105
106                 *flags |= OPT_CREATE_TO;
107
108                 DP("--to %x (%s)", mydata->to,
109                    ip_tostring_numeric(mydata->to));
110
111                 break;
112
113         case '6':
114                 parse_ipandmask(optarg, &mydata->from, &mydata->to);
115
116                 /* Make to the last of from + mask */
117                 if (mydata->to)
118                         mydata->to = mydata->from | ~(mydata->to);
119                 else {
120                         mydata->from = 0x00000000;
121                         mydata->to = 0xFFFFFFFF;
122                 }
123                 *flags |= OPT_CREATE_NETWORK;
124
125                 DP("--network from %x (%s)", 
126                    mydata->from, ip_tostring_numeric(mydata->from));
127                 DP("--network to %x (%s)", 
128                    mydata->to, ip_tostring_numeric(mydata->to));
129
130                 break;
131
132         default:
133                 return 0;
134         }
135
136         return 1;
137 }
138
139 /* Final check; exit if not ok. */
140 static void
141 ipportnethash_create_final(void *data, unsigned int flags)
142 {
143         struct ip_set_req_ipportnethash_create *mydata = data;
144
145 #ifdef IPSET_DEBUG
146         DP("hashsize %u probes %u resize %u",
147            mydata->hashsize, mydata->probes, mydata->resize);
148 #endif
149
150         if (flags & OPT_CREATE_NETWORK) {
151                 /* --network */
152                 if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
153                         exit_error(PARAMETER_PROBLEM,
154                                    "Can't specify --from or --to with --network\n");
155         } else if (flags & (OPT_CREATE_FROM | OPT_CREATE_TO)) {
156                 /* --from --to */
157                 if (!(flags & OPT_CREATE_FROM) || !(flags & OPT_CREATE_TO))
158                         exit_error(PARAMETER_PROBLEM,
159                                    "Need to specify both --from and --to\n");
160         } else {
161                 exit_error(PARAMETER_PROBLEM,
162                            "Need to specify --from and --to, or --network\n");
163
164         }
165
166         DP("from : %x to: %x diff: %x", 
167            mydata->from, mydata->to,
168            mydata->to - mydata->from);
169
170         if (mydata->from > mydata->to)
171                 exit_error(PARAMETER_PROBLEM,
172                            "From can't be higher than to.\n");
173
174         if (mydata->to - mydata->from > MAX_RANGE)
175                 exit_error(PARAMETER_PROBLEM,
176                            "Range too large. Max is %d IPs in range\n",
177                            MAX_RANGE+1);
178 }
179
180 /* Create commandline options */
181 static const struct option create_opts[] = {
182         {.name = "hashsize",    .has_arg = required_argument,   .val = '1'},
183         {.name = "probes",      .has_arg = required_argument,   .val = '2'},
184         {.name = "resize",      .has_arg = required_argument,   .val = '3'},
185         {.name = "from",        .has_arg = required_argument,   .val = '4'},
186         {.name = "to",          .has_arg = required_argument,   .val = '5'},
187         {.name = "network",     .has_arg = required_argument,   .val = '6'},
188         {NULL},
189 };
190
191 /* Add, del, test parser */
192 static ip_set_ip_t
193 ipportnethash_adt_parser(int cmd, const char *arg, void *data)
194 {
195         struct ip_set_req_ipportnethash *mydata = data;
196         char *saved = ipset_strdup(arg);
197         char *ptr, *tmp = saved;
198         ip_set_ip_t cidr;
199
200         DP("ipportnethash: %p %p", arg, data);
201
202         if (((ptr = strchr(tmp, ':')) || (ptr = strchr(tmp, '%'))) && ++warn_once == 1)
203                 fprintf(stderr, "Warning: please use ',' separator token between ip,port,net.\n"
204                                 "Next release won't support old separator tokens.\n");
205
206         ptr = strsep(&tmp, ":%,");
207         parse_ip(ptr, &mydata->ip);
208         if (!tmp)
209                 exit_error(PARAMETER_PROBLEM,
210                            "IP address, port and network address must be specified: ip,port,net");
211
212         ptr = strsep(&tmp, ":%,");
213         parse_port(ptr, &mydata->port);
214         if (!tmp)
215                 exit_error(PARAMETER_PROBLEM,
216                            "IP address, port and network address must be specified: ip,port,net");
217
218         ptr = strsep(&tmp, "/");
219         if (tmp == NULL)
220                 if (cmd == CMD_TEST)
221                         cidr = 32;
222                 else
223                         exit_error(PARAMETER_PROBLEM,
224                                    "Missing /cidr from `%s'", arg);
225         else
226                 if (string_to_number(tmp, 1, 31, &cidr))
227                         exit_error(PARAMETER_PROBLEM,
228                                    "Out of range cidr `%s' specified", arg);
229         
230         mydata->cidr = cidr;
231
232         parse_ip(ptr, &mydata->ip1);
233         ipset_free(saved);
234         return 1;       
235 };
236
237 /*
238  * Print and save
239  */
240
241 static void
242 ipportnethash_initheader(struct set *set, const void *data)
243 {
244         const struct ip_set_req_ipportnethash_create *header = data;
245         struct ip_set_ipportnethash *map = set->settype->header;
246
247         memset(map, 0, sizeof(struct ip_set_ipportnethash));
248         map->hashsize = header->hashsize;
249         map->probes = header->probes;
250         map->resize = header->resize;
251         map->first_ip = header->from;
252         map->last_ip = header->to;
253 }
254
255 static void
256 ipportnethash_printheader(struct set *set, unsigned options)
257 {
258         struct ip_set_ipportnethash *mysetdata = 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         printf(" hashsize: %u", mysetdata->hashsize);
263         printf(" probes: %u", mysetdata->probes);
264         printf(" resize: %u\n", mysetdata->resize);
265 }
266
267 static char buf[20];
268
269 static char *
270 unpack_ip_tostring(ip_set_ip_t ip, unsigned options UNUSED)
271 {
272         int i, j = 3;
273         unsigned char a, b;
274
275         ip = htonl(ip); 
276         for (i = 3; i >= 0; i--)
277                 if (((unsigned char *)&ip)[i] != 0) {
278                         j = i;
279                         break;
280                 }
281                         
282         a = ((unsigned char *)&ip)[j];
283         if (a <= 128) {
284                 a = (a - 1) * 2;
285                 b = 7;
286         } else if (a <= 192) {
287                 a = (a - 129) * 4;
288                 b = 6;
289         } else if (a <= 224) {
290                 a = (a - 193) * 8;
291                 b = 5;
292         } else if (a <= 240) {
293                 a = (a - 225) * 16;
294                 b = 4;
295         } else if (a <= 248) {
296                 a = (a - 241) * 32;
297                 b = 3;
298         } else if (a <= 252) {
299                 a = (a - 249) * 64;
300                 b = 2;
301         } else if (a <= 254) {
302                 a = (a - 253) * 128;
303                 b = 1;
304         } else {
305                 a = b = 0;
306         }
307         ((unsigned char *)&ip)[j] = a;
308         b += j * 8;
309         
310         sprintf(buf, "%u.%u.%u.%u/%u",
311                 ((unsigned char *)&ip)[0],
312                 ((unsigned char *)&ip)[1],
313                 ((unsigned char *)&ip)[2],
314                 ((unsigned char *)&ip)[3],
315                 b);
316
317         DP("%s %s", ip_tostring(ntohl(ip), 0), buf);
318         return buf;
319 }
320
321 static void
322 ipportnethash_printips(struct set *set, void *data, u_int32_t len,
323                        unsigned options, char dont_align)
324 {
325         struct ip_set_ipportnethash *mysetdata = set->settype->header;
326         size_t offset = 0;
327         struct ipportip *ipptr;
328         ip_set_ip_t ip;
329         uint16_t port;
330
331         while (offset < len) {
332                 ipptr = data + offset;
333                 ip = (ipptr->ip>>16) + mysetdata->first_ip;
334                 port = (uint16_t) ipptr->ip;
335                 printf("%s,%s,", 
336                        ip_tostring(ip, options),
337                        port_tostring(port, options));
338                 printf("%s\n", 
339                        unpack_ip_tostring(ipptr->ip1, options));
340                 offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align);
341         }
342 }
343
344 static void
345 ipportnethash_saveheader(struct set *set, unsigned options)
346 {
347         struct ip_set_ipportnethash *mysetdata = set->settype->header;
348
349         printf("-N %s %s --from %s",
350                set->name, set->settype->typename,
351                ip_tostring(mysetdata->first_ip, options));
352         printf(" --to %s",
353                ip_tostring(mysetdata->last_ip, options));
354         printf(" --hashsize %u --probes %u --resize %u\n",
355                mysetdata->hashsize, mysetdata->probes, mysetdata->resize);
356 }
357
358 /* Print save for an IP */
359 static void
360 ipportnethash_saveips(struct set *set, void *data, u_int32_t len,
361                       unsigned options, char dont_align)
362 {
363         struct ip_set_ipportnethash *mysetdata = set->settype->header;
364         size_t offset = 0;
365         struct ipportip *ipptr;
366         ip_set_ip_t ip;
367         uint16_t port;
368
369         while (offset < len) {
370                 ipptr = data + offset;
371                 ip = (ipptr->ip>>16) + mysetdata->first_ip;
372                 port = (uint16_t) ipptr->ip;
373                 printf("-A %s %s,%s,", set->name, 
374                        ip_tostring(ip, options),
375                        port_tostring(port, options));
376                 printf("%s\n",
377                        unpack_ip_tostring(ipptr->ip, options));
378                 offset += IPSET_VALIGN(sizeof(struct ipportip), dont_align);
379         }
380 }
381
382 static void
383 ipportnethash_usage(void)
384 {
385         printf
386             ("-N set ipportnethash --from IP --to IP\n"
387              "   [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
388              "-N set ipportnethash --network IP/mask\n"
389              "   [--hashsize hashsize] [--probes probes ] [--resize resize]\n"
390              "-A set IP,port,IP/net\n"
391              "-D set IP,port,IP/net\n"
392              "-T set IP,port,IP[/net]\n");
393 }
394
395 static struct settype settype_ipportnethash = {
396         .typename = SETTYPE_NAME,
397         .protocol_version = IP_SET_PROTOCOL_VERSION,
398
399         /* Create */
400         .create_size = sizeof(struct ip_set_req_ipportnethash_create),
401         .create_init = ipportnethash_create_init,
402         .create_parse = ipportnethash_create_parse,
403         .create_final = ipportnethash_create_final,
404         .create_opts = create_opts,
405
406         /* Add/del/test */
407         .adt_size = sizeof(struct ip_set_req_ipportnethash),
408         .adt_parser = ipportnethash_adt_parser,
409
410         /* Printing */
411         .header_size = sizeof(struct ip_set_ipportnethash),
412         .initheader = ipportnethash_initheader,
413         .printheader = ipportnethash_printheader,
414         .printips = ipportnethash_printips,
415         .printips_sorted = ipportnethash_printips,
416         .saveheader = ipportnethash_saveheader,
417         .saveips = ipportnethash_saveips,
418         
419         .usage = ipportnethash_usage,
420 };
421
422 CONSTRUCTOR(ipportnethash)
423 {
424         settype_register(&settype_ipportnethash);
425
426 }