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