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