• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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