blob: 5ec8a4508736d7dbe04de5757d79b9f5566f6791 [file] [log] [blame]
Bart De Schuymer9cc9bfa2003-09-02 22:43:25 +00001#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4#include <getopt.h>
5#include <ctype.h>
6#include <netinet/ether.h>
7#include "../include/ebtables_u.h"
8#include "../include/ethernetdb.h"
9#include <linux/if_ether.h>
10#include <linux/netfilter_bridge/ebt_among.h>
11
12/*
13#define DEBUG
14*/
15
16#define AMONG_DST '1'
17#define AMONG_SRC '2'
18
19static struct option opts[] =
20{
21 { "among-dst" , required_argument, 0, AMONG_DST },
22 { "among-src" , required_argument, 0, AMONG_SRC },
23 { 0 }
24};
25
26#ifdef DEBUG
27static void hexdump(const void *mem, int howmany)
28{
29 printf("\n");
30 const unsigned char *p = mem;
31 int i;
32 for (i = 0; i < howmany; i++) {
33 if (i % 32 == 0) {
34 printf("\n%04x: ", i);
35 }
36 printf("%2.2x ", p[i]);
37 }
38 printf("\n");
39}
40#endif /* DEBUG */
41
42static void print_help()
43{
44 printf(
45"`among' options:\n"
46"--among-dst list : matches if ether dst is in list\n"
47"--among-src list : matches if ether src is in list\n"
48"list has form:\n"
49"\txx:xx:xx:xx:xx:xx,yy:yy:yy:yy:yy:yy,...,zz:zz:zz:zz:zz:zz\n"
50"i.e. MAC addresses separated by commas, without spaces.\n"
51"Optional comma can be included after the last MAC address, i.e.:\n"
52"\txx:xx:xx:xx:xx:xx,yy:yy:yy:yy:yy:yy,...,zz:zz:zz:zz:zz:zz,\n"
53"Each list can contain up to 256 addresses.\n"
54 );
55}
56
57static void init(struct ebt_entry_match *match)
58{
59 struct ebt_among_info *amonginfo = (struct ebt_among_info *)match->data;
60
61 memset(amonginfo, 0, sizeof(struct ebt_among_info));
62}
63
64static int fill_mac(char *mac, const char *string)
65{
66 char xnum[3];
67 const char *p = string;
68 int i = 0;
69 int j = 0;
70 while (1) {
71 if (isxdigit(*p)) {
72 xnum[j] = *p;
73 j++;
74 if (j >= 3) {
75 /* 3 or more hex digits for a single byte */
76 return -3;
77 }
78 }
79 else {
80 xnum[j] = 0;
81 j = 0;
82 mac[i] = strtol(xnum, 0, 16);
83 i++;
84 if (i >= 6) {
85 if (*p == ':') {
86 /* MAC address too long */
87 return -2;
88 }
89 else {
90 return 0;
91 }
92 }
93 else {
94 if (*p != ':') {
95 /* MAC address too short */
96 return -1;
97 }
98 }
99 }
100 p++;
101 }
102
103}
104
105static void fill_wormhash(struct ebt_mac_wormhash *wh, const char *arg)
106{
107 const char *pc = arg;
108 const char *anchor;
109 char mac[6];
110 int index;
111 int nmacs = 0;
112 char *base = (char*)wh;
113 memset(wh, 0, sizeof(struct ebt_mac_wormhash));
114 while (1) {
115 anchor = pc;
116 while (*pc && *pc != ',') pc++;
117 while (*pc && *pc == ',') pc++;
118 if (fill_mac(mac, anchor)) {
119 print_error("problem with MAC %20s...", anchor);
120 }
121 index = (unsigned char)mac[5];
122 memcpy(((char*)wh->pool[nmacs].cmp)+2, mac, 6);
123 wh->pool[nmacs].next_ofs = wh->table[index];
124 wh->table[index] = ((const char*)&wh->pool[nmacs]) - base;
125 nmacs++;
126 if (*pc && nmacs >= 256) {
127 print_error("--among-src/--among-dst list can contain no more than 256 addresses\n");
128 }
129 if (!*pc) {
130 break;
131 }
132 }
133}
134
135#define OPT_DST 0x01
136#define OPT_SRC 0x02
137static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry,
138 unsigned int *flags, struct ebt_entry_match **match)
139{
140 struct ebt_among_info *amonginfo = (struct ebt_among_info *)(*match)->data;
141 struct ebt_mac_wormhash *wh;
142
143 switch (c) {
144 case AMONG_DST:
145 case AMONG_SRC:
146 if (c == AMONG_DST) {
147 check_option(flags, OPT_DST);
148 wh = &amonginfo->wh_dst;
149 amonginfo->bitmask |= EBT_AMONG_DST;
150 } else {
151 check_option(flags, OPT_SRC);
152 wh = &amonginfo->wh_src;
153 amonginfo->bitmask |= EBT_AMONG_SRC;
154 }
155 if (optind > argc)
156 print_error("No MAC list specified\n");
157 fill_wormhash(wh, argv[optind - 1]);
158 break;
159 default:
160 return 0;
161 }
162 return 1;
163}
164
165static void final_check(const struct ebt_u_entry *entry,
166 const struct ebt_entry_match *match, const char *name,
167 unsigned int hookmask, unsigned int time)
168{
169}
170
171static void wormhash_printout(const struct ebt_mac_wormhash *wh)
172{
173 int i;
174 int offset;
175 for (i = 0; i < 256; i++) {
176 const struct ebt_mac_wormhash_tuple *p;
177 offset = wh->table[i];
178 while (offset) {
179 p = (const struct ebt_mac_wormhash_tuple*)((const char*)wh + offset);
180 printf("%s,", ether_ntoa((const struct ether_addr *)(((const char*)&p->cmp[0]) + 2)));
181 offset = p->next_ofs;
182 }
183 }
184 printf(" ");
185}
186
187static void print(const struct ebt_u_entry *entry,
188 const struct ebt_entry_match *match)
189{
190 struct ebt_among_info *amonginfo = (struct ebt_among_info *)match->data;
191
192 if (amonginfo->bitmask & EBT_AMONG_DST) {
193 printf("--among-dst ");
194 wormhash_printout(&amonginfo->wh_dst);
195 }
196 if (amonginfo->bitmask & EBT_AMONG_SRC) {
197 printf("--among-src ");
198 wormhash_printout(&amonginfo->wh_src);
199 }
200}
201
202static int compare(const struct ebt_entry_match *m1,
203 const struct ebt_entry_match *m2)
204{
205 struct ebt_among_info *amonginfo1 = (struct ebt_among_info *)m1->data;
206 struct ebt_among_info *amonginfo2 = (struct ebt_among_info *)m2->data;
207
208#ifdef DEBUG
209// hexdump(amonginfo1, sizeof(struct ebt_among_info));
210// hexdump(amonginfo2, sizeof(struct ebt_among_info));
211#endif /* DEBUG */
212
213 return memcmp(amonginfo1, amonginfo2, sizeof(struct ebt_among_info)) == 0;
214}
215
216static struct ebt_u_match among_match =
217{
218 EBT_AMONG_MATCH,
219 sizeof(struct ebt_among_info),
220 print_help,
221 init,
222 parse,
223 final_check,
224 print,
225 compare,
226 opts
227};
228
229static void _init(void) __attribute__ ((constructor));
230static void _init(void)
231{
232 register_match(&among_match);
233}