|
Packit |
7b22a4 |
/*
|
|
Packit |
7b22a4 |
* (C) 2014 by Giuseppe Longo <giuseppelng@gmail.com>
|
|
Packit |
7b22a4 |
*
|
|
Packit |
7b22a4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
7b22a4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
7b22a4 |
* the Free Software Foundation; either version 2 of the License, or
|
|
Packit |
7b22a4 |
* (at your option) any later version.
|
|
Packit |
7b22a4 |
*/
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
#include <stdio.h>
|
|
Packit |
7b22a4 |
#include <stdlib.h>
|
|
Packit |
7b22a4 |
#include <string.h>
|
|
Packit |
7b22a4 |
#include <netinet/ether.h>
|
|
Packit |
7b22a4 |
#include <inttypes.h>
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
#include <xtables.h>
|
|
Packit |
7b22a4 |
#include <libiptc/libxtc.h>
|
|
Packit |
7b22a4 |
#include <linux/netfilter/nf_tables.h>
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
#include <libnftnl/set.h>
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
#include "nft-shared.h"
|
|
Packit |
7b22a4 |
#include "nft-bridge.h"
|
|
Packit |
7b22a4 |
#include "nft-cache.h"
|
|
Packit |
7b22a4 |
#include "nft.h"
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
void ebt_cs_clean(struct iptables_command_state *cs)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct ebt_match *m, *nm;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xtables_rule_matches_free(&cs->matches);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (m = cs->match_list; m;) {
|
|
Packit |
7b22a4 |
if (!m->ismatch) {
|
|
Packit |
7b22a4 |
struct xtables_target *target = m->u.watcher;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (target->t) {
|
|
Packit |
7b22a4 |
free(target->t);
|
|
Packit |
7b22a4 |
target->t = NULL;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
if (target == target->next)
|
|
Packit |
7b22a4 |
free(target);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
nm = m->next;
|
|
Packit |
7b22a4 |
free(m);
|
|
Packit |
7b22a4 |
m = nm;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->target) {
|
|
Packit |
7b22a4 |
free(cs->target->t);
|
|
Packit |
7b22a4 |
cs->target->t = NULL;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->target == cs->target->next) {
|
|
Packit |
7b22a4 |
free(cs->target);
|
|
Packit |
7b22a4 |
cs->target = NULL;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void ebt_print_mac(const unsigned char *mac)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int j;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (j = 0; j < ETH_ALEN; j++)
|
|
Packit |
7b22a4 |
printf("%02x%s", mac[j], (j==ETH_ALEN-1) ? "" : ":");
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static bool mac_all_ones(const unsigned char *mac)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
static const char hlpmsk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return memcmp(mac, hlpmsk, sizeof(hlpmsk)) == 0;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* Put the mac address into 6 (ETH_ALEN) bytes returns 0 on success. */
|
|
Packit |
7b22a4 |
static void ebt_print_mac_and_mask(const unsigned char *mac, const unsigned char *mask)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!memcmp(mac, eb_mac_type_unicast, 6) &&
|
|
Packit |
7b22a4 |
!memcmp(mask, eb_msk_type_unicast, 6))
|
|
Packit |
7b22a4 |
printf("Unicast");
|
|
Packit |
7b22a4 |
else if (!memcmp(mac, eb_mac_type_multicast, 6) &&
|
|
Packit |
7b22a4 |
!memcmp(mask, eb_msk_type_multicast, 6))
|
|
Packit |
7b22a4 |
printf("Multicast");
|
|
Packit |
7b22a4 |
else if (!memcmp(mac, eb_mac_type_broadcast, 6) &&
|
|
Packit |
7b22a4 |
!memcmp(mask, eb_msk_type_broadcast, 6))
|
|
Packit |
7b22a4 |
printf("Broadcast");
|
|
Packit |
7b22a4 |
else if (!memcmp(mac, eb_mac_type_bridge_group, 6) &&
|
|
Packit |
7b22a4 |
!memcmp(mask, eb_msk_type_bridge_group, 6))
|
|
Packit |
7b22a4 |
printf("BGA");
|
|
Packit |
7b22a4 |
else {
|
|
Packit |
7b22a4 |
ebt_print_mac(mac);
|
|
Packit |
7b22a4 |
if (!mac_all_ones(mask)) {
|
|
Packit |
7b22a4 |
printf("/");
|
|
Packit |
7b22a4 |
ebt_print_mac(mask);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void add_logical_iniface(struct nftnl_rule *r, char *iface, uint32_t op)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int iface_len;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
iface_len = strlen(iface);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
add_meta(r, NFT_META_BRI_IIFNAME);
|
|
Packit |
7b22a4 |
if (iface[iface_len - 1] == '+')
|
|
Packit |
7b22a4 |
add_cmp_ptr(r, op, iface, iface_len - 1);
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
add_cmp_ptr(r, op, iface, iface_len + 1);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void add_logical_outiface(struct nftnl_rule *r, char *iface, uint32_t op)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int iface_len;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
iface_len = strlen(iface);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
add_meta(r, NFT_META_BRI_OIFNAME);
|
|
Packit |
7b22a4 |
if (iface[iface_len - 1] == '+')
|
|
Packit |
7b22a4 |
add_cmp_ptr(r, op, iface, iface_len - 1);
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
add_cmp_ptr(r, op, iface, iface_len + 1);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static int _add_action(struct nftnl_rule *r, struct iptables_command_state *cs)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
return add_action(r, cs, false);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static int nft_bridge_add(struct nft_handle *h,
|
|
Packit |
7b22a4 |
struct nftnl_rule *r, void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
struct ebt_match *iter;
|
|
Packit |
7b22a4 |
struct ebt_entry *fw = &cs->eb;
|
|
Packit |
7b22a4 |
uint32_t op;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (fw->in[0] != '\0') {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_IIN);
|
|
Packit |
7b22a4 |
add_iniface(r, fw->in, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (fw->out[0] != '\0') {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_IOUT);
|
|
Packit |
7b22a4 |
add_outiface(r, fw->out, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (fw->logical_in[0] != '\0') {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALIN);
|
|
Packit |
7b22a4 |
add_logical_iniface(r, fw->logical_in, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (fw->logical_out[0] != '\0') {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_ILOGICALOUT);
|
|
Packit |
7b22a4 |
add_logical_outiface(r, fw->logical_out, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (fw->bitmask & EBT_ISOURCE) {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_ISOURCE);
|
|
Packit Service |
bfea89 |
add_addr(r, NFT_PAYLOAD_LL_HEADER,
|
|
Packit Service |
bfea89 |
offsetof(struct ethhdr, h_source),
|
|
Packit Service |
bfea89 |
fw->sourcemac, fw->sourcemsk, ETH_ALEN, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (fw->bitmask & EBT_IDEST) {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_IDEST);
|
|
Packit Service |
bfea89 |
add_addr(r, NFT_PAYLOAD_LL_HEADER,
|
|
Packit Service |
bfea89 |
offsetof(struct ethhdr, h_dest),
|
|
Packit Service |
bfea89 |
fw->destmac, fw->destmsk, ETH_ALEN, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if ((fw->bitmask & EBT_NOPROTO) == 0) {
|
|
Packit |
7b22a4 |
op = nft_invflags2cmp(fw->invflags, EBT_IPROTO);
|
|
Packit |
7b22a4 |
add_payload(r, offsetof(struct ethhdr, h_proto), 2,
|
|
Packit |
7b22a4 |
NFT_PAYLOAD_LL_HEADER);
|
|
Packit |
7b22a4 |
add_cmp_u16(r, fw->ethproto, op);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
add_compat(r, fw->ethproto, fw->invflags & EBT_IPROTO);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (iter = cs->match_list; iter; iter = iter->next) {
|
|
Packit |
7b22a4 |
if (iter->ismatch) {
|
|
Packit |
7b22a4 |
if (add_match(h, r, iter->u.match->m))
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
} else {
|
|
Packit |
7b22a4 |
if (add_target(r, iter->u.watcher->t))
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (add_counters(r, cs->counters.pcnt, cs->counters.bcnt) < 0)
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return _add_action(r, cs);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_parse_meta(struct nft_xt_ctx *ctx,
|
|
Packit |
7b22a4 |
struct nftnl_expr *e, void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
struct ebt_entry *fw = &cs->eb;
|
|
Packit |
7b22a4 |
uint8_t invflags = 0;
|
|
Packit |
7b22a4 |
char iifname[IFNAMSIZ] = {}, oifname[IFNAMSIZ] = {};
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
parse_meta(e, ctx->meta.key, iifname, NULL, oifname, NULL, &invflags);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
switch (ctx->meta.key) {
|
|
Packit |
7b22a4 |
case NFT_META_BRI_IIFNAME:
|
|
Packit |
7b22a4 |
if (invflags & IPT_INV_VIA_IN)
|
|
Packit |
7b22a4 |
cs->eb.invflags |= EBT_ILOGICALIN;
|
|
Packit |
7b22a4 |
snprintf(fw->logical_in, sizeof(fw->logical_in), "%s", iifname);
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case NFT_META_IIFNAME:
|
|
Packit |
7b22a4 |
if (invflags & IPT_INV_VIA_IN)
|
|
Packit |
7b22a4 |
cs->eb.invflags |= EBT_IIN;
|
|
Packit |
7b22a4 |
snprintf(fw->in, sizeof(fw->in), "%s", iifname);
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case NFT_META_BRI_OIFNAME:
|
|
Packit |
7b22a4 |
if (invflags & IPT_INV_VIA_OUT)
|
|
Packit |
7b22a4 |
cs->eb.invflags |= EBT_ILOGICALOUT;
|
|
Packit |
7b22a4 |
snprintf(fw->logical_out, sizeof(fw->logical_out), "%s", oifname);
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case NFT_META_OIFNAME:
|
|
Packit |
7b22a4 |
if (invflags & IPT_INV_VIA_OUT)
|
|
Packit |
7b22a4 |
cs->eb.invflags |= EBT_IOUT;
|
|
Packit |
7b22a4 |
snprintf(fw->out, sizeof(fw->out), "%s", oifname);
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
default:
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_parse_payload(struct nft_xt_ctx *ctx,
|
|
Packit |
7b22a4 |
struct nftnl_expr *e, void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
struct ebt_entry *fw = &cs->eb;
|
|
Packit |
7b22a4 |
unsigned char addr[ETH_ALEN];
|
|
Packit |
7b22a4 |
unsigned short int ethproto;
|
|
Packit |
7b22a4 |
bool inv;
|
|
Packit |
7b22a4 |
int i;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
switch (ctx->payload.offset) {
|
|
Packit |
7b22a4 |
case offsetof(struct ethhdr, h_dest):
|
|
Packit |
7b22a4 |
get_cmp_data(e, addr, sizeof(addr), &inv;;
|
|
Packit |
7b22a4 |
for (i = 0; i < ETH_ALEN; i++)
|
|
Packit |
7b22a4 |
fw->destmac[i] = addr[i];
|
|
Packit |
7b22a4 |
if (inv)
|
|
Packit |
7b22a4 |
fw->invflags |= EBT_IDEST;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (ctx->flags & NFT_XT_CTX_BITWISE) {
|
|
Packit |
7b22a4 |
memcpy(fw->destmsk, ctx->bitwise.mask, ETH_ALEN);
|
|
Packit |
7b22a4 |
ctx->flags &= ~NFT_XT_CTX_BITWISE;
|
|
Packit |
7b22a4 |
} else {
|
|
Packit Service |
bfea89 |
memset(&fw->destmsk, 0xff,
|
|
Packit Service |
bfea89 |
min(ctx->payload.len, ETH_ALEN));
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
fw->bitmask |= EBT_IDEST;
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case offsetof(struct ethhdr, h_source):
|
|
Packit |
7b22a4 |
get_cmp_data(e, addr, sizeof(addr), &inv;;
|
|
Packit |
7b22a4 |
for (i = 0; i < ETH_ALEN; i++)
|
|
Packit |
7b22a4 |
fw->sourcemac[i] = addr[i];
|
|
Packit |
7b22a4 |
if (inv)
|
|
Packit |
7b22a4 |
fw->invflags |= EBT_ISOURCE;
|
|
Packit |
7b22a4 |
if (ctx->flags & NFT_XT_CTX_BITWISE) {
|
|
Packit |
7b22a4 |
memcpy(fw->sourcemsk, ctx->bitwise.mask, ETH_ALEN);
|
|
Packit |
7b22a4 |
ctx->flags &= ~NFT_XT_CTX_BITWISE;
|
|
Packit |
7b22a4 |
} else {
|
|
Packit Service |
bfea89 |
memset(&fw->sourcemsk, 0xff,
|
|
Packit Service |
bfea89 |
min(ctx->payload.len, ETH_ALEN));
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
fw->bitmask |= EBT_ISOURCE;
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case offsetof(struct ethhdr, h_proto):
|
|
Packit |
7b22a4 |
get_cmp_data(e, ðproto, sizeof(ethproto), &inv;;
|
|
Packit |
7b22a4 |
fw->ethproto = ethproto;
|
|
Packit |
7b22a4 |
if (inv)
|
|
Packit |
7b22a4 |
fw->invflags |= EBT_IPROTO;
|
|
Packit |
7b22a4 |
fw->bitmask &= ~EBT_NOPROTO;
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_parse_immediate(const char *jumpto, bool nft_goto,
|
|
Packit |
7b22a4 |
void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
cs->jumpto = jumpto;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* return 0 if saddr, 1 if daddr, -1 on error */
|
|
Packit |
7b22a4 |
static int
|
|
Packit |
7b22a4 |
lookup_check_ether_payload(uint32_t base, uint32_t offset, uint32_t len)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
if (base != 0 || len != ETH_ALEN)
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
switch (offset) {
|
|
Packit |
7b22a4 |
case offsetof(struct ether_header, ether_dhost):
|
|
Packit |
7b22a4 |
return 1;
|
|
Packit |
7b22a4 |
case offsetof(struct ether_header, ether_shost):
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
default:
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* return 0 if saddr, 1 if daddr, -1 on error */
|
|
Packit |
7b22a4 |
static int
|
|
Packit |
7b22a4 |
lookup_check_iphdr_payload(uint32_t base, uint32_t offset, uint32_t len)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
if (base != 1 || len != 4)
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
switch (offset) {
|
|
Packit |
7b22a4 |
case offsetof(struct iphdr, daddr):
|
|
Packit |
7b22a4 |
return 1;
|
|
Packit |
7b22a4 |
case offsetof(struct iphdr, saddr):
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
default:
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* Make sure previous payload expression(s) is/are consistent and extract if
|
|
Packit |
7b22a4 |
* matching on source or destination address and if matching on MAC and IP or
|
|
Packit |
7b22a4 |
* only MAC address. */
|
|
Packit |
7b22a4 |
static int lookup_analyze_payloads(const struct nft_xt_ctx *ctx,
|
|
Packit |
7b22a4 |
bool *dst, bool *ip)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int val, val2 = -1;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (ctx->flags & NFT_XT_CTX_PREV_PAYLOAD) {
|
|
Packit |
7b22a4 |
val = lookup_check_ether_payload(ctx->prev_payload.base,
|
|
Packit |
7b22a4 |
ctx->prev_payload.offset,
|
|
Packit |
7b22a4 |
ctx->prev_payload.len);
|
|
Packit |
7b22a4 |
if (val < 0) {
|
|
Packit |
7b22a4 |
DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
|
|
Packit |
7b22a4 |
ctx->prev_payload.base, ctx->prev_payload.offset,
|
|
Packit |
7b22a4 |
ctx->prev_payload.len);
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
if (!(ctx->flags & NFT_XT_CTX_PAYLOAD)) {
|
|
Packit |
7b22a4 |
DEBUGP("Previous but no current payload?\n");
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
val2 = lookup_check_iphdr_payload(ctx->payload.base,
|
|
Packit |
7b22a4 |
ctx->payload.offset,
|
|
Packit |
7b22a4 |
ctx->payload.len);
|
|
Packit |
7b22a4 |
if (val2 < 0) {
|
|
Packit |
7b22a4 |
DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
|
|
Packit |
7b22a4 |
ctx->payload.base, ctx->payload.offset,
|
|
Packit |
7b22a4 |
ctx->payload.len);
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
} else if (val != val2) {
|
|
Packit |
7b22a4 |
DEBUGP("mismatching payload match offsets\n");
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
} else if (ctx->flags & NFT_XT_CTX_PAYLOAD) {
|
|
Packit |
7b22a4 |
val = lookup_check_ether_payload(ctx->payload.base,
|
|
Packit |
7b22a4 |
ctx->payload.offset,
|
|
Packit |
7b22a4 |
ctx->payload.len);
|
|
Packit |
7b22a4 |
if (val < 0) {
|
|
Packit |
7b22a4 |
DEBUGP("unknown payload base/offset/len %d/%d/%d\n",
|
|
Packit |
7b22a4 |
ctx->payload.base, ctx->payload.offset,
|
|
Packit |
7b22a4 |
ctx->payload.len);
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
} else {
|
|
Packit |
7b22a4 |
DEBUGP("unknown LHS of lookup expression\n");
|
|
Packit |
7b22a4 |
return -1;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (dst)
|
|
Packit |
7b22a4 |
*dst = (val == 1);
|
|
Packit |
7b22a4 |
if (ip)
|
|
Packit |
7b22a4 |
*ip = (val2 != -1);
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static int set_elems_to_among_pairs(struct nft_among_pair *pairs,
|
|
Packit |
7b22a4 |
const struct nftnl_set *s, int cnt)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct nftnl_set_elems_iter *iter = nftnl_set_elems_iter_create(s);
|
|
Packit |
7b22a4 |
struct nftnl_set_elem *elem;
|
|
Packit |
7b22a4 |
size_t tmpcnt = 0;
|
|
Packit |
7b22a4 |
const void *data;
|
|
Packit |
7b22a4 |
uint32_t datalen;
|
|
Packit |
7b22a4 |
int ret = -1;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!iter) {
|
|
Packit |
7b22a4 |
fprintf(stderr, "BUG: set elems iter allocation failed\n");
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
while ((elem = nftnl_set_elems_iter_next(iter))) {
|
|
Packit |
7b22a4 |
data = nftnl_set_elem_get(elem, NFTNL_SET_ELEM_KEY, &datalen);
|
|
Packit |
7b22a4 |
if (!data) {
|
|
Packit |
7b22a4 |
fprintf(stderr, "BUG: set elem without key\n");
|
|
Packit |
7b22a4 |
goto err;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
if (datalen > sizeof(*pairs)) {
|
|
Packit |
7b22a4 |
fprintf(stderr, "BUG: overlong set elem\n");
|
|
Packit |
7b22a4 |
goto err;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
nft_among_insert_pair(pairs, &tmpcnt, data);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
ret = 0;
|
|
Packit |
7b22a4 |
err:
|
|
Packit |
7b22a4 |
nftnl_set_elems_iter_destroy(iter);
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static struct nftnl_set *set_from_lookup_expr(struct nft_xt_ctx *ctx,
|
|
Packit |
7b22a4 |
const struct nftnl_expr *e)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
const char *set_name = nftnl_expr_get_str(e, NFTNL_EXPR_LOOKUP_SET);
|
|
Packit |
7b22a4 |
struct nftnl_set_list *slist;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
slist = nft_set_list_get(ctx->h, ctx->table, set_name);
|
|
Packit |
7b22a4 |
if (slist)
|
|
Packit |
7b22a4 |
return nftnl_set_list_lookup_byname(slist, set_name);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return NULL;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_parse_lookup(struct nft_xt_ctx *ctx,
|
|
Packit |
7b22a4 |
struct nftnl_expr *e, void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct xtables_match *match = NULL;
|
|
Packit |
7b22a4 |
struct nft_among_data *among_data;
|
|
Packit |
7b22a4 |
bool is_dst, have_ip, inv;
|
|
Packit |
7b22a4 |
struct ebt_match *ematch;
|
|
Packit |
7b22a4 |
struct nftnl_set *s;
|
|
Packit |
7b22a4 |
size_t poff, size;
|
|
Packit |
7b22a4 |
uint32_t cnt;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (lookup_analyze_payloads(ctx, &is_dst, &have_ip))
|
|
Packit |
7b22a4 |
return;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
s = set_from_lookup_expr(ctx, e);
|
|
Packit |
7b22a4 |
if (!s)
|
|
Packit |
7b22a4 |
xtables_error(OTHER_PROBLEM,
|
|
Packit |
7b22a4 |
"BUG: lookup expression references unknown set");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
cnt = nftnl_set_get_u32(s, NFTNL_SET_DESC_SIZE);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (ematch = ctx->cs->match_list; ematch; ematch = ematch->next) {
|
|
Packit |
7b22a4 |
if (!ematch->ismatch || strcmp(ematch->u.match->name, "among"))
|
|
Packit |
7b22a4 |
continue;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
match = ematch->u.match;
|
|
Packit |
7b22a4 |
among_data = (struct nft_among_data *)match->m->data;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
size = cnt + among_data->src.cnt + among_data->dst.cnt;
|
|
Packit |
7b22a4 |
size *= sizeof(struct nft_among_pair);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
size += XT_ALIGN(sizeof(struct xt_entry_match)) +
|
|
Packit |
7b22a4 |
sizeof(struct nft_among_data);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
match->m = xtables_realloc(match->m, size);
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
if (!match) {
|
|
Packit |
7b22a4 |
match = xtables_find_match("among", XTF_TRY_LOAD,
|
|
Packit |
7b22a4 |
&ctx->cs->matches);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
size = cnt * sizeof(struct nft_among_pair);
|
|
Packit |
7b22a4 |
size += XT_ALIGN(sizeof(struct xt_entry_match)) +
|
|
Packit |
7b22a4 |
sizeof(struct nft_among_data);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
match->m = xtables_calloc(1, size);
|
|
Packit |
7b22a4 |
strcpy(match->m->u.user.name, match->name);
|
|
Packit |
7b22a4 |
match->m->u.user.revision = match->revision;
|
|
Packit |
7b22a4 |
xs_init_match(match);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (ctx->h->ops->parse_match != NULL)
|
|
Packit |
7b22a4 |
ctx->h->ops->parse_match(match, ctx->cs);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
if (!match)
|
|
Packit |
7b22a4 |
return;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
match->m->u.match_size = size;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
inv = !!(nftnl_expr_get_u32(e, NFTNL_EXPR_LOOKUP_FLAGS) &
|
|
Packit |
7b22a4 |
NFT_LOOKUP_F_INV);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
among_data = (struct nft_among_data *)match->m->data;
|
|
Packit |
7b22a4 |
poff = nft_among_prepare_data(among_data, is_dst, cnt, inv, have_ip);
|
|
Packit |
7b22a4 |
if (set_elems_to_among_pairs(among_data->pairs + poff, s, cnt))
|
|
Packit |
7b22a4 |
xtables_error(OTHER_PROBLEM,
|
|
Packit |
7b22a4 |
"ebtables among pair parsing failed");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
ctx->flags &= ~(NFT_XT_CTX_PAYLOAD | NFT_XT_CTX_PREV_PAYLOAD);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void parse_watcher(void *object, struct ebt_match **match_list,
|
|
Packit |
7b22a4 |
bool ismatch)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct ebt_match *m;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
m = calloc(1, sizeof(struct ebt_match));
|
|
Packit |
7b22a4 |
if (m == NULL)
|
|
Packit |
7b22a4 |
xtables_error(OTHER_PROBLEM, "Can't allocate memory");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (ismatch)
|
|
Packit |
7b22a4 |
m->u.match = object;
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
m->u.watcher = object;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
m->ismatch = ismatch;
|
|
Packit |
7b22a4 |
if (*match_list == NULL)
|
|
Packit |
7b22a4 |
*match_list = m;
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
(*match_list)->next = m;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_parse_match(struct xtables_match *m, void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
parse_watcher(m, &cs->match_list, true);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_parse_target(struct xtables_target *t, void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* harcoded names :-( */
|
|
Packit |
7b22a4 |
if (strcmp(t->name, "log") == 0 ||
|
|
Packit |
7b22a4 |
strcmp(t->name, "nflog") == 0) {
|
|
Packit |
7b22a4 |
parse_watcher(t, &cs->match_list, false);
|
|
Packit |
7b22a4 |
return;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
cs->target = t;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_rule_to_ebtables_command_state(struct nft_handle *h,
|
|
Packit |
7b22a4 |
const struct nftnl_rule *r,
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
cs->eb.bitmask = EBT_NOPROTO;
|
|
Packit |
7b22a4 |
nft_rule_to_iptables_command_state(h, r, cs);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void print_iface(const char *option, const char *name, bool invert)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
if (*name)
|
|
Packit |
7b22a4 |
printf("%s%s %s ", option, invert ? " !" : "", name);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_print_table_header(const char *tablename)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
printf("Bridge table: %s\n\n", tablename);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_print_header(unsigned int format, const char *chain,
|
|
Packit |
7b22a4 |
const char *pol,
|
|
Packit |
7b22a4 |
const struct xt_counters *counters,
|
|
Packit |
7b22a4 |
bool basechain, uint32_t refs, uint32_t entries)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
printf("Bridge chain: %s, entries: %u, policy: %s\n",
|
|
Packit |
7b22a4 |
chain, entries, pol ?: "RETURN");
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void print_matches_and_watchers(const struct iptables_command_state *cs,
|
|
Packit |
7b22a4 |
unsigned int format)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct xtables_target *watcherp;
|
|
Packit |
7b22a4 |
struct xtables_match *matchp;
|
|
Packit |
7b22a4 |
struct ebt_match *m;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (m = cs->match_list; m; m = m->next) {
|
|
Packit |
7b22a4 |
if (m->ismatch) {
|
|
Packit |
7b22a4 |
matchp = m->u.match;
|
|
Packit |
7b22a4 |
if (matchp->print != NULL) {
|
|
Packit |
7b22a4 |
matchp->print(&cs->eb, matchp->m,
|
|
Packit |
7b22a4 |
format & FMT_NUMERIC);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
} else {
|
|
Packit |
7b22a4 |
watcherp = m->u.watcher;
|
|
Packit |
7b22a4 |
if (watcherp->print != NULL) {
|
|
Packit |
7b22a4 |
watcherp->print(&cs->eb, watcherp->t,
|
|
Packit |
7b22a4 |
format & FMT_NUMERIC);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void print_mac(char option, const unsigned char *mac,
|
|
Packit |
7b22a4 |
const unsigned char *mask,
|
|
Packit |
7b22a4 |
bool invert)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
printf("-%c ", option);
|
|
Packit |
7b22a4 |
if (invert)
|
|
Packit |
7b22a4 |
printf("! ");
|
|
Packit |
7b22a4 |
ebt_print_mac_and_mask(mac, mask);
|
|
Packit |
7b22a4 |
printf(" ");
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void print_protocol(uint16_t ethproto, bool invert, unsigned int bitmask)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct xt_ethertypeent *ent;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* Dont print anything about the protocol if no protocol was
|
|
Packit |
7b22a4 |
* specified, obviously this means any protocol will do. */
|
|
Packit |
7b22a4 |
if (bitmask & EBT_NOPROTO)
|
|
Packit |
7b22a4 |
return;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
printf("-p ");
|
|
Packit |
7b22a4 |
if (invert)
|
|
Packit |
7b22a4 |
printf("! ");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (bitmask & EBT_802_3) {
|
|
Packit |
7b22a4 |
printf("length ");
|
|
Packit |
7b22a4 |
return;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
ent = xtables_getethertypebynumber(ntohs(ethproto));
|
|
Packit |
7b22a4 |
if (!ent)
|
|
Packit |
7b22a4 |
printf("0x%x ", ntohs(ethproto));
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
printf("%s ", ent->e_name);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_save_rule(const void *data, unsigned int format)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
const struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->eb.ethproto)
|
|
Packit |
7b22a4 |
print_protocol(cs->eb.ethproto, cs->eb.invflags & EBT_IPROTO,
|
|
Packit |
7b22a4 |
cs->eb.bitmask);
|
|
Packit |
7b22a4 |
if (cs->eb.bitmask & EBT_ISOURCE)
|
|
Packit |
7b22a4 |
print_mac('s', cs->eb.sourcemac, cs->eb.sourcemsk,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_ISOURCE);
|
|
Packit |
7b22a4 |
if (cs->eb.bitmask & EBT_IDEST)
|
|
Packit |
7b22a4 |
print_mac('d', cs->eb.destmac, cs->eb.destmsk,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_IDEST);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
print_iface("-i", cs->eb.in, cs->eb.invflags & EBT_IIN);
|
|
Packit |
7b22a4 |
print_iface("--logical-in", cs->eb.logical_in,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_ILOGICALIN);
|
|
Packit |
7b22a4 |
print_iface("-o", cs->eb.out, cs->eb.invflags & EBT_IOUT);
|
|
Packit |
7b22a4 |
print_iface("--logical-out", cs->eb.logical_out,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_ILOGICALOUT);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
print_matches_and_watchers(cs, format);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
printf("-j ");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->jumpto != NULL) {
|
|
Packit |
7b22a4 |
if (strcmp(cs->jumpto, "") != 0)
|
|
Packit |
7b22a4 |
printf("%s", cs->jumpto);
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
printf("CONTINUE");
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
if (cs->target != NULL && cs->target->print != NULL) {
|
|
Packit |
7b22a4 |
printf(" ");
|
|
Packit |
7b22a4 |
cs->target->print(&cs->fw, cs->target->t, format & FMT_NUMERIC);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if ((format & (FMT_NOCOUNTS | FMT_C_COUNTS)) == FMT_C_COUNTS) {
|
|
Packit |
7b22a4 |
if (format & FMT_EBT_SAVE)
|
|
Packit |
7b22a4 |
printf(" -c %"PRIu64" %"PRIu64"",
|
|
Packit |
7b22a4 |
(uint64_t)cs->counters.pcnt,
|
|
Packit |
7b22a4 |
(uint64_t)cs->counters.bcnt);
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
printf(" , pcnt = %"PRIu64" -- bcnt = %"PRIu64"",
|
|
Packit |
7b22a4 |
(uint64_t)cs->counters.pcnt,
|
|
Packit |
7b22a4 |
(uint64_t)cs->counters.bcnt);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!(format & FMT_NONEWLINE))
|
|
Packit |
7b22a4 |
fputc('\n', stdout);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_print_rule(struct nft_handle *h, struct nftnl_rule *r,
|
|
Packit |
7b22a4 |
unsigned int num, unsigned int format)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state cs = {};
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (format & FMT_LINENUMBERS)
|
|
Packit |
7b22a4 |
printf("%d ", num);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
nft_rule_to_ebtables_command_state(h, r, &cs);
|
|
Packit |
7b22a4 |
nft_bridge_save_rule(&cs, format);
|
|
Packit |
7b22a4 |
ebt_cs_clean(&cs);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_save_chain(const struct nftnl_chain *c,
|
|
Packit |
7b22a4 |
const char *policy)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
const char *chain = nftnl_chain_get_str(c, NFTNL_CHAIN_NAME);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
printf(":%s %s\n", chain, policy ?: "ACCEPT");
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static bool nft_bridge_is_same(const void *data_a, const void *data_b)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
const struct ebt_entry *a = data_a;
|
|
Packit |
7b22a4 |
const struct ebt_entry *b = data_b;
|
|
Packit |
7b22a4 |
int i;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (a->ethproto != b->ethproto ||
|
|
Packit |
7b22a4 |
/* FIXME: a->flags != b->flags || */
|
|
Packit |
7b22a4 |
a->invflags != b->invflags) {
|
|
Packit |
7b22a4 |
DEBUGP("different proto/flags/invflags\n");
|
|
Packit |
7b22a4 |
return false;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (i = 0; i < ETH_ALEN; i++) {
|
|
Packit |
7b22a4 |
if (a->sourcemac[i] != b->sourcemac[i]) {
|
|
Packit |
7b22a4 |
DEBUGP("different source mac %x, %x (%d)\n",
|
|
Packit |
7b22a4 |
a->sourcemac[i] & 0xff, b->sourcemac[i] & 0xff, i);
|
|
Packit |
7b22a4 |
return false;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (a->destmac[i] != b->destmac[i]) {
|
|
Packit |
7b22a4 |
DEBUGP("different destination mac %x, %x (%d)\n",
|
|
Packit |
7b22a4 |
a->destmac[i] & 0xff, b->destmac[i] & 0xff, i);
|
|
Packit |
7b22a4 |
return false;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (i = 0; i < IFNAMSIZ; i++) {
|
|
Packit |
7b22a4 |
if (a->logical_in[i] != b->logical_in[i]) {
|
|
Packit |
7b22a4 |
DEBUGP("different logical iniface %x, %x (%d)\n",
|
|
Packit |
7b22a4 |
a->logical_in[i] & 0xff, b->logical_in[i] & 0xff, i);
|
|
Packit |
7b22a4 |
return false;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (a->logical_out[i] != b->logical_out[i]) {
|
|
Packit |
7b22a4 |
DEBUGP("different logical outiface %x, %x (%d)\n",
|
|
Packit |
7b22a4 |
a->logical_out[i] & 0xff, b->logical_out[i] & 0xff, i);
|
|
Packit |
7b22a4 |
return false;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return strcmp(a->in, b->in) == 0 && strcmp(a->out, b->out) == 0;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static bool nft_bridge_rule_find(struct nft_handle *h, struct nftnl_rule *r,
|
|
Packit |
7b22a4 |
void *data)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
struct iptables_command_state this = {};
|
|
Packit |
7b22a4 |
bool ret = false;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
nft_rule_to_ebtables_command_state(h, r, &this;;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
DEBUGP("comparing with... ");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!nft_bridge_is_same(cs, &this))
|
|
Packit |
7b22a4 |
goto out;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!compare_matches(cs->matches, this.matches)) {
|
|
Packit |
7b22a4 |
DEBUGP("Different matches\n");
|
|
Packit |
7b22a4 |
goto out;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!compare_targets(cs->target, this.target)) {
|
|
Packit |
7b22a4 |
DEBUGP("Different target\n");
|
|
Packit |
7b22a4 |
goto out;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->jumpto != NULL && strcmp(cs->jumpto, this.jumpto) != 0) {
|
|
Packit |
7b22a4 |
DEBUGP("Different verdict\n");
|
|
Packit |
7b22a4 |
goto out;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
ret = true;
|
|
Packit |
7b22a4 |
out:
|
|
Packit |
7b22a4 |
h->ops->clear_cs(&this;;
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static int xlate_ebmatches(const struct iptables_command_state *cs, struct xt_xlate *xl)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int ret = 1, numeric = cs->options & OPT_NUMERIC;
|
|
Packit |
7b22a4 |
struct ebt_match *m;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (m = cs->match_list; m; m = m->next) {
|
|
Packit |
7b22a4 |
if (m->ismatch) {
|
|
Packit |
7b22a4 |
struct xtables_match *matchp = m->u.match;
|
|
Packit |
7b22a4 |
struct xt_xlate_mt_params mt_params = {
|
|
Packit |
7b22a4 |
.ip = (const void *)&cs->eb,
|
|
Packit |
7b22a4 |
.numeric = numeric,
|
|
Packit |
7b22a4 |
.escape_quotes = false,
|
|
Packit |
7b22a4 |
.match = matchp->m,
|
|
Packit |
7b22a4 |
};
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!matchp->xlate)
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
ret = matchp->xlate(xl, &mt_params);
|
|
Packit |
7b22a4 |
} else {
|
|
Packit |
7b22a4 |
struct xtables_target *watcherp = m->u.watcher;
|
|
Packit |
7b22a4 |
struct xt_xlate_tg_params wt_params = {
|
|
Packit |
7b22a4 |
.ip = (const void *)&cs->eb,
|
|
Packit |
7b22a4 |
.numeric = numeric,
|
|
Packit |
7b22a4 |
.escape_quotes = false,
|
|
Packit |
7b22a4 |
.target = watcherp->t,
|
|
Packit |
7b22a4 |
};
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!watcherp->xlate)
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
ret = watcherp->xlate(xl, &wt_params);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!ret)
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static int xlate_ebaction(const struct iptables_command_state *cs, struct xt_xlate *xl)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int ret = 1, numeric = cs->options & OPT_NUMERIC;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* If no target at all, add nothing (default to continue) */
|
|
Packit |
7b22a4 |
if (cs->target != NULL) {
|
|
Packit |
7b22a4 |
/* Standard target? */
|
|
Packit |
7b22a4 |
if (strcmp(cs->jumpto, XTC_LABEL_ACCEPT) == 0)
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " accept");
|
|
Packit |
7b22a4 |
else if (strcmp(cs->jumpto, XTC_LABEL_DROP) == 0)
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " drop");
|
|
Packit |
7b22a4 |
else if (strcmp(cs->jumpto, XTC_LABEL_RETURN) == 0)
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " return");
|
|
Packit |
7b22a4 |
else if (cs->target->xlate) {
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " ");
|
|
Packit |
7b22a4 |
struct xt_xlate_tg_params params = {
|
|
Packit |
7b22a4 |
.ip = (const void *)&cs->eb,
|
|
Packit |
7b22a4 |
.target = cs->target->t,
|
|
Packit |
7b22a4 |
.numeric = numeric,
|
|
Packit |
7b22a4 |
};
|
|
Packit |
7b22a4 |
ret = cs->target->xlate(xl, ¶ms);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
else
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
} else if (cs->jumpto == NULL) {
|
|
Packit |
7b22a4 |
} else if (strlen(cs->jumpto) > 0)
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " jump %s", cs->jumpto);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void xlate_mac(struct xt_xlate *xl, const unsigned char *mac)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
int i;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, "%02x", mac[0]);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
for (i=1; i < ETH_ALEN; i++)
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, ":%02x", mac[i]);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static void nft_bridge_xlate_mac(struct xt_xlate *xl, const char *type, bool invert,
|
|
Packit |
7b22a4 |
const unsigned char *mac, const unsigned char *mask)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
char one_msk[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, "ether %s %s", type, invert ? "!= " : "");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xlate_mac(xl, mac);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (memcmp(mask, one_msk, ETH_ALEN)) {
|
|
Packit |
7b22a4 |
int i;
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " and ");
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xlate_mac(xl, mask);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " == %02x", mac[0] & mask[0]);
|
|
Packit |
7b22a4 |
for (i=1; i < ETH_ALEN; i++)
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, ":%02x", mac[i] & mask[i]);
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, " ");
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
static int nft_bridge_xlate(const void *data, struct xt_xlate *xl)
|
|
Packit |
7b22a4 |
{
|
|
Packit |
7b22a4 |
const struct iptables_command_state *cs = data;
|
|
Packit |
7b22a4 |
int ret;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
xlate_ifname(xl, "iifname", cs->eb.in,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_IIN);
|
|
Packit |
7b22a4 |
xlate_ifname(xl, "meta ibrname", cs->eb.logical_in,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_ILOGICALIN);
|
|
Packit |
7b22a4 |
xlate_ifname(xl, "oifname", cs->eb.out,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_IOUT);
|
|
Packit |
7b22a4 |
xlate_ifname(xl, "meta obrname", cs->eb.logical_out,
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_ILOGICALOUT);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if ((cs->eb.bitmask & EBT_NOPROTO) == 0) {
|
|
Packit |
7b22a4 |
const char *implicit = NULL;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
switch (ntohs(cs->eb.ethproto)) {
|
|
Packit |
7b22a4 |
case ETH_P_IP:
|
|
Packit |
7b22a4 |
implicit = "ip";
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case ETH_P_IPV6:
|
|
Packit |
7b22a4 |
implicit = "ip6";
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
case ETH_P_8021Q:
|
|
Packit |
7b22a4 |
implicit = "vlan";
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
default:
|
|
Packit |
7b22a4 |
break;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (!implicit || !xlate_find_match(cs, implicit))
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, "ether type %s0x%x ",
|
|
Packit |
7b22a4 |
cs->eb.invflags & EBT_IPROTO ? "!= " : "",
|
|
Packit |
7b22a4 |
ntohs(cs->eb.ethproto));
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->eb.bitmask & EBT_802_3)
|
|
Packit |
7b22a4 |
return 0;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
if (cs->eb.bitmask & EBT_ISOURCE)
|
|
Packit |
7b22a4 |
nft_bridge_xlate_mac(xl, "saddr", cs->eb.invflags & EBT_ISOURCE,
|
|
Packit |
7b22a4 |
cs->eb.sourcemac, cs->eb.sourcemsk);
|
|
Packit |
7b22a4 |
if (cs->eb.bitmask & EBT_IDEST)
|
|
Packit |
7b22a4 |
nft_bridge_xlate_mac(xl, "daddr", cs->eb.invflags & EBT_IDEST,
|
|
Packit |
7b22a4 |
cs->eb.destmac, cs->eb.destmsk);
|
|
Packit |
7b22a4 |
ret = xlate_ebmatches(cs, xl);
|
|
Packit |
7b22a4 |
if (ret == 0)
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
/* Always add counters per rule, as in ebtables */
|
|
Packit |
7b22a4 |
xt_xlate_add(xl, "counter");
|
|
Packit |
7b22a4 |
ret = xlate_ebaction(cs, xl);
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
return ret;
|
|
Packit |
7b22a4 |
}
|
|
Packit |
7b22a4 |
|
|
Packit |
7b22a4 |
struct nft_family_ops nft_family_ops_bridge = {
|
|
Packit |
7b22a4 |
.add = nft_bridge_add,
|
|
Packit |
7b22a4 |
.is_same = nft_bridge_is_same,
|
|
Packit |
7b22a4 |
.print_payload = NULL,
|
|
Packit |
7b22a4 |
.parse_meta = nft_bridge_parse_meta,
|
|
Packit |
7b22a4 |
.parse_payload = nft_bridge_parse_payload,
|
|
Packit |
7b22a4 |
.parse_immediate = nft_bridge_parse_immediate,
|
|
Packit |
7b22a4 |
.parse_lookup = nft_bridge_parse_lookup,
|
|
Packit |
7b22a4 |
.parse_match = nft_bridge_parse_match,
|
|
Packit |
7b22a4 |
.parse_target = nft_bridge_parse_target,
|
|
Packit |
7b22a4 |
.print_table_header = nft_bridge_print_table_header,
|
|
Packit |
7b22a4 |
.print_header = nft_bridge_print_header,
|
|
Packit |
7b22a4 |
.print_rule = nft_bridge_print_rule,
|
|
Packit |
7b22a4 |
.save_rule = nft_bridge_save_rule,
|
|
Packit |
7b22a4 |
.save_counters = save_counters,
|
|
Packit |
7b22a4 |
.save_chain = nft_bridge_save_chain,
|
|
Packit |
7b22a4 |
.post_parse = NULL,
|
|
Packit |
7b22a4 |
.rule_to_cs = nft_rule_to_ebtables_command_state,
|
|
Packit |
7b22a4 |
.clear_cs = ebt_cs_clean,
|
|
Packit |
7b22a4 |
.rule_find = nft_bridge_rule_find,
|
|
Packit |
7b22a4 |
.xlate = nft_bridge_xlate,
|
|
Packit |
7b22a4 |
};
|