1 /* ebt_among
2 *
3 * Authors:
4 * Grzegorz Borowiak <[email protected]>
5 *
6 * August, 2003
7 */
8
9 #include <errno.h>
10 #include <ctype.h>
11 #include <fcntl.h>
12 #include <getopt.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <unistd.h>
17 #include <xtables.h>
18 #include <arpa/inet.h>
19 #include <netinet/ether.h>
20 #include <netinet/in.h>
21 #include <linux/if_ether.h>
22 #include <linux/netfilter_bridge/ebt_among.h>
23 #include <sys/mman.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include "iptables/nft.h"
27 #include "iptables/nft-bridge.h"
28
29 #define AMONG_DST '1'
30 #define AMONG_SRC '2'
31 #define AMONG_DST_F '3'
32 #define AMONG_SRC_F '4'
33
34 static const struct option bramong_opts[] = {
35 {"among-dst", required_argument, 0, AMONG_DST},
36 {"among-src", required_argument, 0, AMONG_SRC},
37 {"among-dst-file", required_argument, 0, AMONG_DST_F},
38 {"among-src-file", required_argument, 0, AMONG_SRC_F},
39 {0}
40 };
41
bramong_print_help(void)42 static void bramong_print_help(void)
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 "--among-dst-file [!] file : obtain dst list from file\n"
49 "--among-src-file [!] file : obtain src list from file\n"
50 "list has form:\n"
51 " xx:xx:xx:xx:xx:xx[=ip.ip.ip.ip],yy:yy:yy:yy:yy:yy[=ip.ip.ip.ip]"
52 ",...,zz:zz:zz:zz:zz:zz[=ip.ip.ip.ip][,]\n"
53 "Things in brackets are optional.\n"
54 "If you want to allow two (or more) IP addresses to one MAC address, you\n"
55 "can specify two (or more) pairs with the same MAC, e.g.\n"
56 " 00:00:00:fa:eb:fe=153.19.120.250,00:00:00:fa:eb:fe=192.168.0.1\n"
57 );
58 }
59
60 static void
parse_nft_among_pair(char * buf,struct nft_among_pair * pair,bool have_ip)61 parse_nft_among_pair(char *buf, struct nft_among_pair *pair, bool have_ip)
62 {
63 char *sep = index(buf, '=');
64 struct ether_addr *ether;
65
66 if (sep) {
67 *sep = '\0';
68
69 if (!inet_pton(AF_INET, sep + 1, &pair->in))
70 xtables_error(PARAMETER_PROBLEM,
71 "Invalid IP address '%s'", sep + 1);
72 }
73 ether = ether_aton(buf);
74 if (!ether)
75 xtables_error(PARAMETER_PROBLEM,
76 "Invalid MAC address '%s'", buf);
77 memcpy(&pair->ether, ether, sizeof(*ether));
78 }
79
80 static void
parse_nft_among_pairs(struct nft_among_pair * pairs,char * buf,size_t cnt,bool have_ip)81 parse_nft_among_pairs(struct nft_among_pair *pairs, char *buf,
82 size_t cnt, bool have_ip)
83 {
84 size_t tmpcnt = 0;
85
86 buf = strtok(buf, ",");
87 while (buf) {
88 struct nft_among_pair pair = {};
89
90 parse_nft_among_pair(buf, &pair, have_ip);
91 nft_among_insert_pair(pairs, &tmpcnt, &pair);
92 buf = strtok(NULL, ",");
93 }
94 }
95
count_nft_among_pairs(char * buf)96 static size_t count_nft_among_pairs(char *buf)
97 {
98 size_t cnt = 0;
99 char *p = buf;
100
101 if (!*buf)
102 return 0;
103
104 do {
105 cnt++;
106 p = index(++p, ',');
107 } while (p);
108
109 return cnt;
110 }
111
nft_among_pairs_have_ip(char * buf)112 static bool nft_among_pairs_have_ip(char *buf)
113 {
114 return !!index(buf, '=');
115 }
116
bramong_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)117 static int bramong_parse(int c, char **argv, int invert,
118 unsigned int *flags, const void *entry,
119 struct xt_entry_match **match)
120 {
121 struct nft_among_data *data = (struct nft_among_data *)(*match)->data;
122 bool have_ip, dst = false;
123 size_t new_size, cnt;
124 struct stat stats;
125 int fd = -1, poff;
126 long flen = 0;
127
128 switch (c) {
129 case AMONG_DST_F:
130 dst = true;
131 /* fall through */
132 case AMONG_SRC_F:
133 if ((fd = open(optarg, O_RDONLY)) == -1)
134 xtables_error(PARAMETER_PROBLEM,
135 "Couldn't open file '%s'", optarg);
136 if (fstat(fd, &stats) < 0)
137 xtables_error(PARAMETER_PROBLEM,
138 "fstat(%s) failed: '%s'",
139 optarg, strerror(errno));
140 flen = stats.st_size;
141 /* use mmap because the file will probably be big */
142 optarg = mmap(0, flen, PROT_READ | PROT_WRITE,
143 MAP_PRIVATE, fd, 0);
144 if (optarg == MAP_FAILED)
145 xtables_error(PARAMETER_PROBLEM,
146 "Couldn't map file to memory");
147 if (optarg[flen-1] != '\n')
148 xtables_error(PARAMETER_PROBLEM,
149 "File should end with a newline");
150 if (strchr(optarg, '\n') != optarg+flen-1)
151 xtables_error(PARAMETER_PROBLEM,
152 "File should only contain one line");
153 optarg[flen-1] = '\0';
154 break;
155 case AMONG_DST:
156 dst = true;
157 /* fall through */
158 case AMONG_SRC:
159 break;
160 default:
161 return 0;
162 }
163
164 cnt = count_nft_among_pairs(optarg);
165 if (cnt == 0)
166 return 0;
167
168 new_size = data->src.cnt + data->dst.cnt + cnt;
169 new_size *= sizeof(struct nft_among_pair);
170 new_size += XT_ALIGN(sizeof(struct xt_entry_match)) +
171 sizeof(struct nft_among_data);
172
173 if (new_size > (*match)->u.match_size) {
174 *match = xtables_realloc(*match, new_size);
175 (*match)->u.match_size = new_size;
176 data = (struct nft_among_data *)(*match)->data;
177 }
178
179 have_ip = nft_among_pairs_have_ip(optarg);
180 poff = nft_among_prepare_data(data, dst, cnt, invert, have_ip);
181 parse_nft_among_pairs(data->pairs + poff, optarg, cnt, have_ip);
182
183 if (c == AMONG_DST_F || c == AMONG_SRC_F) {
184 munmap(argv, flen);
185 close(fd);
186 }
187 return 1;
188 }
189
__bramong_print(struct nft_among_pair * pairs,int cnt,bool inv,bool have_ip)190 static void __bramong_print(struct nft_among_pair *pairs,
191 int cnt, bool inv, bool have_ip)
192 {
193 const char *isep = inv ? "! " : "";
194 char abuf[INET_ADDRSTRLEN];
195 int i;
196
197 for (i = 0; i < cnt; i++) {
198 printf("%s", isep);
199 isep = ",";
200
201 printf("%s", ether_ntoa(&pairs[i].ether));
202 if (pairs[i].in.s_addr != INADDR_ANY)
203 printf("=%s", inet_ntop(AF_INET, &pairs[i].in,
204 abuf, sizeof(abuf)));
205 }
206 printf(" ");
207 }
208
bramong_print(const void * ip,const struct xt_entry_match * match,int numeric)209 static void bramong_print(const void *ip, const struct xt_entry_match *match,
210 int numeric)
211 {
212 struct nft_among_data *data = (struct nft_among_data *)match->data;
213
214 if (data->src.cnt) {
215 printf("--among-src ");
216 __bramong_print(data->pairs,
217 data->src.cnt, data->src.inv, data->src.ip);
218 }
219 if (data->dst.cnt) {
220 printf("--among-dst ");
221 __bramong_print(data->pairs + data->src.cnt,
222 data->dst.cnt, data->dst.inv, data->dst.ip);
223 }
224 }
225
226 static struct xtables_match bramong_match = {
227 .name = "among",
228 .revision = 0,
229 .version = XTABLES_VERSION,
230 .family = NFPROTO_BRIDGE,
231 .size = XT_ALIGN(sizeof(struct nft_among_data)),
232 .userspacesize = XT_ALIGN(sizeof(struct nft_among_data)),
233 .help = bramong_print_help,
234 .parse = bramong_parse,
235 .print = bramong_print,
236 .extra_opts = bramong_opts,
237 };
238
_init(void)239 void _init(void)
240 {
241 xtables_register_match(&bramong_match);
242 }
243