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