xref: /aosp_15_r20/external/iptables/extensions/libebt_ip.c (revision a71a954618bbadd4a345637e5edcf36eec826889)
1 /* ebt_ip
2  *
3  * Authors:
4  * Bart De Schuymer <[email protected]>
5  *
6  * Changes:
7  *    added ip-sport and ip-dport; parsing of port arguments is
8  *    based on code from iptables-1.2.7a
9  *    Innominate Security Technologies AG <[email protected]>
10  *    September, 2002
11  *
12  * Adapted by Arturo Borrero Gonzalez <[email protected]>
13  * to use libxtables for ebtables-compat in 2015.
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <getopt.h>
20 #include <netdb.h>
21 #include <inttypes.h>
22 #include <xtables.h>
23 #include <linux/netfilter_bridge/ebt_ip.h>
24 
25 #include "libxt_icmp.h"
26 
27 #define IP_SOURCE	'1'
28 #define IP_DEST		'2'
29 #define IP_EBT_TOS	'3' /* include/bits/in.h seems to already define IP_TOS */
30 #define IP_PROTO	'4'
31 #define IP_SPORT	'5'
32 #define IP_DPORT	'6'
33 #define IP_EBT_ICMP	'7'
34 #define IP_EBT_IGMP	'8'
35 
36 static const struct option brip_opts[] = {
37 	{ .name = "ip-source",		.has_arg = true, .val = IP_SOURCE },
38 	{ .name = "ip-src",		.has_arg = true, .val = IP_SOURCE },
39 	{ .name = "ip-destination",	.has_arg = true, .val = IP_DEST },
40 	{ .name = "ip-dst",		.has_arg = true, .val = IP_DEST },
41 	{ .name = "ip-tos",		.has_arg = true, .val = IP_EBT_TOS },
42 	{ .name = "ip-protocol",	.has_arg = true, .val = IP_PROTO },
43 	{ .name = "ip-proto",		.has_arg = true, .val = IP_PROTO },
44 	{ .name = "ip-source-port",	.has_arg = true, .val = IP_SPORT },
45 	{ .name = "ip-sport",		.has_arg = true, .val = IP_SPORT },
46 	{ .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
47 	{ .name = "ip-dport",		.has_arg = true, .val = IP_DPORT },
48 	{ .name = "ip-icmp-type",       .has_arg = true, .val = IP_EBT_ICMP },
49 	{ .name = "ip-igmp-type",       .has_arg = true, .val = IP_EBT_IGMP },
50 	XT_GETOPT_TABLEEND,
51 };
52 
brip_print_help(void)53 static void brip_print_help(void)
54 {
55 	printf(
56 "ip options:\n"
57 "--ip-src    [!] address[/mask]: ip source specification\n"
58 "--ip-dst    [!] address[/mask]: ip destination specification\n"
59 "--ip-tos    [!] tos           : ip tos specification\n"
60 "--ip-proto  [!] protocol      : ip protocol specification\n"
61 "--ip-sport  [!] port[:port]   : tcp/udp source port or port range\n"
62 "--ip-dport  [!] port[:port]   : tcp/udp destination port or port range\n"
63 "--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
64 "--ip-igmp-type [!] type[:type]               : igmp type or type range\n");
65 
66 	printf("\nValid ICMP Types:\n");
67 	xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
68 	printf("\nValid IGMP Types:\n");
69 	xt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
70 }
71 
brip_init(struct xt_entry_match * match)72 static void brip_init(struct xt_entry_match *match)
73 {
74 	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
75 
76 	info->invflags = 0;
77 	info->bitmask = 0;
78 }
79 
80 static void
parse_port_range(const char * protocol,const char * portstring,uint16_t * ports)81 parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
82 {
83 	char *buffer;
84 	char *cp;
85 
86 	buffer = xtables_strdup(portstring);
87 
88 	if ((cp = strchr(buffer, ':')) == NULL)
89 		ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
90 	else {
91 		*cp = '\0';
92 		cp++;
93 
94 		ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
95 		ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
96 
97 		if (ports[0] > ports[1])
98 			xtables_error(PARAMETER_PROBLEM,
99 				      "invalid portrange (min > max)");
100 	}
101 	free(buffer);
102 }
103 
104 /* original code from ebtables: useful_functions.c */
print_icmp_code(uint8_t * code)105 static void print_icmp_code(uint8_t *code)
106 {
107 	if (!code)
108 		return;
109 
110 	if (code[0] == code[1])
111 		printf("/%"PRIu8 " ", code[0]);
112 	else
113 		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
114 }
115 
ebt_print_icmp_type(const struct xt_icmp_names * codes,size_t n_codes,uint8_t * type,uint8_t * code)116 static void ebt_print_icmp_type(const struct xt_icmp_names *codes,
117 				size_t n_codes, uint8_t *type, uint8_t *code)
118 {
119 	unsigned int i;
120 
121 	if (type[0] != type[1]) {
122 		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
123 		print_icmp_code(code);
124 		return;
125 	}
126 
127 	for (i = 0; i < n_codes; i++) {
128 		if (codes[i].type != type[0])
129 			continue;
130 
131 		if (!code || (codes[i].code_min == code[0] &&
132 			      codes[i].code_max == code[1])) {
133 			printf("%s ", codes[i].name);
134 			return;
135 		}
136 	}
137 	printf("%"PRIu8, type[0]);
138 	print_icmp_code(code);
139 }
140 
141 static int
brip_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)142 brip_parse(int c, char **argv, int invert, unsigned int *flags,
143 	   const void *entry, struct xt_entry_match **match)
144 {
145 	struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data;
146 	struct in_addr *ipaddr, ipmask;
147 	unsigned int ipnr;
148 
149 	switch (c) {
150 	case IP_SOURCE:
151 		if (invert)
152 			info->invflags |= EBT_IP_SOURCE;
153 		xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr);
154 		info->saddr = ipaddr->s_addr;
155 		info->smsk = ipmask.s_addr;
156 		free(ipaddr);
157 		info->bitmask |= EBT_IP_SOURCE;
158 		break;
159 	case IP_DEST:
160 		if (invert)
161 			info->invflags |= EBT_IP_DEST;
162 		xtables_ipparse_any(optarg, &ipaddr, &ipmask, &ipnr);
163 		info->daddr = ipaddr->s_addr;
164 		info->dmsk = ipmask.s_addr;
165 		free(ipaddr);
166 		info->bitmask |= EBT_IP_DEST;
167 		break;
168 	case IP_SPORT:
169 		if (invert)
170 			info->invflags |= EBT_IP_SPORT;
171 		parse_port_range(NULL, optarg, info->sport);
172 		info->bitmask |= EBT_IP_SPORT;
173 		break;
174 	case IP_DPORT:
175 		if (invert)
176 			info->invflags |= EBT_IP_DPORT;
177 		parse_port_range(NULL, optarg, info->dport);
178 		info->bitmask |= EBT_IP_DPORT;
179 		break;
180 	case IP_EBT_ICMP:
181 		if (invert)
182 			info->invflags |= EBT_IP_ICMP;
183 		ebt_parse_icmp(optarg, info->icmp_type, info->icmp_code);
184 		info->bitmask |= EBT_IP_ICMP;
185 		break;
186 	case IP_EBT_IGMP:
187 		if (invert)
188 			info->invflags |= EBT_IP_IGMP;
189 		ebt_parse_igmp(optarg, info->igmp_type);
190 		info->bitmask |= EBT_IP_IGMP;
191 		break;
192 	case IP_EBT_TOS: {
193 		uintmax_t tosvalue;
194 
195 		if (invert)
196 			info->invflags |= EBT_IP_TOS;
197 		if (!xtables_strtoul(optarg, NULL, &tosvalue, 0, 255))
198 			xtables_error(PARAMETER_PROBLEM,
199 				      "Problem with specified IP tos");
200 		info->tos = tosvalue;
201 		info->bitmask |= EBT_IP_TOS;
202 	}
203 		break;
204 	case IP_PROTO:
205 		if (invert)
206 			info->invflags |= EBT_IP_PROTO;
207 		info->protocol = xtables_parse_protocol(optarg);
208 		info->bitmask |= EBT_IP_PROTO;
209 		break;
210 	default:
211 		return 0;
212 	}
213 
214 	*flags |= info->bitmask;
215 	return 1;
216 }
217 
brip_final_check(unsigned int flags)218 static void brip_final_check(unsigned int flags)
219 {
220 	if (!flags)
221 		xtables_error(PARAMETER_PROBLEM,
222 			      "You must specify proper arguments");
223 }
224 
print_port_range(uint16_t * ports)225 static void print_port_range(uint16_t *ports)
226 {
227 	if (ports[0] == ports[1])
228 		printf("%d ", ports[0]);
229 	else
230 		printf("%d:%d ", ports[0], ports[1]);
231 }
232 
brip_print(const void * ip,const struct xt_entry_match * match,int numeric)233 static void brip_print(const void *ip, const struct xt_entry_match *match,
234 		       int numeric)
235 {
236 	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
237 	struct in_addr *addrp, *maskp;
238 
239 	if (info->bitmask & EBT_IP_SOURCE) {
240 		printf("--ip-src ");
241 		if (info->invflags & EBT_IP_SOURCE)
242 			printf("! ");
243 		addrp = (struct in_addr *)&info->saddr;
244 		maskp = (struct in_addr *)&info->smsk;
245 		printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
246 		       xtables_ipmask_to_numeric(maskp));
247 	}
248 	if (info->bitmask & EBT_IP_DEST) {
249 		printf("--ip-dst ");
250 		if (info->invflags & EBT_IP_DEST)
251 			printf("! ");
252 		addrp = (struct in_addr *)&info->daddr;
253 		maskp = (struct in_addr *)&info->dmsk;
254 		printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
255 		       xtables_ipmask_to_numeric(maskp));
256 	}
257 	if (info->bitmask & EBT_IP_TOS) {
258 		printf("--ip-tos ");
259 		if (info->invflags & EBT_IP_TOS)
260 			printf("! ");
261 		printf("0x%02X ", info->tos);
262 	}
263 	if (info->bitmask & EBT_IP_PROTO) {
264 		struct protoent *pe;
265 
266 		printf("--ip-proto ");
267 		if (info->invflags & EBT_IP_PROTO)
268 			printf("! ");
269 		pe = getprotobynumber(info->protocol);
270 		if (pe == NULL) {
271 			printf("%d ", info->protocol);
272 		} else {
273 			printf("%s ", pe->p_name);
274 		}
275 	}
276 	if (info->bitmask & EBT_IP_SPORT) {
277 		printf("--ip-sport ");
278 		if (info->invflags & EBT_IP_SPORT)
279 			printf("! ");
280 		print_port_range(info->sport);
281 	}
282 	if (info->bitmask & EBT_IP_DPORT) {
283 		printf("--ip-dport ");
284 		if (info->invflags & EBT_IP_DPORT)
285 			printf("! ");
286 		print_port_range(info->dport);
287 	}
288 	if (info->bitmask & EBT_IP_ICMP) {
289 		printf("--ip-icmp-type ");
290 		if (info->invflags & EBT_IP_ICMP)
291 			printf("! ");
292 		ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
293 				    info->icmp_type, info->icmp_code);
294 	}
295 	if (info->bitmask & EBT_IP_IGMP) {
296 		printf("--ip-igmp-type ");
297 		if (info->invflags & EBT_IP_IGMP)
298 			printf("! ");
299 		ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
300 				    info->igmp_type, NULL);
301 	}
302 }
303 
brip_xlate_proto_to_name(uint8_t proto)304 static const char *brip_xlate_proto_to_name(uint8_t proto)
305 {
306 	switch (proto) {
307 	case IPPROTO_TCP:
308 		return "tcp";
309 	case IPPROTO_UDP:
310 		return "udp";
311 	case IPPROTO_UDPLITE:
312 		return "udplite";
313 	case IPPROTO_SCTP:
314 		return "sctp";
315 	case IPPROTO_DCCP:
316 		return "dccp";
317 	default:
318 		return NULL;
319 	}
320 }
321 
brip_xlate_icmp(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)322 static void brip_xlate_icmp(struct xt_xlate *xl,
323 			    const struct ebt_ip_info *info, int bit)
324 {
325 	if ((info->bitmask & bit) == 0)
326 		return;
327 
328 	xt_xlate_add(xl, "icmp type ");
329 	if (info->invflags & bit)
330 		xt_xlate_add(xl, "!= ");
331 	if (info->icmp_type[0] == info->icmp_type[1])
332 		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
333 	else
334 		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
335 					   info->icmp_type[1]);
336 	if (info->icmp_code[0] == 0 &&
337 	    info->icmp_code[1] == 0xff)
338 		return;
339 
340 	xt_xlate_add(xl, "icmp code ");
341 	if (info->invflags & bit)
342 		xt_xlate_add(xl, "!= ");
343 	if (info->icmp_code[0] == info->icmp_code[1])
344 		xt_xlate_add(xl, "%d ", info->icmp_code[0]);
345 	else
346 		xt_xlate_add(xl, "%d-%d ", info->icmp_code[0],
347 					   info->icmp_code[1]);
348 }
349 
brip_xlate_igmp(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)350 static void brip_xlate_igmp(struct xt_xlate *xl,
351 			    const struct ebt_ip_info *info, int bit)
352 {
353 	if ((info->bitmask & bit) == 0)
354 		return;
355 
356 	xt_xlate_add(xl, "@th,0,8 ");
357 	if (info->invflags & bit)
358 		xt_xlate_add(xl, "!= ");
359 	if (info->icmp_type[0] == info->icmp_type[1])
360 		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
361 	else
362 		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
363 					   info->icmp_type[1]);
364 }
365 
brip_xlate_th(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit,const char * pname)366 static void brip_xlate_th(struct xt_xlate *xl,
367 			  const struct ebt_ip_info *info, int bit,
368 			  const char *pname)
369 {
370 	const uint16_t *ports;
371 
372 	if ((info->bitmask & bit) == 0)
373 		return;
374 
375 	switch (bit) {
376 	case EBT_IP_SPORT:
377 		if (pname)
378 			xt_xlate_add(xl, "%s sport ", pname);
379 		else
380 			xt_xlate_add(xl, "@th,0,16 ");
381 
382 		ports = info->sport;
383 		break;
384 	case EBT_IP_DPORT:
385 		if (pname)
386 			xt_xlate_add(xl, "%s dport ", pname);
387 		else
388 			xt_xlate_add(xl, "@th,16,16 ");
389 
390 		ports = info->dport;
391 		break;
392 	default:
393 		return;
394 	}
395 
396 	if (info->invflags & bit)
397 		xt_xlate_add(xl, "!= ");
398 
399 	if (ports[0] == ports[1])
400 		xt_xlate_add(xl, "%d ", ports[0]);
401 	else
402 		xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
403 }
404 
brip_xlate_nh(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)405 static void brip_xlate_nh(struct xt_xlate *xl,
406 			  const struct ebt_ip_info *info, int bit)
407 {
408 	struct in_addr *addrp, *maskp;
409 
410 	if ((info->bitmask & bit) == 0)
411 		return;
412 
413 	switch (bit) {
414 	case EBT_IP_SOURCE:
415 		xt_xlate_add(xl, "ip saddr ");
416 		addrp = (struct in_addr *)&info->saddr;
417 		maskp = (struct in_addr *)&info->smsk;
418 		break;
419 	case EBT_IP_DEST:
420 		xt_xlate_add(xl, "ip daddr ");
421 		addrp = (struct in_addr *)&info->daddr;
422 		maskp = (struct in_addr *)&info->dmsk;
423 		break;
424 	default:
425 		return;
426 	}
427 
428 	if (info->invflags & bit)
429 		xt_xlate_add(xl, "!= ");
430 
431 	xt_xlate_add(xl, "%s%s ", xtables_ipaddr_to_numeric(addrp),
432 				  xtables_ipmask_to_numeric(maskp));
433 }
434 
may_skip_ether_type_dep(uint8_t flags)435 static bool may_skip_ether_type_dep(uint8_t flags)
436 {
437 	/* these convert to "ip (s|d)addr" matches */
438 	if (flags & (EBT_IP_SOURCE | EBT_IP_DEST))
439 		return true;
440 
441 	/* icmp match triggers implicit ether type dependency in nft */
442 	if (flags & EBT_IP_ICMP)
443 		return true;
444 
445 	/* allow if "ip protocol" match is created by brip_xlate() */
446 	if (flags & EBT_IP_PROTO &&
447 	    !(flags & (EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP)))
448 		return true;
449 
450 	return false;
451 }
452 
brip_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)453 static int brip_xlate(struct xt_xlate *xl,
454 		      const struct xt_xlate_mt_params *params)
455 {
456 	const struct ebt_ip_info *info = (const void *)params->match->data;
457 	const char *pname = NULL;
458 
459 	brip_xlate_nh(xl, info, EBT_IP_SOURCE);
460 	brip_xlate_nh(xl, info, EBT_IP_DEST);
461 
462 	if (!may_skip_ether_type_dep(info->bitmask))
463 		xt_xlate_add(xl, "ether type ip ");
464 
465 	if (info->bitmask & EBT_IP_TOS) {
466 		xt_xlate_add(xl, "@nh,8,8 ");
467 		if (info->invflags & EBT_IP_TOS)
468 			xt_xlate_add(xl, "!= ");
469 		xt_xlate_add(xl, "0x%02x ", info->tos);
470 	}
471 	if (info->bitmask & EBT_IP_PROTO) {
472 		struct protoent *pe;
473 
474 		if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT|EBT_IP_ICMP) &&
475 		    (info->invflags & EBT_IP_PROTO) == 0) {
476 			/* port number or icmp given and not inverted, no need to print this */
477 			pname = brip_xlate_proto_to_name(info->protocol);
478 		} else {
479 			xt_xlate_add(xl, "ip protocol ");
480 			if (info->invflags & EBT_IP_PROTO)
481 				xt_xlate_add(xl, "!= ");
482 			pe = getprotobynumber(info->protocol);
483 			if (pe == NULL)
484 				xt_xlate_add(xl, "%d ", info->protocol);
485 			else
486 				xt_xlate_add(xl, "%s ", pe->p_name);
487 		}
488 	}
489 
490 	brip_xlate_th(xl, info, EBT_IP_SPORT, pname);
491 	brip_xlate_th(xl, info, EBT_IP_DPORT, pname);
492 
493 	brip_xlate_icmp(xl, info, EBT_IP_ICMP);
494 	brip_xlate_igmp(xl, info, EBT_IP_IGMP);
495 
496 	return 1;
497 }
498 
499 static struct xtables_match brip_match = {
500 	.name		= "ip",
501 	.revision	= 0,
502 	.version	= XTABLES_VERSION,
503 	.family		= NFPROTO_BRIDGE,
504 	.size		= XT_ALIGN(sizeof(struct ebt_ip_info)),
505 	.userspacesize	= XT_ALIGN(sizeof(struct ebt_ip_info)),
506 	.init		= brip_init,
507 	.help		= brip_print_help,
508 	.parse		= brip_parse,
509 	.final_check	= brip_final_check,
510 	.print		= brip_print,
511 	.xlate		= brip_xlate,
512 	.extra_opts	= brip_opts,
513 };
514 
_init(void)515 void _init(void)
516 {
517 	xtables_register_match(&brip_match);
518 }
519