OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / user / ipset / ipset_ipmap.c
1 /* Copyright 2000-2004 Joakim Axelsson (gozem@linux.nu)
2  *                     Patrick Schaaf (bof@bof.de)
3  *                     Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
4  *
5  * This program is free software; you can redistribute it and/or modify   
6  * it under the terms of the GNU General Public License as published by   
7  * the Free Software Foundation; either version 2 of the License, or      
8  * (at your option) any later version.                                    
9  *                                                                         
10  * This program is distributed in the hope that it will be useful,        
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of         
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          
13  * GNU General Public License for more details.                           
14  *                                                                         
15  * You should have received a copy of the GNU General Public License      
16  * along with this program; if not, write to the Free Software            
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */
19
20 #include <stdio.h>                      /* *printf */
21 #include <string.h>                     /* mem* */
22
23 #include "ipset.h"
24
25 #include <linux/netfilter_ipv4/ip_set_ipmap.h>
26
27 #define BUFLEN 30;
28
29 #define OPT_CREATE_FROM    0x01U
30 #define OPT_CREATE_TO      0x02U
31 #define OPT_CREATE_NETWORK 0x04U
32 #define OPT_CREATE_NETMASK 0x08U
33
34 #define OPT_ADDDEL_IP      0x01U
35
36 /* Initialize the create. */
37 static void
38 ipmap_create_init(void *data)
39 {
40         struct ip_set_req_ipmap_create *mydata = data;
41
42         DP("create INIT");
43         mydata->netmask = 0xFFFFFFFF;
44 }
45
46 /* Function which parses command options; returns true if it ate an option */
47 static int
48 ipmap_create_parse(int c, char *argv[] UNUSED, void *data, unsigned *flags)
49 {
50         struct ip_set_req_ipmap_create *mydata = data;
51         unsigned int bits;
52
53         DP("create_parse");
54
55         switch (c) {
56         case '1':
57                 parse_ip(optarg, &mydata->from);
58
59                 *flags |= OPT_CREATE_FROM;
60
61                 DP("--from %x (%s)", mydata->from,
62                    ip_tostring_numeric(mydata->from));
63
64                 break;
65
66         case '2':
67                 parse_ip(optarg, &mydata->to);
68
69                 *flags |= OPT_CREATE_TO;
70
71                 DP("--to %x (%s)", mydata->to,
72                    ip_tostring_numeric(mydata->to));
73
74                 break;
75
76         case '3':
77                 parse_ipandmask(optarg, &mydata->from, &mydata->to);
78
79                 /* Make to the last of from + mask */
80                 if (mydata->to)
81                         mydata->to = mydata->from | ~(mydata->to);
82                 else {
83                         mydata->from = 0x00000000;
84                         mydata->to = 0xFFFFFFFF;
85                 }
86                 *flags |= OPT_CREATE_NETWORK;
87
88                 DP("--network from %x (%s)", 
89                    mydata->from, ip_tostring_numeric(mydata->from));
90                 DP("--network to %x (%s)", 
91                    mydata->to, ip_tostring_numeric(mydata->to));
92
93                 break;
94
95         case '4':
96                 if (string_to_number(optarg, 0, 32, &bits))
97                         exit_error(PARAMETER_PROBLEM, 
98                                   "Invalid netmask `%s' specified", optarg);
99                 
100                 if (bits != 0)
101                         mydata->netmask = 0xFFFFFFFF << (32 - bits);
102
103                 *flags |= OPT_CREATE_NETMASK;
104
105                 DP("--netmask %x", mydata->netmask);
106                 
107                 break;
108
109         default:
110                 return 0;
111         }
112
113         return 1;
114 }
115
116 /* Final check; exit if not ok. */
117 static void
118 ipmap_create_final(void *data, unsigned int flags)
119 {
120         struct ip_set_req_ipmap_create *mydata = data;
121         ip_set_ip_t range;
122
123         if (flags == 0)
124                 exit_error(PARAMETER_PROBLEM,
125                            "Need to specify --from and --to, or --network\n");
126
127         if (flags & OPT_CREATE_NETWORK) {
128                 /* --network */
129                 if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
130                         exit_error(PARAMETER_PROBLEM,
131                                    "Can't specify --from or --to with --network\n");
132         } else {
133                 /* --from --to */
134                 if ((flags & OPT_CREATE_FROM) == 0
135                     || (flags & OPT_CREATE_TO) == 0)
136                         exit_error(PARAMETER_PROBLEM,
137                                    "Need to specify both --from and --to\n");
138         }
139
140         DP("from : %x to: %x diff: %x", 
141            mydata->from, mydata->to,
142            mydata->to - mydata->from);
143
144         if (mydata->from > mydata->to)
145                 exit_error(PARAMETER_PROBLEM,
146                            "From can't be lower than to.\n");
147
148         if (flags & OPT_CREATE_NETMASK) {
149                 unsigned int mask_bits, netmask_bits;
150                 ip_set_ip_t mask;
151
152                 if ((mydata->from & mydata->netmask) != mydata->from)
153                         exit_error(PARAMETER_PROBLEM,
154                                    "%s is not a network address according to netmask %d\n",
155                                    ip_tostring_numeric(mydata->from),
156                                    mask_to_bits(mydata->netmask));
157                 
158                 mask = range_to_mask(mydata->from, mydata->to, &mask_bits);
159                 if (!mask
160                     && (mydata->from || mydata->to != 0xFFFFFFFF)) {
161                         exit_error(PARAMETER_PROBLEM,
162                                    "You have to define a full network with --from"
163                                    " and --to if you specify the --network option\n");
164                 }
165                 netmask_bits = mask_to_bits(mydata->netmask);
166                 if (netmask_bits <= mask_bits) {
167                         exit_error(PARAMETER_PROBLEM,
168                                    "%d netmask specifies larger or equal netblock than the network itself\n");
169                 }
170                 range = (1<<(netmask_bits - mask_bits)) - 1;
171         } else {
172                 range = mydata->to - mydata->from;
173         }
174         if (range > 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 = "from",        .has_arg = required_argument,   .val = '1'},
183         {.name = "to",          .has_arg = required_argument,   .val = '2'},
184         {.name = "network",     .has_arg = required_argument,   .val = '3'},
185         {.name = "netmask",     .has_arg = required_argument,   .val = '4'},
186         {NULL},
187 };
188
189 /* Add, del, test parser */
190 static ip_set_ip_t
191 ipmap_adt_parser(int cmd UNUSED, const char *arg, void *data)
192 {
193         struct ip_set_req_ipmap *mydata = data;
194
195         DP("ipmap: %p %p", arg, data);
196
197         parse_ip(arg, &mydata->ip);
198         DP("%s", ip_tostring_numeric(mydata->ip));
199
200         return 1;       
201 }
202
203 /*
204  * Print and save
205  */
206
207 static void
208 ipmap_initheader(struct set *set, const void *data)
209 {
210         const struct ip_set_req_ipmap_create *header = data;
211         struct ip_set_ipmap *map = set->settype->header;
212                 
213         memset(map, 0, sizeof(struct ip_set_ipmap));
214         map->first_ip = header->from;
215         map->last_ip = header->to;
216         map->netmask = header->netmask;
217
218         if (map->netmask == 0xFFFFFFFF) {
219                 map->hosts = 1;
220                 map->sizeid = map->last_ip - map->first_ip + 1;
221         } else {
222                 unsigned int mask_bits, netmask_bits;
223                 ip_set_ip_t mask;
224         
225                 mask = range_to_mask(header->from, header->to, &mask_bits);
226                 netmask_bits = mask_to_bits(header->netmask);
227
228                 DP("bits: %d %d", mask_bits, netmask_bits);
229                 map->hosts = 2 << (32 - netmask_bits - 1);
230                 map->sizeid = 2 << (netmask_bits - mask_bits - 1);
231         }
232
233         DP("%d %d", map->hosts, map->sizeid );
234 }
235
236 static void
237 ipmap_printheader(struct set *set, unsigned options)
238 {
239         struct ip_set_ipmap *mysetdata = set->settype->header;
240
241         printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
242         printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
243         if (mysetdata->netmask == 0xFFFFFFFF)
244                 printf("\n");
245         else
246                 printf(" netmask: %d\n", mask_to_bits(mysetdata->netmask));
247 }
248
249 static inline void
250 __ipmap_printips_sorted(struct set *set, void *data,
251                         u_int32_t len UNUSED, unsigned options)
252 {
253         struct ip_set_ipmap *mysetdata = set->settype->header;
254         ip_set_ip_t id;
255
256         for (id = 0; id < mysetdata->sizeid; id++)
257                 if (test_bit(id, data))
258                         printf("%s\n",
259                                ip_tostring(mysetdata->first_ip
260                                            + id * mysetdata->hosts,
261                                            options));
262 }
263
264 static void
265 ipmap_printips_sorted(struct set *set, void *data,
266                       u_int32_t len, unsigned options,
267                       char dont_align)
268 {
269         ip_set_ip_t *ip;
270         size_t offset = 0;
271         
272         if (dont_align)
273                 return __ipmap_printips_sorted(set, data, len, options);
274         
275         while (offset < len) {
276                 DP("offset: %zu, len %u\n", offset, len);
277                 ip = data + offset;
278                 printf("%s\n", ip_tostring(*ip, options));
279                 offset += IPSET_ALIGN(sizeof(ip_set_ip_t));
280         }
281 }
282
283 static void
284 ipmap_saveheader(struct set *set, unsigned options)
285 {
286         struct ip_set_ipmap *mysetdata = set->settype->header;
287
288         printf("-N %s %s --from %s",
289                set->name, set->settype->typename,
290                ip_tostring(mysetdata->first_ip, options));
291         printf(" --to %s",
292                ip_tostring(mysetdata->last_ip, options));
293         if (mysetdata->netmask == 0xFFFFFFFF)
294                 printf("\n");
295         else
296                 printf(" --netmask %d\n",
297                        mask_to_bits(mysetdata->netmask));
298 }
299
300 static inline void
301 __ipmap_saveips(struct set *set, void *data, u_int32_t len UNUSED,
302                 unsigned options)
303 {
304         struct ip_set_ipmap *mysetdata = set->settype->header;
305         ip_set_ip_t id;
306
307         DP("%s", set->name);
308         for (id = 0; id < mysetdata->sizeid; id++)
309                 if (test_bit(id, data))
310                         printf("-A %s %s\n",
311                                set->name,
312                                ip_tostring(mysetdata->first_ip 
313                                            + id * mysetdata->hosts,
314                                            options));
315 }
316
317 static void
318 ipmap_saveips(struct set *set, void *data, u_int32_t len,
319               unsigned options, char dont_align)
320 {
321         ip_set_ip_t *ip;
322         size_t offset = 0;
323         
324         if (dont_align)
325                 return __ipmap_saveips(set, data, len, options);
326         
327         while (offset < len) {
328                 ip = data + offset;
329                 printf("-A %s %s\n", set->name, ip_tostring(*ip, options));
330                 offset += IPSET_ALIGN(sizeof(ip_set_ip_t));
331         }
332 }
333
334 static void
335 ipmap_usage(void)
336 {
337         printf
338             ("-N set ipmap --from IP --to IP [--netmask CIDR-netmask]\n"
339              "-N set ipmap --network IP/mask [--netmask CIDR-netmask]\n"
340              "-A set IP\n"
341              "-D set IP\n"
342              "-T set IP\n");
343 }
344
345 static struct settype settype_ipmap = {
346         .typename = SETTYPE_NAME,
347         .protocol_version = IP_SET_PROTOCOL_VERSION,
348
349         /* Create */
350         .create_size = sizeof(struct ip_set_req_ipmap_create),
351         .create_init = ipmap_create_init,
352         .create_parse = ipmap_create_parse,
353         .create_final = ipmap_create_final,
354         .create_opts = create_opts,
355
356         /* Add/del/test */
357         .adt_size = sizeof(struct ip_set_req_ipmap),
358         .adt_parser = ipmap_adt_parser,
359
360         /* Printing */
361         .header_size = sizeof(struct ip_set_ipmap),
362         .initheader = ipmap_initheader,
363         .printheader = ipmap_printheader,
364         .printips = ipmap_printips_sorted,
365         .printips_sorted = ipmap_printips_sorted,
366         .saveheader = ipmap_saveheader,
367         .saveips = ipmap_saveips,
368         
369         .usage = ipmap_usage,
370 };
371
372 CONSTRUCTOR(ipmap)
373 {
374         settype_register(&settype_ipmap);
375
376 }