xref: /aosp_15_r20/external/iptables/extensions/libebt_among.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
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