• 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 <netdb.h>
20 #include <inttypes.h>
21 #include <xtables.h>
22 #include <linux/netfilter_bridge/ebt_ip.h>
23 
24 #include "libxt_icmp.h"
25 
26 /* must correspond to the bit position in EBT_IP6_* defines */
27 enum {
28 	O_SOURCE = 0,
29 	O_DEST,
30 	O_TOS,
31 	O_PROTO,
32 	O_SPORT,
33 	O_DPORT,
34 	O_ICMP,
35 	O_IGMP,
36 	F_PORT = 1 << O_ICMP | 1 << O_IGMP,
37 	F_ICMP = 1 << O_SPORT | 1 << O_DPORT | 1 << O_IGMP,
38 	F_IGMP = 1 << O_SPORT | 1 << O_DPORT | 1 << O_ICMP,
39 };
40 
41 static const struct xt_option_entry brip_opts[] = {
42 	{ .name = "ip-source",		.id = O_SOURCE, .type = XTTYPE_HOSTMASK,
43 	  .flags = XTOPT_INVERT },
44 	{ .name = "ip-src",		.id = O_SOURCE, .type = XTTYPE_HOSTMASK,
45 	  .flags = XTOPT_INVERT },
46 	{ .name = "ip-destination",	.id = O_DEST, .type = XTTYPE_HOSTMASK,
47 	  .flags = XTOPT_INVERT },
48 	{ .name = "ip-dst",		.id = O_DEST, .type = XTTYPE_HOSTMASK,
49 	  .flags = XTOPT_INVERT },
50 	{ .name = "ip-tos",		.id = O_TOS, .type = XTTYPE_UINT8,
51 	  .flags = XTOPT_INVERT | XTOPT_PUT,
52 	  XTOPT_POINTER(struct ebt_ip_info, tos) },
53 	{ .name = "ip-protocol",	.id = O_PROTO, .type = XTTYPE_PROTOCOL,
54 	  .flags = XTOPT_INVERT | XTOPT_PUT,
55 	  XTOPT_POINTER(struct ebt_ip_info, protocol) },
56 	{ .name = "ip-proto",		.id = O_PROTO, .type = XTTYPE_PROTOCOL,
57 	  .flags = XTOPT_INVERT | XTOPT_PUT,
58 	  XTOPT_POINTER(struct ebt_ip_info, protocol) },
59 	{ .name = "ip-source-port",	.id = O_SPORT, .type = XTTYPE_PORTRC,
60 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
61 	  XTOPT_POINTER(struct ebt_ip_info, sport) },
62 	{ .name = "ip-sport",		.id = O_SPORT, .type = XTTYPE_PORTRC,
63 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
64 	  XTOPT_POINTER(struct ebt_ip_info, sport) },
65 	{ .name = "ip-destination-port",.id = O_DPORT, .type = XTTYPE_PORTRC,
66 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
67 	  XTOPT_POINTER(struct ebt_ip_info, dport) },
68 	{ .name = "ip-dport",		.id = O_DPORT, .type = XTTYPE_PORTRC,
69 	  .excl = F_PORT, .flags = XTOPT_INVERT | XTOPT_PUT,
70 	  XTOPT_POINTER(struct ebt_ip_info, dport) },
71 	{ .name = "ip-icmp-type",       .id = O_ICMP, .type = XTTYPE_STRING,
72 	  .excl = F_ICMP, .flags = XTOPT_INVERT },
73 	{ .name = "ip-igmp-type",       .id = O_IGMP, .type = XTTYPE_STRING,
74 	  .excl = F_IGMP, .flags = XTOPT_INVERT },
75 	XTOPT_TABLEEND,
76 };
77 
brip_print_help(void)78 static void brip_print_help(void)
79 {
80 	printf(
81 "ip options:\n"
82 "[!] --ip-src    address[/mask]: ip source specification\n"
83 "[!] --ip-dst    address[/mask]: ip destination specification\n"
84 "[!] --ip-tos    tos           : ip tos specification\n"
85 "[!] --ip-proto  protocol      : ip protocol specification\n"
86 "[!] --ip-sport  port[:port]   : tcp/udp source port or port range\n"
87 "[!] --ip-dport  port[:port]   : tcp/udp destination port or port range\n"
88 "[!] --ip-icmp-type type[[:type]/code[:code]] : icmp type/code or type/code range\n"
89 "[!] --ip-igmp-type type[:type]               : igmp type or type range\n");
90 
91 	printf("\nValid ICMP Types:\n");
92 	xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
93 	printf("\nValid IGMP Types:\n");
94 	xt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
95 }
96 
97 /* original code from ebtables: useful_functions.c */
print_icmp_code(uint8_t * code)98 static void print_icmp_code(uint8_t *code)
99 {
100 	if (!code)
101 		return;
102 
103 	if (code[0] == code[1])
104 		printf("/%"PRIu8 " ", code[0]);
105 	else
106 		printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
107 }
108 
ebt_print_icmp_type(const struct xt_icmp_names * codes,size_t n_codes,uint8_t * type,uint8_t * code)109 static void ebt_print_icmp_type(const struct xt_icmp_names *codes,
110 				size_t n_codes, uint8_t *type, uint8_t *code)
111 {
112 	unsigned int i;
113 
114 	if (type[0] != type[1]) {
115 		printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
116 		print_icmp_code(code);
117 		return;
118 	}
119 
120 	for (i = 0; i < n_codes; i++) {
121 		if (codes[i].type != type[0])
122 			continue;
123 
124 		if (!code || (codes[i].code_min == code[0] &&
125 			      codes[i].code_max == code[1])) {
126 			printf("%s ", codes[i].name);
127 			return;
128 		}
129 	}
130 	printf("%"PRIu8, type[0]);
131 	print_icmp_code(code);
132 }
133 
brip_parse(struct xt_option_call * cb)134 static void brip_parse(struct xt_option_call *cb)
135 {
136 	struct ebt_ip_info *info = cb->data;
137 
138 	xtables_option_parse(cb);
139 
140 	info->bitmask |= 1 << cb->entry->id;
141 	info->invflags |= cb->invert ? 1 << cb->entry->id : 0;
142 
143 	switch (cb->entry->id) {
144 	case O_SOURCE:
145 		cb->val.haddr.all[0] &= cb->val.hmask.all[0];
146 		info->saddr = cb->val.haddr.ip;
147 		info->smsk = cb->val.hmask.ip;
148 		break;
149 	case O_DEST:
150 		cb->val.haddr.all[0] &= cb->val.hmask.all[0];
151 		info->daddr = cb->val.haddr.ip;
152 		info->dmsk = cb->val.hmask.ip;
153 		break;
154 	case O_ICMP:
155 		ebt_parse_icmp(cb->arg, info->icmp_type, info->icmp_code);
156 		break;
157 	case O_IGMP:
158 		ebt_parse_igmp(cb->arg, info->igmp_type);
159 		break;
160 	}
161 }
162 
brip_final_check(struct xt_fcheck_call * fc)163 static void brip_final_check(struct xt_fcheck_call *fc)
164 {
165 	if (!fc->xflags)
166 		xtables_error(PARAMETER_PROBLEM,
167 			      "You must specify proper arguments");
168 }
169 
print_port_range(uint16_t * ports)170 static void print_port_range(uint16_t *ports)
171 {
172 	if (ports[0] == ports[1])
173 		printf("%d ", ports[0]);
174 	else
175 		printf("%d:%d ", ports[0], ports[1]);
176 }
177 
brip_print(const void * ip,const struct xt_entry_match * match,int numeric)178 static void brip_print(const void *ip, const struct xt_entry_match *match,
179 		       int numeric)
180 {
181 	struct ebt_ip_info *info = (struct ebt_ip_info *)match->data;
182 	struct in_addr *addrp, *maskp;
183 
184 	if (info->bitmask & EBT_IP_SOURCE) {
185 		if (info->invflags & EBT_IP_SOURCE)
186 			printf("! ");
187 		addrp = (struct in_addr *)&info->saddr;
188 		maskp = (struct in_addr *)&info->smsk;
189 		printf("--ip-src %s%s ",
190 		       xtables_ipaddr_to_numeric(addrp),
191 		       xtables_ipmask_to_numeric(maskp));
192 	}
193 	if (info->bitmask & EBT_IP_DEST) {
194 		if (info->invflags & EBT_IP_DEST)
195 			printf("! ");
196 		addrp = (struct in_addr *)&info->daddr;
197 		maskp = (struct in_addr *)&info->dmsk;
198 		printf("--ip-dst %s%s ",
199 		       xtables_ipaddr_to_numeric(addrp),
200 		       xtables_ipmask_to_numeric(maskp));
201 	}
202 	if (info->bitmask & EBT_IP_TOS) {
203 		if (info->invflags & EBT_IP_TOS)
204 			printf("! ");
205 		printf("--ip-tos 0x%02X ", info->tos);
206 	}
207 	if (info->bitmask & EBT_IP_PROTO) {
208 		struct protoent *pe;
209 
210 		if (info->invflags & EBT_IP_PROTO)
211 			printf("! ");
212 		printf("--ip-proto ");
213 		pe = getprotobynumber(info->protocol);
214 		if (pe == NULL) {
215 			printf("%d ", info->protocol);
216 		} else {
217 			printf("%s ", pe->p_name);
218 		}
219 	}
220 	if (info->bitmask & EBT_IP_SPORT) {
221 		if (info->invflags & EBT_IP_SPORT)
222 			printf("! ");
223 		printf("--ip-sport ");
224 		print_port_range(info->sport);
225 	}
226 	if (info->bitmask & EBT_IP_DPORT) {
227 		if (info->invflags & EBT_IP_DPORT)
228 			printf("! ");
229 		printf("--ip-dport ");
230 		print_port_range(info->dport);
231 	}
232 	if (info->bitmask & EBT_IP_ICMP) {
233 		if (info->invflags & EBT_IP_ICMP)
234 			printf("! ");
235 		printf("--ip-icmp-type ");
236 		ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
237 				    info->icmp_type, info->icmp_code);
238 	}
239 	if (info->bitmask & EBT_IP_IGMP) {
240 		if (info->invflags & EBT_IP_IGMP)
241 			printf("! ");
242 		printf("--ip-igmp-type ");
243 		ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
244 				    info->igmp_type, NULL);
245 	}
246 }
247 
brip_xlate_proto_to_name(uint8_t proto)248 static const char *brip_xlate_proto_to_name(uint8_t proto)
249 {
250 	switch (proto) {
251 	case IPPROTO_TCP:
252 		return "tcp";
253 	case IPPROTO_UDP:
254 		return "udp";
255 	case IPPROTO_UDPLITE:
256 		return "udplite";
257 	case IPPROTO_SCTP:
258 		return "sctp";
259 	case IPPROTO_DCCP:
260 		return "dccp";
261 	default:
262 		return NULL;
263 	}
264 }
265 
brip_xlate_icmp(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)266 static void brip_xlate_icmp(struct xt_xlate *xl,
267 			    const struct ebt_ip_info *info, int bit)
268 {
269 	if ((info->bitmask & bit) == 0)
270 		return;
271 
272 	xt_xlate_add(xl, "icmp type ");
273 	if (info->invflags & bit)
274 		xt_xlate_add(xl, "!= ");
275 	if (info->icmp_type[0] == info->icmp_type[1])
276 		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
277 	else
278 		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
279 					   info->icmp_type[1]);
280 	if (info->icmp_code[0] == 0 &&
281 	    info->icmp_code[1] == 0xff)
282 		return;
283 
284 	xt_xlate_add(xl, "icmp code ");
285 	if (info->invflags & bit)
286 		xt_xlate_add(xl, "!= ");
287 	if (info->icmp_code[0] == info->icmp_code[1])
288 		xt_xlate_add(xl, "%d ", info->icmp_code[0]);
289 	else
290 		xt_xlate_add(xl, "%d-%d ", info->icmp_code[0],
291 					   info->icmp_code[1]);
292 }
293 
brip_xlate_igmp(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)294 static void brip_xlate_igmp(struct xt_xlate *xl,
295 			    const struct ebt_ip_info *info, int bit)
296 {
297 	if ((info->bitmask & bit) == 0)
298 		return;
299 
300 	xt_xlate_add(xl, "@th,0,8 ");
301 	if (info->invflags & bit)
302 		xt_xlate_add(xl, "!= ");
303 	if (info->icmp_type[0] == info->icmp_type[1])
304 		xt_xlate_add(xl, "%d ", info->icmp_type[0]);
305 	else
306 		xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
307 					   info->icmp_type[1]);
308 }
309 
brip_xlate_th(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit,const char * pname)310 static void brip_xlate_th(struct xt_xlate *xl,
311 			  const struct ebt_ip_info *info, int bit,
312 			  const char *pname)
313 {
314 	const uint16_t *ports;
315 
316 	if ((info->bitmask & bit) == 0)
317 		return;
318 
319 	switch (bit) {
320 	case EBT_IP_SPORT:
321 		if (pname)
322 			xt_xlate_add(xl, "%s sport ", pname);
323 		else
324 			xt_xlate_add(xl, "@th,0,16 ");
325 
326 		ports = info->sport;
327 		break;
328 	case EBT_IP_DPORT:
329 		if (pname)
330 			xt_xlate_add(xl, "%s dport ", pname);
331 		else
332 			xt_xlate_add(xl, "@th,16,16 ");
333 
334 		ports = info->dport;
335 		break;
336 	default:
337 		return;
338 	}
339 
340 	if (info->invflags & bit)
341 		xt_xlate_add(xl, "!= ");
342 
343 	if (ports[0] == ports[1])
344 		xt_xlate_add(xl, "%d ", ports[0]);
345 	else
346 		xt_xlate_add(xl, "%d-%d ", ports[0], ports[1]);
347 }
348 
brip_xlate_nh(struct xt_xlate * xl,const struct ebt_ip_info * info,int bit)349 static void brip_xlate_nh(struct xt_xlate *xl,
350 			  const struct ebt_ip_info *info, int bit)
351 {
352 	struct in_addr *addrp, *maskp;
353 
354 	if ((info->bitmask & bit) == 0)
355 		return;
356 
357 	switch (bit) {
358 	case EBT_IP_SOURCE:
359 		xt_xlate_add(xl, "ip saddr ");
360 		addrp = (struct in_addr *)&info->saddr;
361 		maskp = (struct in_addr *)&info->smsk;
362 		break;
363 	case EBT_IP_DEST:
364 		xt_xlate_add(xl, "ip daddr ");
365 		addrp = (struct in_addr *)&info->daddr;
366 		maskp = (struct in_addr *)&info->dmsk;
367 		break;
368 	default:
369 		return;
370 	}
371 
372 	if (info->invflags & bit)
373 		xt_xlate_add(xl, "!= ");
374 
375 	xt_xlate_add(xl, "%s%s ", xtables_ipaddr_to_numeric(addrp),
376 				  xtables_ipmask_to_numeric(maskp));
377 }
378 
may_skip_ether_type_dep(uint8_t flags)379 static bool may_skip_ether_type_dep(uint8_t flags)
380 {
381 	/* these convert to "ip (s|d)addr" matches */
382 	if (flags & (EBT_IP_SOURCE | EBT_IP_DEST))
383 		return true;
384 
385 	/* icmp match triggers implicit ether type dependency in nft */
386 	if (flags & EBT_IP_ICMP)
387 		return true;
388 
389 	/* allow if "ip protocol" match is created by brip_xlate() */
390 	if (flags & EBT_IP_PROTO &&
391 	    !(flags & (EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP)))
392 		return true;
393 
394 	return false;
395 }
396 
brip_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)397 static int brip_xlate(struct xt_xlate *xl,
398 		      const struct xt_xlate_mt_params *params)
399 {
400 	const struct ebt_ip_info *info = (const void *)params->match->data;
401 	const char *pname = NULL;
402 
403 	brip_xlate_nh(xl, info, EBT_IP_SOURCE);
404 	brip_xlate_nh(xl, info, EBT_IP_DEST);
405 
406 	if (!may_skip_ether_type_dep(info->bitmask))
407 		xt_xlate_add(xl, "ether type ip ");
408 
409 	if (info->bitmask & EBT_IP_TOS) {
410 		xt_xlate_add(xl, "@nh,8,8 ");
411 		if (info->invflags & EBT_IP_TOS)
412 			xt_xlate_add(xl, "!= ");
413 		xt_xlate_add(xl, "0x%02x ", info->tos);
414 	}
415 	if (info->bitmask & EBT_IP_PROTO) {
416 		struct protoent *pe;
417 
418 		if (info->bitmask & (EBT_IP_SPORT|EBT_IP_DPORT|EBT_IP_ICMP) &&
419 		    (info->invflags & EBT_IP_PROTO) == 0) {
420 			/* port number or icmp given and not inverted, no need to print this */
421 			pname = brip_xlate_proto_to_name(info->protocol);
422 		} else {
423 			xt_xlate_add(xl, "ip protocol ");
424 			if (info->invflags & EBT_IP_PROTO)
425 				xt_xlate_add(xl, "!= ");
426 			pe = getprotobynumber(info->protocol);
427 			if (pe == NULL)
428 				xt_xlate_add(xl, "%d ", info->protocol);
429 			else
430 				xt_xlate_add(xl, "%s ", pe->p_name);
431 		}
432 	}
433 
434 	brip_xlate_th(xl, info, EBT_IP_SPORT, pname);
435 	brip_xlate_th(xl, info, EBT_IP_DPORT, pname);
436 
437 	brip_xlate_icmp(xl, info, EBT_IP_ICMP);
438 	brip_xlate_igmp(xl, info, EBT_IP_IGMP);
439 
440 	return 1;
441 }
442 
443 static struct xtables_match brip_match = {
444 	.name		= "ip",
445 	.revision	= 0,
446 	.version	= XTABLES_VERSION,
447 	.family		= NFPROTO_BRIDGE,
448 	.size		= XT_ALIGN(sizeof(struct ebt_ip_info)),
449 	.userspacesize	= XT_ALIGN(sizeof(struct ebt_ip_info)),
450 	.help		= brip_print_help,
451 	.x6_parse	= brip_parse,
452 	.x6_fcheck	= brip_final_check,
453 	.print		= brip_print,
454 	.xlate		= brip_xlate,
455 	.x6_options	= brip_opts,
456 };
457 
_init(void)458 void _init(void)
459 {
460 	xtables_register_match(&brip_match);
461 }
462