• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ebt_ip
2  *
3  * Authors:
4  * Bart De Schuymer <bdschuym@pandora.be>
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 <mhopf@innominate.com>
10  *    September, 2002
11  *
12  * Adapted by Arturo Borrero Gonzalez <arturo@debian.org>
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 
24 #include "libxt_icmp.h"
25 
26 #define EBT_IP_SOURCE 0x01
27 #define EBT_IP_DEST 0x02
28 #define EBT_IP_TOS 0x04
29 #define EBT_IP_PROTO 0x08
30 #define EBT_IP_SPORT 0x10
31 #define EBT_IP_DPORT 0x20
32 #define EBT_IP_ICMP 0x40
33 #define EBT_IP_IGMP 0x80
34 #define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
35 		     EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
36 
37 struct ebt_ip_info {
38 	__be32 saddr;
39 	__be32 daddr;
40 	__be32 smsk;
41 	__be32 dmsk;
42 	__u8  tos;
43 	__u8  protocol;
44 	__u8  bitmask;
45 	__u8  invflags;
46 	union {
47 		__u16 sport[2];
48 		__u8 icmp_type[2];
49 		__u8 igmp_type[2];
50 	};
51 	union {
52 		__u16 dport[2];
53 		__u8 icmp_code[2];
54 	};
55 };
56 
57 #define IP_SOURCE	'1'
58 #define IP_DEST		'2'
59 #define IP_EBT_TOS	'3' /* include/bits/in.h seems to already define IP_TOS */
60 #define IP_PROTO	'4'
61 #define IP_SPORT	'5'
62 #define IP_DPORT	'6'
63 #define IP_EBT_ICMP	'7'
64 #define IP_EBT_IGMP	'8'
65 
66 static const struct option brip_opts[] = {
67 	{ .name = "ip-source",		.has_arg = true, .val = IP_SOURCE },
68 	{ .name = "ip-src",		.has_arg = true, .val = IP_SOURCE },
69 	{ .name = "ip-destination",	.has_arg = true, .val = IP_DEST },
70 	{ .name = "ip-dst",		.has_arg = true, .val = IP_DEST },
71 	{ .name = "ip-tos",		.has_arg = true, .val = IP_EBT_TOS },
72 	{ .name = "ip-protocol",	.has_arg = true, .val = IP_PROTO },
73 	{ .name = "ip-proto",		.has_arg = true, .val = IP_PROTO },
74 	{ .name = "ip-source-port",	.has_arg = true, .val = IP_SPORT },
75 	{ .name = "ip-sport",		.has_arg = true, .val = IP_SPORT },
76 	{ .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
77 	{ .name = "ip-dport",		.has_arg = true, .val = IP_DPORT },
78 	{ .name = "ip-icmp-type",       .has_arg = true, .val = IP_EBT_ICMP },
79 	{ .name = "ip-igmp-type",       .has_arg = true, .val = IP_EBT_IGMP },
80 	XT_GETOPT_TABLEEND,
81 };
82 
83 static const struct xt_icmp_names icmp_codes[] = {
84 	{ "echo-reply", 0, 0, 0xFF },
85 	/* Alias */ { "pong", 0, 0, 0xFF },
86 
87 	{ "destination-unreachable", 3, 0, 0xFF },
88 	{   "network-unreachable", 3, 0, 0 },
89 	{   "host-unreachable", 3, 1, 1 },
90 	{   "protocol-unreachable", 3, 2, 2 },
91 	{   "port-unreachable", 3, 3, 3 },
92 	{   "fragmentation-needed", 3, 4, 4 },
93 	{   "source-route-failed", 3, 5, 5 },
94 	{   "network-unknown", 3, 6, 6 },
95 	{   "host-unknown", 3, 7, 7 },
96 	{   "network-prohibited", 3, 9, 9 },
97 	{   "host-prohibited", 3, 10, 10 },
98 	{   "TOS-network-unreachable", 3, 11, 11 },
99 	{   "TOS-host-unreachable", 3, 12, 12 },
100 	{   "communication-prohibited", 3, 13, 13 },
101 	{   "host-precedence-violation", 3, 14, 14 },
102 	{   "precedence-cutoff", 3, 15, 15 },
103 
104 	{ "source-quench", 4, 0, 0xFF },
105 
106 	{ "redirect", 5, 0, 0xFF },
107 	{   "network-redirect", 5, 0, 0 },
108 	{   "host-redirect", 5, 1, 1 },
109 	{   "TOS-network-redirect", 5, 2, 2 },
110 	{   "TOS-host-redirect", 5, 3, 3 },
111 
112 	{ "echo-request", 8, 0, 0xFF },
113 	/* Alias */ { "ping", 8, 0, 0xFF },
114 
115 	{ "router-advertisement", 9, 0, 0xFF },
116 
117 	{ "router-solicitation", 10, 0, 0xFF },
118 
119 	{ "time-exceeded", 11, 0, 0xFF },
120 	/* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
121 	{   "ttl-zero-during-transit", 11, 0, 0 },
122 	{   "ttl-zero-during-reassembly", 11, 1, 1 },
123 
124 	{ "parameter-problem", 12, 0, 0xFF },
125 	{   "ip-header-bad", 12, 0, 0 },
126 	{   "required-option-missing", 12, 1, 1 },
127 
128 	{ "timestamp-request", 13, 0, 0xFF },
129 
130 	{ "timestamp-reply", 14, 0, 0xFF },
131 
132 	{ "address-mask-request", 17, 0, 0xFF },
133 
134 	{ "address-mask-reply", 18, 0, 0xFF }
135 };
136 
137 static const struct xt_icmp_names igmp_types[] = {
138 	{ "membership-query", 0x11 },
139 	{ "membership-report-v1", 0x12 },
140 	{ "membership-report-v2", 0x16 },
141 	{ "leave-group", 0x17 },
142 	{ "membership-report-v3", 0x22 },
143 };
144 
brip_print_help(void)145 static void brip_print_help(void)
146 {
147 	printf(
148 "ip options:\n"
149 "--ip-src    [!] address[/mask]: ip source specification\n"
150 "--ip-dst    [!] address[/mask]: ip destination specification\n"
151 "--ip-tos    [!] tos           : ip tos specification\n"
152 "--ip-proto  [!] protocol      : ip protocol specification\n"
153 "--ip-sport  [!] port[:port]   : tcp/udp source port or port range\n"
154 "--ip-dport  [!] port[:port]   : tcp/udp destination port or port range\n"
155 "--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
156 "--ip-igmp-type [!] type[:type]               : igmp type or type range\n");
157 
158 	printf("\nValid ICMP Types:\n");
159 	xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
160 	printf("\nValid IGMP Types:\n");
161 	xt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
162 }
163 
brip_init(struct xt_entry_match * match)164 static void brip_init(struct xt_entry_match *match)
165 {
166 	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
167 
168 	info->invflags = 0;
169 	info->bitmask = 0;
170 }
171 
172 static void
parse_port_range(const char * protocol,const char * portstring,uint16_t * ports)173 parse_port_range(const char *protocol, const char *portstring, uint16_t *ports)
174 {
175 	char *buffer;
176 	char *cp;
177 
178 	buffer = strdup(portstring);
179 	if ((cp = strchr(buffer, ':')) == NULL)
180 		ports[0] = ports[1] = xtables_parse_port(buffer, NULL);
181 	else {
182 		*cp = '\0';
183 		cp++;
184 
185 		ports[0] = buffer[0] ? xtables_parse_port(buffer, NULL) : 0;
186 		ports[1] = cp[0] ? xtables_parse_port(cp, NULL) : 0xFFFF;
187 
188 		if (ports[0] > ports[1])
189 			xtables_error(PARAMETER_PROBLEM,
190 				      "invalid portrange (min > max)");
191 	}
192 	free(buffer);
193 }
194 
195 /* original code from ebtables: useful_functions.c */
undot_ip(char * ip,unsigned char * ip2)196 static int undot_ip(char *ip, unsigned char *ip2)
197 {
198 	char *p, *q, *end;
199 	long int onebyte;
200 	int i;
201 	char buf[20];
202 
203 	strncpy(buf, ip, sizeof(buf) - 1);
204 
205 	p = buf;
206 	for (i = 0; i < 3; i++) {
207 		if ((q = strchr(p, '.')) == NULL)
208 			return -1;
209 		*q = '\0';
210 		onebyte = strtol(p, &end, 10);
211 		if (*end != '\0' || onebyte > 255 || onebyte < 0)
212 			return -1;
213 		ip2[i] = (unsigned char)onebyte;
214 		p = q + 1;
215 	}
216 
217 	onebyte = strtol(p, &end, 10);
218 	if (*end != '\0' || onebyte > 255 || onebyte < 0)
219 		return -1;
220 	ip2[3] = (unsigned char)onebyte;
221 
222 	return 0;
223 }
224 
ip_mask(char * mask,unsigned char * mask2)225 static int ip_mask(char *mask, unsigned char *mask2)
226 {
227 	char *end;
228 	long int bits;
229 	uint32_t mask22;
230 
231 	if (undot_ip(mask, mask2)) {
232 		/* not the /a.b.c.e format, maybe the /x format */
233 		bits = strtol(mask, &end, 10);
234 		if (*end != '\0' || bits > 32 || bits < 0)
235 			return -1;
236 		if (bits != 0) {
237 			mask22 = htonl(0xFFFFFFFF << (32 - bits));
238 			memcpy(mask2, &mask22, 4);
239 		} else {
240 			mask22 = 0xFFFFFFFF;
241 			memcpy(mask2, &mask22, 4);
242 		}
243 	}
244 	return 0;
245 }
246 
ebt_parse_ip_address(char * address,uint32_t * addr,uint32_t * msk)247 static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
248 {
249 	char *p;
250 
251 	/* first the mask */
252 	if ((p = strrchr(address, '/')) != NULL) {
253 		*p = '\0';
254 		if (ip_mask(p + 1, (unsigned char *)msk)) {
255 			xtables_error(PARAMETER_PROBLEM,
256 				      "Problem with the IP mask '%s'", p + 1);
257 			return;
258 		}
259 	} else
260 		*msk = 0xFFFFFFFF;
261 
262 	if (undot_ip(address, (unsigned char *)addr)) {
263 		xtables_error(PARAMETER_PROBLEM,
264 			      "Problem with the IP address '%s'", address);
265 		return;
266 	}
267 	*addr = *addr & *msk;
268 }
269 
parse_range(const char * str,unsigned int res[])270 static char *parse_range(const char *str, unsigned int res[])
271 {
272 	char *next;
273 
274 	if (!xtables_strtoui(str, &next, &res[0], 0, 255))
275 		return NULL;
276 
277 	res[1] = res[0];
278 	if (*next == ':') {
279 		str = next + 1;
280 		if (!xtables_strtoui(str, &next, &res[1], 0, 255))
281 			return NULL;
282 	}
283 
284 	return next;
285 }
286 
ebt_parse_icmp(const struct xt_icmp_names * codes,size_t n_codes,const char * icmptype,uint8_t type[],uint8_t code[])287 static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
288 			  const char *icmptype, uint8_t type[], uint8_t code[])
289 {
290 	unsigned int match = n_codes;
291 	unsigned int i, number[2];
292 
293 	for (i = 0; i < n_codes; i++) {
294 		if (strncasecmp(codes[i].name, icmptype, strlen(icmptype)))
295 			continue;
296 		if (match != n_codes)
297 			xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':"
298 					" `%s' or `%s'?",
299 					icmptype, codes[match].name,
300 					codes[i].name);
301 		match = i;
302 	}
303 
304 	if (match < n_codes) {
305 		type[0] = type[1] = codes[match].type;
306 		if (code) {
307 			code[0] = codes[match].code_min;
308 			code[1] = codes[match].code_max;
309 		}
310 	} else {
311 		char *next = parse_range(icmptype, number);
312 		if (!next) {
313 			xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'",
314 							icmptype);
315 			return -1;
316 		}
317 
318 		type[0] = (uint8_t) number[0];
319 		type[1] = (uint8_t) number[1];
320 		switch (*next) {
321 		case 0:
322 			if (code) {
323 				code[0] = 0;
324 				code[1] = 255;
325 			}
326 			return 0;
327 		case '/':
328 			if (code) {
329 				next = parse_range(next+1, number);
330 				code[0] = (uint8_t) number[0];
331 				code[1] = (uint8_t) number[1];
332 				if (next == NULL)
333 					return -1;
334 				if (next && *next == 0)
335 					return 0;
336 			}
337 		/* fallthrough */
338 		default:
339 			xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
340 			return -1;
341 		}
342 	}
343 	return 0;
344 }
345 
print_icmp_code(uint8_t * code)346 static void print_icmp_code(uint8_t *code)
347 {
348 	if (!code)
349 		return;
350 
351 	if (code[0] == code[1])
352 		printf("/%"PRIu8 " ", code[0]);
353 	else
354 		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
355 }
356 
ebt_print_icmp_type(const struct xt_icmp_names * codes,size_t n_codes,uint8_t * type,uint8_t * code)357 static void ebt_print_icmp_type(const struct xt_icmp_names *codes,
358 				size_t n_codes, uint8_t *type, uint8_t *code)
359 {
360 	unsigned int i;
361 
362 	if (type[0] != type[1]) {
363 		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
364 		print_icmp_code(code);
365 		return;
366 	}
367 
368 	for (i = 0; i < n_codes; i++) {
369 		if (codes[i].type != type[0])
370 			continue;
371 
372 		if (!code || (codes[i].code_min == code[0] &&
373 			      codes[i].code_max == code[1])) {
374 			printf("%s ", codes[i].name);
375 			return;
376 		}
377 	}
378 	printf("%"PRIu8, type[0]);
379 	print_icmp_code(code);
380 }
381 
382 static int
brip_parse(int c,char ** argv,int invert,unsigned int * flags,const void * entry,struct xt_entry_match ** match)383 brip_parse(int c, char **argv, int invert, unsigned int *flags,
384 	   const void *entry, struct xt_entry_match **match)
385 {
386 	struct ebt_ip_info *info = (struct ebt_ip_info *)(*match)->data;
387 
388 	switch (c) {
389 	case IP_SOURCE:
390 		if (invert)
391 			info->invflags |= EBT_IP_SOURCE;
392 		ebt_parse_ip_address(optarg, &info->saddr, &info->smsk);
393 		info->bitmask |= EBT_IP_SOURCE;
394 		break;
395 	case IP_DEST:
396 		if (invert)
397 			info->invflags |= EBT_IP_DEST;
398 		ebt_parse_ip_address(optarg, &info->daddr, &info->dmsk);
399 		info->bitmask |= EBT_IP_DEST;
400 		break;
401 	case IP_SPORT:
402 		if (invert)
403 			info->invflags |= EBT_IP_SPORT;
404 		parse_port_range(NULL, optarg, info->sport);
405 		info->bitmask |= EBT_IP_SPORT;
406 		break;
407 	case IP_DPORT:
408 		if (invert)
409 			info->invflags |= EBT_IP_DPORT;
410 		parse_port_range(NULL, optarg, info->dport);
411 		info->bitmask |= EBT_IP_DPORT;
412 		break;
413 	case IP_EBT_ICMP:
414 		if (invert)
415 			info->invflags |= EBT_IP_ICMP;
416 		ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
417 			      info->icmp_type, info->icmp_code);
418 		info->bitmask |= EBT_IP_ICMP;
419 		break;
420 	case IP_EBT_IGMP:
421 		if (invert)
422 			info->invflags |= EBT_IP_IGMP;
423 		ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
424 			       info->igmp_type, NULL);
425 		info->bitmask |= EBT_IP_IGMP;
426 		break;
427 	case IP_EBT_TOS: {
428 		uintmax_t tosvalue;
429 
430 		if (invert)
431 			info->invflags |= EBT_IP_TOS;
432 		if (!xtables_strtoul(optarg, NULL, &tosvalue, 0, 255))
433 			xtables_error(PARAMETER_PROBLEM,
434 				      "Problem with specified IP tos");
435 		info->tos = tosvalue;
436 		info->bitmask |= EBT_IP_TOS;
437 	}
438 		break;
439 	case IP_PROTO:
440 		if (invert)
441 			info->invflags |= EBT_IP_PROTO;
442 		info->protocol = xtables_parse_protocol(optarg);
443 		info->bitmask |= EBT_IP_PROTO;
444 		break;
445 	default:
446 		return 0;
447 	}
448 
449 	*flags |= info->bitmask;
450 	return 1;
451 }
452 
brip_final_check(unsigned int flags)453 static void brip_final_check(unsigned int flags)
454 {
455 	if (!flags)
456 		xtables_error(PARAMETER_PROBLEM,
457 			      "You must specify proper arguments");
458 }
459 
print_port_range(uint16_t * ports)460 static void print_port_range(uint16_t *ports)
461 {
462 	if (ports[0] == ports[1])
463 		printf("%d ", ports[0]);
464 	else
465 		printf("%d:%d ", ports[0], ports[1]);
466 }
467 
brip_print(const void * ip,const struct xt_entry_match * match,int numeric)468 static void brip_print(const void *ip, const struct xt_entry_match *match,
469 		       int numeric)
470 {
471 	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
472 	struct in_addr *addrp, *maskp;
473 
474 	if (info->bitmask & EBT_IP_SOURCE) {
475 		printf("--ip-src ");
476 		if (info->invflags & EBT_IP_SOURCE)
477 			printf("! ");
478 		addrp = (struct in_addr *)&info->saddr;
479 		maskp = (struct in_addr *)&info->smsk;
480 		printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
481 		       xtables_ipmask_to_numeric(maskp));
482 	}
483 	if (info->bitmask & EBT_IP_DEST) {
484 		printf("--ip-dst ");
485 		if (info->invflags & EBT_IP_DEST)
486 			printf("! ");
487 		addrp = (struct in_addr *)&info->daddr;
488 		maskp = (struct in_addr *)&info->dmsk;
489 		printf("%s%s ", xtables_ipaddr_to_numeric(addrp),
490 		       xtables_ipmask_to_numeric(maskp));
491 	}
492 	if (info->bitmask & EBT_IP_TOS) {
493 		printf("--ip-tos ");
494 		if (info->invflags & EBT_IP_TOS)
495 			printf("! ");
496 		printf("0x%02X ", info->tos);
497 	}
498 	if (info->bitmask & EBT_IP_PROTO) {
499 		struct protoent *pe;
500 
501 		printf("--ip-proto ");
502 		if (info->invflags & EBT_IP_PROTO)
503 			printf("! ");
504 		pe = getprotobynumber(info->protocol);
505 		if (pe == NULL) {
506 			printf("%d ", info->protocol);
507 		} else {
508 			printf("%s ", pe->p_name);
509 		}
510 	}
511 	if (info->bitmask & EBT_IP_SPORT) {
512 		printf("--ip-sport ");
513 		if (info->invflags & EBT_IP_SPORT)
514 			printf("! ");
515 		print_port_range(info->sport);
516 	}
517 	if (info->bitmask & EBT_IP_DPORT) {
518 		printf("--ip-dport ");
519 		if (info->invflags & EBT_IP_DPORT)
520 			printf("! ");
521 		print_port_range(info->dport);
522 	}
523 	if (info->bitmask & EBT_IP_ICMP) {
524 		printf("--ip-icmp-type ");
525 		if (info->invflags & EBT_IP_ICMP)
526 			printf("! ");
527 		ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
528 				    info->icmp_type, info->icmp_code);
529 	}
530 	if (info->bitmask & EBT_IP_IGMP) {
531 		printf("--ip-igmp-type ");
532 		if (info->invflags & EBT_IP_IGMP)
533 			printf("! ");
534 		ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
535 				    info->igmp_type, NULL);
536 	}
537 }
538 
brip_xlate_proto_to_name(uint8_t proto)539 static const char *brip_xlate_proto_to_name(uint8_t proto)
540 {
541 	switch (proto) {
542 	case IPPROTO_TCP:
543 		return "tcp";
544 	case IPPROTO_UDP:
545 		return "udp";
546 	case IPPROTO_UDPLITE:
547 		return "udplite";
548 	case IPPROTO_SCTP:
549 		return "sctp";
550 	case IPPROTO_DCCP:
551 		return "dccp";
552 	default:
553 		return NULL;
554 	}
555 }
556 
brip_xlate_icmp(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)557 static void brip_xlate_icmp(struct xt_xlate *xl,
558 			    const struct ebt_ip_info *info, int bit)
559 {
560 	if ((info->bitmask & bit) == 0)
561 		return;
562 
563 	xt_xlate_add(xl, "icmp type ");
564 	if (info->invflags & bit)
565 		xt_xlate_add(xl, "!= ");
566 	if (info->icmp_type[0] == info->icmp_type[1])
567 		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
568 	else
569 		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
570 					   info->icmp_type[1]);
571 	if (info->icmp_code[0] == 0 &&
572 	    info->icmp_code[1] == 0xff)
573 		return;
574 
575 	xt_xlate_add(xl, "icmp code ");
576 	if (info->invflags & bit)
577 		xt_xlate_add(xl, "!= ");
578 	if (info->icmp_code[0] == info->icmp_code[1])
579 		xt_xlate_add(xl, "%d ", info->icmp_code[0]);
580 	else
581 		xt_xlate_add(xl, "%d-%d ", info->icmp_code[0],
582 					   info->icmp_code[1]);
583 }
584 
brip_xlate_igmp(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)585 static void brip_xlate_igmp(struct xt_xlate *xl,
586 			    const struct ebt_ip_info *info, int bit)
587 {
588 	if ((info->bitmask & bit) == 0)
589 		return;
590 
591 	xt_xlate_add(xl, "@th,0,8 ");
592 	if (info->invflags & bit)
593 		xt_xlate_add(xl, "!= ");
594 	if (info->icmp_type[0] == info->icmp_type[1])
595 		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
596 	else
597 		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
598 					   info->icmp_type[1]);
599 }
600 
brip_xlate_th(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit,const char * pname)601 static void brip_xlate_th(struct xt_xlate *xl,
602 			  const struct ebt_ip_info *info, int bit,
603 			  const char *pname)
604 {
605 	const uint16_t *ports;
606 
607 	if ((info->bitmask & bit) == 0)
608 		return;
609 
610 	switch (bit) {
611 	case EBT_IP_SPORT:
612 		if (pname)
613 			xt_xlate_add(xl, "%s sport ", pname);
614 		else
615 			xt_xlate_add(xl, "@th,0,16 ");
616 
617 		ports = info->sport;
618 		break;
619 	case EBT_IP_DPORT:
620 		if (pname)
621 			xt_xlate_add(xl, "%s dport ", pname);
622 		else
623 			xt_xlate_add(xl, "@th,16,16 ");
624 
625 		ports = info->dport;
626 		break;
627 	default:
628 		return;
629 	}
630 
631 	if (info->invflags & bit)
632 		xt_xlate_add(xl, "!= ");
633 
634 	if (ports[0] == ports[1])
635 		xt_xlate_add(xl, "%d ", ports[0]);
636 	else
637 		xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
638 }
639 
brip_xlate_nh(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)640 static void brip_xlate_nh(struct xt_xlate *xl,
641 			  const struct ebt_ip_info *info, int bit)
642 {
643 	struct in_addr *addrp, *maskp;
644 
645 	if ((info->bitmask & bit) == 0)
646 		return;
647 
648 	switch (bit) {
649 	case EBT_IP_SOURCE:
650 		xt_xlate_add(xl, "ip saddr ");
651 		addrp = (struct in_addr *)&info->saddr;
652 		maskp = (struct in_addr *)&info->smsk;
653 		break;
654 	case EBT_IP_DEST:
655 		xt_xlate_add(xl, "ip daddr ");
656 		addrp = (struct in_addr *)&info->daddr;
657 		maskp = (struct in_addr *)&info->dmsk;
658 		break;
659 	default:
660 		return;
661 	}
662 
663 	if (info->invflags & bit)
664 		xt_xlate_add(xl, "!= ");
665 
666 	xt_xlate_add(xl, "%s%s ", xtables_ipaddr_to_numeric(addrp),
667 				  xtables_ipmask_to_numeric(maskp));
668 }
669 
brip_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)670 static int brip_xlate(struct xt_xlate *xl,
671 		      const struct xt_xlate_mt_params *params)
672 {
673 	const struct ebt_ip_info *info = (const void *)params->match->data;
674 	const char *pname = NULL;
675 
676 	brip_xlate_nh(xl, info, EBT_IP_SOURCE);
677 	brip_xlate_nh(xl, info, EBT_IP_DEST);
678 
679 	if (info->bitmask & EBT_IP_TOS) {
680 		xt_xlate_add(xl, "ip dscp ");
681 		if (info->invflags & EBT_IP_TOS)
682 			xt_xlate_add(xl, "!= ");
683 		xt_xlate_add(xl, "0x%02x ", info->tos & 0x3f); /* remove ECN bits */
684 	}
685 	if (info->bitmask & EBT_IP_PROTO) {
686 		struct protoent *pe;
687 
688 		if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT|EBT_IP_ICMP) &&
689 		    (info->invflags & EBT_IP_PROTO) == 0) {
690 			/* port number or icmp given and not inverted, no need to print this */
691 			pname = brip_xlate_proto_to_name(info->protocol);
692 		} else {
693 			xt_xlate_add(xl, "ip protocol ");
694 			if (info->invflags & EBT_IP_PROTO)
695 				xt_xlate_add(xl, "!= ");
696 			pe = getprotobynumber(info->protocol);
697 			if (pe == NULL)
698 				xt_xlate_add(xl, "%d ", info->protocol);
699 			else
700 				xt_xlate_add(xl, "%s ", pe->p_name);
701 		}
702 	}
703 
704 	brip_xlate_th(xl, info, EBT_IP_SPORT, pname);
705 	brip_xlate_th(xl, info, EBT_IP_DPORT, pname);
706 
707 	brip_xlate_icmp(xl, info, EBT_IP_ICMP);
708 	brip_xlate_igmp(xl, info, EBT_IP_IGMP);
709 
710 	return 1;
711 }
712 
713 static struct xtables_match brip_match = {
714 	.name		= "ip",
715 	.revision	= 0,
716 	.version	= XTABLES_VERSION,
717 	.family		= NFPROTO_BRIDGE,
718 	.size		= XT_ALIGN(sizeof(struct ebt_ip_info)),
719 	.userspacesize	= XT_ALIGN(sizeof(struct ebt_ip_info)),
720 	.init		= brip_init,
721 	.help		= brip_print_help,
722 	.parse		= brip_parse,
723 	.final_check	= brip_final_check,
724 	.print		= brip_print,
725 	.xlate		= brip_xlate,
726 	.extra_opts	= brip_opts,
727 };
728 
_init(void)729 void _init(void)
730 {
731 	xtables_register_match(&brip_match);
732 }
733