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