2010-03-25 17:46:09 +00:00
|
|
|
/*
|
|
|
|
* nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
|
|
|
|
*
|
2014-02-19 23:45:54 +00:00
|
|
|
* Copyright (C) 2011-2014 Red Hat, Inc.
|
2012-08-08 16:00:23 +00:00
|
|
|
* Copyright (C) 2010-2012 IBM Corp.
|
|
|
|
* Copyright (C) 2010-2012 Stefan Berger
|
2010-03-25 17:46:09 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-03-25 17:46:09 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
2010-09-24 16:06:17 +00:00
|
|
|
#include <fcntl.h>
|
2013-05-16 01:02:11 +00:00
|
|
|
#include <sys/utsname.h>
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
#include "internal.h"
|
|
|
|
|
2012-12-04 12:04:07 +00:00
|
|
|
#include "virbuffer.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2010-03-25 17:46:09 +00:00
|
|
|
#include "domain_conf.h"
|
2010-04-27 11:26:12 +00:00
|
|
|
#include "nwfilter_conf.h"
|
2012-08-08 16:00:23 +00:00
|
|
|
#include "nwfilter_driver.h"
|
2010-03-25 17:46:09 +00:00
|
|
|
#include "nwfilter_gentech_driver.h"
|
|
|
|
#include "nwfilter_ebiptables_driver.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.h"
|
2011-11-09 17:23:49 +00:00
|
|
|
#include "configmake.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2014-03-14 11:53:06 +00:00
|
|
|
#include "virfirewall.h"
|
2020-02-16 21:59:28 +00:00
|
|
|
#include "virutil.h"
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
|
|
|
|
2014-02-28 12:16:17 +00:00
|
|
|
VIR_LOG_INIT("nwfilter.nwfilter_ebiptables_driver");
|
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
#define EBTABLES_CHAIN_INCOMING "PREROUTING"
|
|
|
|
#define EBTABLES_CHAIN_OUTGOING "POSTROUTING"
|
|
|
|
|
|
|
|
#define CHAINPREFIX_HOST_IN 'I'
|
|
|
|
#define CHAINPREFIX_HOST_OUT 'O'
|
|
|
|
#define CHAINPREFIX_HOST_IN_TEMP 'J'
|
|
|
|
#define CHAINPREFIX_HOST_OUT_TEMP 'P'
|
|
|
|
|
|
|
|
|
2010-09-24 16:06:17 +00:00
|
|
|
#define PROC_BRIDGE_NF_CALL_IPTABLES \
|
|
|
|
"/proc/sys/net/bridge/bridge-nf-call-iptables"
|
|
|
|
#define PROC_BRIDGE_NF_CALL_IP6TABLES \
|
|
|
|
"/proc/sys/net/bridge/bridge-nf-call-ip6tables"
|
|
|
|
|
|
|
|
#define BRIDGE_NF_CALL_ALERT_INTERVAL 10 /* seconds */
|
|
|
|
|
2013-05-16 01:02:11 +00:00
|
|
|
/*
|
|
|
|
* --ctdir original vs. --ctdir reply's meaning was inverted in netfilter
|
|
|
|
* at some point (Linux 2.6.39)
|
|
|
|
*/
|
|
|
|
enum ctdirStatus {
|
|
|
|
CTDIR_STATUS_UNKNOWN = 0,
|
|
|
|
CTDIR_STATUS_CORRECTED = 1,
|
|
|
|
CTDIR_STATUS_OLD = 2,
|
|
|
|
};
|
|
|
|
static enum ctdirStatus iptables_ctdir_corrected;
|
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
#define PRINT_ROOT_CHAIN(buf, prefix, ifname) \
|
2019-11-13 13:53:42 +00:00
|
|
|
g_snprintf(buf, sizeof(buf), "libvirt-%c-%s", prefix, ifname)
|
2010-03-25 17:46:09 +00:00
|
|
|
#define PRINT_CHAIN(buf, prefix, ifname, suffix) \
|
2019-11-13 13:53:42 +00:00
|
|
|
g_snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix)
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
#define VIRT_IN_CHAIN "libvirt-in"
|
|
|
|
#define VIRT_OUT_CHAIN "libvirt-out"
|
|
|
|
#define VIRT_IN_POST_CHAIN "libvirt-in-post"
|
|
|
|
#define HOST_IN_CHAIN "libvirt-host-in"
|
|
|
|
|
|
|
|
#define PRINT_IPT_ROOT_CHAIN(buf, prefix, ifname) \
|
2019-11-13 13:53:42 +00:00
|
|
|
g_snprintf(buf, sizeof(buf), "%c%c-%s", prefix[0], prefix[1], ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
static bool newMatchState;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
#define MATCH_PHYSDEV_IN_FW "-m", "physdev", "--physdev-in"
|
|
|
|
#define MATCH_PHYSDEV_OUT_FW "-m", "physdev", "--physdev-is-bridged", "--physdev-out"
|
|
|
|
#define MATCH_PHYSDEV_OUT_OLD_FW "-m", "physdev", "--physdev-out"
|
|
|
|
|
2010-04-20 21:07:15 +00:00
|
|
|
static int ebtablesRemoveBasicRules(const char *ifname);
|
2011-02-10 10:46:21 +00:00
|
|
|
static int ebiptablesDriverInit(bool privileged);
|
2010-04-14 10:29:55 +00:00
|
|
|
static void ebiptablesDriverShutdown(void);
|
2014-03-14 12:14:13 +00:00
|
|
|
static int ebtablesCleanAll(const char *ifname);
|
2010-11-17 02:18:21 +00:00
|
|
|
static int ebiptablesAllTeardown(const char *ifname);
|
2010-04-14 10:29:55 +00:00
|
|
|
|
2010-04-27 11:26:12 +00:00
|
|
|
struct ushort_map {
|
|
|
|
unsigned short attr;
|
|
|
|
const char *val;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
enum l3_proto_idx {
|
|
|
|
L3_PROTO_IPV4_IDX = 0,
|
|
|
|
L3_PROTO_IPV6_IDX,
|
|
|
|
L3_PROTO_ARP_IDX,
|
|
|
|
L3_PROTO_RARP_IDX,
|
2011-11-22 20:12:03 +00:00
|
|
|
L2_PROTO_MAC_IDX,
|
2011-11-19 12:26:56 +00:00
|
|
|
L2_PROTO_VLAN_IDX,
|
2011-11-22 20:12:03 +00:00
|
|
|
L2_PROTO_STP_IDX,
|
2010-04-27 11:26:12 +00:00
|
|
|
L3_PROTO_LAST_IDX
|
|
|
|
};
|
|
|
|
|
|
|
|
#define USHORTMAP_ENTRY_IDX(IDX, ATT, VAL) [IDX] = { .attr = ATT, .val = VAL }
|
|
|
|
|
2011-11-18 16:58:17 +00:00
|
|
|
/* A lookup table for translating ethernet protocol IDs to human readable
|
|
|
|
* strings. None of the human readable strings must be found as a prefix
|
|
|
|
* in another entry here (example 'ab' would be found in 'abc') to allow
|
|
|
|
* for prefix matching.
|
|
|
|
*/
|
2010-04-27 11:26:12 +00:00
|
|
|
static const struct ushort_map l3_protocols[] = {
|
2013-11-19 23:33:37 +00:00
|
|
|
USHORTMAP_ENTRY_IDX(L3_PROTO_IPV4_IDX, ETHERTYPE_IP, "ipv4"),
|
|
|
|
USHORTMAP_ENTRY_IDX(L3_PROTO_IPV6_IDX, ETHERTYPE_IPV6, "ipv6"),
|
|
|
|
USHORTMAP_ENTRY_IDX(L3_PROTO_ARP_IDX, ETHERTYPE_ARP, "arp"),
|
2010-04-27 11:26:12 +00:00
|
|
|
USHORTMAP_ENTRY_IDX(L3_PROTO_RARP_IDX, ETHERTYPE_REVARP, "rarp"),
|
2013-11-19 23:33:37 +00:00
|
|
|
USHORTMAP_ENTRY_IDX(L2_PROTO_VLAN_IDX, ETHERTYPE_VLAN, "vlan"),
|
|
|
|
USHORTMAP_ENTRY_IDX(L2_PROTO_STP_IDX, 0, "stp"),
|
|
|
|
USHORTMAP_ENTRY_IDX(L2_PROTO_MAC_IDX, 0, "mac"),
|
|
|
|
USHORTMAP_ENTRY_IDX(L3_PROTO_LAST_IDX, 0, NULL),
|
2010-03-25 17:46:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static char chainprefixes_host[3] = {
|
|
|
|
CHAINPREFIX_HOST_IN,
|
|
|
|
CHAINPREFIX_HOST_OUT,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
static char chainprefixes_host_temp[3] = {
|
|
|
|
CHAINPREFIX_HOST_IN_TEMP,
|
|
|
|
CHAINPREFIX_HOST_OUT_TEMP,
|
|
|
|
0
|
|
|
|
};
|
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
static int
|
2011-11-18 16:58:18 +00:00
|
|
|
printVar(virNWFilterVarCombIterPtr vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
char *buf, int bufsize,
|
|
|
|
nwItemDescPtr item,
|
2013-05-24 10:32:31 +00:00
|
|
|
bool *done)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2013-05-24 10:32:31 +00:00
|
|
|
*done = false;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
|
2011-11-18 16:58:18 +00:00
|
|
|
const char *val;
|
|
|
|
|
2012-01-11 11:42:37 +00:00
|
|
|
val = virNWFilterVarCombIterGetVarValue(vars, item->varAccess);
|
2011-11-18 16:58:18 +00:00
|
|
|
if (!val) {
|
2011-11-18 16:58:18 +00:00
|
|
|
/* error has been reported */
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2011-11-18 16:58:18 +00:00
|
|
|
}
|
|
|
|
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpy(buf, val, bufsize) < 0) {
|
2012-01-11 11:42:37 +00:00
|
|
|
const char *varName;
|
|
|
|
|
|
|
|
varName = virNWFilterVarAccessGetVarName(item->varAccess);
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Buffer too small to print variable "
|
|
|
|
"'%s' into"), varName);
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2013-05-24 10:32:31 +00:00
|
|
|
*done = true;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2011-11-18 16:58:18 +00:00
|
|
|
_printDataType(virNWFilterVarCombIterPtr vars,
|
2010-04-02 17:21:10 +00:00
|
|
|
char *buf, int bufsize,
|
|
|
|
nwItemDescPtr item,
|
2012-05-21 10:26:34 +00:00
|
|
|
bool asHex, bool directionIn)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2013-05-24 10:32:31 +00:00
|
|
|
bool done;
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree char *data = NULL;
|
2012-05-21 10:26:34 +00:00
|
|
|
uint8_t ctr;
|
2020-07-03 02:39:38 +00:00
|
|
|
g_auto(virBuffer) vb = VIR_BUFFER_INITIALIZER;
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree char *flags = NULL;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2011-12-09 02:26:34 +00:00
|
|
|
if (printVar(vars, buf, bufsize, item, &done) < 0)
|
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (done)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (item->datatype) {
|
|
|
|
case DATATYPE_IPADDR:
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
data = virSocketAddrFormat(&item->u.ipaddr);
|
2010-10-20 14:13:00 +00:00
|
|
|
if (!data)
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2019-11-13 13:53:42 +00:00
|
|
|
if (g_snprintf(buf, bufsize, "%s", data) >= bufsize) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("buffer too small for IP address"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-03-25 17:46:11 +00:00
|
|
|
case DATATYPE_IPV6ADDR:
|
Santize naming of socket address APIs
The socket address APIs in src/util/network.h either take the
form virSocketAddrXXX, virSocketXXX or virSocketXXXAddr.
Sanitize this so everything is virSocketAddrXXXX, and ensure
that the virSocketAddr parameter is always the first one.
* src/util/network.c, src/util/network.h: Santize socket
address API naming
* src/conf/domain_conf.c, src/conf/network_conf.c,
src/conf/nwfilter_conf.c, src/network/bridge_driver.c,
src/nwfilter/nwfilter_ebiptables_driver.c,
src/nwfilter/nwfilter_learnipaddr.c,
src/qemu/qemu_command.c, src/rpc/virnetsocket.c,
src/util/dnsmasq.c, src/util/iptables.c,
src/util/virnetdev.c, src/vbox/vbox_tmpl.c: Update for
API renaming
2011-11-02 14:06:59 +00:00
|
|
|
data = virSocketAddrFormat(&item->u.ipaddr);
|
2010-10-20 14:13:00 +00:00
|
|
|
if (!data)
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-30 15:18:04 +00:00
|
|
|
|
2019-11-13 13:53:42 +00:00
|
|
|
if (g_snprintf(buf, bufsize, "%s", data) >= bufsize) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("buffer too small for IPv6 address"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
case DATATYPE_MACADDR:
|
2010-04-01 10:37:26 +00:00
|
|
|
case DATATYPE_MACMASK:
|
2010-03-25 17:46:09 +00:00
|
|
|
if (bufsize < VIR_MAC_STRING_BUFLEN) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer too small for MAC address"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2012-07-17 12:07:59 +00:00
|
|
|
virMacAddrFormat(&item->u.macaddr, buf);
|
2010-03-25 17:46:09 +00:00
|
|
|
break;
|
|
|
|
|
2010-04-02 17:21:10 +00:00
|
|
|
case DATATYPE_IPV6MASK:
|
|
|
|
case DATATYPE_IPMASK:
|
2019-11-13 13:53:42 +00:00
|
|
|
if (g_snprintf(buf, bufsize, "%d",
|
|
|
|
item->u.u8) >= bufsize) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer too small for uint8 type"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-04-02 17:21:10 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2011-11-22 20:12:03 +00:00
|
|
|
case DATATYPE_UINT32:
|
|
|
|
case DATATYPE_UINT32_HEX:
|
2019-11-13 13:53:42 +00:00
|
|
|
if (g_snprintf(buf, bufsize, asHex ? "0x%x" : "%u",
|
|
|
|
item->u.u32) >= bufsize) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer too small for uint32 type"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2011-11-22 20:12:03 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-04-02 17:21:10 +00:00
|
|
|
case DATATYPE_UINT16:
|
2010-04-26 17:50:40 +00:00
|
|
|
case DATATYPE_UINT16_HEX:
|
2019-11-13 13:53:42 +00:00
|
|
|
if (g_snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
|
|
|
|
item->u.u16) >= bufsize) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer too small for uint16 type"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATATYPE_UINT8:
|
2010-04-26 17:50:40 +00:00
|
|
|
case DATATYPE_UINT8_HEX:
|
2019-11-13 13:53:42 +00:00
|
|
|
if (g_snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
|
|
|
|
item->u.u8) >= bufsize) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer too small for uint8 type"));
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2012-05-21 10:26:34 +00:00
|
|
|
case DATATYPE_IPSETNAME:
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpy(buf, item->u.ipset.setname, bufsize) < 0) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer to small for ipset name"));
|
2012-05-21 10:26:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DATATYPE_IPSETFLAGS:
|
|
|
|
for (ctr = 0; ctr < item->u.ipset.numFlags; ctr++) {
|
|
|
|
if (ctr != 0)
|
|
|
|
virBufferAddLit(&vb, ",");
|
|
|
|
if ((item->u.ipset.flags & (1 << ctr))) {
|
|
|
|
if (directionIn)
|
|
|
|
virBufferAddLit(&vb, "dst");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&vb, "src");
|
|
|
|
} else {
|
|
|
|
if (directionIn)
|
|
|
|
virBufferAddLit(&vb, "src");
|
|
|
|
else
|
|
|
|
virBufferAddLit(&vb, "dst");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
flags = virBufferContentAndReset(&vb);
|
|
|
|
|
2018-07-20 07:50:37 +00:00
|
|
|
if (virStrcpy(buf, flags, bufsize) < 0) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("Buffer too small for IPSETFLAGS type"));
|
2012-05-21 10:26:34 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
case DATATYPE_STRING:
|
|
|
|
case DATATYPE_STRINGCOPY:
|
|
|
|
case DATATYPE_BOOLEAN:
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
2018-02-14 09:43:59 +00:00
|
|
|
_("Cannot print data type %x"), item->datatype);
|
|
|
|
return -1;
|
|
|
|
case DATATYPE_LAST:
|
|
|
|
default:
|
|
|
|
virReportEnumRangeError(virNWFilterAttrDataType, item->datatype);
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-02 17:21:10 +00:00
|
|
|
static int
|
2011-11-18 16:58:18 +00:00
|
|
|
printDataType(virNWFilterVarCombIterPtr vars,
|
2010-04-02 17:21:10 +00:00
|
|
|
char *buf, int bufsize,
|
|
|
|
nwItemDescPtr item)
|
|
|
|
{
|
2012-05-21 10:26:34 +00:00
|
|
|
return _printDataType(vars, buf, bufsize, item, 0, 0);
|
2010-04-02 17:21:10 +00:00
|
|
|
}
|
|
|
|
|
2012-05-21 10:26:34 +00:00
|
|
|
static int
|
|
|
|
printDataTypeDirection(virNWFilterVarCombIterPtr vars,
|
|
|
|
char *buf, int bufsize,
|
|
|
|
nwItemDescPtr item, bool directionIn)
|
|
|
|
{
|
|
|
|
return _printDataType(vars, buf, bufsize, item, 0, directionIn);
|
|
|
|
}
|
2010-04-02 17:21:10 +00:00
|
|
|
|
|
|
|
static int
|
2011-11-18 16:58:18 +00:00
|
|
|
printDataTypeAsHex(virNWFilterVarCombIterPtr vars,
|
2010-04-02 17:21:10 +00:00
|
|
|
char *buf, int bufsize,
|
|
|
|
nwItemDescPtr item)
|
|
|
|
{
|
2012-05-21 10:26:34 +00:00
|
|
|
return _printDataType(vars, buf, bufsize, item, 1, 0);
|
2010-04-02 17:21:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesHandleEthHdr(virFirewallPtr fw,
|
|
|
|
virFirewallRulePtr fwrule,
|
2011-11-18 16:58:18 +00:00
|
|
|
virNWFilterVarCombIterPtr vars,
|
2010-04-06 14:40:35 +00:00
|
|
|
ethHdrDataDefPtr ethHdr,
|
|
|
|
bool reverse)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
2014-03-25 14:33:19 +00:00
|
|
|
char macmask[VIR_MAC_STRING_BUFLEN];
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
macaddr, sizeof(macaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
ðHdr->dataSrcMACAddr) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
reverse ? "-d" : "-s",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(ðHdr->dataSrcMACAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
macmask, sizeof(macmask),
|
2011-12-09 02:26:34 +00:00
|
|
|
ðHdr->dataSrcMACMask) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", macaddr, macmask);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, macaddr);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(ðHdr->dataDstMACAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
macaddr, sizeof(macaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
ðHdr->dataDstMACAddr) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
reverse ? "-s" : "-d",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(ðHdr->dataDstMACAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(ðHdr->dataDstMACMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
macmask, sizeof(macmask),
|
2011-12-09 02:26:34 +00:00
|
|
|
ðHdr->dataDstMACMask) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", macaddr, macmask);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, macaddr);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/************************ iptables support ************************/
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateBaseChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-N", VIRT_IN_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-N", VIRT_OUT_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-N", VIRT_IN_POST_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-N", HOST_IN_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", "FORWARD", "-j", VIRT_IN_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", "FORWARD", "-j", VIRT_OUT_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", "FORWARD", "-j", VIRT_IN_POST_CHAIN, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", "INPUT", "-j", HOST_IN_CHAIN, NULL);
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-I", "FORWARD", "1", "-j", VIRT_IN_CHAIN, NULL);
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-I", "FORWARD", "2", "-j", VIRT_OUT_CHAIN, NULL);
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-I", "FORWARD", "3", "-j", VIRT_IN_POST_CHAIN, NULL);
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-I", "INPUT", "1", "-j", HOST_IN_CHAIN, NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
char prefix,
|
|
|
|
bool incoming, const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix[2] = {
|
|
|
|
prefix,
|
2014-03-14 13:24:28 +00:00
|
|
|
incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP
|
2010-03-25 17:46:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-N", chain, NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateTmpRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateTmpRootChainFW(fw, layer, 'F', false, ifname);
|
|
|
|
iptablesCreateTmpRootChainFW(fw, layer, 'F', true, ifname);
|
|
|
|
iptablesCreateTmpRootChainFW(fw, layer, 'H', true, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static void
|
|
|
|
_iptablesRemoveRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
char prefix,
|
|
|
|
bool incoming, const char *ifname,
|
|
|
|
int isTempChain)
|
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix[2] = {
|
|
|
|
prefix,
|
|
|
|
};
|
|
|
|
|
|
|
|
if (isTempChain)
|
|
|
|
chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
else
|
|
|
|
chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN
|
|
|
|
: CHAINPREFIX_HOST_OUT;
|
|
|
|
|
|
|
|
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-F", chain, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-X", chain, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
iptablesRemoveRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
char prefix,
|
|
|
|
bool incoming,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
_iptablesRemoveRootChainFW(fw, layer, prefix, incoming, ifname, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 12:48:33 +00:00
|
|
|
static void
|
|
|
|
iptablesRemoveTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
char prefix,
|
|
|
|
bool incoming,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
_iptablesRemoveRootChainFW(fw, layer, prefix,
|
|
|
|
incoming, ifname, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
iptablesRemoveTmpRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
iptablesRemoveTmpRootChainFW(fw, layer, 'F', false, ifname);
|
|
|
|
iptablesRemoveTmpRootChainFW(fw, layer, 'F', true, ifname);
|
|
|
|
iptablesRemoveTmpRootChainFW(fw, layer, 'H', true, ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static void
|
|
|
|
iptablesRemoveRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
iptablesRemoveRootChainFW(fw, layer, 'F', false, ifname);
|
|
|
|
iptablesRemoveRootChainFW(fw, layer, 'F', true, ifname);
|
|
|
|
iptablesRemoveRootChainFW(fw, layer, 'H', true, ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesLinkTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *basechain,
|
|
|
|
char prefix,
|
|
|
|
bool incoming, const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix[2] = {
|
|
|
|
prefix,
|
2014-03-14 13:24:28 +00:00
|
|
|
incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP
|
2010-03-25 17:46:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (incoming)
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-A", basechain,
|
|
|
|
MATCH_PHYSDEV_IN_FW,
|
|
|
|
ifname,
|
|
|
|
"-g", chain, NULL);
|
|
|
|
else
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-A", basechain,
|
|
|
|
MATCH_PHYSDEV_OUT_FW,
|
|
|
|
ifname,
|
|
|
|
"-g", chain, NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesLinkTmpRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesLinkTmpRootChainFW(fw, layer, VIRT_OUT_CHAIN, 'F', false, ifname);
|
|
|
|
iptablesLinkTmpRootChainFW(fw, layer, VIRT_IN_CHAIN, 'F', true, ifname);
|
|
|
|
iptablesLinkTmpRootChainFW(fw, layer, HOST_IN_CHAIN, 'H', true, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2019-10-14 12:45:33 +00:00
|
|
|
iptablesSetupVirtInPostFW(virFirewallPtr fw G_GNUC_UNUSED,
|
|
|
|
virFirewallLayer layer G_GNUC_UNUSED,
|
|
|
|
const char *ifname G_GNUC_UNUSED)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", VIRT_IN_POST_CHAIN,
|
|
|
|
MATCH_PHYSDEV_IN_FW,
|
|
|
|
ifname, "-j", "ACCEPT", NULL);
|
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-A", VIRT_IN_POST_CHAIN,
|
|
|
|
MATCH_PHYSDEV_IN_FW,
|
|
|
|
ifname, "-j", "ACCEPT", NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-14 11:53:06 +00:00
|
|
|
iptablesClearVirtInPostFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2014-03-14 11:53:06 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", VIRT_IN_POST_CHAIN,
|
|
|
|
MATCH_PHYSDEV_IN_FW,
|
|
|
|
ifname, "-j", "ACCEPT", NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static void
|
|
|
|
_iptablesUnlinkRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *basechain,
|
|
|
|
char prefix,
|
|
|
|
bool incoming, const char *ifname,
|
|
|
|
int isTempChain)
|
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix[2] = {
|
|
|
|
prefix,
|
|
|
|
};
|
|
|
|
if (isTempChain)
|
|
|
|
chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
else
|
|
|
|
chainPrefix[1] = incoming ? CHAINPREFIX_HOST_IN
|
|
|
|
: CHAINPREFIX_HOST_OUT;
|
|
|
|
|
|
|
|
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
|
|
|
if (incoming)
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", basechain,
|
|
|
|
MATCH_PHYSDEV_IN_FW, ifname,
|
|
|
|
"-g", chain,
|
|
|
|
NULL);
|
|
|
|
else
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", basechain,
|
|
|
|
MATCH_PHYSDEV_OUT_FW, ifname,
|
|
|
|
"-g", chain,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Previous versions of libvirt may have created a rule
|
|
|
|
* with the --physdev-is-bridged missing. Remove this one
|
|
|
|
* as well.
|
|
|
|
*/
|
|
|
|
if (!incoming)
|
|
|
|
virFirewallAddRuleFull(fw, layer,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-D", basechain,
|
|
|
|
MATCH_PHYSDEV_OUT_OLD_FW, ifname,
|
|
|
|
"-g", chain,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
iptablesUnlinkRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *basechain,
|
|
|
|
char prefix,
|
|
|
|
bool incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
_iptablesUnlinkRootChainFW(fw, layer,
|
|
|
|
basechain, prefix, incoming, ifname, false);
|
|
|
|
}
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-14 12:48:33 +00:00
|
|
|
static void
|
|
|
|
iptablesUnlinkTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *basechain,
|
|
|
|
char prefix,
|
|
|
|
bool incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
_iptablesUnlinkRootChainFW(fw, layer,
|
|
|
|
basechain, prefix, incoming, ifname, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static void
|
|
|
|
iptablesUnlinkRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
iptablesUnlinkRootChainFW(fw, layer, VIRT_OUT_CHAIN, 'F', false, ifname);
|
|
|
|
iptablesUnlinkRootChainFW(fw, layer, VIRT_IN_CHAIN, 'F', true, ifname);
|
|
|
|
iptablesUnlinkRootChainFW(fw, layer, HOST_IN_CHAIN, 'H', true, ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 12:48:33 +00:00
|
|
|
static void
|
|
|
|
iptablesUnlinkTmpRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
iptablesUnlinkTmpRootChainFW(fw, layer, VIRT_OUT_CHAIN, 'F', false, ifname);
|
|
|
|
iptablesUnlinkTmpRootChainFW(fw, layer, VIRT_IN_CHAIN, 'F', true, ifname);
|
|
|
|
iptablesUnlinkTmpRootChainFW(fw, layer, HOST_IN_CHAIN, 'H', true, ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-14 12:05:00 +00:00
|
|
|
iptablesRenameTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
char prefix,
|
|
|
|
bool incoming,
|
|
|
|
const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char tmpChainPrefix[2] = {
|
|
|
|
prefix,
|
2014-03-14 13:24:28 +00:00
|
|
|
incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP
|
2010-03-25 17:46:12 +00:00
|
|
|
};
|
|
|
|
char chainPrefix[2] = {
|
|
|
|
prefix,
|
2014-03-14 13:24:28 +00:00
|
|
|
incoming ? CHAINPREFIX_HOST_IN
|
|
|
|
: CHAINPREFIX_HOST_OUT
|
2010-03-25 17:46:12 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
PRINT_IPT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
|
2012-10-17 09:23:12 +00:00
|
|
|
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
virFirewallAddRule(fw, layer,
|
|
|
|
"-E", tmpchain, chain, NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-14 12:05:00 +00:00
|
|
|
iptablesRenameTmpRootChainsFW(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
const char *ifname)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2014-03-14 12:05:00 +00:00
|
|
|
iptablesRenameTmpRootChainFW(fw, layer, 'F', false, ifname);
|
|
|
|
iptablesRenameTmpRootChainFW(fw, layer, 'F', true, ifname);
|
|
|
|
iptablesRenameTmpRootChainFW(fw, layer, 'H', true, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesHandleSrcMacAddr(virFirewallPtr fw,
|
|
|
|
virFirewallRulePtr fwrule,
|
2011-11-18 16:58:18 +00:00
|
|
|
virNWFilterVarCombIterPtr vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
nwItemDescPtr srcMacAddr,
|
2013-05-24 10:32:31 +00:00
|
|
|
bool directionIn,
|
2010-04-07 10:28:16 +00:00
|
|
|
bool *srcmacskipped)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
2014-03-25 14:33:19 +00:00
|
|
|
|
2010-04-07 10:28:16 +00:00
|
|
|
*srcmacskipped = false;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(srcMacAddr)) {
|
2010-04-07 10:28:16 +00:00
|
|
|
if (directionIn) {
|
|
|
|
*srcmacskipped = true;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
macaddr, sizeof(macaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
srcMacAddr) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "mac",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(srcMacAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"--mac-source",
|
|
|
|
macaddr,
|
|
|
|
NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2016-06-08 16:48:50 +00:00
|
|
|
iptablesHandleIPHdr(virFirewallPtr fw,
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRulePtr fwrule,
|
2011-11-18 16:58:18 +00:00
|
|
|
virNWFilterVarCombIterPtr vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
ipHdrDataDefPtr ipHdr,
|
2013-05-24 10:32:31 +00:00
|
|
|
bool directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
bool *skipRule, bool *skipMatch)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
2020-01-14 13:30:07 +00:00
|
|
|
char ipaddr[INET6_ADDRSTRLEN];
|
|
|
|
char ipaddralt[INET6_ADDRSTRLEN];
|
|
|
|
char number[VIR_INT64_STR_BUFLEN];
|
2010-03-25 17:46:12 +00:00
|
|
|
const char *src = "--source";
|
|
|
|
const char *dst = "--destination";
|
|
|
|
const char *srcrange = "--src-range";
|
|
|
|
const char *dstrange = "--dst-range";
|
2014-03-25 14:33:19 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (directionIn) {
|
|
|
|
src = "--destination";
|
|
|
|
dst = "--source";
|
|
|
|
srcrange = "--dst-range";
|
|
|
|
dstrange = "--src-range";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataSrcIPAddr) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&ipHdr->dataSrcIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, src);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPMask)) {
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataSrcIPMask) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipaddr, number);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipaddr);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
} else if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPFrom)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataSrcIPFrom) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "iprange",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&ipHdr->dataSrcIPFrom))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, srcrange);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPTo)) {
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
ipaddralt, sizeof(ipaddralt),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataSrcIPTo) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s-%s", ipaddr, ipaddralt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipaddr);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataDstIPAddr) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&ipHdr->dataDstIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, dst);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataDstIPMask) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipaddr, number);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipaddr);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
} else if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPFrom)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataDstIPFrom) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "iprange",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&ipHdr->dataDstIPFrom))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, dstrange);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPTo)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
ipaddralt, sizeof(ipaddralt),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataDstIPTo) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s-%s", ipaddr, ipaddralt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipaddr);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataDSCP)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataDSCP) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "dscp",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&ipHdr->dataDSCP))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"--dscp", number,
|
|
|
|
NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2010-04-20 21:14:38 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataConnlimitAbove)) {
|
|
|
|
if (directionIn) {
|
2011-01-28 21:38:06 +00:00
|
|
|
/* only support for limit in outgoing dir. */
|
2010-04-20 21:14:38 +00:00
|
|
|
*skipRule = true;
|
|
|
|
} else {
|
2014-03-25 14:33:19 +00:00
|
|
|
*skipMatch = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2014-03-25 14:33:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2016-06-08 16:48:50 +00:00
|
|
|
iptablesHandleIPHdrAfterStateMatch(virFirewallPtr fw,
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRulePtr fwrule,
|
|
|
|
virNWFilterVarCombIterPtr vars,
|
|
|
|
ipHdrDataDefPtr ipHdr,
|
|
|
|
bool directionIn)
|
|
|
|
{
|
2020-01-14 13:30:07 +00:00
|
|
|
char number[VIR_INT64_STR_BUFLEN];
|
2014-03-25 14:33:19 +00:00
|
|
|
char str[MAX_IPSET_NAME_LENGTH];
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataIPSet) &&
|
|
|
|
HAS_ENTRY_ITEM(&ipHdr->dataIPSetFlags)) {
|
|
|
|
|
|
|
|
if (printDataType(vars,
|
|
|
|
str, sizeof(str),
|
|
|
|
&ipHdr->dataIPSet) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "set",
|
|
|
|
"--match-set", str,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (printDataTypeDirection(vars,
|
|
|
|
str, sizeof(str),
|
|
|
|
&ipHdr->dataIPSetFlags, directionIn) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, str);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataConnlimitAbove)) {
|
|
|
|
if (!directionIn) {
|
2010-04-20 21:14:38 +00:00
|
|
|
if (printDataType(vars,
|
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&ipHdr->dataConnlimitAbove) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-04-20 21:14:38 +00:00
|
|
|
|
2011-02-14 19:10:24 +00:00
|
|
|
/* place connlimit after potential -m state --state ...
|
|
|
|
since this is the most useful order */
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "connlimit",
|
|
|
|
NULL);
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&ipHdr->dataConnlimitAbove))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"--connlimit-above", number,
|
|
|
|
NULL);
|
2010-04-20 21:14:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-30 19:56:09 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&ipHdr->dataComment)) {
|
2011-02-14 19:10:24 +00:00
|
|
|
/* keep comments behind everything else -- they are packet eval.
|
|
|
|
no-ops */
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "comment",
|
|
|
|
"--comment", ipHdr->dataComment.u.string,
|
|
|
|
NULL);
|
2010-09-30 19:56:09 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesHandlePortData(virFirewallPtr fw,
|
|
|
|
virFirewallRulePtr fwrule,
|
2011-11-18 16:58:18 +00:00
|
|
|
virNWFilterVarCombIterPtr vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
portDataDefPtr portData,
|
2013-05-24 10:32:31 +00:00
|
|
|
bool directionIn)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2010-03-25 17:46:12 +00:00
|
|
|
char portstr[20];
|
2014-03-25 14:33:19 +00:00
|
|
|
char portstralt[20];
|
2010-03-25 17:46:12 +00:00
|
|
|
const char *sport = "--sport";
|
|
|
|
const char *dport = "--dport";
|
|
|
|
if (directionIn) {
|
|
|
|
sport = "--dport";
|
|
|
|
dport = "--sport";
|
|
|
|
}
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
portstr, sizeof(portstr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&portData->dataSrcPortStart) < 0)
|
2020-01-06 21:57:31 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&portData->dataSrcPortStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, sport);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&portData->dataSrcPortEnd)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
portstralt, sizeof(portstralt),
|
2011-12-09 02:26:34 +00:00
|
|
|
&portData->dataSrcPortEnd) < 0)
|
2020-01-06 21:57:31 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s:%s", portstr, portstralt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, portstr);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&portData->dataDstPortStart)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
portstr, sizeof(portstr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&portData->dataDstPortStart) < 0)
|
2020-01-06 21:57:31 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&portData->dataDstPortStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, dport);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
portstralt, sizeof(portstralt),
|
2011-12-09 02:26:34 +00:00
|
|
|
&portData->dataDstPortEnd) < 0)
|
2020-01-06 21:57:31 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s:%s", portstr, portstralt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, portstr);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-14 12:54:03 +00:00
|
|
|
|
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesEnforceDirection(virFirewallPtr fw,
|
|
|
|
virFirewallRulePtr fwrule,
|
|
|
|
bool directionIn,
|
|
|
|
virNWFilterRuleDefPtr rule)
|
2010-10-14 12:54:03 +00:00
|
|
|
{
|
2013-05-16 01:02:11 +00:00
|
|
|
switch (iptables_ctdir_corrected) {
|
|
|
|
case CTDIR_STATUS_UNKNOWN:
|
|
|
|
/* could not be determined or s.th. is seriously wrong */
|
|
|
|
return;
|
|
|
|
case CTDIR_STATUS_CORRECTED:
|
|
|
|
directionIn = !directionIn;
|
|
|
|
break;
|
|
|
|
case CTDIR_STATUS_OLD:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-10-14 12:54:03 +00:00
|
|
|
if (rule->tt != VIR_NWFILTER_RULE_DIRECTION_INOUT)
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "conntrack",
|
|
|
|
"--ctdir",
|
|
|
|
(directionIn ?
|
|
|
|
"Original" :
|
|
|
|
"Reply"),
|
|
|
|
NULL);
|
2010-10-14 12:54:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
/*
|
|
|
|
* _iptablesCreateRuleInstance:
|
2014-03-25 14:33:19 +00:00
|
|
|
* @fw: the firewall ruleset instance
|
|
|
|
* @layer: the firewall layer
|
2010-03-25 17:46:12 +00:00
|
|
|
* @chainPrefix : The prefix to put in front of the name of the chain
|
|
|
|
* @rule: The rule of the filter to convert
|
|
|
|
* @ifname : The name of the interface to apply the rule to
|
|
|
|
* @vars : A map containing the variables to resolve
|
2010-04-08 10:25:38 +00:00
|
|
|
* @match : optional string for state match
|
|
|
|
* @accept_target : where to jump to on accepted traffic, i.e., "RETURN"
|
|
|
|
* "ACCEPT"
|
|
|
|
* @maySkipICMP : whether this rule may under certain circumstances skip
|
|
|
|
* the ICMP rule from being created
|
2010-03-25 17:46:12 +00:00
|
|
|
*
|
|
|
|
* Convert a single rule into its representation for later instantiation
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success with the result stored in the data structure
|
2011-11-23 19:13:03 +00:00
|
|
|
* pointed to by res, != 0 otherwise.
|
2010-03-25 17:46:12 +00:00
|
|
|
*/
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
_iptablesCreateRuleInstance(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
bool directionIn,
|
2010-03-25 17:46:12 +00:00
|
|
|
const char *chainPrefix,
|
|
|
|
virNWFilterRuleDefPtr rule,
|
|
|
|
const char *ifname,
|
2011-11-18 16:58:18 +00:00
|
|
|
virNWFilterVarCombIterPtr vars,
|
2010-10-07 10:41:37 +00:00
|
|
|
const char *match, bool defMatch,
|
2010-03-30 14:36:35 +00:00
|
|
|
const char *accept_target,
|
2014-03-25 14:33:19 +00:00
|
|
|
bool maySkipICMP)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
2020-01-14 13:30:07 +00:00
|
|
|
char number[VIR_INT64_STR_BUFLEN];
|
|
|
|
char numberalt[VIR_INT64_STR_BUFLEN];
|
2010-03-25 17:46:12 +00:00
|
|
|
const char *target;
|
2010-04-07 10:28:16 +00:00
|
|
|
bool srcMacSkipped = false;
|
2010-04-20 21:14:38 +00:00
|
|
|
bool skipRule = false;
|
|
|
|
bool skipMatch = false;
|
2010-10-19 23:25:37 +00:00
|
|
|
bool hasICMPType = false;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRulePtr fwrule;
|
|
|
|
size_t fwruleargs;
|
2010-04-14 10:29:55 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
switch ((int)rule->prtclType) {
|
2010-03-25 17:46:12 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_TCP:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "tcp",
|
|
|
|
NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.tcpHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.tcpHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2011-04-08 00:13:38 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPFlags)) {
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree char *mask = NULL;
|
|
|
|
g_autofree char *flags = NULL;
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPFlags))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--tcp-flags");
|
|
|
|
|
2020-06-25 01:59:39 +00:00
|
|
|
if (!(mask = virNWFilterPrintTCPFlags(rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.mask)))
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2020-06-25 01:59:39 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, mask);
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (!(flags = virNWFilterPrintTCPFlags(rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.flags)))
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, flags);
|
2011-04-08 00:13:38 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandlePortData(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.tcpHdrFilter.portData,
|
2011-12-09 02:26:34 +00:00
|
|
|
directionIn) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPOption)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.tcpHdrFilter.dataTCPOption) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPOption))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"--tcp-option", number, NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_UDP:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "udp",
|
|
|
|
NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.udpHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.udpHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandlePortData(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.udpHdrFilter.portData,
|
2011-12-09 02:26:34 +00:00
|
|
|
directionIn) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
break;
|
|
|
|
|
2010-03-30 14:16:40 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "udplite",
|
|
|
|
NULL);
|
2010-03-30 14:16:40 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-04-07 10:28:16 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-30 14:16:40 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.udpliteHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-30 14:16:40 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-30 14:16:40 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.udpliteHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-30 14:16:40 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ESP:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "esp",
|
|
|
|
NULL);
|
2010-03-30 14:16:40 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-04-07 10:28:16 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-30 14:16:40 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.espHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-30 14:16:40 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-30 14:16:40 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.espHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-30 14:16:40 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_AH:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "ah",
|
|
|
|
NULL);
|
2010-03-30 14:16:40 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-04-07 10:28:16 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-30 14:16:40 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.ahHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-30 14:16:40 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-30 14:16:40 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.ahHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-30 14:16:40 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "sctp",
|
|
|
|
NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.sctpHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.sctpHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandlePortData(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.sctpHdrFilter.portData,
|
2011-12-09 02:26:34 +00:00
|
|
|
directionIn) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2010-03-30 14:36:35 +00:00
|
|
|
if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-p", "icmp", NULL);
|
2010-03-30 14:36:35 +00:00
|
|
|
else
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-p", "icmpv6", NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-04-07 10:28:16 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.icmpHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.icmpHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPType)) {
|
2010-04-02 17:21:10 +00:00
|
|
|
const char *parm;
|
2010-04-08 10:25:38 +00:00
|
|
|
|
2010-10-19 23:25:37 +00:00
|
|
|
hasICMPType = true;
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (maySkipICMP) {
|
|
|
|
virFirewallRemoveRule(fw, fwrule);
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2014-03-25 14:33:19 +00:00
|
|
|
}
|
2010-04-08 10:25:38 +00:00
|
|
|
|
2010-04-02 17:21:10 +00:00
|
|
|
if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
|
|
|
|
parm = "--icmp-type";
|
|
|
|
else
|
|
|
|
parm = "--icmpv6-type";
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:12 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.icmpHdrFilter.dataICMPType) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.icmpHdrFilter.dataICMPType))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, parm);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPCode)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
numberalt, sizeof(numberalt),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.icmpHdrFilter.dataICMPCode) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", number, numberalt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-04-02 17:21:10 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "igmp",
|
|
|
|
NULL);
|
2010-04-02 17:21:10 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-04-07 10:28:16 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-04-02 17:21:10 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.igmpHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-04-02 17:21:10 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-04-02 17:21:10 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.igmpHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-04-02 17:21:10 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ALL:
|
2010-03-30 14:36:35 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, layer,
|
|
|
|
"-A", chain,
|
|
|
|
"-p", "all",
|
|
|
|
NULL);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwruleargs = virFirewallRuleGetArgCount(fwrule);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesHandleSrcMacAddr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.allHdrFilter.dataSrcMACAddr,
|
2010-04-07 10:28:16 +00:00
|
|
|
directionIn,
|
2011-12-09 02:26:34 +00:00
|
|
|
&srcMacSkipped) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdr(fw, fwrule,
|
2010-03-25 17:46:12 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.allHdrFilter.ipHdr,
|
2010-04-20 21:14:38 +00:00
|
|
|
directionIn,
|
2014-03-25 14:33:19 +00:00
|
|
|
&skipRule, &skipMatch) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-03-25 14:33:19 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unexpected protocol %d"),
|
|
|
|
rule->prtclType);
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if ((srcMacSkipped &&
|
|
|
|
fwruleargs == virFirewallRuleGetArgCount(fwrule)) ||
|
|
|
|
skipRule) {
|
|
|
|
virFirewallRemoveRule(fw, fwrule);
|
2010-04-07 10:28:16 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-03 17:29:38 +00:00
|
|
|
if (rule->action == VIR_NWFILTER_RULE_ACTION_ACCEPT) {
|
2010-03-25 17:46:12 +00:00
|
|
|
target = accept_target;
|
2014-09-03 17:29:38 +00:00
|
|
|
} else {
|
2014-03-25 14:33:19 +00:00
|
|
|
target = virNWFilterJumpTargetTypeToString(rule->action);
|
|
|
|
skipMatch = defMatch;
|
2014-03-25 10:32:55 +00:00
|
|
|
}
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (match && !skipMatch) {
|
|
|
|
if (newMatchState)
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "conntrack",
|
|
|
|
"--ctstate", match,
|
|
|
|
NULL);
|
|
|
|
else
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-m", "state",
|
|
|
|
"--state", match,
|
|
|
|
NULL);
|
|
|
|
}
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (defMatch && match != NULL && !skipMatch && !hasICMPType)
|
|
|
|
iptablesEnforceDirection(fw, fwrule,
|
|
|
|
directionIn,
|
|
|
|
rule);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2016-06-08 16:48:50 +00:00
|
|
|
if (iptablesHandleIPHdrAfterStateMatch(fw, fwrule,
|
2014-03-25 14:33:19 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.allHdrFilter.ipHdr,
|
|
|
|
directionIn) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-j", target, NULL);
|
2010-04-08 10:25:38 +00:00
|
|
|
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-07 10:41:37 +00:00
|
|
|
static int
|
|
|
|
printStateMatchFlags(int32_t flags, char **bufptr)
|
|
|
|
{
|
2020-07-03 02:39:38 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
2010-10-07 10:41:37 +00:00
|
|
|
virNWFilterPrintStateMatchFlags(&buf,
|
2014-03-25 14:33:19 +00:00
|
|
|
"",
|
2010-10-07 10:41:37 +00:00
|
|
|
flags,
|
|
|
|
false);
|
|
|
|
*bufptr = virBufferContentAndReset(&buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateRuleInstanceStateCtrl(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
virNWFilterRuleDefPtr rule,
|
2010-10-07 10:41:37 +00:00
|
|
|
const char *ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
virNWFilterVarCombIterPtr vars)
|
2010-10-07 10:41:37 +00:00
|
|
|
{
|
2016-06-03 11:26:30 +00:00
|
|
|
int rc = 0;
|
2013-05-24 10:32:31 +00:00
|
|
|
bool directionIn = false;
|
2010-10-07 10:41:37 +00:00
|
|
|
char chainPrefix[2];
|
|
|
|
bool maySkipICMP, inout = false;
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree char *matchState1 = NULL;
|
|
|
|
g_autofree char *matchState2 = NULL;
|
|
|
|
g_autofree char *matchState3 = NULL;
|
2010-10-07 10:41:37 +00:00
|
|
|
bool create;
|
|
|
|
|
|
|
|
if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
|
|
|
|
(rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
|
2013-05-24 10:32:31 +00:00
|
|
|
directionIn = true;
|
2011-04-14 09:22:35 +00:00
|
|
|
inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
|
|
|
|
}
|
2010-10-07 10:41:37 +00:00
|
|
|
|
|
|
|
chainPrefix[0] = 'F';
|
|
|
|
|
|
|
|
maySkipICMP = directionIn || inout;
|
|
|
|
|
|
|
|
create = true;
|
|
|
|
|
|
|
|
if (directionIn && !inout) {
|
|
|
|
if ((rule->flags & IPTABLES_STATE_FLAGS))
|
|
|
|
create = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
|
2020-06-25 01:59:39 +00:00
|
|
|
if (printStateMatchFlags(rule->flags, &matchState1) < 0)
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-10-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
|
|
|
|
if (create) {
|
2014-03-25 14:33:19 +00:00
|
|
|
rc = _iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
directionIn,
|
2010-10-07 10:41:37 +00:00
|
|
|
chainPrefix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2020-06-25 01:59:39 +00:00
|
|
|
matchState1, false,
|
2010-10-07 10:41:37 +00:00
|
|
|
"RETURN",
|
2014-03-25 14:33:19 +00:00
|
|
|
maySkipICMP);
|
2010-10-07 10:41:37 +00:00
|
|
|
|
2011-12-09 02:26:34 +00:00
|
|
|
if (rc < 0)
|
2010-10-07 10:41:37 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
maySkipICMP = !directionIn || inout;
|
|
|
|
create = true;
|
|
|
|
|
|
|
|
if (!directionIn) {
|
|
|
|
if ((rule->flags & IPTABLES_STATE_FLAGS))
|
|
|
|
create = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
|
2020-06-25 01:59:39 +00:00
|
|
|
if (printStateMatchFlags(rule->flags, &matchState2) < 0)
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-10-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
if (create) {
|
2014-03-25 14:33:19 +00:00
|
|
|
rc = _iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
!directionIn,
|
2010-10-07 10:41:37 +00:00
|
|
|
chainPrefix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2020-06-25 01:59:39 +00:00
|
|
|
matchState2, false,
|
2010-10-07 10:41:37 +00:00
|
|
|
"ACCEPT",
|
2014-03-25 14:33:19 +00:00
|
|
|
maySkipICMP);
|
2011-12-09 02:26:34 +00:00
|
|
|
if (rc < 0)
|
2010-10-07 10:41:37 +00:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
maySkipICMP = directionIn;
|
|
|
|
|
|
|
|
create = true;
|
|
|
|
|
|
|
|
if (directionIn && !inout) {
|
|
|
|
if ((rule->flags & IPTABLES_STATE_FLAGS))
|
|
|
|
create = false;
|
|
|
|
} else {
|
|
|
|
if ((rule->flags & IPTABLES_STATE_FLAGS)) {
|
2020-06-25 01:59:39 +00:00
|
|
|
if (printStateMatchFlags(rule->flags, &matchState3) < 0)
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-10-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (create) {
|
|
|
|
chainPrefix[0] = 'H';
|
|
|
|
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
|
2014-03-25 14:33:19 +00:00
|
|
|
rc = _iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
directionIn,
|
2010-10-07 10:41:37 +00:00
|
|
|
chainPrefix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2020-06-25 01:59:39 +00:00
|
|
|
matchState3, false,
|
2010-10-07 10:41:37 +00:00
|
|
|
"RETURN",
|
2014-03-25 14:33:19 +00:00
|
|
|
maySkipICMP);
|
2010-10-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateRuleInstance(virFirewallPtr fw,
|
|
|
|
virFirewallLayer layer,
|
|
|
|
virNWFilterRuleDefPtr rule,
|
2010-03-25 17:46:12 +00:00
|
|
|
const char *ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
virNWFilterVarCombIterPtr vars)
|
2010-03-25 17:46:12 +00:00
|
|
|
{
|
|
|
|
int rc;
|
2013-05-24 10:32:31 +00:00
|
|
|
bool directionIn = false;
|
2010-03-25 17:46:12 +00:00
|
|
|
char chainPrefix[2];
|
2013-05-24 10:14:02 +00:00
|
|
|
bool needState = true;
|
2010-04-08 10:25:38 +00:00
|
|
|
bool maySkipICMP, inout = false;
|
2010-06-17 11:15:20 +00:00
|
|
|
const char *matchState;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2010-10-07 10:41:37 +00:00
|
|
|
if (!(rule->flags & RULE_FLAG_NO_STATEMATCH) &&
|
|
|
|
(rule->flags & IPTABLES_STATE_FLAGS)) {
|
2014-03-25 14:33:19 +00:00
|
|
|
return iptablesCreateRuleInstanceStateCtrl(fw,
|
|
|
|
layer,
|
|
|
|
rule,
|
2010-10-07 10:41:37 +00:00
|
|
|
ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
vars);
|
2010-10-07 10:41:37 +00:00
|
|
|
}
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
|
|
|
|
(rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
|
2013-05-24 10:32:31 +00:00
|
|
|
directionIn = true;
|
2010-04-08 10:25:38 +00:00
|
|
|
inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
|
2010-06-17 11:15:20 +00:00
|
|
|
if (inout)
|
2013-05-24 10:14:02 +00:00
|
|
|
needState = false;
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
2010-06-17 18:12:34 +00:00
|
|
|
if ((rule->flags & RULE_FLAG_NO_STATEMATCH))
|
2013-05-24 10:14:02 +00:00
|
|
|
needState = false;
|
2010-06-17 18:12:34 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix[0] = 'F';
|
|
|
|
|
2010-04-08 10:25:38 +00:00
|
|
|
maySkipICMP = directionIn || inout;
|
|
|
|
|
2010-06-17 11:15:20 +00:00
|
|
|
if (needState)
|
2014-03-25 14:33:19 +00:00
|
|
|
matchState = directionIn ? "ESTABLISHED" : "NEW,ESTABLISHED";
|
2010-06-17 11:15:20 +00:00
|
|
|
else
|
|
|
|
matchState = NULL;
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
|
2014-03-25 14:33:19 +00:00
|
|
|
rc = _iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
directionIn,
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2010-10-07 10:41:37 +00:00
|
|
|
matchState, true,
|
2010-03-30 14:36:35 +00:00
|
|
|
"RETURN",
|
2014-03-25 14:33:19 +00:00
|
|
|
maySkipICMP);
|
2011-12-09 02:26:34 +00:00
|
|
|
if (rc < 0)
|
2010-03-25 17:46:12 +00:00
|
|
|
return rc;
|
|
|
|
|
2010-04-08 10:25:38 +00:00
|
|
|
|
|
|
|
maySkipICMP = !directionIn || inout;
|
2010-06-17 11:15:20 +00:00
|
|
|
if (needState)
|
2014-03-25 14:33:19 +00:00
|
|
|
matchState = directionIn ? "NEW,ESTABLISHED" : "ESTABLISHED";
|
2010-06-17 11:15:20 +00:00
|
|
|
else
|
|
|
|
matchState = NULL;
|
2010-04-08 10:25:38 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
|
2014-03-25 14:33:19 +00:00
|
|
|
rc = _iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
!directionIn,
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2010-10-07 10:41:37 +00:00
|
|
|
matchState, true,
|
2010-03-30 14:36:35 +00:00
|
|
|
"ACCEPT",
|
2014-03-25 14:33:19 +00:00
|
|
|
maySkipICMP);
|
2011-12-09 02:26:34 +00:00
|
|
|
if (rc < 0)
|
2010-03-25 17:46:12 +00:00
|
|
|
return rc;
|
|
|
|
|
2010-04-08 10:25:38 +00:00
|
|
|
maySkipICMP = directionIn;
|
2010-10-19 15:35:58 +00:00
|
|
|
if (needState)
|
2014-03-25 14:33:19 +00:00
|
|
|
matchState = directionIn ? "ESTABLISHED" : "NEW,ESTABLISHED";
|
2010-10-19 15:35:58 +00:00
|
|
|
else
|
|
|
|
matchState = NULL;
|
2010-04-08 10:25:38 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix[0] = 'H';
|
|
|
|
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
|
2014-03-25 14:33:19 +00:00
|
|
|
rc = _iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
directionIn,
|
2010-03-25 17:46:12 +00:00
|
|
|
chainPrefix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2010-10-19 15:35:58 +00:00
|
|
|
matchState, true,
|
|
|
|
"RETURN",
|
2014-03-25 14:33:19 +00:00
|
|
|
maySkipICMP);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
/*
|
|
|
|
* ebtablesCreateRuleInstance:
|
2014-03-25 14:33:19 +00:00
|
|
|
* @fw: the firewall ruleset to add to
|
2010-03-25 17:46:09 +00:00
|
|
|
* @chainPrefix : The prefix to put in front of the name of the chain
|
2014-03-25 10:32:55 +00:00
|
|
|
* @chainSuffix: The suffix to put on the end of the name of the chain
|
2010-03-25 17:46:09 +00:00
|
|
|
* @rule: The rule of the filter to convert
|
|
|
|
* @ifname : The name of the interface to apply the rule to
|
|
|
|
* @vars : A map containing the variables to resolve
|
2010-04-06 14:40:35 +00:00
|
|
|
* @reverse : Whether to reverse src and dst attributes
|
2010-03-25 17:46:09 +00:00
|
|
|
*
|
|
|
|
* Convert a single rule into its representation for later instantiation
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success with the result stored in the data structure
|
2011-11-23 19:13:03 +00:00
|
|
|
* pointed to by res, != 0 otherwise.
|
2010-03-25 17:46:09 +00:00
|
|
|
*/
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesCreateRuleInstance(virFirewallPtr fw,
|
|
|
|
char chainPrefix,
|
2014-03-25 10:32:55 +00:00
|
|
|
const char *chainSuffix,
|
2010-03-25 17:46:09 +00:00
|
|
|
virNWFilterRuleDefPtr rule,
|
|
|
|
const char *ifname,
|
2011-11-18 16:58:18 +00:00
|
|
|
virNWFilterVarCombIterPtr vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
bool reverse)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2020-01-14 13:30:07 +00:00
|
|
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
|
|
|
char ipaddr[INET_ADDRSTRLEN];
|
|
|
|
char ipmask[INET_ADDRSTRLEN];
|
|
|
|
char ipv6addr[INET6_ADDRSTRLEN];
|
|
|
|
char number[VIR_INT64_STR_BUFLEN];
|
|
|
|
char numberalt[VIR_INT64_STR_BUFLEN];
|
|
|
|
char field[VIR_INT64_STR_BUFLEN];
|
|
|
|
char fieldalt[VIR_INT64_STR_BUFLEN];
|
2010-03-25 17:46:09 +00:00
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
2011-02-19 01:13:40 +00:00
|
|
|
const char *target;
|
2014-03-13 22:30:09 +00:00
|
|
|
bool hasMask = false;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRulePtr fwrule;
|
2010-04-14 10:29:55 +00:00
|
|
|
|
2014-03-25 10:32:55 +00:00
|
|
|
if (STREQ(chainSuffix,
|
2011-11-18 16:58:17 +00:00
|
|
|
virNWFilterChainSuffixTypeToString(
|
|
|
|
VIR_NWFILTER_CHAINSUFFIX_ROOT)))
|
2010-03-25 17:46:09 +00:00
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
else
|
|
|
|
PRINT_CHAIN(chain, chainPrefix, ifname,
|
2014-03-25 10:32:55 +00:00
|
|
|
chainSuffix);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define INST_ITEM(STRUCT, ITEM, CLI) \
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
|
|
|
|
if (printDataType(vars, \
|
|
|
|
field, sizeof(field), \
|
|
|
|
&rule->p.STRUCT.ITEM) < 0) \
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1; \
|
2017-11-03 12:09:47 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, CLI); \
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.STRUCT.ITEM)) \
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!"); \
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, field); \
|
2014-03-25 14:33:19 +00:00
|
|
|
}
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
#define INST_ITEM_2PARMS(STRUCT, ITEM, ITEM_HI, CLI, SEP) \
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
|
|
|
|
if (printDataType(vars, \
|
|
|
|
field, sizeof(field), \
|
|
|
|
&rule->p.STRUCT.ITEM) < 0) \
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1; \
|
2017-11-03 12:09:47 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, CLI); \
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.STRUCT.ITEM)) \
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!"); \
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM_HI)) { \
|
|
|
|
if (printDataType(vars, \
|
|
|
|
fieldalt, sizeof(fieldalt), \
|
|
|
|
&rule->p.STRUCT.ITEM_HI) < 0) \
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1; \
|
2017-11-03 12:09:47 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule, \
|
2014-03-25 14:33:19 +00:00
|
|
|
"%s%s%s", field, SEP, fieldalt); \
|
2017-11-03 12:09:47 +00:00
|
|
|
} else { \
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, field); \
|
|
|
|
} \
|
2014-03-25 14:33:19 +00:00
|
|
|
}
|
|
|
|
#define INST_ITEM_RANGE(S, I, I_HI, C) \
|
|
|
|
INST_ITEM_2PARMS(S, I, I_HI, C, ":")
|
|
|
|
#define INST_ITEM_MASK(S, I, MASK, C) \
|
|
|
|
INST_ITEM_2PARMS(S, I, MASK, C, "/")
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
switch ((int)rule->prtclType) {
|
2010-03-25 17:46:09 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat",
|
|
|
|
"-A", chain, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesHandleEthHdr(fw, fwrule,
|
2010-03-25 17:46:09 +00:00
|
|
|
vars,
|
2010-04-06 14:40:35 +00:00
|
|
|
&rule->p.ethHdrFilter.ethHdr,
|
2011-12-09 02:26:34 +00:00
|
|
|
reverse) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataTypeAsHex(vars,
|
2010-04-02 17:21:10 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ethHdrFilter.dataProtocolID) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "-p");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2011-11-19 12:26:56 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain, NULL);
|
2011-11-19 12:26:56 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesHandleEthHdr(fw, fwrule,
|
2011-11-19 12:26:56 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.vlanHdrFilter.ethHdr,
|
2011-12-09 02:26:34 +00:00
|
|
|
reverse) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2011-11-22 20:12:03 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-p", "0x8100", NULL);
|
2011-11-19 12:26:56 +00:00
|
|
|
|
|
|
|
INST_ITEM(vlanHdrFilter, dataVlanID, "--vlan-id")
|
|
|
|
INST_ITEM(vlanHdrFilter, dataVlanEncap, "--vlan-encap")
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2011-11-19 12:26:56 +00:00
|
|
|
|
2011-11-22 20:12:03 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_STP:
|
|
|
|
/* cannot handle inout direction with srcmask set in reverse dir.
|
|
|
|
since this clashes with -d below... */
|
|
|
|
if (reverse &&
|
|
|
|
HAS_ENTRY_ITEM(&rule->p.stpHdrFilter.ethHdr.dataSrcMACAddr)) {
|
2012-07-18 11:45:15 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("STP filtering in %s direction with "
|
|
|
|
"source MAC address set is not supported"),
|
|
|
|
virNWFilterRuleDirectionTypeToString(
|
|
|
|
VIR_NWFILTER_RULE_DIRECTION_INOUT));
|
2011-11-22 20:12:03 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain, NULL);
|
2011-11-22 20:12:03 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesHandleEthHdr(fw, fwrule,
|
2011-11-22 20:12:03 +00:00
|
|
|
vars,
|
|
|
|
&rule->p.stpHdrFilter.ethHdr,
|
2011-12-09 02:26:34 +00:00
|
|
|
reverse) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2011-11-22 20:12:03 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-d", NWFILTER_MAC_BGA, NULL);
|
2011-11-22 20:12:03 +00:00
|
|
|
|
|
|
|
INST_ITEM(stpHdrFilter, dataType, "--stp-type")
|
|
|
|
INST_ITEM(stpHdrFilter, dataFlags, "--stp-flags")
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataRootPri, dataRootPriHi,
|
|
|
|
"--stp-root-pri");
|
2012-10-17 09:23:12 +00:00
|
|
|
INST_ITEM_MASK(stpHdrFilter, dataRootAddr, dataRootAddrMask,
|
2011-11-22 20:12:03 +00:00
|
|
|
"--stp-root-addr");
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataRootCost, dataRootCostHi,
|
|
|
|
"--stp-root-cost");
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataSndrPrio, dataSndrPrioHi,
|
|
|
|
"--stp-sender-prio");
|
2012-10-17 09:23:12 +00:00
|
|
|
INST_ITEM_MASK(stpHdrFilter, dataSndrAddr, dataSndrAddrMask,
|
|
|
|
"--stp-sender-addr");
|
2011-11-22 20:12:03 +00:00
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataPort, dataPortHi, "--stp-port");
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataAge, dataAgeHi, "--stp-msg-age");
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataMaxAge, dataMaxAgeHi,
|
|
|
|
"--stp-max-age");
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataHelloTime, dataHelloTimeHi,
|
|
|
|
"--stp-hello-time");
|
|
|
|
INST_ITEM_RANGE(stpHdrFilter, dataFwdDelay, dataFwdDelayHi,
|
|
|
|
"--stp-forward-delay");
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2011-11-22 20:12:03 +00:00
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
|
2010-04-27 11:26:12 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesHandleEthHdr(fw, fwrule,
|
2010-03-25 17:46:09 +00:00
|
|
|
vars,
|
2010-04-06 14:40:35 +00:00
|
|
|
&rule->p.arpHdrFilter.ethHdr,
|
2011-12-09 02:26:34 +00:00
|
|
|
reverse) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "-p");
|
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule, "0x%x",
|
|
|
|
(rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ARP)
|
|
|
|
? l3_protocols[L3_PROTO_ARP_IDX].attr
|
|
|
|
: l3_protocols[L3_PROTO_RARP_IDX].attr);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (printDataType(vars,
|
|
|
|
number, sizeof(number),
|
|
|
|
&rule->p.arpHdrFilter.dataHWType) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--arp-htype");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.arpHdrFilter.dataOpcode) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--arp-opcode");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataTypeAsHex(vars,
|
2010-04-02 17:21:10 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.arpHdrFilter.dataProtocolType) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--arp-ptype");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.arpHdrFilter.dataARPSrcIPAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-13 22:30:09 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPMask)) {
|
|
|
|
if (printDataType(vars,
|
|
|
|
ipmask, sizeof(ipmask),
|
|
|
|
&rule->p.arpHdrFilter.dataARPSrcIPMask) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-13 22:30:09 +00:00
|
|
|
hasMask = true;
|
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--arp-ip-dst" : "--arp-ip-src");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipaddr, hasMask ? ipmask : "32");
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.arpHdrFilter.dataARPDstIPAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-13 22:30:09 +00:00
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPMask)) {
|
|
|
|
if (printDataType(vars,
|
|
|
|
ipmask, sizeof(ipmask),
|
|
|
|
&rule->p.arpHdrFilter.dataARPDstIPMask) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-13 22:30:09 +00:00
|
|
|
hasMask = true;
|
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--arp-ip-src" : "--arp-ip-dst");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipaddr, hasMask ? ipmask : "32");
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcMACAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
macaddr, sizeof(macaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.arpHdrFilter.dataARPSrcMACAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--arp-mac-dst" : "--arp-mac-src");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcMACAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, macaddr);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstMACAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
macaddr, sizeof(macaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.arpHdrFilter.dataARPDstMACAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--arp-mac-src" : "--arp-mac-dst");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstMACAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, macaddr);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
2011-05-23 23:41:18 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataGratuitousARP) &&
|
|
|
|
rule->p.arpHdrFilter.dataGratuitousARP.u.boolean) {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.arpHdrFilter.dataGratuitousARP))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--arp-gratuitous");
|
2011-05-23 23:41:18 +00:00
|
|
|
}
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_IP:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesHandleEthHdr(fw, fwrule,
|
2010-03-25 17:46:09 +00:00
|
|
|
vars,
|
2010-04-06 14:40:35 +00:00
|
|
|
&rule->p.ipHdrFilter.ethHdr,
|
2011-12-09 02:26:34 +00:00
|
|
|
reverse) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-p", "ipv4", NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip-destination" : "--ip-source");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipaddr, number);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipaddr);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr)) {
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
ipaddr, sizeof(ipaddr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip-source" : "--ip-destination");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipHdrFilter.ipHdr.dataDstIPMask) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipaddr, number);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipaddr);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipHdrFilter.ipHdr.dataProtocolID) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--ip-protocol");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipHdrFilter.portData.dataSrcPortStart) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip-destination-port" : "--ip-source-port");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
numberalt, sizeof(numberalt),
|
|
|
|
&rule->p.ipHdrFilter.portData.dataSrcPortEnd) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s:%s", number, numberalt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:09 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipHdrFilter.portData.dataDstPortStart) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip-source-port" : "--ip-destination-port");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
numberalt, sizeof(numberalt),
|
|
|
|
&rule->p.ipHdrFilter.portData.dataDstPortEnd) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
|
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s:%s", number, numberalt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDSCP)) {
|
2010-04-08 10:25:38 +00:00
|
|
|
if (printDataTypeAsHex(vars,
|
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipHdrFilter.ipHdr.dataDSCP) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--ip-tos");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDSCP))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:11 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain, NULL);
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesHandleEthHdr(fw, fwrule,
|
2010-03-25 17:46:11 +00:00
|
|
|
vars,
|
2010-04-06 14:40:35 +00:00
|
|
|
&rule->p.ipv6HdrFilter.ethHdr,
|
2011-12-09 02:26:34 +00:00
|
|
|
reverse) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-p", "ipv6", NULL);
|
2010-03-25 17:46:11 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
ipv6addr, sizeof(ipv6addr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip6-destination" : "--ip6-source");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:11 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipv6addr, number);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipv6addr);
|
2010-03-25 17:46:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr)) {
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
ipv6addr, sizeof(ipv6addr),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip6-source" : "--ip6-destination");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:11 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s/%s", ipv6addr, number);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, ipv6addr);
|
2010-03-25 17:46:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
number, sizeof(number),
|
2011-12-09 02:26:34 +00:00
|
|
|
&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule, "--ip6-protocol");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart)) {
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipv6HdrFilter.portData.dataSrcPortStart) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip6-destination-port" : "--ip6-source-port");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:11 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
numberalt, sizeof(numberalt),
|
|
|
|
&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s:%s", number, numberalt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortStart)) {
|
|
|
|
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2010-03-25 17:46:11 +00:00
|
|
|
number, sizeof(number),
|
2014-03-25 14:33:19 +00:00
|
|
|
&rule->p.ipv6HdrFilter.portData.dataDstPortStart) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
reverse ? "--ip6-source-port" : "--ip6-destination-port");
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataDstPortStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
2010-03-25 17:46:11 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortEnd)) {
|
2010-04-05 16:34:55 +00:00
|
|
|
if (printDataType(vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
numberalt, sizeof(numberalt),
|
|
|
|
&rule->p.ipv6HdrFilter.portData.dataDstPortEnd) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"%s:%s", number, numberalt);
|
|
|
|
} else {
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, number);
|
2010-03-25 17:46:11 +00:00
|
|
|
}
|
|
|
|
}
|
2015-01-07 16:41:49 +00:00
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeStart) ||
|
|
|
|
HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeEnd) ||
|
|
|
|
HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeStart) ||
|
|
|
|
HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeEnd)) {
|
|
|
|
bool lo = false;
|
2020-06-25 01:59:39 +00:00
|
|
|
g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
|
|
|
|
g_autofree char *r = NULL;
|
2015-01-07 16:41:49 +00:00
|
|
|
|
|
|
|
virFirewallRuleAddArg(fw, fwrule,
|
|
|
|
"--ip6-icmp-type");
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeStart)) {
|
|
|
|
if (printDataType(vars,
|
|
|
|
number, sizeof(number),
|
|
|
|
&rule->p.ipv6HdrFilter.dataICMPTypeStart) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2015-01-07 16:41:49 +00:00
|
|
|
lo = true;
|
|
|
|
} else {
|
|
|
|
ignore_value(virStrcpyStatic(number, "0"));
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferStrcat(&buf, number, ":", NULL);
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPTypeEnd)) {
|
|
|
|
if (printDataType(vars,
|
|
|
|
numberalt, sizeof(numberalt),
|
|
|
|
&rule->p.ipv6HdrFilter.dataICMPTypeEnd) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2015-01-07 16:41:49 +00:00
|
|
|
} else {
|
|
|
|
if (lo)
|
|
|
|
ignore_value(virStrcpyStatic(numberalt, number));
|
|
|
|
else
|
|
|
|
ignore_value(virStrcpyStatic(numberalt, "255"));
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferStrcat(&buf, numberalt, "/", NULL);
|
|
|
|
|
|
|
|
lo = false;
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeStart)) {
|
|
|
|
if (printDataType(vars,
|
|
|
|
number, sizeof(number),
|
|
|
|
&rule->p.ipv6HdrFilter.dataICMPCodeStart) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2015-01-07 16:41:49 +00:00
|
|
|
lo = true;
|
|
|
|
} else {
|
|
|
|
ignore_value(virStrcpyStatic(number, "0"));
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferStrcat(&buf, number, ":", NULL);
|
|
|
|
|
|
|
|
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.dataICMPCodeEnd)) {
|
|
|
|
if (printDataType(vars,
|
|
|
|
numberalt, sizeof(numberalt),
|
|
|
|
&rule->p.ipv6HdrFilter.dataICMPCodeEnd) < 0)
|
2020-07-03 03:24:30 +00:00
|
|
|
return -1;
|
2015-01-07 16:41:49 +00:00
|
|
|
} else {
|
|
|
|
if (lo)
|
|
|
|
ignore_value(virStrcpyStatic(numberalt, number));
|
|
|
|
else
|
|
|
|
ignore_value(virStrcpyStatic(numberalt, "255"));
|
|
|
|
}
|
|
|
|
|
|
|
|
virBufferStrcat(&buf, numberalt, NULL);
|
|
|
|
|
|
|
|
if (ENTRY_WANT_NEG_SIGN(&rule->p.ipv6HdrFilter.dataICMPTypeStart))
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "!");
|
|
|
|
|
|
|
|
r = virBufferContentAndReset(&buf);
|
|
|
|
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, r);
|
|
|
|
}
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2010-03-25 17:46:11 +00:00
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain, NULL);
|
|
|
|
break;
|
2010-03-25 17:46:12 +00:00
|
|
|
|
|
|
|
default:
|
2014-03-25 14:33:19 +00:00
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Unexpected rule protocol %d"),
|
|
|
|
rule->prtclType);
|
2010-03-25 17:46:12 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2011-02-19 01:13:40 +00:00
|
|
|
switch (rule->action) {
|
|
|
|
case VIR_NWFILTER_RULE_ACTION_REJECT:
|
|
|
|
/* REJECT not supported */
|
|
|
|
target = virNWFilterJumpTargetTypeToString(
|
|
|
|
VIR_NWFILTER_RULE_ACTION_DROP);
|
2014-03-25 14:33:19 +00:00
|
|
|
break;
|
2011-02-19 01:13:40 +00:00
|
|
|
default:
|
|
|
|
target = virNWFilterJumpTargetTypeToString(rule->action);
|
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-j", target, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
#undef INST_ITEM_RANGE
|
|
|
|
#undef INST_ITEM_MASK
|
|
|
|
#undef INST_ITEM_2PARMS
|
|
|
|
#undef INST_ITEM
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2020-07-03 03:24:30 +00:00
|
|
|
return 0;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ebiptablesCreateRuleInstance:
|
2014-03-25 10:32:55 +00:00
|
|
|
* @chainPriority : The priority of the chain
|
|
|
|
* @chainSuffix: The suffix to put on the end of the name of the chain
|
2010-03-25 17:46:09 +00:00
|
|
|
* @rule: The rule of the filter to convert
|
|
|
|
* @ifname : The name of the interface to apply the rule to
|
|
|
|
* @vars : A map containing the variables to resolve
|
|
|
|
* @res : The data structure to store the result(s) into
|
|
|
|
*
|
|
|
|
* Convert a single rule into its representation for later instantiation
|
|
|
|
*
|
|
|
|
* Returns 0 in case of success with the result stored in the data structure
|
2011-12-09 02:26:34 +00:00
|
|
|
* pointed to by res, -1 otherwise
|
2010-03-25 17:46:09 +00:00
|
|
|
*/
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
ebiptablesCreateRuleInstance(virFirewallPtr fw,
|
|
|
|
const char *chainSuffix,
|
2010-03-25 17:46:09 +00:00
|
|
|
virNWFilterRuleDefPtr rule,
|
|
|
|
const char *ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
virNWFilterVarCombIterPtr vars)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2014-03-25 11:50:18 +00:00
|
|
|
if (virNWFilterRuleIsProtocolEthernet(rule)) {
|
2010-03-25 17:46:09 +00:00
|
|
|
if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
|
|
|
|
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesCreateRuleInstance(fw,
|
|
|
|
CHAINPREFIX_HOST_IN_TEMP,
|
2014-03-25 10:32:55 +00:00
|
|
|
chainSuffix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
|
|
|
|
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebtablesCreateRuleInstance(fw,
|
|
|
|
CHAINPREFIX_HOST_OUT_TEMP,
|
2014-03-25 10:32:55 +00:00
|
|
|
chainSuffix,
|
|
|
|
rule,
|
|
|
|
ifname,
|
|
|
|
vars,
|
2014-03-25 14:33:19 +00:00
|
|
|
false) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
2014-03-25 11:50:18 +00:00
|
|
|
} else {
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallLayer layer;
|
2014-03-25 11:50:18 +00:00
|
|
|
if (virNWFilterRuleIsProtocolIPv6(rule)) {
|
2014-03-25 14:33:19 +00:00
|
|
|
layer = VIR_FIREWALL_LAYER_IPV6;
|
2014-03-25 11:50:18 +00:00
|
|
|
} else if (virNWFilterRuleIsProtocolIPv4(rule)) {
|
2014-03-25 14:33:19 +00:00
|
|
|
layer = VIR_FIREWALL_LAYER_IPV4;
|
2014-03-25 11:50:18 +00:00
|
|
|
} else {
|
|
|
|
virReportError(VIR_ERR_OPERATION_FAILED,
|
|
|
|
"%s", _("unexpected protocol type"));
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2014-03-25 11:50:18 +00:00
|
|
|
}
|
2010-03-30 14:36:35 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
if (iptablesCreateRuleInstance(fw,
|
|
|
|
layer,
|
|
|
|
rule,
|
2014-03-25 10:32:55 +00:00
|
|
|
ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
vars) < 0)
|
2019-10-21 18:18:53 +00:00
|
|
|
return -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2019-10-21 18:18:53 +00:00
|
|
|
return 0;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 12:58:18 +00:00
|
|
|
static void
|
|
|
|
ebtablesCreateTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
int incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
|
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-N", chain, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
ebtablesLinkTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
int incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix = incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
|
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A",
|
|
|
|
incoming ? EBTABLES_CHAIN_INCOMING : EBTABLES_CHAIN_OUTGOING,
|
|
|
|
incoming ? "-i" : "-o",
|
|
|
|
ifname, "-j", chain, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static void
|
|
|
|
_ebtablesRemoveRootChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming, const char *ifname,
|
|
|
|
int isTempChain)
|
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix;
|
|
|
|
if (isTempChain)
|
|
|
|
chainPrefix = incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
else
|
|
|
|
chainPrefix = incoming ? CHAINPREFIX_HOST_IN
|
|
|
|
: CHAINPREFIX_HOST_OUT;
|
|
|
|
|
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-F", chain, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-X", chain, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
ebtablesRemoveRootChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
_ebtablesRemoveRootChainFW(fw, incoming, ifname, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
static void
|
|
|
|
ebtablesRemoveTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
_ebtablesRemoveRootChainFW(fw, incoming, ifname, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
static void
|
|
|
|
_ebtablesUnlinkRootChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming, const char *ifname,
|
|
|
|
int isTempChain)
|
|
|
|
{
|
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix;
|
|
|
|
|
|
|
|
if (isTempChain) {
|
|
|
|
chainPrefix = incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
} else {
|
|
|
|
chainPrefix = incoming ? CHAINPREFIX_HOST_IN
|
|
|
|
: CHAINPREFIX_HOST_OUT;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
|
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-D",
|
|
|
|
incoming ? EBTABLES_CHAIN_INCOMING : EBTABLES_CHAIN_OUTGOING,
|
|
|
|
incoming ? "-i" : "-o",
|
|
|
|
ifname, "-j", chain, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
ebtablesUnlinkRootChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
_ebtablesUnlinkRootChainFW(fw, incoming, ifname, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
static void
|
|
|
|
ebtablesUnlinkTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
int incoming, const char *ifname)
|
|
|
|
{
|
|
|
|
_ebtablesUnlinkRootChainFW(fw, incoming, ifname, 1);
|
|
|
|
}
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesCreateTmpSubChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming,
|
|
|
|
const char *ifname,
|
|
|
|
enum l3_proto_idx protoidx,
|
|
|
|
const char *filtername)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2014-03-25 14:33:19 +00:00
|
|
|
char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix = incoming ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
virFirewallRulePtr fwrule;
|
|
|
|
|
|
|
|
PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
|
|
|
|
PRINT_CHAIN(chain, chainPrefix, ifname,
|
|
|
|
(filtername) ? filtername : l3_protocols[protoidx].val);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-F", chain, NULL);
|
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-X", chain, NULL);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-N", chain, NULL);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
fwrule = virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", rootchain, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2018-02-14 09:43:59 +00:00
|
|
|
switch ((int)protoidx) {
|
2014-03-25 14:33:19 +00:00
|
|
|
case L2_PROTO_MAC_IDX:
|
|
|
|
break;
|
|
|
|
case L2_PROTO_STP_IDX:
|
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-d", NWFILTER_MAC_BGA, NULL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
virFirewallRuleAddArg(fw, fwrule, "-p");
|
|
|
|
virFirewallRuleAddArgFormat(fw, fwrule,
|
|
|
|
"0x%04x",
|
|
|
|
l3_protocols[protoidx].attr);
|
|
|
|
break;
|
2011-11-18 16:58:17 +00:00
|
|
|
}
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallRuleAddArgList(fw, fwrule,
|
|
|
|
"-j", chain, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
|
|
|
|
static int
|
|
|
|
ebtablesRemoveSubChainsQuery(virFirewallPtr fw,
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallLayer layer,
|
2014-03-14 11:53:06 +00:00
|
|
|
const char *const *lines,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
size_t i, j;
|
|
|
|
const char *chainprefixes = opaque;
|
|
|
|
|
|
|
|
for (i = 0; lines[i] != NULL; i++) {
|
|
|
|
VIR_DEBUG("Considering '%s'", lines[i]);
|
|
|
|
char *tmp = strstr(lines[i], "-j ");
|
|
|
|
if (!tmp)
|
|
|
|
continue;
|
|
|
|
tmp = tmp + 3;
|
|
|
|
for (j = 0; chainprefixes[j]; j++) {
|
|
|
|
if (tmp[0] == chainprefixes[j] &&
|
|
|
|
tmp[1] == '-') {
|
|
|
|
VIR_DEBUG("Processing chain '%s'", tmp);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
2014-03-14 11:53:06 +00:00
|
|
|
false, ebtablesRemoveSubChainsQuery,
|
|
|
|
(void *)chainprefixes,
|
|
|
|
"-t", "nat", "-L", tmp, NULL);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
2014-03-14 11:53:06 +00:00
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-F", tmp, NULL);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
2014-03-14 11:53:06 +00:00
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-X", tmp, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
_ebtablesRemoveSubChainsFW(virFirewallPtr fw,
|
|
|
|
const char *ifname,
|
|
|
|
const char *chainprefixes)
|
|
|
|
{
|
|
|
|
char rootchain[MAX_CHAINNAME_LENGTH];
|
|
|
|
size_t i;
|
|
|
|
|
|
|
|
for (i = 0; chainprefixes[i] != 0; i++) {
|
|
|
|
PRINT_ROOT_CHAIN(rootchain, chainprefixes[i], ifname);
|
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
false, ebtablesRemoveSubChainsQuery,
|
|
|
|
(void *)chainprefixes,
|
|
|
|
"-t", "nat", "-L", rootchain, NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ebtablesRemoveSubChainsFW(virFirewallPtr fw,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
_ebtablesRemoveSubChainsFW(fw, ifname, chainprefixes_host);
|
|
|
|
}
|
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
static void
|
|
|
|
ebtablesRemoveTmpSubChainsFW(virFirewallPtr fw,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
_ebtablesRemoveSubChainsFW(fw, ifname, chainprefixes_host_temp);
|
|
|
|
}
|
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
static void
|
|
|
|
ebtablesRenameTmpSubChainFW(virFirewallPtr fw,
|
|
|
|
int incoming,
|
|
|
|
const char *ifname,
|
|
|
|
const char *protocol)
|
|
|
|
{
|
|
|
|
char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char tmpChainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
|
|
|
|
: CHAINPREFIX_HOST_OUT_TEMP;
|
|
|
|
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
|
|
|
|
: CHAINPREFIX_HOST_OUT;
|
|
|
|
|
|
|
|
if (protocol) {
|
|
|
|
PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
|
|
|
|
PRINT_CHAIN(chain, chainPrefix, ifname, protocol);
|
|
|
|
} else {
|
|
|
|
PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
|
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
|
|
|
}
|
|
|
|
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-E", tmpchain, chain, NULL);
|
|
|
|
}
|
|
|
|
|
2014-03-14 13:39:51 +00:00
|
|
|
static void
|
2014-03-14 12:05:00 +00:00
|
|
|
ebtablesRenameTmpRootChainFW(virFirewallPtr fw,
|
|
|
|
bool incoming,
|
|
|
|
const char *ifname)
|
|
|
|
{
|
|
|
|
ebtablesRenameTmpSubChainFW(fw, incoming, ifname, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
ebtablesRenameTmpSubAndRootChainsQuery(virFirewallPtr fw,
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallLayer layer,
|
2014-03-14 12:05:00 +00:00
|
|
|
const char *const *lines,
|
2019-10-14 12:45:33 +00:00
|
|
|
void *opaque G_GNUC_UNUSED)
|
2014-03-14 12:05:00 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
|
|
|
char newchain[MAX_CHAINNAME_LENGTH];
|
|
|
|
|
|
|
|
for (i = 0; lines[i] != NULL; i++) {
|
|
|
|
VIR_DEBUG("Considering '%s'", lines[i]);
|
|
|
|
char *tmp = strstr(lines[i], "-j ");
|
|
|
|
if (!tmp)
|
|
|
|
continue;
|
|
|
|
tmp = tmp + 3;
|
|
|
|
if (tmp[0] != CHAINPREFIX_HOST_IN_TEMP &&
|
|
|
|
tmp[0] != CHAINPREFIX_HOST_OUT_TEMP)
|
|
|
|
continue;
|
|
|
|
if (tmp[1] != '-')
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ignore_value(virStrcpyStatic(newchain, tmp));
|
|
|
|
if (newchain[0] == CHAINPREFIX_HOST_IN_TEMP)
|
|
|
|
newchain[0] = CHAINPREFIX_HOST_IN;
|
|
|
|
else
|
|
|
|
newchain[0] = CHAINPREFIX_HOST_OUT;
|
|
|
|
VIR_DEBUG("Renaming chain '%s' to '%s'", tmp, newchain);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
2014-03-14 12:05:00 +00:00
|
|
|
false, ebtablesRenameTmpSubAndRootChainsQuery,
|
|
|
|
NULL,
|
|
|
|
"-t", "nat", "-L", tmp, NULL);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
2014-03-14 12:05:00 +00:00
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-F", newchain, NULL);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRuleFull(fw, layer,
|
2014-03-14 12:05:00 +00:00
|
|
|
true, NULL, NULL,
|
|
|
|
"-t", "nat", "-X", newchain, NULL);
|
2018-12-04 16:33:28 +00:00
|
|
|
virFirewallAddRule(fw, layer,
|
2014-03-14 12:05:00 +00:00
|
|
|
"-t", "nat", "-E", tmp, newchain, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
ebtablesRenameTmpSubAndRootChainsFW(virFirewallPtr fw,
|
|
|
|
const char *ifname)
|
2011-11-18 16:58:17 +00:00
|
|
|
{
|
|
|
|
char rootchain[MAX_CHAINNAME_LENGTH];
|
Convert 'int i' to 'size_t i' in src/nwfilter/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i;
|
2011-11-18 16:58:17 +00:00
|
|
|
char chains[3] = {
|
|
|
|
CHAINPREFIX_HOST_IN_TEMP,
|
|
|
|
CHAINPREFIX_HOST_OUT_TEMP,
|
2014-03-14 12:05:00 +00:00
|
|
|
0
|
|
|
|
};
|
2011-11-18 16:58:17 +00:00
|
|
|
for (i = 0; chains[i] != 0; i++) {
|
|
|
|
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
|
2014-03-14 12:05:00 +00:00
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
false, ebtablesRenameTmpSubAndRootChainsQuery,
|
|
|
|
NULL,
|
|
|
|
"-t", "nat", "-L", rootchain, NULL);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
ebtablesRenameTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRenameTmpRootChainFW(fw, false, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-20 21:07:15 +00:00
|
|
|
/**
|
|
|
|
* ebiptablesCanApplyBasicRules
|
|
|
|
*
|
|
|
|
* Determine whether this driver can apply the basic rules, meaning
|
|
|
|
* run ebtablesApplyBasicRules and ebtablesApplyDHCPOnlyRules.
|
|
|
|
* In case of this driver we need the ebtables tool available.
|
|
|
|
*/
|
|
|
|
static int
|
2014-03-18 08:16:54 +00:00
|
|
|
ebiptablesCanApplyBasicRules(void)
|
|
|
|
{
|
2014-03-31 12:01:04 +00:00
|
|
|
return true;
|
2010-04-20 21:07:15 +00:00
|
|
|
}
|
|
|
|
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
/**
|
|
|
|
* ebtablesApplyBasicRules
|
|
|
|
*
|
|
|
|
* @ifname: name of the backend-interface to which to apply the rules
|
|
|
|
* @macaddr: MAC address the VM is using in packets sent through the
|
|
|
|
* interface
|
|
|
|
*
|
2011-12-09 02:26:34 +00:00
|
|
|
* Returns 0 on success, -1 on failure with the rules removed
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
*
|
|
|
|
* Apply basic filtering rules on the given interface
|
|
|
|
* - filtering for MAC address spoofing
|
|
|
|
* - allowing IPv4 & ARP traffic
|
|
|
|
*/
|
2010-04-20 21:07:15 +00:00
|
|
|
static int
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
ebtablesApplyBasicRules(const char *ifname,
|
maint: avoid 'const fooPtr' in nwfilter files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in nwfilter code.
This patch does nothing about the stupidity evident in having
__virNWFilterInstantiateFilter, _virNWFilterInstantiateFilter,
and virNWFilterInstantiateFilter, which differ only by leading
underscores, and which infringes on the namespace reserved to
the implementation - that would need to be a separate cleanup.
* src/nwfilter/nwfilter_dhcpsnoop.h (virNWFilterDHCPSnoopReq): Use
intended type.
* src/nwfilter/nwfilter_gentech_driver.h
(virNWFilterInstantiateFilter)
(virNWFilterUpdateInstantiateFilter)
(virNWFilterInstantiataeFilterLate, virNWFilterTeardownFilter)
(virNWFilterCreateVarHashmap): Likewise.
* src/nwfilter/nwfilter_learnipaddr.h (virNWFilterLearnIPAddress):
Likewise.
* src/conf/nwfilter_conf.h (virNWFilterApplyBasicRules)
(virNWFilterApplyDHCPOnlyRules): Likewise.
(virNWFilterDefFormat): Make const-correct.
* src/conf/nwfilter_params.h (virNWFilterVarValueCopy)
(virNWFilterVarValueGetSimple, virNWFilterVarValueGetCardinality)
(virNWFilterVarValueEqual, virNWFilterVarAccessEqual)
(virNWFilterVarAccessGetVarName, virNWFilterVarAccessGetType)
(virNWFilterVarAccessGetIterId, virNWFilterVarAccessGetIndex)
(virNWFilterVarAccessIsAvailable)
(virNWFilterVarCombIterGetVarValue): Use intended type.
(virNWFilterVarValueGetNthValue): Make const-correct.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterSnoopIFKeyFMT, virNWFilterDHCPSnoopReq)
(virNWFilterSnoopPruneIter, virNWFilterSnoopRemAllReqIter)
(virNWFilterDHCPSnoopReq): Fix fallout.
* src/nwfilter/nwfilter_gentech_driver.c
(virNWFilterVarHashmapAddStdValues, virNWFilterCreateVarHashmap)
(virNWFilterInstantiate, __virNWFilterInstantiateFilter)
(_virNWFilterInstantiateFilter, virNWFilterInstantiateFilterLate)
(virNWFilterInstantiateFilter)
(virNWFilterUpdateInstantiateFilter)
(virNWFilterRollbackUpdateFilter, virNWFilterTeardownFilter):
Likewise.
* src/nwfilter/nwfilter_learnipaddr.c (virNWFilterLearnIPAddress):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCopy)
(virNWFilterVarValueGetSimple)
(virNWFilterVarValueGetCardinality, virNWFilterVarValueEqual)
(virNWFilterVarCombIterAddVariable)
(virNWFilterVarCombIterGetVarValue, virNWFilterVarValueCompare)
(virNWFilterFormatParamAttributes, virNWFilterVarAccessEqual)
(virNWFilterVarAccessGetVarName, virNWFilterVarAccessGetType)
(virNWFilterVarAccessGetIterId, virNWFilterVarAccessGetIndex)
(virNWFilterVarAccessGetIntIterId)
(virNWFilterVarAccessIsAvailable)
(virNWFilterVarValueGetNthValue): Likewise.
* src/nwfilter/nwfilter_ebiptables_driver.c (ebtablesApplyBasicRules)
(ebtablesApplyDHCPOnlyRules, ebiptablesRuleOrderSort)
(ebiptablesRuleOrderSortPtr): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterDefEqual)
(virNWFilterDefFormat): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-07 16:55:22 +00:00
|
|
|
const virMacAddr *macaddr)
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
char chain[MAX_CHAINNAME_LENGTH];
|
|
|
|
char chainPrefix = CHAINPREFIX_HOST_IN_TEMP;
|
|
|
|
char macaddr_str[VIR_MAC_STRING_BUFLEN];
|
|
|
|
|
2012-01-27 16:48:38 +00:00
|
|
|
virMacAddrFormat(macaddr, macaddr_str);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 12:58:18 +00:00
|
|
|
if (ebiptablesAllTeardown(ifname) < 0)
|
2020-07-04 20:38:37 +00:00
|
|
|
return -1;
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 12:58:18 +00:00
|
|
|
virFirewallStartTransaction(fw, 0);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-14 12:58:18 +00:00
|
|
|
ebtablesCreateTmpRootChainFW(fw, true, ifname);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
|
|
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
2014-03-14 12:58:18 +00:00
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain,
|
|
|
|
"-s", "!", macaddr_str,
|
|
|
|
"-j", "DROP", NULL);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain,
|
|
|
|
"-p", "IPv4",
|
|
|
|
"-j", "ACCEPT", NULL);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain,
|
|
|
|
"-p", "ARP",
|
|
|
|
"-j", "ACCEPT", NULL);
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain,
|
|
|
|
"-j", "DROP", NULL);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 12:58:18 +00:00
|
|
|
ebtablesLinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRenameTmpRootChainFW(fw, true, ifname);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-31 12:01:04 +00:00
|
|
|
if (virFirewallApply(fw) < 0)
|
2020-06-25 02:20:56 +00:00
|
|
|
goto error;
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2020-06-25 02:20:56 +00:00
|
|
|
error:
|
2010-04-30 12:06:18 +00:00
|
|
|
ebtablesCleanAll(ifname);
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ebtablesApplyDHCPOnlyRules
|
|
|
|
*
|
|
|
|
* @ifname: name of the backend-interface to which to apply the rules
|
|
|
|
* @macaddr: MAC address the VM is using in packets sent through the
|
|
|
|
* interface
|
2012-04-19 14:21:43 +00:00
|
|
|
* @dhcpsrvrs: The DHCP server(s) from which the VM may receive traffic
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
* from; may be NULL
|
2011-11-22 20:59:26 +00:00
|
|
|
* @leaveTemporary: Whether to leave the table names with their temporary
|
|
|
|
* names (true) or also perform the renaming to their final names as
|
|
|
|
* part of this call (false)
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
*
|
2011-12-09 02:26:34 +00:00
|
|
|
* Returns 0 on success, -1 on failure with the rules removed
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
*
|
|
|
|
* Apply filtering rules so that the VM can only send and receive
|
|
|
|
* DHCP traffic and nothing else.
|
|
|
|
*/
|
2010-04-20 21:07:15 +00:00
|
|
|
static int
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
ebtablesApplyDHCPOnlyRules(const char *ifname,
|
maint: avoid 'const fooPtr' in nwfilter files
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up offenders in nwfilter code.
This patch does nothing about the stupidity evident in having
__virNWFilterInstantiateFilter, _virNWFilterInstantiateFilter,
and virNWFilterInstantiateFilter, which differ only by leading
underscores, and which infringes on the namespace reserved to
the implementation - that would need to be a separate cleanup.
* src/nwfilter/nwfilter_dhcpsnoop.h (virNWFilterDHCPSnoopReq): Use
intended type.
* src/nwfilter/nwfilter_gentech_driver.h
(virNWFilterInstantiateFilter)
(virNWFilterUpdateInstantiateFilter)
(virNWFilterInstantiataeFilterLate, virNWFilterTeardownFilter)
(virNWFilterCreateVarHashmap): Likewise.
* src/nwfilter/nwfilter_learnipaddr.h (virNWFilterLearnIPAddress):
Likewise.
* src/conf/nwfilter_conf.h (virNWFilterApplyBasicRules)
(virNWFilterApplyDHCPOnlyRules): Likewise.
(virNWFilterDefFormat): Make const-correct.
* src/conf/nwfilter_params.h (virNWFilterVarValueCopy)
(virNWFilterVarValueGetSimple, virNWFilterVarValueGetCardinality)
(virNWFilterVarValueEqual, virNWFilterVarAccessEqual)
(virNWFilterVarAccessGetVarName, virNWFilterVarAccessGetType)
(virNWFilterVarAccessGetIterId, virNWFilterVarAccessGetIndex)
(virNWFilterVarAccessIsAvailable)
(virNWFilterVarCombIterGetVarValue): Use intended type.
(virNWFilterVarValueGetNthValue): Make const-correct.
* src/nwfilter/nwfilter_dhcpsnoop.c (virNWFilterSnoopReqLeaseDel)
(virNWFilterSnoopIFKeyFMT, virNWFilterDHCPSnoopReq)
(virNWFilterSnoopPruneIter, virNWFilterSnoopRemAllReqIter)
(virNWFilterDHCPSnoopReq): Fix fallout.
* src/nwfilter/nwfilter_gentech_driver.c
(virNWFilterVarHashmapAddStdValues, virNWFilterCreateVarHashmap)
(virNWFilterInstantiate, __virNWFilterInstantiateFilter)
(_virNWFilterInstantiateFilter, virNWFilterInstantiateFilterLate)
(virNWFilterInstantiateFilter)
(virNWFilterUpdateInstantiateFilter)
(virNWFilterRollbackUpdateFilter, virNWFilterTeardownFilter):
Likewise.
* src/nwfilter/nwfilter_learnipaddr.c (virNWFilterLearnIPAddress):
Likewise.
* src/conf/nwfilter_params.c (virNWFilterVarValueCopy)
(virNWFilterVarValueGetSimple)
(virNWFilterVarValueGetCardinality, virNWFilterVarValueEqual)
(virNWFilterVarCombIterAddVariable)
(virNWFilterVarCombIterGetVarValue, virNWFilterVarValueCompare)
(virNWFilterFormatParamAttributes, virNWFilterVarAccessEqual)
(virNWFilterVarAccessGetVarName, virNWFilterVarAccessGetType)
(virNWFilterVarAccessGetIterId, virNWFilterVarAccessGetIndex)
(virNWFilterVarAccessGetIntIterId)
(virNWFilterVarAccessIsAvailable)
(virNWFilterVarValueGetNthValue): Likewise.
* src/nwfilter/nwfilter_ebiptables_driver.c (ebtablesApplyBasicRules)
(ebtablesApplyDHCPOnlyRules, ebiptablesRuleOrderSort)
(ebiptablesRuleOrderSortPtr): Likewise.
* src/conf/nwfilter_conf.c (virNWFilterDefEqual)
(virNWFilterDefFormat): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-07 16:55:22 +00:00
|
|
|
const virMacAddr *macaddr,
|
2012-04-19 14:21:43 +00:00
|
|
|
virNWFilterVarValuePtr dhcpsrvrs,
|
2011-11-22 20:59:26 +00:00
|
|
|
bool leaveTemporary)
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
{
|
|
|
|
char chain_in [MAX_CHAINNAME_LENGTH],
|
|
|
|
chain_out[MAX_CHAINNAME_LENGTH];
|
|
|
|
char macaddr_str[VIR_MAC_STRING_BUFLEN];
|
2012-04-19 14:21:43 +00:00
|
|
|
unsigned int idx = 0;
|
|
|
|
unsigned int num_dhcpsrvrs;
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2010-04-14 10:29:55 +00:00
|
|
|
|
2012-01-27 16:48:38 +00:00
|
|
|
virMacAddrFormat(macaddr, macaddr_str);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
if (ebiptablesAllTeardown(ifname) < 0)
|
2020-07-04 20:38:37 +00:00
|
|
|
return -1;
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
virFirewallStartTransaction(fw, 0);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
ebtablesCreateTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesCreateTmpRootChainFW(fw, false, ifname);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2013-11-19 23:33:37 +00:00
|
|
|
PRINT_ROOT_CHAIN(chain_in, CHAINPREFIX_HOST_IN_TEMP, ifname);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
|
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_in,
|
|
|
|
"-s", macaddr_str,
|
|
|
|
"-p", "ipv4", "--ip-protocol", "udp",
|
|
|
|
"--ip-sport", "68", "--ip-dport", "67",
|
|
|
|
"-j", "ACCEPT", NULL);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_in,
|
|
|
|
"-j", "DROP", NULL);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2012-04-19 14:21:43 +00:00
|
|
|
num_dhcpsrvrs = (dhcpsrvrs != NULL)
|
|
|
|
? virNWFilterVarValueGetCardinality(dhcpsrvrs)
|
|
|
|
: 0;
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2012-04-19 14:21:43 +00:00
|
|
|
while (true) {
|
2014-03-14 16:25:12 +00:00
|
|
|
const char *dhcpserver = NULL;
|
2012-08-30 18:29:50 +00:00
|
|
|
int ctr;
|
2012-04-19 14:21:43 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
if (idx < num_dhcpsrvrs)
|
2012-04-19 14:21:43 +00:00
|
|
|
dhcpserver = virNWFilterVarValueGetNthValue(dhcpsrvrs, idx);
|
|
|
|
|
2012-08-30 18:29:50 +00:00
|
|
|
/*
|
|
|
|
* create two rules allowing response to MAC address of VM
|
|
|
|
* or to broadcast MAC address
|
|
|
|
*/
|
|
|
|
for (ctr = 0; ctr < 2; ctr++) {
|
2014-03-14 16:25:12 +00:00
|
|
|
if (dhcpserver)
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_out,
|
|
|
|
"-d", (ctr == 0) ? macaddr_str : "ff:ff:ff:ff:ff:ff",
|
|
|
|
"-p", "ipv4", "--ip-protocol", "udp",
|
|
|
|
"--ip-src", dhcpserver,
|
|
|
|
"--ip-sport", "67", "--ip-dport", "68",
|
|
|
|
"-j", "ACCEPT", NULL);
|
|
|
|
else
|
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_out,
|
|
|
|
"-d", (ctr == 0) ? macaddr_str : "ff:ff:ff:ff:ff:ff",
|
|
|
|
"-p", "ipv4", "--ip-protocol", "udp",
|
|
|
|
"--ip-sport", "67", "--ip-dport", "68",
|
|
|
|
"-j", "ACCEPT", NULL);
|
2012-08-30 18:29:50 +00:00
|
|
|
}
|
2012-04-19 14:21:43 +00:00
|
|
|
|
|
|
|
idx++;
|
2012-08-30 17:51:27 +00:00
|
|
|
|
|
|
|
if (idx >= num_dhcpsrvrs)
|
|
|
|
break;
|
2012-04-19 14:21:43 +00:00
|
|
|
}
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_out,
|
|
|
|
"-j", "DROP", NULL);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-14 16:25:12 +00:00
|
|
|
ebtablesLinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesLinkTmpRootChainFW(fw, false, ifname);
|
2011-11-22 20:59:26 +00:00
|
|
|
|
|
|
|
if (!leaveTemporary) {
|
2014-03-14 16:25:12 +00:00
|
|
|
ebtablesRenameTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRenameTmpRootChainFW(fw, false, ifname);
|
2011-11-22 20:59:26 +00:00
|
|
|
}
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2014-03-31 12:01:04 +00:00
|
|
|
if (virFirewallApply(fw) < 0)
|
2020-06-25 02:20:56 +00:00
|
|
|
goto error;
|
2014-03-14 16:25:12 +00:00
|
|
|
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
return 0;
|
|
|
|
|
2020-06-25 02:20:56 +00:00
|
|
|
error:
|
2010-04-30 12:06:18 +00:00
|
|
|
ebtablesCleanAll(ifname);
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-30 12:06:18 +00:00
|
|
|
/**
|
|
|
|
* ebtablesApplyDropAllRules
|
|
|
|
*
|
|
|
|
* @ifname: name of the backend-interface to which to apply the rules
|
|
|
|
*
|
2011-12-09 02:26:34 +00:00
|
|
|
* Returns 0 on success, -1 on failure with the rules removed
|
2010-04-30 12:06:18 +00:00
|
|
|
*
|
|
|
|
* Apply filtering rules so that the VM cannot receive or send traffic.
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ebtablesApplyDropAllRules(const char *ifname)
|
|
|
|
{
|
|
|
|
char chain_in [MAX_CHAINNAME_LENGTH],
|
|
|
|
chain_out[MAX_CHAINNAME_LENGTH];
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2014-03-14 16:27:39 +00:00
|
|
|
if (ebiptablesAllTeardown(ifname) < 0)
|
2020-07-04 20:38:37 +00:00
|
|
|
return -1;
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2014-03-14 16:27:39 +00:00
|
|
|
virFirewallStartTransaction(fw, 0);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-14 16:27:39 +00:00
|
|
|
ebtablesCreateTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesCreateTmpRootChainFW(fw, false, ifname);
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2013-11-19 23:33:37 +00:00
|
|
|
PRINT_ROOT_CHAIN(chain_in, CHAINPREFIX_HOST_IN_TEMP, ifname);
|
2010-04-30 12:06:18 +00:00
|
|
|
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
|
|
|
|
|
2014-03-14 16:27:39 +00:00
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_in,
|
|
|
|
"-j", "DROP", NULL);
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2014-03-14 16:27:39 +00:00
|
|
|
virFirewallAddRule(fw, VIR_FIREWALL_LAYER_ETHERNET,
|
|
|
|
"-t", "nat", "-A", chain_out,
|
|
|
|
"-j", "DROP", NULL);
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2014-03-14 16:27:39 +00:00
|
|
|
ebtablesLinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesLinkTmpRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRenameTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRenameTmpRootChainFW(fw, false, ifname);
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2014-03-31 12:01:04 +00:00
|
|
|
if (virFirewallApply(fw) < 0)
|
2020-06-25 02:20:56 +00:00
|
|
|
goto error;
|
2010-04-30 12:06:18 +00:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2020-06-25 02:20:56 +00:00
|
|
|
error:
|
2010-04-30 12:06:18 +00:00
|
|
|
ebtablesCleanAll(ifname);
|
2011-12-09 02:26:34 +00:00
|
|
|
return -1;
|
2010-04-30 12:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-20 21:07:15 +00:00
|
|
|
static int
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
ebtablesRemoveBasicRules(const char *ifname)
|
2010-04-30 12:06:18 +00:00
|
|
|
{
|
2014-03-14 12:14:13 +00:00
|
|
|
return ebtablesCleanAll(ifname);
|
2010-04-30 12:06:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
static int
|
2014-03-14 13:39:51 +00:00
|
|
|
ebtablesCleanAll(const char *ifname)
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2010-04-14 10:29:55 +00:00
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
ebtablesUnlinkRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRemoveSubChainsFW(fw, ifname);
|
|
|
|
ebtablesRemoveRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveRootChainFW(fw, false, ifname);
|
2010-04-30 12:06:18 +00:00
|
|
|
|
2014-03-14 12:14:13 +00:00
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRemoveTmpSubChainsFW(fw, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, false, ifname);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return virFirewallApply(fw);
|
nwfilter: Support for learning a VM's IP address
This patch implements support for learning a VM's IP address. It uses
the pcap library to listen on the VM's backend network interface (tap)
or the physical ethernet device (macvtap) and tries to capture packets
with source or destination MAC address of the VM and learn from DHCP
Offers, ARP traffic, or first-sent IPv4 packet what the IP address of
the VM's interface is. This then allows to instantiate the network
traffic filtering rules without the user having to provide the IP
parameter somewhere in the filter description or in the interface
description as a parameter. This only supports to detect the parameter
IP, which is for the assumed single IPv4 address of a VM. There is not
support for interfaces that may have multiple IP addresses (IP
aliasing) or IPv6 that may then require more than one valid IP address
to be detected. A VM can have multiple independent interfaces that each
uses a different IP address and in that case it will be attempted to
detect each one of the address independently.
So, when for example an interface description in the domain XML has
looked like this up to now:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'>
<parameter name='IP' value='10.2.3.4'/>
</filterref>
</interface>
you may omit the IP parameter:
<interface type='bridge'>
<source bridge='mybridge'/>
<model type='virtio'/>
<filterref filter='clean-traffic'/>
</interface>
Internally I am walking the 'tree' of a VM's referenced network filters
and determine with the given variables which variables are missing. Now,
the above IP parameter may be missing and this causes a libvirt-internal
thread to be started that uses the pcap library's API to listen to the
backend interface (in case of macvtap to the physical interface) in an
attempt to determine the missing IP parameter. If the backend interface
disappears the thread terminates assuming the VM was brought down. In
case of a macvtap device a timeout is being used to wait for packets
from the given VM (filtering by VM's interface MAC address). If the VM's
macvtap device disappeared the thread also terminates. In all other
cases it tries to determine the IP address of the VM and will then apply
the rules late on the given interface, which would have happened
immediately if the IP parameter had been explicitly given. In case an
error happens while the firewall rules are applied, the VM's backend
interface is 'down'ed preventing it to communicate. Reasons for failure
for applying the network firewall rules may that an ebtables/iptables
command failes or OOM errors. Essentially the same failure reasons may
occur as when the firewall rules are applied immediately on VM start,
except that due to the late application of the filtering rules the VM
now is already running and cannot be hindered anymore from starting.
Bringing down the whole VM would probably be considered too drastic.
While a VM's IP address is attempted to be determined only limited
updates to network filters are allowed. In particular it is prevented
that filters are modified in such a way that they would introduce new
variables.
A caveat: The algorithm does not know which one is the appropriate IP
address of a VM. If the VM spoofs an IP address in its first ARP traffic
or IPv4 packets its filtering rules will be instantiated for this IP
address, thus 'locking' it to the found IP address. So, it's still
'safer' to explicitly provide the IP address of a VM's interface in the
filter description if it is known beforehand.
* configure.ac: detect libpcap
* libvirt.spec.in: require libpcap[-devel] if qemu is built
* src/internal.h: add the new ATTRIBUTE_PACKED define
* src/Makefile.am src/libvirt_private.syms: add the new modules and symbols
* src/nwfilter/nwfilter_learnipaddr.[ch]: new module being added
* src/nwfilter/nwfilter_driver.c src/conf/nwfilter_conf.[ch]
src/nwfilter/nwfilter_ebiptables_driver.[ch]
src/nwfilter/nwfilter_gentech_driver.[ch]: plu the new functionality in
* tests/nwfilterxml2xmltest: extend testing
2010-04-07 21:02:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
static int
|
|
|
|
virNWFilterRuleInstSort(const void *a, const void *b)
|
|
|
|
{
|
|
|
|
const virNWFilterRuleInst *insta = a;
|
|
|
|
const virNWFilterRuleInst *instb = b;
|
|
|
|
const char *root = virNWFilterChainSuffixTypeToString(
|
|
|
|
VIR_NWFILTER_CHAINSUFFIX_ROOT);
|
|
|
|
bool root_a = STREQ(insta->chainSuffix, root);
|
|
|
|
bool root_b = STREQ(instb->chainSuffix, root);
|
|
|
|
|
|
|
|
/* ensure root chain commands appear before all others since
|
|
|
|
we will need them to create the child chains */
|
|
|
|
if (root_a) {
|
2020-06-25 02:30:38 +00:00
|
|
|
if (!root_b)
|
|
|
|
return -1; /* a before b */
|
|
|
|
} else if (root_b) {
|
2014-03-25 13:44:50 +00:00
|
|
|
return 1; /* b before a */
|
2020-06-25 02:30:38 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
/* priorities are limited to range [-1000, 1000] */
|
|
|
|
return insta->priority - instb->priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-11-18 16:58:18 +00:00
|
|
|
static int
|
2014-03-25 13:44:50 +00:00
|
|
|
virNWFilterRuleInstSortPtr(const void *a, const void *b)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2014-03-25 13:44:50 +00:00
|
|
|
virNWFilterRuleInst * const *insta = a;
|
|
|
|
virNWFilterRuleInst * const *instb = b;
|
|
|
|
return virNWFilterRuleInstSort(*insta, *instb);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
|
2011-11-18 16:58:17 +00:00
|
|
|
static int
|
maint: avoid 'const fooPtr' in hashes
'const fooPtr' is the same as 'foo * const' (the pointer won't
change, but it's contents can). But in general, if an interface
is trying to be const-correct, it should be using 'const foo *'
(the pointer is to data that can't be changed).
Fix up virhash to provide a const-correct interface: all actions
that don't modify the table take a const table. Note that in
one case (virHashSearch), we actually strip const away - we aren't
modifying the contents of the table, so much as associated data
for ensuring that the code uses the table correctly (if this were
C++, it would be a case for the 'mutable' keyword).
* src/util/virhash.h (virHashKeyComparator, virHashEqual): Use
intended type.
(virHashSize, virHashTableSize, virHashLookup, virHashSearch):
Make const-correct.
* src/util/virhash.c (virHashEqualData, virHashEqual)
(virHashLookup, virHashSize, virHashTableSize, virHashSearch)
(virHashComputeKey): Fix fallout.
* src/conf/nwfilter_params.c
(virNWFilterFormatParameterNameSorter): Likewise.
* src/nwfilter/nwfilter_ebiptables_driver.c
(ebiptablesFilterOrderSort): Likewise.
* tests/virhashtest.c (testHashGetItemsCompKey)
(testHashGetItemsCompValue): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-10-05 02:30:35 +00:00
|
|
|
ebiptablesFilterOrderSort(const virHashKeyValuePair *a,
|
|
|
|
const virHashKeyValuePair *b)
|
2011-11-18 16:58:17 +00:00
|
|
|
{
|
|
|
|
/* elements' values has been limited to range [-1000, 1000] */
|
|
|
|
return *(virNWFilterChainPriority *)a->value -
|
|
|
|
*(virNWFilterChainPriority *)b->value;
|
|
|
|
}
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
|
2010-09-24 16:06:17 +00:00
|
|
|
static void
|
|
|
|
iptablesCheckBridgeNFCallEnabled(bool isIPv6)
|
|
|
|
{
|
|
|
|
static time_t lastReport, lastReportIPv6;
|
|
|
|
const char *pathname = NULL;
|
|
|
|
char buffer[1];
|
|
|
|
time_t now = time(NULL);
|
|
|
|
|
|
|
|
if (isIPv6 &&
|
2012-10-17 09:23:12 +00:00
|
|
|
(now - lastReportIPv6) > BRIDGE_NF_CALL_ALERT_INTERVAL) {
|
2010-09-24 16:06:17 +00:00
|
|
|
pathname = PROC_BRIDGE_NF_CALL_IP6TABLES;
|
|
|
|
} else if (now - lastReport > BRIDGE_NF_CALL_ALERT_INTERVAL) {
|
|
|
|
pathname = PROC_BRIDGE_NF_CALL_IPTABLES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pathname) {
|
|
|
|
int fd = open(pathname, O_RDONLY);
|
|
|
|
if (fd >= 0) {
|
|
|
|
if (read(fd, buffer, 1) == 1) {
|
|
|
|
if (buffer[0] == '0') {
|
|
|
|
char msg[256];
|
2019-11-13 13:53:42 +00:00
|
|
|
g_snprintf(msg, sizeof(msg),
|
|
|
|
_("To enable ip%stables filtering for the VM do "
|
|
|
|
"'echo 1 > %s'"),
|
|
|
|
isIPv6 ? "6" : "",
|
|
|
|
pathname);
|
2011-05-09 09:24:09 +00:00
|
|
|
VIR_WARN("%s", msg);
|
2010-09-24 16:06:17 +00:00
|
|
|
if (isIPv6)
|
|
|
|
lastReportIPv6 = now;
|
|
|
|
else
|
|
|
|
lastReport = now;
|
|
|
|
}
|
|
|
|
}
|
2010-11-09 20:48:48 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
2010-09-24 16:06:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-11-18 16:58:17 +00:00
|
|
|
/*
|
|
|
|
* Given a filtername determine the protocol it is used for evaluating
|
|
|
|
* We do prefix-matching to determine the protocol.
|
|
|
|
*/
|
|
|
|
static enum l3_proto_idx
|
|
|
|
ebtablesGetProtoIdxByFiltername(const char *filtername)
|
|
|
|
{
|
|
|
|
enum l3_proto_idx idx;
|
|
|
|
|
|
|
|
for (idx = 0; idx < L3_PROTO_LAST_IDX; idx++) {
|
2014-11-13 14:27:11 +00:00
|
|
|
if (STRPREFIX(filtername, l3_protocols[idx].val))
|
2011-11-18 16:58:17 +00:00
|
|
|
return idx;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesRuleInstCommand(virFirewallPtr fw,
|
2014-03-25 13:44:50 +00:00
|
|
|
const char *ifname,
|
2014-03-25 16:10:56 +00:00
|
|
|
virNWFilterRuleInstPtr rule)
|
2014-03-25 13:44:50 +00:00
|
|
|
{
|
|
|
|
virNWFilterVarCombIterPtr vciter, tmp;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/* rule->vars holds all the variables names that this rule will access.
|
|
|
|
* iterate over all combinations of the variables' values and instantiate
|
|
|
|
* the filtering rule with each combination.
|
|
|
|
*/
|
|
|
|
tmp = vciter = virNWFilterVarCombIterCreate(rule->vars,
|
|
|
|
rule->def->varAccess,
|
|
|
|
rule->def->nVarAccess);
|
|
|
|
if (!vciter)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
do {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebiptablesCreateRuleInstance(fw,
|
|
|
|
rule->chainSuffix,
|
2014-03-25 13:44:50 +00:00
|
|
|
rule->def,
|
|
|
|
ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
tmp) < 0)
|
2014-03-25 13:44:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
tmp = virNWFilterVarCombIterNext(tmp);
|
|
|
|
} while (tmp != NULL);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virNWFilterVarCombIterFree(vciter);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesRuleInstCommand(virFirewallPtr fw,
|
2014-03-25 13:44:50 +00:00
|
|
|
const char *ifname,
|
2014-03-25 16:10:56 +00:00
|
|
|
virNWFilterRuleInstPtr rule)
|
2014-03-25 13:44:50 +00:00
|
|
|
{
|
|
|
|
virNWFilterVarCombIterPtr vciter, tmp;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
/* rule->vars holds all the variables names that this rule will access.
|
|
|
|
* iterate over all combinations of the variables' values and instantiate
|
|
|
|
* the filtering rule with each combination.
|
|
|
|
*/
|
|
|
|
tmp = vciter = virNWFilterVarCombIterCreate(rule->vars,
|
|
|
|
rule->def->varAccess,
|
|
|
|
rule->def->nVarAccess);
|
|
|
|
if (!vciter)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
do {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (ebiptablesCreateRuleInstance(fw,
|
|
|
|
rule->chainSuffix,
|
2014-03-25 13:44:50 +00:00
|
|
|
rule->def,
|
|
|
|
ifname,
|
2014-03-25 14:33:19 +00:00
|
|
|
tmp) < 0)
|
2014-03-25 13:44:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
tmp = virNWFilterVarCombIterNext(tmp);
|
|
|
|
} while (tmp != NULL);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
virNWFilterVarCombIterFree(vciter);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-06-24 19:56:43 +00:00
|
|
|
typedef struct _ebtablesSubChainInst ebtablesSubChainInst;
|
|
|
|
typedef ebtablesSubChainInst *ebtablesSubChainInstPtr;
|
|
|
|
struct _ebtablesSubChainInst {
|
2014-03-25 14:33:19 +00:00
|
|
|
virNWFilterChainPriority priority;
|
|
|
|
bool incoming;
|
|
|
|
enum l3_proto_idx protoidx;
|
|
|
|
const char *filtername;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
ebtablesSubChainInstSort(const void *a, const void *b)
|
|
|
|
{
|
2020-06-24 19:56:43 +00:00
|
|
|
const ebtablesSubChainInst **insta = (const ebtablesSubChainInst **)a;
|
|
|
|
const ebtablesSubChainInst **instb = (const ebtablesSubChainInst **)b;
|
2014-03-25 14:33:19 +00:00
|
|
|
|
|
|
|
/* priorities are limited to range [-1000, 1000] */
|
|
|
|
return (*insta)->priority - (*instb)->priority;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
ebtablesGetSubChainInsts(virHashTablePtr chains,
|
|
|
|
bool incoming,
|
2020-06-24 19:56:43 +00:00
|
|
|
ebtablesSubChainInstPtr **insts,
|
2014-03-25 14:33:19 +00:00
|
|
|
size_t *ninsts)
|
|
|
|
{
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree virHashKeyValuePairPtr filter_names = NULL;
|
2014-03-25 14:33:19 +00:00
|
|
|
size_t i;
|
|
|
|
|
|
|
|
filter_names = virHashGetItems(chains,
|
|
|
|
ebiptablesFilterOrderSort);
|
|
|
|
if (filter_names == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
for (i = 0; filter_names[i].key; i++) {
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree ebtablesSubChainInstPtr inst = NULL;
|
2014-03-25 14:33:19 +00:00
|
|
|
enum l3_proto_idx idx = ebtablesGetProtoIdxByFiltername(
|
|
|
|
filter_names[i].key);
|
|
|
|
|
|
|
|
if ((int)idx < 0)
|
|
|
|
continue;
|
|
|
|
|
2020-06-24 20:55:23 +00:00
|
|
|
inst = g_new0(ebtablesSubChainInst, 1);
|
2014-03-25 14:33:19 +00:00
|
|
|
inst->priority = *(const virNWFilterChainPriority *)filter_names[i].value;
|
|
|
|
inst->incoming = incoming;
|
|
|
|
inst->protoidx = idx;
|
|
|
|
inst->filtername = filter_names[i].key;
|
|
|
|
|
2020-06-25 01:59:39 +00:00
|
|
|
if (VIR_APPEND_ELEMENT(*insts, *ninsts, inst) < 0)
|
|
|
|
return -1;
|
2014-03-25 14:33:19 +00:00
|
|
|
}
|
|
|
|
|
2020-06-25 01:59:39 +00:00
|
|
|
return 0;
|
2014-03-25 14:33:19 +00:00
|
|
|
}
|
2014-03-25 13:44:50 +00:00
|
|
|
|
2010-03-25 17:46:09 +00:00
|
|
|
static int
|
2011-11-23 19:13:03 +00:00
|
|
|
ebiptablesApplyNewRules(const char *ifname,
|
2014-03-25 13:44:50 +00:00
|
|
|
virNWFilterRuleInstPtr *rules,
|
|
|
|
size_t nrules)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
Convert 'int i' to 'size_t i' in src/nwfilter/ files
Convert the type of loop iterators named 'i', 'j', k',
'ii', 'jj', 'kk', to be 'size_t' instead of 'int' or
'unsigned int', also santizing 'ii', 'jj', 'kk' to use
the normal 'i', 'j', 'k' naming
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
2013-07-08 14:09:33 +00:00
|
|
|
size_t i, j;
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autoptr(virHashTable) chains_in_set = virHashCreate(10, NULL);
|
|
|
|
g_autoptr(virHashTable) chains_out_set = virHashCreate(10, NULL);
|
2014-03-25 14:33:19 +00:00
|
|
|
bool haveEbtables = false;
|
2010-04-14 10:29:55 +00:00
|
|
|
bool haveIptables = false;
|
|
|
|
bool haveIp6tables = false;
|
2020-06-25 01:59:39 +00:00
|
|
|
g_autofree ebtablesSubChainInstPtr *subchains = NULL;
|
2014-03-25 14:33:19 +00:00
|
|
|
size_t nsubchains = 0;
|
|
|
|
int ret = -1;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2013-07-04 10:12:44 +00:00
|
|
|
if (!chains_in_set || !chains_out_set)
|
2014-03-25 14:33:19 +00:00
|
|
|
goto cleanup;
|
2011-11-18 16:58:17 +00:00
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
if (nrules)
|
|
|
|
qsort(rules, nrules, sizeof(rules[0]),
|
|
|
|
virNWFilterRuleInstSortPtr);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2011-11-18 16:58:17 +00:00
|
|
|
/* cleanup whatever may exist */
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRemoveTmpSubChainsFW(fw, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, false, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallStartTransaction(fw, 0);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-13 22:30:09 +00:00
|
|
|
/* walk the list of rules and increase the priority
|
|
|
|
* of rules in case the chain priority is of higher value;
|
|
|
|
* this preserves the order of the rules and ensures that
|
|
|
|
* the chain will be created before the chain's rules
|
|
|
|
* are created; don't adjust rules in the root chain
|
|
|
|
* example: a rule of priority -510 will be adjusted to
|
|
|
|
* priority -500 and the chain with priority -500 will
|
|
|
|
* then be created before it.
|
|
|
|
*/
|
2014-03-25 13:44:50 +00:00
|
|
|
for (i = 0; i < nrules; i++) {
|
|
|
|
if (rules[i]->chainPriority > rules[i]->priority &&
|
|
|
|
!strstr("root", rules[i]->chainSuffix)) {
|
2014-03-13 22:30:09 +00:00
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
rules[i]->priority = rules[i]->chainPriority;
|
2014-03-13 22:30:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
for (i = 0; i < nrules; i++) {
|
|
|
|
if (virNWFilterRuleIsProtocolEthernet(rules[i]->def)) {
|
2014-03-25 14:33:19 +00:00
|
|
|
haveEbtables = true;
|
2014-03-25 13:44:50 +00:00
|
|
|
} else {
|
|
|
|
if (virNWFilterRuleIsProtocolIPv4(rules[i]->def))
|
|
|
|
haveIptables = true;
|
|
|
|
else if (virNWFilterRuleIsProtocolIPv6(rules[i]->def))
|
|
|
|
haveIp6tables = true;
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
2010-04-15 01:24:21 +00:00
|
|
|
}
|
2014-03-25 14:33:19 +00:00
|
|
|
/* process ebtables commands; interleave commands from filters with
|
|
|
|
commands for creating and connecting ebtables chains */
|
|
|
|
if (haveEbtables) {
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
/* scan the rules to see which chains need to be created */
|
|
|
|
for (i = 0; i < nrules; i++) {
|
|
|
|
if (virNWFilterRuleIsProtocolEthernet(rules[i]->def)) {
|
|
|
|
const char *name = rules[i]->chainSuffix;
|
|
|
|
if (rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
|
|
|
|
rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
|
|
|
|
if (virHashUpdateEntry(chains_in_set, name,
|
|
|
|
&rules[i]->chainPriority) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
|
|
|
|
rules[i]->def->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
|
|
|
|
if (virHashUpdateEntry(chains_out_set, name,
|
|
|
|
&rules[i]->chainPriority) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-11-18 16:58:18 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
/* create needed chains */
|
|
|
|
if (virHashSize(chains_in_set) > 0) {
|
|
|
|
ebtablesCreateTmpRootChainFW(fw, true, ifname);
|
|
|
|
if (ebtablesGetSubChainInsts(chains_in_set,
|
|
|
|
true,
|
|
|
|
&subchains,
|
|
|
|
&nsubchains) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (virHashSize(chains_out_set) > 0) {
|
|
|
|
ebtablesCreateTmpRootChainFW(fw, false, ifname);
|
|
|
|
if (ebtablesGetSubChainInsts(chains_out_set,
|
|
|
|
false,
|
|
|
|
&subchains,
|
|
|
|
&nsubchains) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nsubchains > 0)
|
|
|
|
qsort(subchains, nsubchains, sizeof(subchains[0]),
|
|
|
|
ebtablesSubChainInstSort);
|
|
|
|
|
|
|
|
for (i = 0, j = 0; i < nrules; i++) {
|
|
|
|
if (virNWFilterRuleIsProtocolEthernet(rules[i]->def)) {
|
|
|
|
while (j < nsubchains &&
|
|
|
|
subchains[j]->priority <= rules[i]->priority) {
|
|
|
|
ebtablesCreateTmpSubChainFW(fw,
|
|
|
|
subchains[j]->incoming,
|
|
|
|
ifname,
|
|
|
|
subchains[j]->protoidx,
|
|
|
|
subchains[j]->filtername);
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
if (ebtablesRuleInstCommand(fw,
|
|
|
|
ifname,
|
|
|
|
rules[i]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while (j < nsubchains) {
|
|
|
|
ebtablesCreateTmpSubChainFW(fw,
|
|
|
|
subchains[j]->incoming,
|
|
|
|
ifname,
|
|
|
|
subchains[j]->protoidx,
|
|
|
|
subchains[j]->filtername);
|
|
|
|
j++;
|
|
|
|
}
|
|
|
|
}
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (haveIptables) {
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesUnlinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesRemoveTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateBaseChainsFW(fw, VIR_FIREWALL_LAYER_IPV4);
|
|
|
|
iptablesCreateTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesLinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesSetupVirtInPostFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
for (i = 0; i < nrules; i++) {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (virNWFilterRuleIsProtocolIPv4(rules[i]->def)) {
|
|
|
|
if (iptablesRuleInstCommand(fw,
|
|
|
|
ifname,
|
|
|
|
rules[i]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
2010-09-24 16:06:17 +00:00
|
|
|
iptablesCheckBridgeNFCallEnabled(false);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
2010-03-30 14:36:35 +00:00
|
|
|
if (haveIp6tables) {
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesUnlinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesRemoveTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2010-03-30 14:36:35 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesCreateBaseChainsFW(fw, VIR_FIREWALL_LAYER_IPV6);
|
|
|
|
iptablesCreateTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2010-03-30 14:36:35 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesLinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesSetupVirtInPostFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-25 13:44:50 +00:00
|
|
|
for (i = 0; i < nrules; i++) {
|
2014-03-25 14:33:19 +00:00
|
|
|
if (virNWFilterRuleIsProtocolIPv6(rules[i]->def)) {
|
|
|
|
if (iptablesRuleInstCommand(fw,
|
|
|
|
ifname,
|
|
|
|
rules[i]) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-03-30 14:36:35 +00:00
|
|
|
}
|
|
|
|
|
2010-09-24 16:06:17 +00:00
|
|
|
iptablesCheckBridgeNFCallEnabled(true);
|
2010-03-30 14:36:35 +00:00
|
|
|
}
|
|
|
|
|
2011-11-18 16:58:17 +00:00
|
|
|
if (virHashSize(chains_in_set) != 0)
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesLinkTmpRootChainFW(fw, true, ifname);
|
2011-11-18 16:58:17 +00:00
|
|
|
if (virHashSize(chains_out_set) != 0)
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesLinkTmpRootChainFW(fw, false, ifname);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
virFirewallStartRollback(fw, 0);
|
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, false, ifname);
|
2010-03-30 14:36:35 +00:00
|
|
|
if (haveIp6tables) {
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesUnlinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesRemoveTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2010-03-30 14:36:35 +00:00
|
|
|
}
|
|
|
|
|
2010-03-25 17:46:12 +00:00
|
|
|
if (haveIptables) {
|
2014-03-25 14:33:19 +00:00
|
|
|
iptablesUnlinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesRemoveTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
}
|
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
ebtablesRemoveTmpSubChainsFW(fw, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, false, ifname);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-31 12:01:04 +00:00
|
|
|
if (virFirewallApply(fw) < 0)
|
2014-03-25 14:33:19 +00:00
|
|
|
goto cleanup;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
ret = 0;
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
cleanup:
|
|
|
|
for (i = 0; i < nsubchains; i++)
|
2020-06-25 02:06:47 +00:00
|
|
|
g_free(subchains[i]);
|
2011-11-18 16:58:17 +00:00
|
|
|
|
2014-03-25 14:33:19 +00:00
|
|
|
return ret;
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2014-04-30 16:51:38 +00:00
|
|
|
static void
|
|
|
|
ebiptablesTearNewRulesFW(virFirewallPtr fw, const char *ifname)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2014-03-14 12:48:33 +00:00
|
|
|
iptablesUnlinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesRemoveTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:48:33 +00:00
|
|
|
iptablesUnlinkTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesRemoveTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:48:33 +00:00
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkTmpRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRemoveTmpSubChainsFW(fw, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveTmpRootChainFW(fw, false, ifname);
|
2014-04-30 16:51:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
ebiptablesTearNewRules(const char *ifname)
|
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2014-04-30 16:51:38 +00:00
|
|
|
|
|
|
|
virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
|
|
|
|
|
|
|
ebiptablesTearNewRulesFW(fw, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return virFirewallApply(fw);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2011-11-23 19:13:03 +00:00
|
|
|
ebiptablesTearOldRules(const char *ifname)
|
2010-03-25 17:46:09 +00:00
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
iptablesUnlinkRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesRemoveRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesRenameTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
iptablesUnlinkRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesRemoveRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesRenameTmpRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 12:05:00 +00:00
|
|
|
ebtablesUnlinkRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRemoveSubChainsFW(fw, ifname);
|
|
|
|
ebtablesRemoveRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveRootChainFW(fw, false, ifname);
|
|
|
|
ebtablesRenameTmpSubAndRootChainsFW(fw, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return virFirewallApply(fw);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ebiptablesAllTeardown:
|
|
|
|
* @ifname : the name of the interface to which the rules apply
|
|
|
|
*
|
|
|
|
* Unconditionally remove all possible user defined tables and rules
|
|
|
|
* that were created for the given interface (ifname).
|
|
|
|
*
|
2014-03-14 11:53:06 +00:00
|
|
|
* Returns 0 on success, -1 on OOM
|
2010-03-25 17:46:09 +00:00
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ebiptablesAllTeardown(const char *ifname)
|
|
|
|
{
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2010-03-30 14:36:35 +00:00
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
virFirewallStartTransaction(fw, VIR_FIREWALL_TRANSACTION_IGNORE_ERRORS);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-04-30 16:51:38 +00:00
|
|
|
ebiptablesTearNewRulesFW(fw, ifname);
|
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
iptablesUnlinkRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesClearVirtInPostFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
|
|
|
iptablesRemoveRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV4, ifname);
|
2010-03-25 17:46:12 +00:00
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
iptablesUnlinkRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesClearVirtInPostFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
|
|
|
iptablesRemoveRootChainsFW(fw, VIR_FIREWALL_LAYER_IPV6, ifname);
|
2011-11-22 20:12:04 +00:00
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
ebtablesUnlinkRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesUnlinkRootChainFW(fw, false, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
ebtablesRemoveSubChainsFW(fw, ifname);
|
2011-11-18 16:58:17 +00:00
|
|
|
|
2014-03-14 11:53:06 +00:00
|
|
|
ebtablesRemoveRootChainFW(fw, true, ifname);
|
|
|
|
ebtablesRemoveRootChainFW(fw, false, ifname);
|
2010-03-25 17:46:09 +00:00
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return virFirewallApply(fw);
|
2010-03-25 17:46:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virNWFilterTechDriver ebiptables_driver = {
|
|
|
|
.name = EBIPTABLES_DRIVER_ID,
|
2010-04-14 10:29:55 +00:00
|
|
|
.flags = 0,
|
|
|
|
|
|
|
|
.init = ebiptablesDriverInit,
|
|
|
|
.shutdown = ebiptablesDriverShutdown,
|
2010-03-25 17:46:09 +00:00
|
|
|
|
|
|
|
.applyNewRules = ebiptablesApplyNewRules,
|
|
|
|
.tearNewRules = ebiptablesTearNewRules,
|
|
|
|
.tearOldRules = ebiptablesTearOldRules,
|
|
|
|
.allTeardown = ebiptablesAllTeardown,
|
2010-04-20 21:07:15 +00:00
|
|
|
|
|
|
|
.canApplyBasicRules = ebiptablesCanApplyBasicRules,
|
|
|
|
.applyBasicRules = ebtablesApplyBasicRules,
|
|
|
|
.applyDHCPOnlyRules = ebtablesApplyDHCPOnlyRules,
|
2010-04-30 12:06:18 +00:00
|
|
|
.applyDropAllRules = ebtablesApplyDropAllRules,
|
2010-04-20 21:07:15 +00:00
|
|
|
.removeBasicRules = ebtablesRemoveBasicRules,
|
2010-03-25 17:46:09 +00:00
|
|
|
};
|
2010-04-14 10:29:55 +00:00
|
|
|
|
2013-05-16 01:02:11 +00:00
|
|
|
static void
|
|
|
|
ebiptablesDriverProbeCtdir(void)
|
|
|
|
{
|
|
|
|
struct utsname utsname;
|
|
|
|
unsigned long thisversion;
|
|
|
|
|
|
|
|
iptables_ctdir_corrected = CTDIR_STATUS_UNKNOWN;
|
|
|
|
|
|
|
|
if (uname(&utsname) < 0) {
|
|
|
|
VIR_ERROR(_("Call to utsname failed: %d"), errno);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* following Linux lxr, the logic was inverted in 2.6.39 */
|
|
|
|
if (virParseVersionString(utsname.release, &thisversion, true) < 0) {
|
|
|
|
VIR_ERROR(_("Could not determine kernel version from string %s"),
|
|
|
|
utsname.release);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (thisversion >= 2 * 1000000 + 6 * 1000 + 39)
|
|
|
|
iptables_ctdir_corrected = CTDIR_STATUS_CORRECTED;
|
|
|
|
else
|
|
|
|
iptables_ctdir_corrected = CTDIR_STATUS_OLD;
|
|
|
|
}
|
|
|
|
|
2013-08-07 00:30:46 +00:00
|
|
|
|
2014-03-31 11:58:20 +00:00
|
|
|
static int
|
2019-10-14 12:45:33 +00:00
|
|
|
ebiptablesDriverProbeStateMatchQuery(virFirewallPtr fw G_GNUC_UNUSED,
|
|
|
|
virFirewallLayer layer G_GNUC_UNUSED,
|
2014-03-31 11:58:20 +00:00
|
|
|
const char *const *lines,
|
|
|
|
void *opaque)
|
|
|
|
{
|
|
|
|
unsigned long *version = opaque;
|
|
|
|
char *tmp;
|
2013-08-07 00:30:46 +00:00
|
|
|
|
2014-03-31 11:58:20 +00:00
|
|
|
if (!lines || !lines[0]) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
_("No output from iptables --version"));
|
|
|
|
return -1;
|
2013-08-07 00:30:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* we expect output in the format
|
2014-03-31 11:58:20 +00:00
|
|
|
* 'iptables v1.4.16'
|
2013-08-07 00:30:46 +00:00
|
|
|
*/
|
2014-03-31 11:58:20 +00:00
|
|
|
if (!(tmp = strchr(lines[0], 'v')) ||
|
|
|
|
virParseVersionString(tmp + 1, version, true) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
_("Cannot parse version string '%s'"),
|
|
|
|
lines[0]);
|
|
|
|
return -1;
|
2013-08-07 00:30:46 +00:00
|
|
|
}
|
|
|
|
|
2014-03-31 11:58:20 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
ebiptablesDriverProbeStateMatch(void)
|
|
|
|
{
|
|
|
|
unsigned long version;
|
2020-07-04 20:35:10 +00:00
|
|
|
g_autoptr(virFirewall) fw = virFirewallNew();
|
2014-03-31 11:58:20 +00:00
|
|
|
|
|
|
|
virFirewallStartTransaction(fw, 0);
|
|
|
|
virFirewallAddRuleFull(fw, VIR_FIREWALL_LAYER_IPV4,
|
|
|
|
false, ebiptablesDriverProbeStateMatchQuery, &version,
|
|
|
|
"--version", NULL);
|
|
|
|
|
|
|
|
if (virFirewallApply(fw) < 0)
|
2020-07-04 20:38:37 +00:00
|
|
|
return -1;
|
2014-03-31 11:58:20 +00:00
|
|
|
|
2013-08-07 00:30:46 +00:00
|
|
|
/*
|
|
|
|
* since version 1.4.16 '-m state --state ...' will be converted to
|
|
|
|
* '-m conntrack --ctstate ...'
|
|
|
|
*/
|
2014-03-31 11:58:20 +00:00
|
|
|
if (version >= 1 * 1000000 + 4 * 1000 + 16)
|
2014-03-25 14:33:19 +00:00
|
|
|
newMatchState = true;
|
2013-08-07 00:30:46 +00:00
|
|
|
|
2020-07-04 20:38:37 +00:00
|
|
|
return 0;
|
2013-08-07 00:30:46 +00:00
|
|
|
}
|
|
|
|
|
2012-08-08 16:00:23 +00:00
|
|
|
static int
|
|
|
|
ebiptablesDriverInit(bool privileged)
|
|
|
|
{
|
|
|
|
if (!privileged)
|
|
|
|
return 0;
|
|
|
|
|
2014-03-31 12:01:04 +00:00
|
|
|
ebiptablesDriverProbeCtdir();
|
|
|
|
if (ebiptablesDriverProbeStateMatch() < 0)
|
|
|
|
return -1;
|
2013-05-16 01:02:11 +00:00
|
|
|
|
2010-04-14 10:29:55 +00:00
|
|
|
ebiptables_driver.flags = TECHDRV_FLAG_INITIALIZED;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
2011-02-10 10:46:21 +00:00
|
|
|
ebiptablesDriverShutdown(void)
|
2010-04-14 10:29:55 +00:00
|
|
|
{
|
|
|
|
ebiptables_driver.flags = 0;
|
|
|
|
}
|