summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFlorian Westphal <fw@strlen.de>2018-04-18 00:09:06 +0200
committerFlorian Westphal <fw@strlen.de>2018-04-19 10:18:22 +0200
commitb6f0bec11e2cc7c3f99d432a5e1204a855f361dd (patch)
tree50c34dd8ee1c1da3e5401555739e4657a1c36e62
parentf38ed1e59f8d3b62e322563401cabc6dbac5fca5 (diff)
libebt_ip: add icmp support
Was added to ebtables recently, so backport this to ebt-compat. Signed-off-by: Florian Westphal <fw@strlen.de>
-rw-r--r--extensions/libebt_ip.c297
-rw-r--r--extensions/libebt_ip.txlate9
2 files changed, 304 insertions, 2 deletions
diff --git a/extensions/libebt_ip.c b/extensions/libebt_ip.c
index 1a87585c..72728542 100644
--- a/extensions/libebt_ip.c
+++ b/extensions/libebt_ip.c
@@ -18,8 +18,41 @@
#include <string.h>
#include <getopt.h>
#include <netdb.h>
+#include <inttypes.h>
#include <xtables.h>
-#include <linux/netfilter_bridge/ebt_ip.h>
+
+#include "libxt_icmp.h"
+
+#define EBT_IP_SOURCE 0x01
+#define EBT_IP_DEST 0x02
+#define EBT_IP_TOS 0x04
+#define EBT_IP_PROTO 0x08
+#define EBT_IP_SPORT 0x10
+#define EBT_IP_DPORT 0x20
+#define EBT_IP_ICMP 0x40
+#define EBT_IP_IGMP 0x80
+#define EBT_IP_MASK (EBT_IP_SOURCE | EBT_IP_DEST | EBT_IP_TOS | EBT_IP_PROTO |\
+ EBT_IP_SPORT | EBT_IP_DPORT | EBT_IP_ICMP | EBT_IP_IGMP)
+
+struct ebt_ip_info {
+ __be32 saddr;
+ __be32 daddr;
+ __be32 smsk;
+ __be32 dmsk;
+ __u8 tos;
+ __u8 protocol;
+ __u8 bitmask;
+ __u8 invflags;
+ union {
+ __u16 sport[2];
+ __u8 icmp_type[2];
+ __u8 igmp_type[2];
+ };
+ union {
+ __u16 dport[2];
+ __u8 icmp_code[2];
+ };
+};
#define IP_SOURCE '1'
#define IP_DEST '2'
@@ -27,6 +60,8 @@
#define IP_PROTO '4'
#define IP_SPORT '5'
#define IP_DPORT '6'
+#define IP_EBT_ICMP '7'
+#define IP_EBT_IGMP '8'
static const struct option brip_opts[] = {
{ .name = "ip-source", .has_arg = true, .val = IP_SOURCE },
@@ -40,9 +75,73 @@ static const struct option brip_opts[] = {
{ .name = "ip-sport", .has_arg = true, .val = IP_SPORT },
{ .name = "ip-destination-port",.has_arg = true, .val = IP_DPORT },
{ .name = "ip-dport", .has_arg = true, .val = IP_DPORT },
+ { .name = "ip-icmp-type", .has_arg = true, .val = IP_EBT_ICMP },
+ { .name = "ip-igmp-type", .has_arg = true, .val = IP_EBT_IGMP },
XT_GETOPT_TABLEEND,
};
+static const struct xt_icmp_names icmp_codes[] = {
+ { "echo-reply", 0, 0, 0xFF },
+ /* Alias */ { "pong", 0, 0, 0xFF },
+
+ { "destination-unreachable", 3, 0, 0xFF },
+ { "network-unreachable", 3, 0, 0 },
+ { "host-unreachable", 3, 1, 1 },
+ { "protocol-unreachable", 3, 2, 2 },
+ { "port-unreachable", 3, 3, 3 },
+ { "fragmentation-needed", 3, 4, 4 },
+ { "source-route-failed", 3, 5, 5 },
+ { "network-unknown", 3, 6, 6 },
+ { "host-unknown", 3, 7, 7 },
+ { "network-prohibited", 3, 9, 9 },
+ { "host-prohibited", 3, 10, 10 },
+ { "TOS-network-unreachable", 3, 11, 11 },
+ { "TOS-host-unreachable", 3, 12, 12 },
+ { "communication-prohibited", 3, 13, 13 },
+ { "host-precedence-violation", 3, 14, 14 },
+ { "precedence-cutoff", 3, 15, 15 },
+
+ { "source-quench", 4, 0, 0xFF },
+
+ { "redirect", 5, 0, 0xFF },
+ { "network-redirect", 5, 0, 0 },
+ { "host-redirect", 5, 1, 1 },
+ { "TOS-network-redirect", 5, 2, 2 },
+ { "TOS-host-redirect", 5, 3, 3 },
+
+ { "echo-request", 8, 0, 0xFF },
+ /* Alias */ { "ping", 8, 0, 0xFF },
+
+ { "router-advertisement", 9, 0, 0xFF },
+
+ { "router-solicitation", 10, 0, 0xFF },
+
+ { "time-exceeded", 11, 0, 0xFF },
+ /* Alias */ { "ttl-exceeded", 11, 0, 0xFF },
+ { "ttl-zero-during-transit", 11, 0, 0 },
+ { "ttl-zero-during-reassembly", 11, 1, 1 },
+
+ { "parameter-problem", 12, 0, 0xFF },
+ { "ip-header-bad", 12, 0, 0 },
+ { "required-option-missing", 12, 1, 1 },
+
+ { "timestamp-request", 13, 0, 0xFF },
+
+ { "timestamp-reply", 14, 0, 0xFF },
+
+ { "address-mask-request", 17, 0, 0xFF },
+
+ { "address-mask-reply", 18, 0, 0xFF }
+};
+
+static const struct xt_icmp_names igmp_types[] = {
+ { "membership-query", 0x11 },
+ { "membership-report-v1", 0x12 },
+ { "membership-report-v2", 0x16 },
+ { "leave-group", 0x17 },
+ { "membership-report-v3", 0x22 },
+};
+
static void brip_print_help(void)
{
printf(
@@ -52,7 +151,14 @@ static void brip_print_help(void)
"--ip-tos [!] tos : ip tos specification\n"
"--ip-proto [!] protocol : ip protocol specification\n"
"--ip-sport [!] port[:port] : tcp/udp source port or port range\n"
-"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n");
+"--ip-dport [!] port[:port] : tcp/udp destination port or port range\n"
+"--ip-icmp-type [!] type[[:type]/code[:code]] : icmp type/code or type/code range\n"
+"--ip-igmp-type [!] type[:type] : igmp type or type range\n");
+
+ printf("\nValid ICMP Types:\n");
+ xt_print_icmp_types(icmp_codes, ARRAY_SIZE(icmp_codes));
+ printf("\nValid IGMP Types:\n");
+ xt_print_icmp_types(igmp_types, ARRAY_SIZE(igmp_types));
}
static void brip_init(struct xt_entry_match *match)
@@ -161,6 +267,118 @@ static void ebt_parse_ip_address(char *address, uint32_t *addr, uint32_t *msk)
*addr = *addr & *msk;
}
+static char *parse_range(const char *str, unsigned int res[])
+{
+ char *next;
+
+ if (!xtables_strtoui(str, &next, &res[0], 0, 255))
+ return NULL;
+
+ res[1] = res[0];
+ if (*next == ':') {
+ str = next + 1;
+ if (!xtables_strtoui(str, &next, &res[1], 0, 255))
+ return NULL;
+ }
+
+ return next;
+}
+
+static int ebt_parse_icmp(const struct xt_icmp_names *codes, size_t n_codes,
+ const char *icmptype, uint8_t type[], uint8_t code[])
+{
+ unsigned int match = n_codes;
+ unsigned int i, number[2];
+
+ for (i = 0; i < n_codes; i++) {
+ if (strncasecmp(codes[i].name, icmptype, strlen(icmptype)))
+ continue;
+ if (match != n_codes)
+ xtables_error(PARAMETER_PROBLEM, "Ambiguous ICMP type `%s':"
+ " `%s' or `%s'?",
+ icmptype, codes[match].name,
+ codes[i].name);
+ match = i;
+ }
+
+ if (match < n_codes) {
+ type[0] = type[1] = codes[match].type;
+ if (code) {
+ code[0] = codes[match].code_min;
+ code[1] = codes[match].code_max;
+ }
+ } else {
+ char *next = parse_range(icmptype, number);
+ if (!next) {
+ xtables_error(PARAMETER_PROBLEM, "Unknown ICMP type `%s'",
+ icmptype);
+ return -1;
+ }
+
+ type[0] = (uint8_t) number[0];
+ type[1] = (uint8_t) number[1];
+ switch (*next) {
+ case 0:
+ if (code) {
+ code[0] = 0;
+ code[1] = 255;
+ }
+ return 0;
+ case '/':
+ if (code) {
+ next = parse_range(next+1, number);
+ code[0] = (uint8_t) number[0];
+ code[1] = (uint8_t) number[1];
+ if (next == NULL)
+ return -1;
+ if (next && *next == 0)
+ return 0;
+ }
+ /* fallthrough */
+ default:
+ xtables_error(PARAMETER_PROBLEM, "unknown character %c", *next);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static void print_icmp_code(uint8_t *code)
+{
+ if (!code)
+ return;
+
+ if (code[0] == code[1])
+ printf("/%"PRIu8 " ", code[0]);
+ else
+ printf("/%"PRIu8":%"PRIu8 " ", code[0], code[1]);
+}
+
+static void ebt_print_icmp_type(const struct xt_icmp_names *codes,
+ size_t n_codes, uint8_t *type, uint8_t *code)
+{
+ unsigned int i;
+
+ if (type[0] != type[1]) {
+ printf("%"PRIu8 ":%" PRIu8, type[0], type[1]);
+ print_icmp_code(code);
+ return;
+ }
+
+ for (i = 0; i < n_codes; i++) {
+ if (codes[i].type != type[0])
+ continue;
+
+ if (!code || (codes[i].code_min == code[0] &&
+ codes[i].code_max == code[1])) {
+ printf("%s ", codes[i].name);
+ return;
+ }
+ }
+ printf("%"PRIu8, type[0]);
+ print_icmp_code(code);
+}
+
static int
brip_parse(int c, char **argv, int invert, unsigned int *flags,
const void *entry, struct xt_entry_match **match)
@@ -192,6 +410,20 @@ brip_parse(int c, char **argv, int invert, unsigned int *flags,
parse_port_range(NULL, optarg, info->dport);
info->bitmask |= EBT_IP_DPORT;
break;
+ case IP_EBT_ICMP:
+ if (invert)
+ info->invflags |= EBT_IP_ICMP;
+ ebt_parse_icmp(icmp_codes, ARRAY_SIZE(icmp_codes), optarg,
+ info->icmp_type, info->icmp_code);
+ info->bitmask |= EBT_IP_ICMP;
+ break;
+ case IP_EBT_IGMP:
+ if (invert)
+ info->invflags |= EBT_IP_IGMP;
+ ebt_parse_icmp(igmp_types, ARRAY_SIZE(igmp_types), optarg,
+ info->igmp_type, NULL);
+ info->bitmask |= EBT_IP_IGMP;
+ break;
case IP_EBT_TOS:
if (invert)
info->invflags |= EBT_IP_TOS;
@@ -289,6 +521,20 @@ static void brip_print(const void *ip, const struct xt_entry_match *match,
printf("! ");
print_port_range(info->dport);
}
+ if (info->bitmask & EBT_IP_ICMP) {
+ printf("--ip-icmp-type ");
+ if (info->invflags & EBT_IP_ICMP)
+ printf("! ");
+ ebt_print_icmp_type(icmp_codes, ARRAY_SIZE(icmp_codes),
+ info->icmp_type, info->icmp_code);
+ }
+ if (info->bitmask & EBT_IP_IGMP) {
+ printf("--ip-igmp-type ");
+ if (info->invflags & EBT_IP_IGMP)
+ printf("! ");
+ ebt_print_icmp_type(igmp_types, ARRAY_SIZE(igmp_types),
+ info->igmp_type, NULL);
+ }
}
static const char *brip_xlate_proto_to_name(uint8_t proto)
@@ -309,6 +555,50 @@ static const char *brip_xlate_proto_to_name(uint8_t proto)
}
}
+static void brip_xlate_icmp(struct xt_xlate *xl,
+ const struct ebt_ip_info *info, int bit)
+{
+ if ((info->bitmask & bit) == 0)
+ return;
+
+ xt_xlate_add(xl, "ip icmp type ");
+ if (info->invflags & bit)
+ xt_xlate_add(xl, "!= ");
+ if (info->icmp_type[0] == info->icmp_type[1])
+ xt_xlate_add(xl, "%d ", info->icmp_type[0]);
+ else
+ xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
+ info->icmp_type[1]);
+ if (info->icmp_code[0] == 0 &&
+ info->icmp_code[1] == 0xff)
+ return;
+
+ xt_xlate_add(xl, "ip icmp code ");
+ if (info->invflags & bit)
+ xt_xlate_add(xl, "!= ");
+ if (info->icmp_code[0] == info->icmp_code[1])
+ xt_xlate_add(xl, "%d ", info->icmp_code[0]);
+ else
+ xt_xlate_add(xl, "%d-%d ", info->icmp_code[0],
+ info->icmp_code[1]);
+}
+
+static void brip_xlate_igmp(struct xt_xlate *xl,
+ const struct ebt_ip_info *info, int bit)
+{
+ if ((info->bitmask & bit) == 0)
+ return;
+
+ xt_xlate_add(xl, "@th,0,8 ");
+ if (info->invflags & bit)
+ xt_xlate_add(xl, "!= ");
+ if (info->icmp_type[0] == info->icmp_type[1])
+ xt_xlate_add(xl, "%d ", info->icmp_type[0]);
+ else
+ xt_xlate_add(xl, "%d-%d ", info->icmp_type[0],
+ info->icmp_type[1]);
+}
+
static void brip_xlate_th(struct xt_xlate *xl,
const struct ebt_ip_info *info, int bit,
const char *pname)
@@ -415,6 +705,9 @@ static int brip_xlate(struct xt_xlate *xl,
brip_xlate_th(xl, info, EBT_IP_SPORT, pname);
brip_xlate_th(xl, info, EBT_IP_DPORT, pname);
+ brip_xlate_icmp(xl, info, EBT_IP_ICMP);
+ brip_xlate_igmp(xl, info, EBT_IP_IGMP);
+
return 1;
}
diff --git a/extensions/libebt_ip.txlate b/extensions/libebt_ip.txlate
index 4d31a700..11594cdc 100644
--- a/extensions/libebt_ip.txlate
+++ b/extensions/libebt_ip.txlate
@@ -15,3 +15,12 @@ nft add rule bridge filter FORWARD udp sport 1024-65535 counter
ebtables-translate -A FORWARD --ip-proto 253
nft add rule bridge filter FORWARD ip protocol 253 counter
+
+ebtables-translate -A FORWARD --ip-icmp-type "echo-request"
+nft add rule bridge filter FORWARD ip icmp type 8 counter
+
+ebtables-translate -A FORWARD --ip-icmp-type 1/1
+nft add rule bridge filter FORWARD ip icmp type 1 ip icmp code 1 counter
+
+ebtables-translate -A FORWARD --ip-icmp-type ! 1:10
+nft add rule bridge filter FORWARD ip icmp type != 1-10 counter