3385f19b540ce93c313330a7de71ffdd8e98d20b
[iptables.git] / ipset / ipset_macipmap.c
1 /* Copyright 2000, 2001, 2002 Joakim Axelsson (gozem@linux.nu)
2  *                            Patrick Schaaf (bof@bof.de)
3  *                            Martin Josefsson (gandalf@wlug.westbo.se)
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
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <linux/if_ether.h>
28
29 #include <linux/netfilter_ipv4/ip_set_macipmap.h>
30 #include "ipset.h"
31
32 #define BUFLEN 30;
33
34 #define OPT_CREATE_FROM    0x01U
35 #define OPT_CREATE_TO      0x02U
36 #define OPT_CREATE_NETWORK 0x04U
37 #define OPT_CREATE_MATCHUNSET   0x08U
38
39 #define OPT_ADDDEL_IP      0x01U
40 #define OPT_ADDDEL_MAC     0x02U
41
42 /* Initialize the create. */
43 void create_init(void *data)
44 {
45         DP("create INIT");
46         /* Nothing */
47 }
48
49 /* Function which parses command options; returns true if it ate an option */
50 int create_parse(int c, char *argv[], void *data, unsigned *flags)
51 {
52         struct ip_set_req_macipmap_create *mydata =
53             (struct ip_set_req_macipmap_create *) data;
54
55         DP("create_parse");
56
57         switch (c) {
58         case '1':
59                 parse_ip(optarg, &mydata->from);
60
61                 *flags |= OPT_CREATE_FROM;
62
63                 DP("--from %x (%s)", mydata->from,
64                    ip_tostring_numeric(mydata->from));
65
66                 break;
67
68         case '2':
69                 parse_ip(optarg, &mydata->to);
70
71                 *flags |= OPT_CREATE_TO;
72
73                 DP("--to %x (%s)", mydata->to,
74                    ip_tostring_numeric(mydata->to));
75
76                 break;
77
78         case '3':
79                 parse_ipandmask(optarg, &mydata->from, &mydata->to);
80
81                 /* Make to the last of from + mask */
82                 mydata->to = mydata->from | (~mydata->to);
83
84                 *flags |= OPT_CREATE_NETWORK;
85
86                 DP("--network from %x (%s)", 
87                    mydata->from, ip_tostring_numeric(mydata->from));
88                 DP("--network to %x (%s)", 
89                    mydata->to, ip_tostring_numeric(mydata->to));
90
91                 break;
92
93         case '4':
94                 mydata->flags |= IPSET_MACIP_MATCHUNSET;
95
96                 *flags |= OPT_CREATE_MATCHUNSET;
97
98                 DP("--matchunset");
99
100                 break;
101
102         default:
103                 return 0;
104         }
105
106         return 1;
107 }
108
109 /* Final check; exit if not ok. */
110 void create_final(void *data, unsigned int flags)
111 {
112         struct ip_set_req_macipmap_create *mydata =
113             (struct ip_set_req_macipmap_create *) data;
114
115         if (flags == 0)
116                 exit_error(PARAMETER_PROBLEM,
117                            "Need to specify --from and --to, or --network\n");
118
119         if (flags & OPT_CREATE_NETWORK) {
120                 /* --network */
121                 if ((flags & OPT_CREATE_FROM) || (flags & OPT_CREATE_TO))
122                         exit_error(PARAMETER_PROBLEM,
123                                    "Can't specify --from or --to with --network\n");
124         } else {
125                 /* --from --to */
126                 if ((flags & OPT_CREATE_FROM) == 0
127                     || (flags & OPT_CREATE_TO) == 0)
128                         exit_error(PARAMETER_PROBLEM,
129                                    "Need to specify both --from and --to\n");
130         }
131
132
133         DP("from : %x to: %x  diff: %d  match unset: %d", mydata->from,
134            mydata->to, mydata->to - mydata->from,
135            flags & OPT_CREATE_MATCHUNSET);
136
137         if (mydata->from > mydata->to)
138                 exit_error(PARAMETER_PROBLEM,
139                            "From can't be lower than to.\n");
140
141         if (mydata->to - mydata->from > MAX_RANGE)
142                 exit_error(PARAMETER_PROBLEM,
143                            "Range too large. Max is %d IPs in range\n",
144                            MAX_RANGE+1);
145 }
146
147 /* Create commandline options */
148 static struct option create_opts[] = {
149         {"from", 1, 0, '1'},
150         {"to", 1, 0, '2'},
151         {"network", 1, 0, '3'},
152         {"matchunset", 0, 0, '4'},
153         {0}
154 };
155
156 static void parse_mac(const char *mac, unsigned char *ethernet)
157 {
158         unsigned int i = 0;
159
160         if (strlen(mac) != ETH_ALEN * 3 - 1)
161                 exit_error(PARAMETER_PROBLEM, "Bad mac address `%s'", mac);
162
163         for (i = 0; i < ETH_ALEN; i++) {
164                 long number;
165                 char *end;
166
167                 number = strtol(mac + i * 3, &end, 16);
168
169                 if (end == mac + i * 3 + 2 && number >= 0 && number <= 255)
170                         ethernet[i] = number;
171                 else
172                         exit_error(PARAMETER_PROBLEM,
173                                    "Bad mac address `%s'", mac);
174         }
175 }
176
177 /* Add, del, test parser */
178 ip_set_ip_t adt_parser(unsigned cmd, const char *optarg, void *data)
179 {
180         struct ip_set_req_macipmap *mydata =
181             (struct ip_set_req_macipmap *) data;
182         char *saved = ipset_strdup(optarg);
183         char *ptr, *tmp = saved;
184
185         DP("macipmap: %p %p", optarg, data);
186
187         ptr = strsep(&tmp, ":%");
188         parse_ip(ptr, &mydata->ip);
189
190         if (tmp)
191                 parse_mac(tmp, mydata->ethernet);
192         else
193                 memset(mydata->ethernet, 0, ETH_ALEN);  
194
195         free(saved);
196         return 1;       
197 }
198
199 /*
200  * Print and save
201  */
202
203 void initheader(struct set *set, const void *data)
204 {
205         struct ip_set_req_macipmap_create *header =
206             (struct ip_set_req_macipmap_create *) data;
207         struct ip_set_macipmap *map =
208                 (struct ip_set_macipmap *) set->settype->header;
209
210         memset(map, 0, sizeof(struct ip_set_macipmap));
211         map->first_ip = header->from;
212         map->last_ip = header->to;
213         map->flags = header->flags;
214 }
215
216 void printheader(struct set *set, unsigned options)
217 {
218         struct ip_set_macipmap *mysetdata =
219             (struct ip_set_macipmap *) set->settype->header;
220
221         printf(" from: %s", ip_tostring(mysetdata->first_ip, options));
222         printf(" to: %s", ip_tostring(mysetdata->last_ip, options));
223
224         if (mysetdata->flags & IPSET_MACIP_MATCHUNSET)
225                 printf(" matchunset");
226         printf("\n");
227 }
228
229 static void print_mac(unsigned char macaddress[ETH_ALEN])
230 {
231         unsigned int i;
232
233         printf("%02X", macaddress[0]);
234         for (i = 1; i < ETH_ALEN; i++)
235                 printf(":%02X", macaddress[i]);
236 }
237
238 void printips_sorted(struct set *set, void *data, size_t len, unsigned options)
239 {
240         struct ip_set_macipmap *mysetdata =
241             (struct ip_set_macipmap *) set->settype->header;
242         struct ip_set_macip *table =
243             (struct ip_set_macip *) data;
244         u_int32_t addr = mysetdata->first_ip;
245
246         while (addr <= mysetdata->last_ip) {
247                 if (test_bit(IPSET_MACIP_ISSET,
248                              (void *)&table[addr - mysetdata->first_ip].flags)) {
249                         printf("%s:", ip_tostring(addr, options));
250                         print_mac(table[addr - mysetdata->first_ip].
251                                   ethernet);
252                         printf("\n");
253                 }
254                 addr++;
255         }
256 }
257
258 void saveheader(struct set *set, unsigned options)
259 {
260         struct ip_set_macipmap *mysetdata =
261             (struct ip_set_macipmap *) set->settype->header;
262
263         printf("-N %s %s --from %s",
264                set->name, set->settype->typename,
265                ip_tostring(mysetdata->first_ip, options));
266         printf(" --to %s", ip_tostring(mysetdata->last_ip, options));
267
268         if (mysetdata->flags & IPSET_MACIP_MATCHUNSET)
269                 printf(" --matchunset");
270         printf("\n");
271 }
272
273 void saveips(struct set *set, void *data, size_t len, unsigned options)
274 {
275         struct ip_set_macipmap *mysetdata =
276             (struct ip_set_macipmap *) set->settype->header;
277         struct ip_set_macip *table =
278             (struct ip_set_macip *) data;
279         u_int32_t addr = mysetdata->first_ip;
280
281         while (addr <= mysetdata->last_ip) {
282                 if (test_bit(IPSET_MACIP_ISSET,
283                              (void *)&table[addr - mysetdata->first_ip].flags)) {
284                         printf("-A %s %s:",
285                                set->name, ip_tostring(addr, options));
286                         print_mac(table[addr - mysetdata->first_ip].
287                                   ethernet);
288                         printf("\n");
289                 }
290                 addr++;
291         }
292 }
293
294 void usage(void)
295 {
296         printf
297             ("-N set macipmap --from IP --to IP [--matchunset]\n"
298              "-N set macipmap --network IP/mask [--matchunset]\n"
299              "-A set IP:MAC\n"
300              "-D set IP[:MAC]\n"
301              "-T set IP[:MAC]\n");
302 }
303
304 static struct settype settype_macipmap = {
305         .typename = SETTYPE_NAME,
306         .protocol_version = IP_SET_PROTOCOL_VERSION,
307
308         /* Create */
309         .create_size = sizeof(struct ip_set_req_macipmap_create),
310         .create_init = &create_init,
311         .create_parse = &create_parse,
312         .create_final = &create_final,
313         .create_opts = create_opts,
314
315         /* Add/del/test */
316         .adt_size = sizeof(struct ip_set_req_macipmap),
317         .adt_parser = &adt_parser,
318
319         /* Printing */
320         .header_size = sizeof(struct ip_set_macipmap),
321         .initheader = &initheader,
322         .printheader = &printheader,
323         .printips = &printips_sorted,   /* We only have sorted version */
324         .printips_sorted = &printips_sorted,
325         .saveheader = &saveheader,
326         .saveips = &saveips,
327
328         /* Bindings */
329         .bindip_tostring = &binding_ip_tostring,
330         .bindip_parse = &parse_ip,
331
332         .usage = &usage,
333 };
334
335 void _init(void)
336 {
337         settype_register(&settype_macipmap);
338
339 }