mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-22 04:25:18 +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
This commit is contained in:
parent
7be5c26d74
commit
3bf24abc8c
39
configure.ac
39
configure.ac
@ -41,6 +41,7 @@ XMLRPC_REQUIRED=1.14.0
|
|||||||
HAL_REQUIRED=0.5.0
|
HAL_REQUIRED=0.5.0
|
||||||
DEVMAPPER_REQUIRED=1.0.0
|
DEVMAPPER_REQUIRED=1.0.0
|
||||||
LIBCURL_REQUIRED="7.18.0"
|
LIBCURL_REQUIRED="7.18.0"
|
||||||
|
LIBPCAP_REQUIRED="1.0.0"
|
||||||
|
|
||||||
dnl Checks for C compiler.
|
dnl Checks for C compiler.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
@ -1045,6 +1046,39 @@ AC_SUBST([NUMACTL_CFLAGS])
|
|||||||
AC_SUBST([NUMACTL_LIBS])
|
AC_SUBST([NUMACTL_LIBS])
|
||||||
|
|
||||||
|
|
||||||
|
dnl pcap lib
|
||||||
|
LIBPCAP_CONFIG="pcap-config"
|
||||||
|
LIBPCAP_CFLAGS=""
|
||||||
|
LIBPCAP_LIBS=""
|
||||||
|
LIBPCAP_FOUND="no"
|
||||||
|
|
||||||
|
AC_ARG_WITH([libpcap], AC_HELP_STRING([--with-libpcap=@<:@PFX@:>@], [libpcap location]))
|
||||||
|
if test "$with_qemu" = "yes"; then
|
||||||
|
if test "x$with_libpcap" != "xno" ; then
|
||||||
|
if test "x$with_libpcap" != "x" ; then
|
||||||
|
LIBPCAP_CONFIG=$with_libpcap/bin/$LIBPCAP_CONFIG
|
||||||
|
fi
|
||||||
|
AC_MSG_CHECKING(libpcap $LIBPCAP_CONFIG >= $LIBPCAP_REQUIRED )
|
||||||
|
if ! $LIBPCAP_CONFIG --libs > /dev/null 2>&1 ; then
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
else
|
||||||
|
LIBPCAP_LIBS="`$LIBPCAP_CONFIG --libs`"
|
||||||
|
LIBPCAP_CFLAGS="`$LIBPCAP_CONFIG --cflags`"
|
||||||
|
LIBPCAP_FOUND="yes"
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test "x$LIBPCAP_FOUND" = "xyes"; then
|
||||||
|
AC_DEFINE_UNQUOTED([HAVE_LIBPCAP], 1, [whether libpcap can be used])
|
||||||
|
fi
|
||||||
|
|
||||||
|
AC_SUBST([LIBPCAP_CFLAGS])
|
||||||
|
AC_SUBST([LIBPCAP_LIBS])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
dnl
|
dnl
|
||||||
dnl Checks for the UML driver
|
dnl Checks for the UML driver
|
||||||
dnl
|
dnl
|
||||||
@ -2129,6 +2163,11 @@ AC_MSG_NOTICE([ xmlrpc: $XMLRPC_CFLAGS $XMLRPC_LIBS])
|
|||||||
else
|
else
|
||||||
AC_MSG_NOTICE([ xmlrpc: no])
|
AC_MSG_NOTICE([ xmlrpc: no])
|
||||||
fi
|
fi
|
||||||
|
if test "$with_qemu" = "yes" ; then
|
||||||
|
AC_MSG_NOTICE([ pcap: $LIBPCAP_CFLAGS $LIBPCAP_LIBS])
|
||||||
|
else
|
||||||
|
AC_MSG_NOTICE([ pcap: no])
|
||||||
|
fi
|
||||||
AC_MSG_NOTICE([])
|
AC_MSG_NOTICE([])
|
||||||
AC_MSG_NOTICE([Test suite])
|
AC_MSG_NOTICE([Test suite])
|
||||||
AC_MSG_NOTICE([])
|
AC_MSG_NOTICE([])
|
||||||
|
@ -61,6 +61,7 @@
|
|||||||
%define with_udev 0%{!?_without_udev:0}
|
%define with_udev 0%{!?_without_udev:0}
|
||||||
%define with_hal 0%{!?_without_hal:0}
|
%define with_hal 0%{!?_without_hal:0}
|
||||||
%define with_yajl 0%{!?_without_yajl:0}
|
%define with_yajl 0%{!?_without_yajl:0}
|
||||||
|
%define with_libpcap 0%{!?_without_libpcap:0}
|
||||||
|
|
||||||
# Non-server/HV driver defaults which are always enabled
|
# Non-server/HV driver defaults which are always enabled
|
||||||
%define with_python 0%{!?_without_python:1}
|
%define with_python 0%{!?_without_python:1}
|
||||||
@ -147,6 +148,11 @@
|
|||||||
%define with_yajl 0%{!?_without_yajl:%{server_drivers}}
|
%define with_yajl 0%{!?_without_yajl:%{server_drivers}}
|
||||||
%endif
|
%endif
|
||||||
|
|
||||||
|
# Enable libpcap library
|
||||||
|
%if %{with_qemu}
|
||||||
|
%define with_libpcap 0%{!?_without_libpcap:%{server_drivers}}
|
||||||
|
%endif
|
||||||
|
|
||||||
# Force QEMU to run as non-root
|
# Force QEMU to run as non-root
|
||||||
%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
|
%if 0%{?fedora} >= 12 || 0%{?rhel} >= 6
|
||||||
%define qemu_user qemu
|
%define qemu_user qemu
|
||||||
@ -266,6 +272,9 @@ BuildRequires: libpciaccess-devel >= 0.10.9
|
|||||||
%if %{with_yajl}
|
%if %{with_yajl}
|
||||||
BuildRequires: yajl-devel
|
BuildRequires: yajl-devel
|
||||||
%endif
|
%endif
|
||||||
|
%if %{with_libpcap}
|
||||||
|
BuildRequires: libpcap-devel
|
||||||
|
%endif
|
||||||
%if %{with_avahi}
|
%if %{with_avahi}
|
||||||
BuildRequires: avahi-devel
|
BuildRequires: avahi-devel
|
||||||
%endif
|
%endif
|
||||||
|
@ -308,7 +308,9 @@ NWFILTER_DRIVER_SOURCES = \
|
|||||||
nwfilter/nwfilter_gentech_driver.c \
|
nwfilter/nwfilter_gentech_driver.c \
|
||||||
nwfilter/nwfilter_gentech_driver.h \
|
nwfilter/nwfilter_gentech_driver.h \
|
||||||
nwfilter/nwfilter_ebiptables_driver.c \
|
nwfilter/nwfilter_ebiptables_driver.c \
|
||||||
nwfilter/nwfilter_ebiptables_driver.h
|
nwfilter/nwfilter_ebiptables_driver.h \
|
||||||
|
nwfilter/nwfilter_learnipaddr.c \
|
||||||
|
nwfilter/nwfilter_learnipaddr.h
|
||||||
|
|
||||||
|
|
||||||
# Security framework and drivers for various models
|
# Security framework and drivers for various models
|
||||||
@ -764,10 +766,11 @@ else
|
|||||||
libvirt_la_LIBADD += libvirt_driver_nwfilter.la
|
libvirt_la_LIBADD += libvirt_driver_nwfilter.la
|
||||||
noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
|
noinst_LTLIBRARIES += libvirt_driver_nwfilter.la
|
||||||
endif
|
endif
|
||||||
libvirt_driver_nwfilter_la_CFLAGS = \
|
libvirt_driver_nwfilter_la_CFLAGS = $(LIBPCAP_CFLAGS) \
|
||||||
-I@top_srcdir@/src/conf
|
-I@top_srcdir@/src/conf
|
||||||
|
libvirt_driver_nwfilter_la_LDFLAGS = $(LIBPCAP_LIBS)
|
||||||
if WITH_DRIVER_MODULES
|
if WITH_DRIVER_MODULES
|
||||||
libvirt_driver_nwfilter_la_LDFLAGS = -module -avoid-version ../gnulib/lib/libgnu.la
|
libvirt_driver_nwfilter_la_LDFLAGS += -module -avoid-version ../gnulib/lib/libgnu.la
|
||||||
endif
|
endif
|
||||||
libvirt_driver_nwfilter_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
|
libvirt_driver_nwfilter_la_SOURCES = $(NWFILTER_DRIVER_SOURCES)
|
||||||
endif
|
endif
|
||||||
@ -912,6 +915,7 @@ libvirt_la_LDFLAGS = $(VERSION_SCRIPT_FLAGS)libvirt.syms \
|
|||||||
-version-info $(LIBVIRT_VERSION_INFO) \
|
-version-info $(LIBVIRT_VERSION_INFO) \
|
||||||
$(COVERAGE_CFLAGS:-f%=-Wc,-f%) \
|
$(COVERAGE_CFLAGS:-f%=-Wc,-f%) \
|
||||||
$(LIBXML_LIBS) \
|
$(LIBXML_LIBS) \
|
||||||
|
$(LIBPCAP_LIBS) \
|
||||||
$(DRIVER_MODULE_LIBS) \
|
$(DRIVER_MODULE_LIBS) \
|
||||||
$(CYGWIN_EXTRA_LDFLAGS) $(MINGW_EXTRA_LDFLAGS)
|
$(CYGWIN_EXTRA_LDFLAGS) $(MINGW_EXTRA_LDFLAGS)
|
||||||
libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) -DIN_LIBVIRT
|
libvirt_la_CFLAGS = $(COVERAGE_CFLAGS) -DIN_LIBVIRT
|
||||||
@ -960,8 +964,8 @@ libvirt_lxc_SOURCES = \
|
|||||||
$(NODE_INFO_SOURCES) \
|
$(NODE_INFO_SOURCES) \
|
||||||
$(ENCRYPTION_CONF_SOURCES) \
|
$(ENCRYPTION_CONF_SOURCES) \
|
||||||
$(DOMAIN_CONF_SOURCES) \
|
$(DOMAIN_CONF_SOURCES) \
|
||||||
$(NWFILTER_PARAM_CONF_SOURCES) \
|
$(CPU_CONF_SOURCES) \
|
||||||
$(CPU_CONF_SOURCES)
|
$(NWFILTER_PARAM_CONF_SOURCES)
|
||||||
libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) $(YAJL_LIBS)
|
libvirt_lxc_LDFLAGS = $(WARN_CFLAGS) $(COVERAGE_LDCFLAGS) $(CAPNG_LIBS) $(YAJL_LIBS)
|
||||||
libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
|
libvirt_lxc_LDADD = $(LIBXML_LIBS) $(NUMACTL_LIBS) ../gnulib/lib/libgnu.la
|
||||||
libvirt_lxc_CFLAGS = \
|
libvirt_lxc_CFLAGS = \
|
||||||
|
@ -114,17 +114,18 @@ struct int_map {
|
|||||||
*/
|
*/
|
||||||
static virMutex updateMutex;
|
static virMutex updateMutex;
|
||||||
|
|
||||||
static void
|
void
|
||||||
virNWFilterLockFilterUpdates(void) {
|
virNWFilterLockFilterUpdates(void) {
|
||||||
virMutexLock(&updateMutex);
|
virMutexLock(&updateMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
virNWFilterUnlockFilterUpdates(void) {
|
virNWFilterUnlockFilterUpdates(void) {
|
||||||
virMutexUnlock(&updateMutex);
|
virMutexUnlock(&updateMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* attribute names for the rules XML
|
* attribute names for the rules XML
|
||||||
*/
|
*/
|
||||||
@ -2615,7 +2616,7 @@ int virNWFilterConfLayerInit(virHashIterator domUpdateCB)
|
|||||||
{
|
{
|
||||||
virNWFilterDomainFWUpdateCB = domUpdateCB;
|
virNWFilterDomainFWUpdateCB = domUpdateCB;
|
||||||
|
|
||||||
if (virMutexInit(&updateMutex))
|
if (virMutexInitRecursive(&updateMutex))
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -558,6 +558,9 @@ virNWFilterDefPtr virNWFilterDefParseFile(virConnectPtr conn,
|
|||||||
void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj);
|
void virNWFilterPoolObjLock(virNWFilterPoolObjPtr obj);
|
||||||
void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj);
|
void virNWFilterPoolObjUnlock(virNWFilterPoolObjPtr obj);
|
||||||
|
|
||||||
|
void virNWFilterLockFilterUpdates(void);
|
||||||
|
void virNWFilterUnlockFilterUpdates(void);
|
||||||
|
|
||||||
int virNWFilterConfLayerInit(virHashIterator domUpdateCB);
|
int virNWFilterConfLayerInit(virHashIterator domUpdateCB);
|
||||||
void virNWFilterConfLayerShutdown(void);
|
void virNWFilterConfLayerShutdown(void);
|
||||||
|
|
||||||
|
@ -138,6 +138,23 @@
|
|||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ATTRIBUTE_PACKED
|
||||||
|
*
|
||||||
|
* force a structure to be packed, i.e. not following architecture and
|
||||||
|
* compiler best alignments for its sub components. It's needed for example
|
||||||
|
* for the network filetering code when defining the content of raw
|
||||||
|
* ethernet packets.
|
||||||
|
* Others compiler than gcc may use something different e.g. #pragma pack(1)
|
||||||
|
*/
|
||||||
|
# ifndef ATTRIBUTE_PACKED
|
||||||
|
# if __GNUC_PREREQ (3, 3)
|
||||||
|
# define ATTRIBUTE_PACKED __attribute__((packed))
|
||||||
|
# else
|
||||||
|
# error "Need an __attribute__((packed)) equivalent"
|
||||||
|
# endif
|
||||||
|
# endif
|
||||||
|
|
||||||
# ifndef ATTRIBUTE_NONNULL
|
# ifndef ATTRIBUTE_NONNULL
|
||||||
# if __GNUC_PREREQ (3, 3)
|
# if __GNUC_PREREQ (3, 3)
|
||||||
# define ATTRIBUTE_NONNULL(m) __attribute__((__nonnull__(m)))
|
# define ATTRIBUTE_NONNULL(m) __attribute__((__nonnull__(m)))
|
||||||
|
@ -499,6 +499,8 @@ virNWFilterRegisterCallbackDriver;
|
|||||||
virNWFilterTestUnassignDef;
|
virNWFilterTestUnassignDef;
|
||||||
virNWFilterConfLayerInit;
|
virNWFilterConfLayerInit;
|
||||||
virNWFilterConfLayerShutdown;
|
virNWFilterConfLayerShutdown;
|
||||||
|
virNWFilterLockFilterUpdates;
|
||||||
|
virNWFilterUnlockFilterUpdates;
|
||||||
|
|
||||||
|
|
||||||
#nwfilter_params.h
|
#nwfilter_params.h
|
||||||
@ -514,6 +516,16 @@ virNWFilterInstantiateFilter;
|
|||||||
virNWFilterTeardownFilter;
|
virNWFilterTeardownFilter;
|
||||||
|
|
||||||
|
|
||||||
|
#nwfilter_learnipaddr.h
|
||||||
|
ipAddressMap;
|
||||||
|
ipAddressMapLock;
|
||||||
|
pendingLearnReq;
|
||||||
|
pendingLearnReqLock;
|
||||||
|
virNWFilterGetIpAddrForIfname;
|
||||||
|
virNWFilterDelIpAddrForIfname;
|
||||||
|
virNWFilterLookupLearnReq;
|
||||||
|
|
||||||
|
|
||||||
# pci.h
|
# pci.h
|
||||||
pciGetDevice;
|
pciGetDevice;
|
||||||
pciFreeDevice;
|
pciFreeDevice;
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
#include "nwfilter_gentech_driver.h"
|
#include "nwfilter_gentech_driver.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "nwfilter_learnipaddr.h"
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
||||||
|
|
||||||
#define nwfilterLog(msg...) fprintf(stderr, msg)
|
#define nwfilterLog(msg...) fprintf(stderr, msg)
|
||||||
@ -65,9 +67,12 @@ static int
|
|||||||
nwfilterDriverStartup(int privileged) {
|
nwfilterDriverStartup(int privileged) {
|
||||||
char *base = NULL;
|
char *base = NULL;
|
||||||
|
|
||||||
if (virNWFilterConfLayerInit(virNWFilterDomainFWUpdateCB) < 0)
|
if (virNWFilterLearnInit() < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (virNWFilterConfLayerInit(virNWFilterDomainFWUpdateCB) < 0)
|
||||||
|
goto conf_init_err;
|
||||||
|
|
||||||
if (VIR_ALLOC(driverState) < 0)
|
if (VIR_ALLOC(driverState) < 0)
|
||||||
goto alloc_err_exit;
|
goto alloc_err_exit;
|
||||||
|
|
||||||
@ -120,6 +125,9 @@ error:
|
|||||||
alloc_err_exit:
|
alloc_err_exit:
|
||||||
virNWFilterConfLayerShutdown();
|
virNWFilterConfLayerShutdown();
|
||||||
|
|
||||||
|
conf_init_err:
|
||||||
|
virNWFilterLearnShutdown();
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -413,5 +421,6 @@ static virStateDriver stateDriver = {
|
|||||||
int nwfilterRegister(void) {
|
int nwfilterRegister(void) {
|
||||||
virRegisterNWFilterDriver(&nwfilterDriver);
|
virRegisterNWFilterDriver(&nwfilterDriver);
|
||||||
virRegisterStateDriver(&stateDriver);
|
virRegisterStateDriver(&stateDriver);
|
||||||
|
virNWFilterLearnInit();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -2519,6 +2519,242 @@ ebiptablesInstCommand(virBufferPtr buf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ebtablesApplyBasicRules
|
||||||
|
*
|
||||||
|
* @conn: virConnect object
|
||||||
|
* @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
|
||||||
|
*
|
||||||
|
* Returns 0 on success, 1 on failure with the rules removed
|
||||||
|
*
|
||||||
|
* Apply basic filtering rules on the given interface
|
||||||
|
* - filtering for MAC address spoofing
|
||||||
|
* - allowing IPv4 & ARP traffic
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ebtablesApplyBasicRules(const char *ifname,
|
||||||
|
const unsigned char *macaddr)
|
||||||
|
{
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
int cli_status;
|
||||||
|
char chain[MAX_CHAINNAME_LENGTH];
|
||||||
|
char chainPrefix = CHAINPREFIX_HOST_IN_TEMP;
|
||||||
|
char macaddr_str[VIR_MAC_STRING_BUFLEN];
|
||||||
|
|
||||||
|
virFormatMacAddr(macaddr, macaddr_str);
|
||||||
|
|
||||||
|
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
|
||||||
|
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
|
||||||
|
ebtablesRemoveTmpSubChains(&buf, ifname);
|
||||||
|
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
|
||||||
|
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
|
||||||
|
ebiptablesExecCLI(&buf, &cli_status);
|
||||||
|
|
||||||
|
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
|
||||||
|
|
||||||
|
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s -s ! %s -j DROP") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain,
|
||||||
|
macaddr_str,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s -p IPv4 -j ACCEPT") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s -p ARP -j ACCEPT") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s -j DROP") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
|
||||||
|
|
||||||
|
if (ebiptablesExecCLI(&buf, &cli_status) || cli_status != 0)
|
||||||
|
goto tear_down_tmpebchains;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tear_down_tmpebchains:
|
||||||
|
ebtablesRemoveBasicRules(ifname);
|
||||||
|
|
||||||
|
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
|
||||||
|
"%s",
|
||||||
|
_("Some rules could not be created."));
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
* @dhcpserver: The DHCP server from which the VM may receive traffic
|
||||||
|
* from; may be NULL
|
||||||
|
*
|
||||||
|
* Returns 0 on success, 1 on failure with the rules removed
|
||||||
|
*
|
||||||
|
* Apply filtering rules so that the VM can only send and receive
|
||||||
|
* DHCP traffic and nothing else.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
ebtablesApplyDHCPOnlyRules(const char *ifname,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *dhcpserver)
|
||||||
|
{
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
int cli_status;
|
||||||
|
char chain_in [MAX_CHAINNAME_LENGTH],
|
||||||
|
chain_out[MAX_CHAINNAME_LENGTH];
|
||||||
|
char macaddr_str[VIR_MAC_STRING_BUFLEN];
|
||||||
|
char *srcIPParam = NULL;
|
||||||
|
|
||||||
|
if (dhcpserver) {
|
||||||
|
virBufferVSprintf(&buf, " --ip-src %s", dhcpserver);
|
||||||
|
if (virBufferError(&buf))
|
||||||
|
return 1;
|
||||||
|
srcIPParam = virBufferContentAndReset(&buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
virFormatMacAddr(macaddr, macaddr_str);
|
||||||
|
|
||||||
|
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
|
||||||
|
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
|
||||||
|
ebtablesRemoveTmpSubChains(&buf, ifname);
|
||||||
|
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
|
||||||
|
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
|
||||||
|
ebiptablesExecCLI(&buf, &cli_status);
|
||||||
|
|
||||||
|
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
|
||||||
|
ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
|
||||||
|
|
||||||
|
PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
|
||||||
|
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s"
|
||||||
|
" -s %s -d Broadcast "
|
||||||
|
" -p ipv4 --ip-protocol udp"
|
||||||
|
" --ip-src 0.0.0.0 --ip-dst 255.255.255.255"
|
||||||
|
" --ip-sport 68 --ip-dport 67"
|
||||||
|
" -j ACCEPT") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain_in,
|
||||||
|
macaddr_str,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s -j DROP") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain_in,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s"
|
||||||
|
" -d %s"
|
||||||
|
" -p ipv4 --ip-protocol udp"
|
||||||
|
" %s"
|
||||||
|
" --ip-sport 67 --ip-dport 68"
|
||||||
|
" -j ACCEPT") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain_out,
|
||||||
|
macaddr_str,
|
||||||
|
srcIPParam != NULL ? srcIPParam : "",
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
virBufferVSprintf(&buf,
|
||||||
|
CMD_DEF(EBTABLES_CMD
|
||||||
|
" -t %s -A %s -j DROP") CMD_SEPARATOR
|
||||||
|
CMD_EXEC
|
||||||
|
"%s",
|
||||||
|
|
||||||
|
EBTABLES_DEFAULT_TABLE,
|
||||||
|
chain_out,
|
||||||
|
CMD_STOPONERR(1));
|
||||||
|
|
||||||
|
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
|
||||||
|
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
|
||||||
|
|
||||||
|
if (ebiptablesExecCLI(&buf, &cli_status) || cli_status != 0)
|
||||||
|
goto tear_down_tmpebchains;
|
||||||
|
|
||||||
|
VIR_FREE(srcIPParam);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
tear_down_tmpebchains:
|
||||||
|
ebtablesRemoveBasicRules(ifname);
|
||||||
|
|
||||||
|
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
|
||||||
|
"%s",
|
||||||
|
_("Some rules could not be created."));
|
||||||
|
|
||||||
|
VIR_FREE(srcIPParam);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
ebtablesRemoveBasicRules(const char *ifname)
|
||||||
|
{
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
int cli_status;
|
||||||
|
|
||||||
|
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
|
||||||
|
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
|
||||||
|
ebtablesRemoveTmpSubChains(&buf, ifname);
|
||||||
|
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
|
||||||
|
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
|
||||||
|
|
||||||
|
ebiptablesExecCLI(&buf, &cli_status);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ebiptablesRuleOrderSort(const void *a, const void *b)
|
ebiptablesRuleOrderSort(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
|
@ -45,4 +45,12 @@ extern virNWFilterTechDriver ebiptables_driver;
|
|||||||
|
|
||||||
# define EBIPTABLES_DRIVER_ID "ebiptables"
|
# define EBIPTABLES_DRIVER_ID "ebiptables"
|
||||||
|
|
||||||
|
|
||||||
|
int ebtablesApplyBasicRules(const char *ifname,
|
||||||
|
const unsigned char *macaddr);
|
||||||
|
int ebtablesApplyDHCPOnlyRules(const char *ifname,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *dhcpServer);
|
||||||
|
int ebtablesRemoveBasicRules(const char *ifname);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -24,6 +24,9 @@
|
|||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <linux/if.h>
|
||||||
|
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
|
||||||
@ -34,12 +37,16 @@
|
|||||||
#include "virterror_internal.h"
|
#include "virterror_internal.h"
|
||||||
#include "nwfilter_gentech_driver.h"
|
#include "nwfilter_gentech_driver.h"
|
||||||
#include "nwfilter_ebiptables_driver.h"
|
#include "nwfilter_ebiptables_driver.h"
|
||||||
|
#include "nwfilter_learnipaddr.h"
|
||||||
|
|
||||||
|
|
||||||
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
||||||
|
|
||||||
|
|
||||||
#define NWFILTER_STD_VAR_MAC "MAC"
|
#define NWFILTER_STD_VAR_MAC "MAC"
|
||||||
|
#define NWFILTER_STD_VAR_IP "IP"
|
||||||
|
|
||||||
|
static int _virNWFilterTeardownFilter(const char *ifname);
|
||||||
|
|
||||||
|
|
||||||
static virNWFilterTechDriverPtr filter_tech_drivers[] = {
|
static virNWFilterTechDriverPtr filter_tech_drivers[] = {
|
||||||
@ -108,6 +115,8 @@ virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
|
|||||||
* @tables: pointer to hash tabel to add values to
|
* @tables: pointer to hash tabel to add values to
|
||||||
* @macaddr: The string of the MAC address to add to the hash table,
|
* @macaddr: The string of the MAC address to add to the hash table,
|
||||||
* may be NULL
|
* may be NULL
|
||||||
|
* @ipaddr: The string of the IP address to add to the hash table;
|
||||||
|
* may be NULL
|
||||||
*
|
*
|
||||||
* Returns 0 in case of success, 1 in case an error happened with
|
* Returns 0 in case of success, 1 in case an error happened with
|
||||||
* error having been reported.
|
* error having been reported.
|
||||||
@ -116,7 +125,8 @@ virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table,
|
virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table,
|
||||||
char *macaddr)
|
char *macaddr,
|
||||||
|
char *ipaddr)
|
||||||
{
|
{
|
||||||
if (macaddr) {
|
if (macaddr) {
|
||||||
if (virHashAddEntry(table->hashTable,
|
if (virHashAddEntry(table->hashTable,
|
||||||
@ -128,6 +138,16 @@ virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ipaddr) {
|
||||||
|
if (virHashAddEntry(table->hashTable,
|
||||||
|
NWFILTER_STD_VAR_IP,
|
||||||
|
ipaddr) < 0) {
|
||||||
|
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
"%s", _("Could not add variable 'IP' to hashmap"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,22 +155,24 @@ virNWFilterVarHashmapAddStdValues(virNWFilterHashTablePtr table,
|
|||||||
/**
|
/**
|
||||||
* virNWFilterCreateVarHashmap:
|
* virNWFilterCreateVarHashmap:
|
||||||
* @macaddr: pointer to string containing formatted MAC address of interface
|
* @macaddr: pointer to string containing formatted MAC address of interface
|
||||||
|
* @ipaddr: pointer to string containing formatted IP address used by
|
||||||
|
* VM on this interface; may be NULL
|
||||||
*
|
*
|
||||||
* Create a hashmap used for evaluating the firewall rules. Initializes
|
* Create a hashmap used for evaluating the firewall rules. Initializes
|
||||||
* it with the standard variable 'MAC'.
|
* it with the standard variable 'MAC' and 'IP' if provided.
|
||||||
*
|
*
|
||||||
* Returns pointer to hashmap, NULL if an error occcurred and error message
|
* Returns pointer to hashmap, NULL if an error occcurred and error message
|
||||||
* is attached to the virConnect object.
|
* is attached to the virConnect object.
|
||||||
*/
|
*/
|
||||||
virNWFilterHashTablePtr
|
virNWFilterHashTablePtr
|
||||||
virNWFilterCreateVarHashmap(char *macaddr) {
|
virNWFilterCreateVarHashmap(char *macaddr, char *ipaddr) {
|
||||||
virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
|
virNWFilterHashTablePtr table = virNWFilterHashTableCreate(0);
|
||||||
if (!table) {
|
if (!table) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virNWFilterVarHashmapAddStdValues(table, macaddr)) {
|
if (virNWFilterVarHashmapAddStdValues(table, macaddr, ipaddr)) {
|
||||||
virNWFilterHashTableFree(table);
|
virNWFilterHashTableFree(table);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -276,9 +298,9 @@ _virNWFilterInstantiateRec(virConnectPtr conn,
|
|||||||
virNWFilterHashTablePtr vars,
|
virNWFilterHashTablePtr vars,
|
||||||
int *nEntries,
|
int *nEntries,
|
||||||
virNWFilterRuleInstPtr **insts,
|
virNWFilterRuleInstPtr **insts,
|
||||||
enum instCase useNewFilter, int *foundNewFilter)
|
enum instCase useNewFilter, int *foundNewFilter,
|
||||||
|
virNWFilterDriverStatePtr driver)
|
||||||
{
|
{
|
||||||
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
|
||||||
virNWFilterPoolObjPtr obj;
|
virNWFilterPoolObjPtr obj;
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int i;
|
int i;
|
||||||
@ -356,7 +378,95 @@ _virNWFilterInstantiateRec(virConnectPtr conn,
|
|||||||
tmpvars,
|
tmpvars,
|
||||||
nEntries, insts,
|
nEntries, insts,
|
||||||
useNewFilter,
|
useNewFilter,
|
||||||
foundNewFilter);
|
foundNewFilter,
|
||||||
|
driver);
|
||||||
|
|
||||||
|
virNWFilterHashTableFree(tmpvars);
|
||||||
|
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
if (rc)
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("referenced filter '%s' is missing"),
|
||||||
|
inc->filterref);
|
||||||
|
rc = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
virNWFilterDetermineMissingVarsRec(virConnectPtr conn,
|
||||||
|
virNWFilterDefPtr filter,
|
||||||
|
virNWFilterHashTablePtr vars,
|
||||||
|
virNWFilterHashTablePtr missing_vars,
|
||||||
|
int useNewFilter,
|
||||||
|
virNWFilterDriverStatePtr driver)
|
||||||
|
{
|
||||||
|
virNWFilterPoolObjPtr obj;
|
||||||
|
int rc = 0;
|
||||||
|
int i, j;
|
||||||
|
virNWFilterDefPtr next_filter;
|
||||||
|
|
||||||
|
for (i = 0; i < filter->nentries; i++) {
|
||||||
|
virNWFilterRuleDefPtr rule = filter->filterEntries[i]->rule;
|
||||||
|
virNWFilterIncludeDefPtr inc = filter->filterEntries[i]->include;
|
||||||
|
if (rule) {
|
||||||
|
// check all variables of this rule
|
||||||
|
for (j = 0; j < rule->nvars; j++) {
|
||||||
|
if (!virHashLookup(vars->hashTable, rule->vars[j])) {
|
||||||
|
virNWFilterHashTablePut(missing_vars, rule->vars[j],
|
||||||
|
strdup("1"), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (inc) {
|
||||||
|
VIR_DEBUG("Following filter %s\n", inc->filterref);
|
||||||
|
obj = virNWFilterPoolObjFindByName(&driver->pools,
|
||||||
|
inc->filterref);
|
||||||
|
if (obj) {
|
||||||
|
|
||||||
|
if (obj->wantRemoved) {
|
||||||
|
virNWFilterReportError(VIR_ERR_NO_NWFILTER,
|
||||||
|
_("Filter '%s' is in use."),
|
||||||
|
inc->filterref);
|
||||||
|
rc = 1;
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// create a temporary hashmap for depth-first tree traversal
|
||||||
|
virNWFilterHashTablePtr tmpvars =
|
||||||
|
virNWFilterCreateVarsFrom(inc->params,
|
||||||
|
vars);
|
||||||
|
if (!tmpvars) {
|
||||||
|
virReportOOMError();
|
||||||
|
rc = 1;
|
||||||
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next_filter = obj->def;
|
||||||
|
|
||||||
|
switch (useNewFilter) {
|
||||||
|
case INSTANTIATE_FOLLOW_NEWFILTER:
|
||||||
|
if (obj->newDef) {
|
||||||
|
next_filter = obj->newDef;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INSTANTIATE_ALWAYS:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = virNWFilterDetermineMissingVarsRec(conn,
|
||||||
|
next_filter,
|
||||||
|
tmpvars,
|
||||||
|
missing_vars,
|
||||||
|
useNewFilter,
|
||||||
|
driver);
|
||||||
|
|
||||||
virNWFilterHashTableFree(tmpvars);
|
virNWFilterHashTableFree(tmpvars);
|
||||||
|
|
||||||
@ -429,9 +539,12 @@ virNWFilterInstantiate(virConnectPtr conn,
|
|||||||
enum virDomainNetType nettype,
|
enum virDomainNetType nettype,
|
||||||
virNWFilterDefPtr filter,
|
virNWFilterDefPtr filter,
|
||||||
const char *ifname,
|
const char *ifname,
|
||||||
|
const char *linkdev,
|
||||||
virNWFilterHashTablePtr vars,
|
virNWFilterHashTablePtr vars,
|
||||||
enum instCase useNewFilter, int *foundNewFilter,
|
enum instCase useNewFilter, int *foundNewFilter,
|
||||||
bool teardownOld)
|
bool teardownOld,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
virNWFilterDriverStatePtr driver)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
int j, nptrs;
|
int j, nptrs;
|
||||||
@ -440,6 +553,44 @@ virNWFilterInstantiate(virConnectPtr conn,
|
|||||||
void **ptrs = NULL;
|
void **ptrs = NULL;
|
||||||
int instantiate = 1;
|
int instantiate = 1;
|
||||||
|
|
||||||
|
virNWFilterLockFilterUpdates();
|
||||||
|
|
||||||
|
virNWFilterHashTablePtr missing_vars = virNWFilterHashTableCreate(0);
|
||||||
|
if (!missing_vars) {
|
||||||
|
virReportOOMError();
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = virNWFilterDetermineMissingVarsRec(conn,
|
||||||
|
filter,
|
||||||
|
vars,
|
||||||
|
missing_vars,
|
||||||
|
useNewFilter,
|
||||||
|
driver);
|
||||||
|
if (rc)
|
||||||
|
goto err_exit;
|
||||||
|
|
||||||
|
if (virHashSize(missing_vars->hashTable) == 1) {
|
||||||
|
if (virHashLookup(missing_vars->hashTable,
|
||||||
|
NWFILTER_STD_VAR_IP) != NULL) {
|
||||||
|
if (virNWFilterLookupLearnReq(ifname) == NULL) {
|
||||||
|
rc = virNWFilterLearnIPAddress(ifname,
|
||||||
|
linkdev,
|
||||||
|
nettype, macaddr,
|
||||||
|
filter->name,
|
||||||
|
vars, driver,
|
||||||
|
DETECT_DHCP|DETECT_STATIC);
|
||||||
|
}
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
} else if (virHashSize(missing_vars->hashTable) > 1) {
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
rc = _virNWFilterInstantiateRec(conn,
|
rc = _virNWFilterInstantiateRec(conn,
|
||||||
techdriver,
|
techdriver,
|
||||||
nettype,
|
nettype,
|
||||||
@ -447,7 +598,8 @@ virNWFilterInstantiate(virConnectPtr conn,
|
|||||||
ifname,
|
ifname,
|
||||||
vars,
|
vars,
|
||||||
&nEntries, &insts,
|
&nEntries, &insts,
|
||||||
useNewFilter, foundNewFilter);
|
useNewFilter, foundNewFilter,
|
||||||
|
driver);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
@ -478,24 +630,33 @@ virNWFilterInstantiate(virConnectPtr conn,
|
|||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
|
|
||||||
|
virNWFilterUnlockFilterUpdates();
|
||||||
|
|
||||||
for (j = 0; j < nEntries; j++)
|
for (j = 0; j < nEntries; j++)
|
||||||
virNWFilterRuleInstFree(insts[j]);
|
virNWFilterRuleInstFree(insts[j]);
|
||||||
|
|
||||||
VIR_FREE(insts);
|
VIR_FREE(insts);
|
||||||
|
|
||||||
|
virNWFilterHashTableFree(missing_vars);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_virNWFilterInstantiateFilter(virConnectPtr conn,
|
__virNWFilterInstantiateFilter(virConnectPtr conn,
|
||||||
const virDomainNetDefPtr net,
|
bool teardownOld,
|
||||||
bool teardownOld,
|
const char *ifname,
|
||||||
enum instCase useNewFilter)
|
const char *linkdev,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *filtername,
|
||||||
|
virNWFilterHashTablePtr filterparams,
|
||||||
|
enum instCase useNewFilter,
|
||||||
|
virNWFilterDriverStatePtr driver)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
const char *drvname = EBIPTABLES_DRIVER_ID;
|
const char *drvname = EBIPTABLES_DRIVER_ID;
|
||||||
virNWFilterDriverStatePtr driver = conn->nwfilterPrivateData;
|
|
||||||
virNWFilterTechDriverPtr techdriver;
|
virNWFilterTechDriverPtr techdriver;
|
||||||
virNWFilterPoolObjPtr obj;
|
virNWFilterPoolObjPtr obj;
|
||||||
virNWFilterHashTablePtr vars, vars1;
|
virNWFilterHashTablePtr vars, vars1;
|
||||||
@ -503,6 +664,8 @@ _virNWFilterInstantiateFilter(virConnectPtr conn,
|
|||||||
char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
|
char vmmacaddr[VIR_MAC_STRING_BUFLEN] = {0};
|
||||||
int foundNewFilter = 0;
|
int foundNewFilter = 0;
|
||||||
char *str_macaddr = NULL;
|
char *str_macaddr = NULL;
|
||||||
|
const char *ipaddr;
|
||||||
|
char *str_ipaddr = NULL;
|
||||||
|
|
||||||
techdriver = virNWFilterTechDriverForName(drvname);
|
techdriver = virNWFilterTechDriverForName(drvname);
|
||||||
|
|
||||||
@ -514,25 +677,25 @@ _virNWFilterInstantiateFilter(virConnectPtr conn,
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VIR_DEBUG("filter name: %s", net->filter);
|
VIR_DEBUG("filter name: %s", filtername);
|
||||||
|
|
||||||
obj = virNWFilterPoolObjFindByName(&driver->pools, net->filter);
|
obj = virNWFilterPoolObjFindByName(&driver->pools, filtername);
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
virNWFilterReportError(VIR_ERR_NO_NWFILTER,
|
virNWFilterReportError(VIR_ERR_NO_NWFILTER,
|
||||||
_("Could not find filter '%s'"),
|
_("Could not find filter '%s'"),
|
||||||
net->filter);
|
filtername);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj->wantRemoved) {
|
if (obj->wantRemoved) {
|
||||||
virNWFilterReportError(VIR_ERR_NO_NWFILTER,
|
virNWFilterReportError(VIR_ERR_NO_NWFILTER,
|
||||||
_("Filter '%s' is in use."),
|
_("Filter '%s' is in use."),
|
||||||
net->filter);
|
filtername);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
virFormatMacAddr(net->mac, vmmacaddr);
|
virFormatMacAddr(macaddr, vmmacaddr);
|
||||||
str_macaddr = strdup(vmmacaddr);
|
str_macaddr = strdup(vmmacaddr);
|
||||||
if (!str_macaddr) {
|
if (!str_macaddr) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
@ -540,16 +703,27 @@ _virNWFilterInstantiateFilter(virConnectPtr conn,
|
|||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
vars1 = virNWFilterCreateVarHashmap(str_macaddr);
|
ipaddr = virNWFilterGetIpAddrForIfname(ifname);
|
||||||
|
if (ipaddr) {
|
||||||
|
str_ipaddr = strdup(ipaddr);
|
||||||
|
if (!str_ipaddr) {
|
||||||
|
virReportOOMError();
|
||||||
|
rc = 1;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vars1 = virNWFilterCreateVarHashmap(str_macaddr, str_ipaddr);
|
||||||
if (!vars1) {
|
if (!vars1) {
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto err_exit;
|
goto err_exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
str_macaddr = NULL;
|
str_macaddr = NULL;
|
||||||
|
str_ipaddr = NULL;
|
||||||
|
|
||||||
vars = virNWFilterCreateVarsFrom(vars1,
|
vars = virNWFilterCreateVarsFrom(vars1,
|
||||||
net->filterparams);
|
filterparams);
|
||||||
if (!vars) {
|
if (!vars) {
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto err_exit_vars1;
|
goto err_exit_vars1;
|
||||||
@ -571,12 +745,15 @@ _virNWFilterInstantiateFilter(virConnectPtr conn,
|
|||||||
|
|
||||||
rc = virNWFilterInstantiate(conn,
|
rc = virNWFilterInstantiate(conn,
|
||||||
techdriver,
|
techdriver,
|
||||||
net->type,
|
nettype,
|
||||||
filter,
|
filter,
|
||||||
net->ifname,
|
ifname,
|
||||||
|
linkdev,
|
||||||
vars,
|
vars,
|
||||||
useNewFilter, &foundNewFilter,
|
useNewFilter, &foundNewFilter,
|
||||||
teardownOld);
|
teardownOld,
|
||||||
|
macaddr,
|
||||||
|
driver);
|
||||||
|
|
||||||
virNWFilterHashTableFree(vars);
|
virNWFilterHashTableFree(vars);
|
||||||
|
|
||||||
@ -584,15 +761,180 @@ err_exit_vars1:
|
|||||||
virNWFilterHashTableFree(vars1);
|
virNWFilterHashTableFree(vars1);
|
||||||
|
|
||||||
err_exit:
|
err_exit:
|
||||||
|
|
||||||
virNWFilterPoolObjUnlock(obj);
|
virNWFilterPoolObjUnlock(obj);
|
||||||
|
|
||||||
|
VIR_FREE(str_ipaddr);
|
||||||
VIR_FREE(str_macaddr);
|
VIR_FREE(str_macaddr);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_virNWFilterInstantiateFilter(virConnectPtr conn,
|
||||||
|
const virDomainNetDefPtr net,
|
||||||
|
bool teardownOld,
|
||||||
|
enum instCase useNewFilter)
|
||||||
|
{
|
||||||
|
const char *linkdev = (net->type == VIR_DOMAIN_NET_TYPE_DIRECT)
|
||||||
|
? net->data.direct.linkdev
|
||||||
|
: NULL;
|
||||||
|
return __virNWFilterInstantiateFilter(conn,
|
||||||
|
teardownOld,
|
||||||
|
net->ifname,
|
||||||
|
linkdev,
|
||||||
|
net->type,
|
||||||
|
net->mac,
|
||||||
|
net->filter,
|
||||||
|
net->filterparams,
|
||||||
|
useNewFilter,
|
||||||
|
conn->nwfilterPrivateData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: move chgIfFlags, ifUp, checkIf into common file & share w/ macvtap.c
|
||||||
|
|
||||||
|
/*
|
||||||
|
* chgIfFlags: Change flags on an interface
|
||||||
|
* @ifname : name of the interface
|
||||||
|
* @flagclear : the flags to clear
|
||||||
|
* @flagset : the flags to set
|
||||||
|
*
|
||||||
|
* The new flags of the interface will be calculated as
|
||||||
|
* flagmask = (~0 ^ flagclear)
|
||||||
|
* newflags = (curflags & flagmask) | flagset;
|
||||||
|
*
|
||||||
|
* Returns 0 on success, errno on failure.
|
||||||
|
*/
|
||||||
|
static int chgIfFlags(const char *ifname, short flagclear, short flagset) {
|
||||||
|
struct ifreq ifr;
|
||||||
|
int rc = 0;
|
||||||
|
int flags;
|
||||||
|
short flagmask = (~0 ^ flagclear);
|
||||||
|
int fd = socket(PF_PACKET, SOCK_DGRAM, 0);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
if (virStrncpy(ifr.ifr_name,
|
||||||
|
ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) {
|
||||||
|
rc = ENODEV;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||||
|
rc = errno;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = (ifr.ifr_flags & flagmask) | flagset;
|
||||||
|
|
||||||
|
if (ifr.ifr_flags != flags) {
|
||||||
|
ifr.ifr_flags = flags;
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0)
|
||||||
|
rc = errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
close(fd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ifUp
|
||||||
|
* @name: name of the interface
|
||||||
|
* @up: 1 for up, 0 for down
|
||||||
|
*
|
||||||
|
* Function to control if an interface is activated (up, 1) or not (down, 0)
|
||||||
|
*
|
||||||
|
* Returns 0 in case of success or an errno code in case of failure.
|
||||||
|
*/
|
||||||
|
static int
|
||||||
|
ifUp(const char *name, int up)
|
||||||
|
{
|
||||||
|
return chgIfFlags(name,
|
||||||
|
(up) ? 0 : IFF_UP,
|
||||||
|
(up) ? IFF_UP : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkIf
|
||||||
|
*
|
||||||
|
* @ifname: Name of the interface
|
||||||
|
* @macaddr: expected MAC address of the interface
|
||||||
|
*
|
||||||
|
* FIXME: the interface's index is another good parameter to check
|
||||||
|
*
|
||||||
|
* Determine whether a given interface is still available. If so,
|
||||||
|
* it must have the given MAC address.
|
||||||
|
*
|
||||||
|
* Returns an error code ENODEV in case the interface does not exist
|
||||||
|
* anymore or its MAC address is different, 0 otherwise.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
checkIf(const char *ifname, const unsigned char *macaddr)
|
||||||
|
{
|
||||||
|
struct ifreq ifr;
|
||||||
|
int fd = socket(PF_PACKET, SOCK_DGRAM, 0);
|
||||||
|
int rc = 0;
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
if (virStrncpy(ifr.ifr_name,
|
||||||
|
ifname, strlen(ifname), sizeof(ifr.ifr_name)) == NULL) {
|
||||||
|
rc = ENODEV;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
||||||
|
rc = errno;
|
||||||
|
goto err_exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(&ifr.ifr_hwaddr.sa_data, macaddr, 6) != 0)
|
||||||
|
rc = ENODEV;
|
||||||
|
|
||||||
|
err_exit:
|
||||||
|
close(fd);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterInstantiateFilterLate(virConnectPtr conn,
|
||||||
|
const char *ifname,
|
||||||
|
const char *linkdev,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *filtername,
|
||||||
|
virNWFilterHashTablePtr filterparams,
|
||||||
|
virNWFilterDriverStatePtr driver)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
rc = __virNWFilterInstantiateFilter(conn,
|
||||||
|
1,
|
||||||
|
ifname,
|
||||||
|
linkdev,
|
||||||
|
nettype,
|
||||||
|
macaddr,
|
||||||
|
filtername,
|
||||||
|
filterparams,
|
||||||
|
INSTANTIATE_ALWAYS,
|
||||||
|
driver);
|
||||||
|
if (rc) {
|
||||||
|
//something went wrong... 'DOWN' the interface
|
||||||
|
if (ifUp(ifname ,0)) {
|
||||||
|
// assuming interface disappeared...
|
||||||
|
_virNWFilterTeardownFilter(ifname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
virNWFilterInstantiateFilter(virConnectPtr conn,
|
virNWFilterInstantiateFilter(virConnectPtr conn,
|
||||||
const virDomainNetDefPtr net)
|
const virDomainNetDefPtr net)
|
||||||
@ -649,8 +991,8 @@ virNWFilterTearOldFilter(virConnectPtr conn,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
static int
|
||||||
virNWFilterTeardownFilter(const virDomainNetDefPtr net)
|
_virNWFilterTeardownFilter(const char *ifname)
|
||||||
{
|
{
|
||||||
const char *drvname = EBIPTABLES_DRIVER_ID;
|
const char *drvname = EBIPTABLES_DRIVER_ID;
|
||||||
virNWFilterTechDriverPtr techdriver;
|
virNWFilterTechDriverPtr techdriver;
|
||||||
@ -663,13 +1005,21 @@ virNWFilterTeardownFilter(const virDomainNetDefPtr net)
|
|||||||
drvname);
|
drvname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
techdriver->allTeardown(ifname);
|
||||||
|
|
||||||
techdriver->allTeardown(net->ifname);
|
virNWFilterDelIpAddrForIfname(ifname);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterTeardownFilter(const virDomainNetDefPtr net)
|
||||||
|
{
|
||||||
|
return _virNWFilterTeardownFilter(net->ifname);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
virNWFilterDomainFWUpdateCB(void *payload,
|
virNWFilterDomainFWUpdateCB(void *payload,
|
||||||
const char *name ATTRIBUTE_UNUSED,
|
const char *name ATTRIBUTE_UNUSED,
|
||||||
|
@ -45,12 +45,24 @@ int virNWFilterRollbackUpdateFilter(virConnectPtr conn,
|
|||||||
int virNWFilterTearOldFilter(virConnectPtr conn,
|
int virNWFilterTearOldFilter(virConnectPtr conn,
|
||||||
const virDomainNetDefPtr net);
|
const virDomainNetDefPtr net);
|
||||||
|
|
||||||
|
int virNWFilterInstantiateFilterLate(virConnectPtr conn,
|
||||||
|
const char *ifname,
|
||||||
|
const char *linkdev,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *filtername,
|
||||||
|
virNWFilterHashTablePtr filterparams,
|
||||||
|
virNWFilterDriverStatePtr driver);
|
||||||
|
|
||||||
int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
|
int virNWFilterTeardownFilter(const virDomainNetDefPtr net);
|
||||||
|
|
||||||
virNWFilterHashTablePtr virNWFilterCreateVarHashmap(char *macaddr);
|
virNWFilterHashTablePtr virNWFilterCreateVarHashmap(char *macaddr,
|
||||||
|
char *ipaddr);
|
||||||
|
|
||||||
void virNWFilterDomainFWUpdateCB(void *payload,
|
void virNWFilterDomainFWUpdateCB(void *payload,
|
||||||
const char *name ATTRIBUTE_UNUSED,
|
const char *name ATTRIBUTE_UNUSED,
|
||||||
void *data);
|
void *data);
|
||||||
|
|
||||||
|
int checkIf(const char *ifname, const unsigned char *macaddr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
622
src/nwfilter/nwfilter_learnipaddr.c
Normal file
622
src/nwfilter/nwfilter_learnipaddr.c
Normal file
@ -0,0 +1,622 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_learnipaddr.c: support for learning IP address used by a VM
|
||||||
|
* on an interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 IBM Corp.
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <config.h>
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
# include <pcap.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <net/ethernet.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/udp.h>
|
||||||
|
#include <net/if_arp.h>
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
#include "buf.h"
|
||||||
|
#include "memory.h"
|
||||||
|
#include "logging.h"
|
||||||
|
#include "datatypes.h"
|
||||||
|
#include "virterror_internal.h"
|
||||||
|
#include "threads.h"
|
||||||
|
#include "conf/nwfilter_params.h"
|
||||||
|
#include "conf/domain_conf.h"
|
||||||
|
#include "nwfilter_gentech_driver.h"
|
||||||
|
#include "nwfilter_ebiptables_driver.h"
|
||||||
|
#include "nwfilter_learnipaddr.h"
|
||||||
|
|
||||||
|
#define VIR_FROM_THIS VIR_FROM_NWFILTER
|
||||||
|
|
||||||
|
|
||||||
|
/* structure of an ARP request/reply message */
|
||||||
|
struct f_arphdr {
|
||||||
|
struct arphdr arphdr;
|
||||||
|
uint8_t ar_sha[ETH_ALEN];
|
||||||
|
uint32_t ar_sip;
|
||||||
|
uint8_t ar_tha[ETH_ALEN];
|
||||||
|
uint32_t ar_tip;
|
||||||
|
} ATTRIBUTE_PACKED;
|
||||||
|
|
||||||
|
|
||||||
|
/* structure representing DHCP message */
|
||||||
|
struct dhcp {
|
||||||
|
uint8_t op;
|
||||||
|
uint8_t htype;
|
||||||
|
uint8_t hlen;
|
||||||
|
uint8_t hops;
|
||||||
|
uint32_t xid;
|
||||||
|
uint16_t secs;
|
||||||
|
uint16_t flags;
|
||||||
|
uint32_t ciaddr;
|
||||||
|
uint32_t yiaddr;
|
||||||
|
uint32_t siaddr;
|
||||||
|
uint32_t giaddr;
|
||||||
|
uint8_t chaddr[16];
|
||||||
|
/* omitted */
|
||||||
|
} ATTRIBUTE_PACKED;
|
||||||
|
|
||||||
|
|
||||||
|
struct ether_vlan_header
|
||||||
|
{
|
||||||
|
uint8_t dhost[ETH_ALEN];
|
||||||
|
uint8_t shost[ETH_ALEN];
|
||||||
|
uint16_t vlan_type;
|
||||||
|
uint16_t vlan_flags;
|
||||||
|
uint16_t ether_type;
|
||||||
|
} ATTRIBUTE_PACKED;
|
||||||
|
|
||||||
|
|
||||||
|
static virMutex pendingLearnReqLock;
|
||||||
|
static virHashTablePtr pendingLearnReq;
|
||||||
|
|
||||||
|
static virMutex ipAddressMapLock;
|
||||||
|
static virNWFilterHashTablePtr ipAddressMap;
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
virNWFilterIPAddrLearnReqFree(virNWFilterIPAddrLearnReqPtr req) {
|
||||||
|
if (!req)
|
||||||
|
return;
|
||||||
|
|
||||||
|
VIR_FREE(req->filtername);
|
||||||
|
virNWFilterHashTableFree(req->filterparams);
|
||||||
|
|
||||||
|
VIR_FREE(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if HAVE_LIBPCAP
|
||||||
|
|
||||||
|
static int
|
||||||
|
virNWFilterRegisterLearnReq(virNWFilterIPAddrLearnReqPtr req) {
|
||||||
|
int res = -1;
|
||||||
|
virMutexLock(&pendingLearnReqLock);
|
||||||
|
|
||||||
|
if (!virHashLookup(pendingLearnReq, req->ifname))
|
||||||
|
res = virHashAddEntry(pendingLearnReq, req->ifname, req);
|
||||||
|
|
||||||
|
virMutexUnlock(&pendingLearnReqLock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
virNWFilterIPAddrLearnReqPtr
|
||||||
|
virNWFilterLookupLearnReq(const char *ifname) {
|
||||||
|
void *res;
|
||||||
|
|
||||||
|
virMutexLock(&pendingLearnReqLock);
|
||||||
|
|
||||||
|
res = virHashLookup(pendingLearnReq, ifname);
|
||||||
|
|
||||||
|
virMutexUnlock(&pendingLearnReqLock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
freeLearnReqEntry(void *payload, const char *name ATTRIBUTE_UNUSED) {
|
||||||
|
virNWFilterIPAddrLearnReqFree(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
|
||||||
|
static virNWFilterIPAddrLearnReqPtr
|
||||||
|
virNWFilterDeregisterLearnReq(const char *ifname) {
|
||||||
|
virNWFilterIPAddrLearnReqPtr res;
|
||||||
|
|
||||||
|
virMutexLock(&pendingLearnReqLock);
|
||||||
|
|
||||||
|
res = virHashLookup(pendingLearnReq, ifname);
|
||||||
|
|
||||||
|
if (res)
|
||||||
|
virHashRemoveEntry(pendingLearnReq, ifname, NULL);
|
||||||
|
|
||||||
|
virMutexUnlock(&pendingLearnReqLock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
virNWFilterAddIpAddrForIfname(const char *ifname, char *addr) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
virMutexLock(&ipAddressMapLock);
|
||||||
|
|
||||||
|
ret = virNWFilterHashTablePut(ipAddressMap, ifname, addr, 1);
|
||||||
|
|
||||||
|
virMutexUnlock(&ipAddressMapLock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
virNWFilterDelIpAddrForIfname(const char *ifname) {
|
||||||
|
|
||||||
|
virMutexLock(&ipAddressMapLock);
|
||||||
|
|
||||||
|
if (virHashLookup(ipAddressMap->hashTable, ifname))
|
||||||
|
virNWFilterHashTableRemoveEntry(ipAddressMap, ifname);
|
||||||
|
|
||||||
|
virMutexUnlock(&ipAddressMapLock);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const char *
|
||||||
|
virNWFilterGetIpAddrForIfname(const char *ifname) {
|
||||||
|
const char *res;
|
||||||
|
|
||||||
|
virMutexLock(&ipAddressMapLock);
|
||||||
|
|
||||||
|
res = virHashLookup(ipAddressMap->hashTable, ifname);
|
||||||
|
|
||||||
|
virMutexUnlock(&ipAddressMapLock);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBPCAP
|
||||||
|
|
||||||
|
/**
|
||||||
|
* learnIPAddressThread
|
||||||
|
* arg: pointer to virNWFilterIPAddrLearnReq structure
|
||||||
|
*
|
||||||
|
* Learn the IP address being used on an interface. Use ARP Request and
|
||||||
|
* Reply messages, DHCP offers and the first IP packet being sent from
|
||||||
|
* the VM to detect the IP address it is using. Detects only one IP address
|
||||||
|
* per interface (IP aliasing not supported). The method on how the
|
||||||
|
* IP address is detected can be chosen through flags. DETECT_DHCP will
|
||||||
|
* require that the IP address is detected from a DHCP OFFER, DETECT_STATIC
|
||||||
|
* will require that the IP address was taken from an ARP packet or an IPv4
|
||||||
|
* packet. Both flags can be set at the same time.
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
learnIPAddressThread(void *arg)
|
||||||
|
{
|
||||||
|
char errbuf[PCAP_ERRBUF_SIZE] = {0};
|
||||||
|
pcap_t *handle;
|
||||||
|
struct bpf_program fp;
|
||||||
|
struct pcap_pkthdr header;
|
||||||
|
const u_char *packet;
|
||||||
|
struct ether_header *ether_hdr;
|
||||||
|
struct ether_vlan_header *vlan_hdr;
|
||||||
|
virNWFilterIPAddrLearnReqPtr req = arg;
|
||||||
|
uint32_t vmaddr = 0;
|
||||||
|
unsigned int ethHdrSize;
|
||||||
|
char *listen_if = (strlen(req->linkdev) != 0) ? req->linkdev
|
||||||
|
: req->ifname;
|
||||||
|
int to_ms = (strlen(req->linkdev) != 0) ? 1000
|
||||||
|
: 0;
|
||||||
|
char macaddr[VIR_MAC_STRING_BUFLEN];
|
||||||
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
char *filter= NULL;
|
||||||
|
uint16_t etherType;
|
||||||
|
enum howDetect howDetected = 0;
|
||||||
|
|
||||||
|
req->status = 0;
|
||||||
|
|
||||||
|
handle = pcap_open_live(listen_if, BUFSIZ, 0, to_ms, errbuf);
|
||||||
|
|
||||||
|
if (handle == NULL) {
|
||||||
|
VIR_DEBUG("Couldn't open device %s: %s\n", listen_if, errbuf);
|
||||||
|
req->status = ENODEV;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
virFormatMacAddr(req->macaddr, macaddr);
|
||||||
|
|
||||||
|
switch (req->howDetect) {
|
||||||
|
case DETECT_DHCP:
|
||||||
|
virBufferVSprintf(&buf, " ether dst %s"
|
||||||
|
" and src port 67 and dst port 68",
|
||||||
|
macaddr);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
virBufferVSprintf(&buf, "ether host %s", macaddr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virBufferError(&buf)) {
|
||||||
|
req->status = ENOMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = virBufferContentAndReset(&buf);
|
||||||
|
|
||||||
|
if (pcap_compile(handle, &fp, filter, 1, 0) != 0 ||
|
||||||
|
pcap_setfilter(handle, &fp) != 0) {
|
||||||
|
VIR_DEBUG("Couldn't compile or set filter '%s'.\n", filter);
|
||||||
|
req->status = EINVAL;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (req->status == 0 && vmaddr == 0) {
|
||||||
|
packet = pcap_next(handle, &header);
|
||||||
|
|
||||||
|
if (!packet) {
|
||||||
|
if (to_ms == 0) {
|
||||||
|
/* assuming IF disappeared */
|
||||||
|
req->status = ENODEV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* listening on linkdev, check whether VM's dev is still there */
|
||||||
|
if (checkIf(req->ifname, req->macaddr)) {
|
||||||
|
req->status = ENODEV;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header.len >= sizeof(struct ether_header)) {
|
||||||
|
ether_hdr = (struct ether_header*)packet;
|
||||||
|
|
||||||
|
switch (ntohs(ether_hdr->ether_type)) {
|
||||||
|
|
||||||
|
case ETHERTYPE_IP:
|
||||||
|
ethHdrSize = sizeof(struct ether_header);
|
||||||
|
etherType = ntohs(ether_hdr->ether_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ETHERTYPE_VLAN:
|
||||||
|
ethHdrSize = sizeof(struct ether_vlan_header);
|
||||||
|
vlan_hdr = (struct ether_vlan_header *)packet;
|
||||||
|
if (ntohs(vlan_hdr->ether_type) != ETHERTYPE_IP ||
|
||||||
|
header.len < ethHdrSize)
|
||||||
|
continue;
|
||||||
|
etherType = ntohs(vlan_hdr->ether_type);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(ether_hdr->ether_shost,
|
||||||
|
req->macaddr,
|
||||||
|
VIR_MAC_BUFLEN) == 0) {
|
||||||
|
// packets from the VM
|
||||||
|
|
||||||
|
if (etherType == ETHERTYPE_IP &&
|
||||||
|
(header.len >= ethHdrSize +
|
||||||
|
sizeof(struct iphdr))) {
|
||||||
|
struct iphdr *iphdr = (struct iphdr*)(packet +
|
||||||
|
ethHdrSize);
|
||||||
|
vmaddr = iphdr->saddr;
|
||||||
|
// skip eth. bcast and mcast addresses,
|
||||||
|
// and zero address in DHCP Requests
|
||||||
|
if ((ntohl(vmaddr) & 0xc0000000) || vmaddr == 0) {
|
||||||
|
vmaddr = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
howDetected = DETECT_STATIC;
|
||||||
|
} else if (etherType == ETHERTYPE_ARP &&
|
||||||
|
(header.len >= ethHdrSize +
|
||||||
|
sizeof(struct f_arphdr))) {
|
||||||
|
struct f_arphdr *arphdr = (struct f_arphdr*)(packet +
|
||||||
|
ethHdrSize);
|
||||||
|
switch (ntohs(arphdr->arphdr.ar_op)) {
|
||||||
|
case ARPOP_REPLY:
|
||||||
|
vmaddr = arphdr->ar_sip;
|
||||||
|
howDetected = DETECT_STATIC;
|
||||||
|
break;
|
||||||
|
case ARPOP_REQUEST:
|
||||||
|
vmaddr = arphdr->ar_tip;
|
||||||
|
howDetected = DETECT_STATIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (memcmp(ether_hdr->ether_dhost,
|
||||||
|
req->macaddr,
|
||||||
|
VIR_MAC_BUFLEN) == 0) {
|
||||||
|
// packets to the VM
|
||||||
|
if (etherType == ETHERTYPE_IP &&
|
||||||
|
(header.len >= ethHdrSize +
|
||||||
|
sizeof(struct iphdr))) {
|
||||||
|
struct iphdr *iphdr = (struct iphdr*)(packet +
|
||||||
|
ethHdrSize);
|
||||||
|
if ((iphdr->protocol == IPPROTO_UDP) &&
|
||||||
|
(header.len >= ethHdrSize +
|
||||||
|
iphdr->ihl * 4 +
|
||||||
|
sizeof(struct udphdr))) {
|
||||||
|
struct udphdr *udphdr= (struct udphdr *)
|
||||||
|
((char *)iphdr + iphdr->ihl * 4);
|
||||||
|
if (ntohs(udphdr->source) == 67 &&
|
||||||
|
ntohs(udphdr->dest) == 68 &&
|
||||||
|
header.len >= ethHdrSize +
|
||||||
|
iphdr->ihl * 4 +
|
||||||
|
sizeof(struct udphdr) +
|
||||||
|
sizeof(struct dhcp)) {
|
||||||
|
struct dhcp *dhcp = (struct dhcp *)
|
||||||
|
((char *)udphdr + sizeof(udphdr));
|
||||||
|
if (dhcp->op == 2 /* DHCP OFFER */ &&
|
||||||
|
!memcmp(&dhcp->chaddr[0],
|
||||||
|
req->macaddr,
|
||||||
|
6)) {
|
||||||
|
vmaddr = dhcp->yiaddr;
|
||||||
|
howDetected = DETECT_DHCP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (vmaddr && (req->howDetect & howDetected) == 0) {
|
||||||
|
vmaddr = 0;
|
||||||
|
howDetected = 0;
|
||||||
|
}
|
||||||
|
} /* while */
|
||||||
|
|
||||||
|
done:
|
||||||
|
VIR_FREE(filter);
|
||||||
|
|
||||||
|
if (handle)
|
||||||
|
pcap_close(handle);
|
||||||
|
|
||||||
|
ebtablesRemoveBasicRules(req->ifname);
|
||||||
|
|
||||||
|
if (req->status == 0) {
|
||||||
|
int ret;
|
||||||
|
char inetaddr[INET_ADDRSTRLEN];
|
||||||
|
inet_ntop(AF_INET, &vmaddr, inetaddr, sizeof(inetaddr));
|
||||||
|
|
||||||
|
virNWFilterAddIpAddrForIfname(req->ifname, strdup(inetaddr));
|
||||||
|
|
||||||
|
ret = virNWFilterInstantiateFilterLate(NULL,
|
||||||
|
req->ifname,
|
||||||
|
req->linkdev,
|
||||||
|
req->nettype,
|
||||||
|
req->macaddr,
|
||||||
|
req->filtername,
|
||||||
|
req->filterparams,
|
||||||
|
req->driver);
|
||||||
|
VIR_DEBUG("Result from applying firewall rules on "
|
||||||
|
"%s with IP addr %s : %d\n", req->ifname, inetaddr, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&req->thread, 0x0, sizeof(req->thread));
|
||||||
|
|
||||||
|
VIR_DEBUG("pcap thread terminating for interface %s\n",req->ifname);
|
||||||
|
|
||||||
|
virNWFilterDeregisterLearnReq(req->ifname);
|
||||||
|
|
||||||
|
virNWFilterIPAddrLearnReqFree(req);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterLearnIPAddress
|
||||||
|
* @conn: pointer to virConnect object
|
||||||
|
* @ifname: the name of the interface
|
||||||
|
* @linkdev : the name of the link device; currently only used in case of a
|
||||||
|
* macvtap device
|
||||||
|
* @nettype : the type of interface
|
||||||
|
* @macaddr : the MAC address of the interface
|
||||||
|
* @filtername : the name of the top-level filter to apply to the interface
|
||||||
|
* once its IP address has been detected
|
||||||
|
* @driver : the network filter driver
|
||||||
|
* @howDetect : the method on how the thread is supposed to detect the
|
||||||
|
* IP address; must choose any of the available flags
|
||||||
|
*
|
||||||
|
* Instruct to learn the IP address being used on a given interface (ifname).
|
||||||
|
* Unless there already is a thread attempting to learn the IP address
|
||||||
|
* being used on the interface, a thread is started that will listen on
|
||||||
|
* the traffic being sent on the interface (or link device) with the
|
||||||
|
* MAC address that is provided. Will then launch the application of the
|
||||||
|
* firewall rules on the interface.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virNWFilterLearnIPAddress(const char *ifname,
|
||||||
|
const char *linkdev,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *filtername,
|
||||||
|
virNWFilterHashTablePtr filterparams,
|
||||||
|
virNWFilterDriverStatePtr driver,
|
||||||
|
enum howDetect howDetect) {
|
||||||
|
int rc;
|
||||||
|
virNWFilterIPAddrLearnReqPtr req = NULL;
|
||||||
|
virNWFilterHashTablePtr ht = NULL;
|
||||||
|
|
||||||
|
if (howDetect == 0)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (VIR_ALLOC(req) < 0) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto err_no_req;
|
||||||
|
}
|
||||||
|
|
||||||
|
ht = virNWFilterHashTableCreate(0);
|
||||||
|
if (ht == NULL) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto err_no_ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virNWFilterHashTablePutAll(filterparams, ht))
|
||||||
|
goto err_free_ht;
|
||||||
|
|
||||||
|
req->filtername = strdup(filtername);
|
||||||
|
if (req->filtername == NULL) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto err_free_ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virStrcpyStatic(req->ifname, ifname) == NULL) {
|
||||||
|
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Destination buffer for ifname ('%s') "
|
||||||
|
"not large enough"), ifname);
|
||||||
|
goto err_free_ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (linkdev) {
|
||||||
|
if (virStrcpyStatic(req->linkdev, linkdev) == NULL) {
|
||||||
|
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("Destination buffer for linkdev ('%s') "
|
||||||
|
"not large enough"), linkdev);
|
||||||
|
goto err_free_ht;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
req->nettype = nettype;
|
||||||
|
memcpy(req->macaddr, macaddr, sizeof(req->macaddr));
|
||||||
|
req->driver = driver;
|
||||||
|
req->filterparams = ht;
|
||||||
|
ht = NULL;
|
||||||
|
req->howDetect = howDetect;
|
||||||
|
|
||||||
|
rc = virNWFilterRegisterLearnReq(req);
|
||||||
|
|
||||||
|
if (rc)
|
||||||
|
goto err_free_ht;
|
||||||
|
|
||||||
|
switch (howDetect) {
|
||||||
|
case DETECT_DHCP:
|
||||||
|
if (ebtablesApplyDHCPOnlyRules(ifname,
|
||||||
|
macaddr,
|
||||||
|
NULL))
|
||||||
|
goto err_free_ht;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (ebtablesApplyBasicRules(ifname,
|
||||||
|
macaddr))
|
||||||
|
goto err_free_ht;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (pthread_create(&req->thread,
|
||||||
|
NULL,
|
||||||
|
learnIPAddressThread,
|
||||||
|
req) != 0)
|
||||||
|
goto err_remove_rules;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err_remove_rules:
|
||||||
|
ebtablesRemoveBasicRules(ifname);
|
||||||
|
err_free_ht:
|
||||||
|
virNWFilterHashTableFree(ht);
|
||||||
|
err_no_ht:
|
||||||
|
virNWFilterIPAddrLearnReqFree(req);
|
||||||
|
err_no_req:
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
int
|
||||||
|
virNWFilterLearnIPAddress(const char *ifname ATTRIBUTE_UNUSED,
|
||||||
|
const char *linkdev ATTRIBUTE_UNUSED,
|
||||||
|
enum virDomainNetType nettype ATTRIBUTE_UNUSED,
|
||||||
|
const unsigned char *macaddr ATTRIBUTE_UNUSED,
|
||||||
|
const char *filtername ATTRIBUTE_UNUSED,
|
||||||
|
virNWFilterHashTablePtr filterparams ATTRIBUTE_UNUSED,
|
||||||
|
virNWFilterDriverStatePtr driver ATTRIBUTE_UNUSED,
|
||||||
|
enum howDetect howDetect ATTRIBUTE_UNUSED) {
|
||||||
|
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
||||||
|
_("IP parameter must be given since libvirt "
|
||||||
|
"was not compiled with IP address learning "
|
||||||
|
"support"));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
#endif /* HAVE_LIBPCAP */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterLearnInit
|
||||||
|
* Initialization of this layer
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
virNWFilterLearnInit(void) {
|
||||||
|
pendingLearnReq = virHashCreate(0);
|
||||||
|
if (!pendingLearnReq) {
|
||||||
|
virReportOOMError();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virMutexInit(&pendingLearnReqLock)) {
|
||||||
|
virNWFilterLearnShutdown();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipAddressMap = virNWFilterHashTableCreate(0);
|
||||||
|
if (!ipAddressMap) {
|
||||||
|
virReportOOMError();
|
||||||
|
virNWFilterLearnShutdown();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (virMutexInit(&ipAddressMapLock)) {
|
||||||
|
virNWFilterLearnShutdown();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* virNWFilterLearnShutdown
|
||||||
|
* Shutdown of this layer
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
virNWFilterLearnShutdown(void) {
|
||||||
|
virHashFree(pendingLearnReq, freeLearnReqEntry);
|
||||||
|
pendingLearnReq = NULL;
|
||||||
|
|
||||||
|
virNWFilterHashTableFree(ipAddressMap);
|
||||||
|
ipAddressMap = NULL;
|
||||||
|
}
|
67
src/nwfilter/nwfilter_learnipaddr.h
Normal file
67
src/nwfilter/nwfilter_learnipaddr.h
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* nwfilter_learnipaddr.h: support for learning IP address used by a VM
|
||||||
|
* on an interface
|
||||||
|
*
|
||||||
|
* Copyright (C) 2010 IBM Corp.
|
||||||
|
* Copyright (C) 2010 Stefan Berger
|
||||||
|
*
|
||||||
|
* 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
|
||||||
|
* License along with this library; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
*
|
||||||
|
* Author: Stefan Berger <stefanb@us.ibm.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __NWFILTER_LEARNIPADDR_H
|
||||||
|
# define __NWFILTER_LEARNIPADDR_H
|
||||||
|
|
||||||
|
enum howDetect {
|
||||||
|
DETECT_DHCP = 1,
|
||||||
|
DETECT_STATIC = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _virNWFilterIPAddrLearnReq virNWFilterIPAddrLearnReq;
|
||||||
|
typedef virNWFilterIPAddrLearnReq *virNWFilterIPAddrLearnReqPtr;
|
||||||
|
struct _virNWFilterIPAddrLearnReq {
|
||||||
|
char ifname[IF_NAMESIZE];
|
||||||
|
char linkdev[IF_NAMESIZE];
|
||||||
|
enum virDomainNetType nettype;
|
||||||
|
unsigned char macaddr[VIR_MAC_BUFLEN];
|
||||||
|
char *filtername;
|
||||||
|
virNWFilterHashTablePtr filterparams;
|
||||||
|
virNWFilterDriverStatePtr driver;
|
||||||
|
enum howDetect howDetect;
|
||||||
|
|
||||||
|
int status;
|
||||||
|
pthread_t thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
int virNWFilterLearnIPAddress(const char *ifname,
|
||||||
|
const char *linkdev,
|
||||||
|
enum virDomainNetType nettype,
|
||||||
|
const unsigned char *macaddr,
|
||||||
|
const char *filtername,
|
||||||
|
virNWFilterHashTablePtr filterparams,
|
||||||
|
virNWFilterDriverStatePtr driver,
|
||||||
|
enum howDetect howDetect);
|
||||||
|
|
||||||
|
virNWFilterIPAddrLearnReqPtr virNWFilterLookupLearnReq(const char *ifname);
|
||||||
|
|
||||||
|
|
||||||
|
void virNWFilterDelIpAddrForIfname(const char *ifname);
|
||||||
|
const char *virNWFilterGetIpAddrForIfname(const char *ifname);
|
||||||
|
|
||||||
|
int virNWFilterLearnInit(void);
|
||||||
|
void virNWFilterLearnShutdown(void);
|
||||||
|
|
||||||
|
#endif /* __NWFILTER_LEARNIPADDR_H */
|
BIN
tests/nwfilterxml2xmltest
Executable file
BIN
tests/nwfilterxml2xmltest
Executable file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user