2
* nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
4
* Copyright (C) 2011 Red Hat, Inc.
5
* Copyright (C) 2010 IBM Corp.
6
* Copyright (C) 2010 Stefan Berger
8
* This library is free software; you can redistribute it and/or
9
* modify it under the terms of the GNU Lesser General Public
10
* License as published by the Free Software Foundation; either
11
* version 2.1 of the License, or (at your option) any later version.
13
* This library is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
* Lesser General Public License for more details.
18
* You should have received a copy of the GNU Lesser General Public
19
* License along with this library; if not, write to the Free Software
20
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
* Author: Stefan Berger <stefanb@us.ibm.com>
36
#include "virterror_internal.h"
37
#include "domain_conf.h"
38
#include "nwfilter_conf.h"
39
#include "nwfilter_gentech_driver.h"
40
#include "nwfilter_ebiptables_driver.h"
43
#include "configmake.h"
47
#define VIR_FROM_THIS VIR_FROM_NWFILTER
50
#define EBTABLES_CHAIN_INCOMING "PREROUTING"
51
#define EBTABLES_CHAIN_OUTGOING "POSTROUTING"
53
#define CHAINPREFIX_HOST_IN 'I'
54
#define CHAINPREFIX_HOST_OUT 'O'
55
#define CHAINPREFIX_HOST_IN_TEMP 'J'
56
#define CHAINPREFIX_HOST_OUT_TEMP 'P'
58
/* This file generates a temporary shell script. Since ebiptables is
59
Linux-specific, we can be reasonably certain that /bin/sh is more
60
or less POSIX-compliant, so we can use $() and $(()). However, we
61
cannot assume that /bin/sh is bash, so stick to POSIX syntax. */
63
#define CMD_SEPARATOR "\n"
64
#define CMD_DEF_PRE "cmd='"
65
#define CMD_DEF_POST "'"
66
#define CMD_DEF(X) CMD_DEF_PRE X CMD_DEF_POST
67
#define CMD_EXEC "eval res=\\$\\(\"${cmd} 2>&1\"\\)" CMD_SEPARATOR
68
#define CMD_STOPONERR(X) \
69
X ? "if [ $? -ne 0 ]; then" \
70
" echo \"Failure to execute command '${cmd}' : '${res}'.\";" \
76
#define PROC_BRIDGE_NF_CALL_IPTABLES \
77
"/proc/sys/net/bridge/bridge-nf-call-iptables"
78
#define PROC_BRIDGE_NF_CALL_IP6TABLES \
79
"/proc/sys/net/bridge/bridge-nf-call-ip6tables"
81
#define BRIDGE_NF_CALL_ALERT_INTERVAL 10 /* seconds */
83
static char *ebtables_cmd_path;
84
static char *iptables_cmd_path;
85
static char *ip6tables_cmd_path;
86
static char *grep_cmd_path;
87
static char *gawk_cmd_path;
89
#define PRINT_ROOT_CHAIN(buf, prefix, ifname) \
90
snprintf(buf, sizeof(buf), "libvirt-%c-%s", prefix, ifname)
91
#define PRINT_CHAIN(buf, prefix, ifname, suffix) \
92
snprintf(buf, sizeof(buf), "%c-%s-%s", prefix, ifname, suffix)
94
/* The collect_chains() script recursively determines all names
95
* of ebtables (nat) chains that are 'children' of a given 'root' chain.
96
* The typical output of an ebtables call is as follows:
98
* #> ebtables -t nat -L libvirt-I-tck-test205002
101
* Bridge chain: libvirt-I-tck-test205002, entries: 5, policy: ACCEPT
102
* -p IPv4 -j I-tck-test205002-ipv4
103
* -p ARP -j I-tck-test205002-arp
104
* -p 0x8035 -j I-tck-test205002-rarp
108
static const char ebtables_script_func_collect_chains[] =
111
" for tmp2 in $*; do\n"
112
" for tmp in $($EBT -t nat -L $tmp2 | \\\n"
113
" sed -n \"/Bridge chain/,\\$ s/.*-j \\\\([%s]-.*\\\\)/\\\\1/p\");\n"
116
" collect_chains $tmp\n"
121
static const char ebiptables_script_func_rm_chains[] =
124
" for tmp in $*; do $EBT -t nat -F $tmp; done\n"
125
" for tmp in $*; do $EBT -t nat -X $tmp; done\n"
128
static const char ebiptables_script_func_rename_chains[] =
131
" for tmp in $*; do\n"
133
" %c*) $EBT -t nat -E $tmp %c${tmp#?} ;;\n"
134
" %c*) $EBT -t nat -E $tmp %c${tmp#?} ;;\n"
139
static const char ebiptables_script_set_ifs[] =
143
#define NWFILTER_FUNC_COLLECT_CHAINS ebtables_script_func_collect_chains
144
#define NWFILTER_FUNC_RM_CHAINS ebiptables_script_func_rm_chains
145
#define NWFILTER_FUNC_RENAME_CHAINS ebiptables_script_func_rename_chains
146
#define NWFILTER_FUNC_SET_IFS ebiptables_script_set_ifs
148
#define NWFILTER_SET_EBTABLES_SHELLVAR(BUFPTR) \
149
virBufferAsprintf(BUFPTR, "EBT=%s\n", ebtables_cmd_path);
150
#define NWFILTER_SET_IPTABLES_SHELLVAR(BUFPTR) \
151
virBufferAsprintf(BUFPTR, "IPT=%s\n", iptables_cmd_path);
152
#define NWFILTER_SET_IP6TABLES_SHELLVAR(BUFPTR) \
153
virBufferAsprintf(BUFPTR, "IPT=%s\n", ip6tables_cmd_path);
155
#define VIRT_IN_CHAIN "libvirt-in"
156
#define VIRT_OUT_CHAIN "libvirt-out"
157
#define VIRT_IN_POST_CHAIN "libvirt-in-post"
158
#define HOST_IN_CHAIN "libvirt-host-in"
160
#define PRINT_IPT_ROOT_CHAIN(buf, prefix, ifname) \
161
snprintf(buf, sizeof(buf), "%c%c-%s", prefix[0], prefix[1], ifname)
163
#define PHYSDEV_IN "--physdev-in"
164
#define PHYSDEV_OUT "--physdev-out"
166
static const char *m_state_out_str = "-m state --state NEW,ESTABLISHED";
167
static const char *m_state_in_str = "-m state --state ESTABLISHED";
168
static const char *m_physdev_in_str = "-m physdev " PHYSDEV_IN;
169
static const char *m_physdev_out_str = "-m physdev " PHYSDEV_OUT;
171
#define MATCH_STATE_OUT m_state_out_str
172
#define MATCH_STATE_IN m_state_in_str
173
#define MATCH_PHYSDEV_IN m_physdev_in_str
174
#define MATCH_PHYSDEV_OUT m_physdev_out_str
176
#define COMMENT_VARNAME "comment"
178
static int ebtablesRemoveBasicRules(const char *ifname);
179
static int ebiptablesDriverInit(bool privileged);
180
static void ebiptablesDriverShutdown(void);
181
static int ebtablesCleanAll(const char *ifname);
182
static int ebiptablesAllTeardown(const char *ifname);
184
static virMutex execCLIMutex;
193
L3_PROTO_IPV4_IDX = 0,
203
#define USHORTMAP_ENTRY_IDX(IDX, ATT, VAL) [IDX] = { .attr = ATT, .val = VAL }
205
/* A lookup table for translating ethernet protocol IDs to human readable
206
* strings. None of the human readable strings must be found as a prefix
207
* in another entry here (example 'ab' would be found in 'abc') to allow
208
* for prefix matching.
210
static const struct ushort_map l3_protocols[] = {
211
USHORTMAP_ENTRY_IDX(L3_PROTO_IPV4_IDX, ETHERTYPE_IP , "ipv4"),
212
USHORTMAP_ENTRY_IDX(L3_PROTO_IPV6_IDX, ETHERTYPE_IPV6 , "ipv6"),
213
USHORTMAP_ENTRY_IDX(L3_PROTO_ARP_IDX , ETHERTYPE_ARP , "arp"),
214
USHORTMAP_ENTRY_IDX(L3_PROTO_RARP_IDX, ETHERTYPE_REVARP, "rarp"),
215
USHORTMAP_ENTRY_IDX(L2_PROTO_VLAN_IDX, ETHERTYPE_VLAN , "vlan"),
216
USHORTMAP_ENTRY_IDX(L2_PROTO_STP_IDX, 0 , "stp"),
217
USHORTMAP_ENTRY_IDX(L2_PROTO_MAC_IDX, 0 , "mac"),
218
USHORTMAP_ENTRY_IDX(L3_PROTO_LAST_IDX, 0 , NULL),
223
printVar(virNWFilterVarCombIterPtr vars,
224
char *buf, int bufsize,
230
if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
233
val = virNWFilterVarCombIterGetVarValue(vars, item->varAccess);
235
/* error has been reported */
239
if (!virStrcpy(buf, val, bufsize)) {
242
varName = virNWFilterVarAccessGetVarName(item->varAccess);
243
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
244
_("Buffer too small to print variable "
245
"'%s' into"), varName);
256
_printDataType(virNWFilterVarCombIterPtr vars,
257
char *buf, int bufsize,
264
if (printVar(vars, buf, bufsize, item, &done) < 0)
270
switch (item->datatype) {
271
case DATATYPE_IPADDR:
272
data = virSocketAddrFormat(&item->u.ipaddr);
275
if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
276
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
277
_("buffer too small for IP address"));
284
case DATATYPE_IPV6ADDR:
285
data = virSocketAddrFormat(&item->u.ipaddr);
289
if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
290
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
291
_("buffer too small for IPv6 address"));
298
case DATATYPE_MACADDR:
299
case DATATYPE_MACMASK:
300
if (bufsize < VIR_MAC_STRING_BUFLEN) {
301
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
302
_("Buffer too small for MAC address"));
306
virMacAddrFormat(item->u.macaddr.addr, buf);
309
case DATATYPE_IPV6MASK:
310
case DATATYPE_IPMASK:
311
if (snprintf(buf, bufsize, "%d",
312
item->u.u8) >= bufsize) {
313
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
314
_("Buffer too small for uint8 type"));
319
case DATATYPE_UINT32:
320
case DATATYPE_UINT32_HEX:
321
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%u",
322
item->u.u32) >= bufsize) {
323
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
324
_("Buffer too small for uint32 type"));
329
case DATATYPE_UINT16:
330
case DATATYPE_UINT16_HEX:
331
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
332
item->u.u16) >= bufsize) {
333
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
334
_("Buffer too small for uint16 type"));
340
case DATATYPE_UINT8_HEX:
341
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
342
item->u.u8) >= bufsize) {
343
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
344
_("Buffer too small for uint8 type"));
350
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
351
_("Unhandled datatype %x"), item->datatype);
361
printDataType(virNWFilterVarCombIterPtr vars,
362
char *buf, int bufsize,
365
return _printDataType(vars, buf, bufsize, item, 0);
370
printDataTypeAsHex(virNWFilterVarCombIterPtr vars,
371
char *buf, int bufsize,
374
return _printDataType(vars, buf, bufsize, item, 1);
379
printCommentVar(virBufferPtr dest, const char *buf)
381
size_t i, len = strlen(buf);
383
virBufferAddLit(dest, COMMENT_VARNAME "='");
385
if (len > IPTABLES_MAX_COMMENT_LENGTH)
386
len = IPTABLES_MAX_COMMENT_LENGTH;
388
for (i = 0; i < len; i++) {
390
virBufferAddLit(dest, "'\\''");
392
virBufferAddChar(dest, buf[i]);
394
virBufferAddLit(dest,"'" CMD_SEPARATOR);
399
ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
404
VIR_FREE(inst->commandTemplate);
410
ebiptablesAddRuleInst(virNWFilterRuleInstPtr res,
411
char *commandTemplate,
412
const char *neededChain,
413
virNWFilterChainPriority chainPriority,
415
virNWFilterRulePriority priority,
416
enum RuleType ruleType)
418
ebiptablesRuleInstPtr inst;
420
if (VIR_ALLOC(inst) < 0) {
425
inst->commandTemplate = commandTemplate;
426
inst->neededProtocolChain = neededChain;
427
inst->chainPriority = chainPriority;
428
inst->chainprefix = chainprefix;
429
inst->priority = priority;
430
inst->ruleType = ruleType;
432
return virNWFilterRuleInstAddData(res, inst);
437
ebtablesHandleEthHdr(virBufferPtr buf,
438
virNWFilterVarCombIterPtr vars,
439
ethHdrDataDefPtr ethHdr,
442
char macaddr[VIR_MAC_STRING_BUFLEN];
444
if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACAddr)) {
445
if (printDataType(vars,
446
macaddr, sizeof(macaddr),
447
ðHdr->dataSrcMACAddr) < 0)
450
virBufferAsprintf(buf,
452
reverse ? "-d" : "-s",
453
ENTRY_GET_NEG_SIGN(ðHdr->dataSrcMACAddr),
456
if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACMask)) {
457
if (printDataType(vars,
458
macaddr, sizeof(macaddr),
459
ðHdr->dataSrcMACMask) < 0)
462
virBufferAsprintf(buf,
468
if (HAS_ENTRY_ITEM(ðHdr->dataDstMACAddr)) {
469
if (printDataType(vars,
470
macaddr, sizeof(macaddr),
471
ðHdr->dataDstMACAddr) < 0)
474
virBufferAsprintf(buf,
476
reverse ? "-s" : "-d",
477
ENTRY_GET_NEG_SIGN(ðHdr->dataDstMACAddr),
480
if (HAS_ENTRY_ITEM(ðHdr->dataDstMACMask)) {
481
if (printDataType(vars,
482
macaddr, sizeof(macaddr),
483
ðHdr->dataDstMACMask) < 0)
486
virBufferAsprintf(buf,
495
virBufferFreeAndReset(buf);
501
/************************ iptables support ************************/
503
static int iptablesLinkIPTablesBaseChain(virBufferPtr buf,
505
const char *syschain,
509
virBufferAsprintf(buf,
510
"res=$($IPT -L %s -n --line-number | "
512
"if [ $? -ne 0 ]; then\n"
513
" $IPT -I %s %d -j %s\n"
515
" r=$(echo $res | %s '{print $1}')\n"
516
" if [ \"${r}\" != \"%d\" ]; then\n"
517
" " CMD_DEF("$IPT -I %s %d -j %s") CMD_SEPARATOR
521
" " CMD_DEF("$IPT -D %s ${r}") CMD_SEPARATOR
528
grep_cmd_path, udchain,
530
syschain, pos, udchain,
535
syschain, pos, udchain,
536
CMD_STOPONERR(stopOnError),
539
CMD_STOPONERR(stopOnError));
544
static int iptablesCreateBaseChains(virBufferPtr buf)
546
virBufferAddLit(buf, "$IPT -N " VIRT_IN_CHAIN CMD_SEPARATOR
547
"$IPT -N " VIRT_OUT_CHAIN CMD_SEPARATOR
548
"$IPT -N " VIRT_IN_POST_CHAIN CMD_SEPARATOR
549
"$IPT -N " HOST_IN_CHAIN CMD_SEPARATOR);
550
iptablesLinkIPTablesBaseChain(buf,
551
VIRT_IN_CHAIN , "FORWARD", 1, 1);
552
iptablesLinkIPTablesBaseChain(buf,
553
VIRT_OUT_CHAIN , "FORWARD", 2, 1);
554
iptablesLinkIPTablesBaseChain(buf,
555
VIRT_IN_POST_CHAIN, "FORWARD", 3, 1);
556
iptablesLinkIPTablesBaseChain(buf,
557
HOST_IN_CHAIN , "INPUT" , 1, 1);
564
iptablesCreateTmpRootChain(virBufferPtr buf,
566
int incoming, const char *ifname,
569
char chain[MAX_CHAINNAME_LENGTH];
570
char chainPrefix[2] = {
572
(incoming) ? CHAINPREFIX_HOST_IN_TEMP
573
: CHAINPREFIX_HOST_OUT_TEMP
576
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
578
virBufferAsprintf(buf,
579
CMD_DEF("$IPT -N %s") CMD_SEPARATOR
583
CMD_STOPONERR(stopOnError));
590
iptablesCreateTmpRootChains(virBufferPtr buf,
593
iptablesCreateTmpRootChain(buf, 'F', 0, ifname, 1);
594
iptablesCreateTmpRootChain(buf, 'F', 1, ifname, 1);
595
iptablesCreateTmpRootChain(buf, 'H', 1, ifname, 1);
601
_iptablesRemoveRootChain(virBufferPtr buf,
603
int incoming, const char *ifname,
606
char chain[MAX_CHAINNAME_LENGTH];
607
char chainPrefix[2] = {
612
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
613
: CHAINPREFIX_HOST_OUT_TEMP;
615
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
616
: CHAINPREFIX_HOST_OUT;
618
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
620
virBufferAsprintf(buf,
621
"$IPT -F %s" CMD_SEPARATOR
622
"$IPT -X %s" CMD_SEPARATOR,
631
iptablesRemoveRootChain(virBufferPtr buf,
636
return _iptablesRemoveRootChain(buf, prefix, incoming, ifname, 0);
641
iptablesRemoveTmpRootChain(virBufferPtr buf,
646
return _iptablesRemoveRootChain(buf, prefix,
647
incoming, ifname, 1);
652
iptablesRemoveTmpRootChains(virBufferPtr buf,
655
iptablesRemoveTmpRootChain(buf, 'F', 0, ifname);
656
iptablesRemoveTmpRootChain(buf, 'F', 1, ifname);
657
iptablesRemoveTmpRootChain(buf, 'H', 1, ifname);
663
iptablesRemoveRootChains(virBufferPtr buf,
666
iptablesRemoveRootChain(buf, 'F', 0, ifname);
667
iptablesRemoveRootChain(buf, 'F', 1, ifname);
668
iptablesRemoveRootChain(buf, 'H', 1, ifname);
674
iptablesLinkTmpRootChain(virBufferPtr buf,
675
const char *basechain,
677
int incoming, const char *ifname,
680
char chain[MAX_CHAINNAME_LENGTH];
681
char chainPrefix[2] = {
683
(incoming) ? CHAINPREFIX_HOST_IN_TEMP
684
: CHAINPREFIX_HOST_OUT_TEMP
686
const char *match = (incoming) ? MATCH_PHYSDEV_IN
689
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
691
virBufferAsprintf(buf,
692
CMD_DEF("$IPT -A %s "
693
"%s %s -g %s") CMD_SEPARATOR
697
match, ifname, chain,
699
CMD_STOPONERR(stopOnError));
706
iptablesLinkTmpRootChains(virBufferPtr buf,
709
iptablesLinkTmpRootChain(buf, VIRT_OUT_CHAIN, 'F', 0, ifname, 1);
710
iptablesLinkTmpRootChain(buf, VIRT_IN_CHAIN , 'F', 1, ifname, 1);
711
iptablesLinkTmpRootChain(buf, HOST_IN_CHAIN , 'H', 1, ifname, 1);
718
iptablesSetupVirtInPost(virBufferPtr buf,
721
const char *match = MATCH_PHYSDEV_IN;
722
virBufferAsprintf(buf,
723
"res=$($IPT -n -L " VIRT_IN_POST_CHAIN
724
" | grep \"\\%s %s\")\n"
725
"if [ \"${res}\" = \"\" ]; then "
727
" -A " VIRT_IN_POST_CHAIN
728
" %s %s -j ACCEPT") CMD_SEPARATOR
740
iptablesClearVirtInPost(virBufferPtr buf,
743
const char *match = MATCH_PHYSDEV_IN;
744
virBufferAsprintf(buf,
745
"$IPT -D " VIRT_IN_POST_CHAIN
746
" %s %s -j ACCEPT" CMD_SEPARATOR,
752
_iptablesUnlinkRootChain(virBufferPtr buf,
753
const char *basechain,
755
int incoming, const char *ifname,
758
char chain[MAX_CHAINNAME_LENGTH];
759
char chainPrefix[2] = {
763
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
764
: CHAINPREFIX_HOST_OUT_TEMP;
766
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
767
: CHAINPREFIX_HOST_OUT;
768
const char *match = (incoming) ? MATCH_PHYSDEV_IN
771
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
773
virBufferAsprintf(buf,
775
"%s %s -g %s" CMD_SEPARATOR,
777
match, ifname, chain);
784
iptablesUnlinkRootChain(virBufferPtr buf,
785
const char *basechain,
787
int incoming, const char *ifname)
789
return _iptablesUnlinkRootChain(buf,
790
basechain, prefix, incoming, ifname, 0);
795
iptablesUnlinkTmpRootChain(virBufferPtr buf,
796
const char *basechain,
798
int incoming, const char *ifname)
800
return _iptablesUnlinkRootChain(buf,
801
basechain, prefix, incoming, ifname, 1);
806
iptablesUnlinkRootChains(virBufferPtr buf,
809
iptablesUnlinkRootChain(buf, VIRT_OUT_CHAIN, 'F', 0, ifname);
810
iptablesUnlinkRootChain(buf, VIRT_IN_CHAIN , 'F', 1, ifname);
811
iptablesUnlinkRootChain(buf, HOST_IN_CHAIN , 'H', 1, ifname);
818
iptablesUnlinkTmpRootChains(virBufferPtr buf,
821
iptablesUnlinkTmpRootChain(buf, VIRT_OUT_CHAIN, 'F', 0, ifname);
822
iptablesUnlinkTmpRootChain(buf, VIRT_IN_CHAIN , 'F', 1, ifname);
823
iptablesUnlinkTmpRootChain(buf, HOST_IN_CHAIN , 'H', 1, ifname);
829
iptablesRenameTmpRootChain(virBufferPtr buf,
834
char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
835
char tmpChainPrefix[2] = {
837
(incoming) ? CHAINPREFIX_HOST_IN_TEMP
838
: CHAINPREFIX_HOST_OUT_TEMP
840
char chainPrefix[2] = {
842
(incoming) ? CHAINPREFIX_HOST_IN
843
: CHAINPREFIX_HOST_OUT
846
PRINT_IPT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
847
PRINT_IPT_ROOT_CHAIN( chain, chainPrefix, ifname);
849
virBufferAsprintf(buf,
850
"$IPT -E %s %s" CMD_SEPARATOR,
858
iptablesRenameTmpRootChains(virBufferPtr buf,
861
iptablesRenameTmpRootChain(buf, 'F', 0, ifname);
862
iptablesRenameTmpRootChain(buf, 'F', 1, ifname);
863
iptablesRenameTmpRootChain(buf, 'H', 1, ifname);
869
iptablesInstCommand(virBufferPtr buf,
870
const char *templ, char cmd, int pos,
873
char position[10] = { 0 };
875
snprintf(position, sizeof(position), "%d", pos);
876
virBufferAsprintf(buf, templ, cmd, position);
877
virBufferAsprintf(buf, CMD_SEPARATOR "%s",
878
CMD_STOPONERR(stopOnError));
883
iptablesHandleSrcMacAddr(virBufferPtr buf,
884
virNWFilterVarCombIterPtr vars,
885
nwItemDescPtr srcMacAddr,
889
char macaddr[VIR_MAC_STRING_BUFLEN];
890
*srcmacskipped = false;
892
if (HAS_ENTRY_ITEM(srcMacAddr)) {
894
*srcmacskipped = true;
898
if (printDataType(vars,
899
macaddr, sizeof(macaddr),
903
virBufferAsprintf(buf,
904
" -m mac %s --mac-source %s",
905
ENTRY_GET_NEG_SIGN(srcMacAddr),
912
virBufferFreeAndReset(buf);
919
iptablesHandleIpHdr(virBufferPtr buf,
920
virBufferPtr afterStateMatch,
921
virNWFilterVarCombIterPtr vars,
922
ipHdrDataDefPtr ipHdr,
924
bool *skipRule, bool *skipMatch,
927
char ipaddr[INET6_ADDRSTRLEN],
928
number[MAX(INT_BUFSIZE_BOUND(uint32_t),
929
INT_BUFSIZE_BOUND(int))];
930
const char *src = "--source";
931
const char *dst = "--destination";
932
const char *srcrange = "--src-range";
933
const char *dstrange = "--dst-range";
935
src = "--destination";
937
srcrange = "--dst-range";
938
dstrange = "--src-range";
941
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPAddr)) {
943
if (printDataType(vars,
944
ipaddr, sizeof(ipaddr),
945
&ipHdr->dataSrcIPAddr) < 0)
948
virBufferAsprintf(buf,
950
ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPAddr),
954
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPMask)) {
956
if (printDataType(vars,
957
number, sizeof(number),
958
&ipHdr->dataSrcIPMask) < 0)
961
virBufferAsprintf(buf,
965
} else if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPFrom)) {
967
if (printDataType(vars,
968
ipaddr, sizeof(ipaddr),
969
&ipHdr->dataSrcIPFrom) < 0)
972
virBufferAsprintf(buf,
973
" -m iprange %s %s %s",
974
ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPFrom),
978
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPTo)) {
980
if (printDataType(vars,
981
ipaddr, sizeof(ipaddr),
982
&ipHdr->dataSrcIPTo) < 0)
985
virBufferAsprintf(buf,
991
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPAddr)) {
993
if (printDataType(vars,
994
ipaddr, sizeof(ipaddr),
995
&ipHdr->dataDstIPAddr) < 0)
998
virBufferAsprintf(buf,
1000
ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPAddr),
1004
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPMask)) {
1006
if (printDataType(vars,
1007
number, sizeof(number),
1008
&ipHdr->dataDstIPMask) < 0)
1011
virBufferAsprintf(buf,
1016
} else if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPFrom)) {
1018
if (printDataType(vars,
1019
ipaddr, sizeof(ipaddr),
1020
&ipHdr->dataDstIPFrom) < 0)
1023
virBufferAsprintf(buf,
1024
" -m iprange %s %s %s",
1025
ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPFrom),
1029
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPTo)) {
1031
if (printDataType(vars,
1032
ipaddr, sizeof(ipaddr),
1033
&ipHdr->dataDstIPTo) < 0)
1036
virBufferAsprintf(buf,
1042
if (HAS_ENTRY_ITEM(&ipHdr->dataDSCP)) {
1044
if (printDataType(vars,
1045
number, sizeof(number),
1046
&ipHdr->dataDSCP) < 0)
1049
virBufferAsprintf(buf,
1050
" -m dscp %s --dscp %s",
1051
ENTRY_GET_NEG_SIGN(&ipHdr->dataDSCP),
1055
if (HAS_ENTRY_ITEM(&ipHdr->dataConnlimitAbove)) {
1057
/* only support for limit in outgoing dir. */
1060
if (printDataType(vars,
1061
number, sizeof(number),
1062
&ipHdr->dataConnlimitAbove) < 0)
1065
/* place connlimit after potential -m state --state ...
1066
since this is the most useful order */
1067
virBufferAsprintf(afterStateMatch,
1068
" -m connlimit %s --connlimit-above %s",
1069
ENTRY_GET_NEG_SIGN(&ipHdr->dataConnlimitAbove),
1075
if (HAS_ENTRY_ITEM(&ipHdr->dataComment)) {
1076
printCommentVar(prefix, ipHdr->dataComment.u.string);
1078
/* keep comments behind everything else -- they are packet eval.
1080
virBufferAddLit(afterStateMatch,
1081
" -m comment --comment \"$" COMMENT_VARNAME "\"");
1087
virBufferFreeAndReset(buf);
1088
virBufferFreeAndReset(afterStateMatch);
1095
iptablesHandlePortData(virBufferPtr buf,
1096
virNWFilterVarCombIterPtr vars,
1097
portDataDefPtr portData,
1101
const char *sport = "--sport";
1102
const char *dport = "--dport";
1108
if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart)) {
1109
if (printDataType(vars,
1110
portstr, sizeof(portstr),
1111
&portData->dataSrcPortStart) < 0)
1114
virBufferAsprintf(buf,
1116
ENTRY_GET_NEG_SIGN(&portData->dataSrcPortStart),
1120
if (HAS_ENTRY_ITEM(&portData->dataSrcPortEnd)) {
1121
if (printDataType(vars,
1122
portstr, sizeof(portstr),
1123
&portData->dataSrcPortEnd) < 0)
1126
virBufferAsprintf(buf,
1132
if (HAS_ENTRY_ITEM(&portData->dataDstPortStart)) {
1133
if (printDataType(vars,
1134
portstr, sizeof(portstr),
1135
&portData->dataDstPortStart) < 0)
1138
virBufferAsprintf(buf,
1140
ENTRY_GET_NEG_SIGN(&portData->dataDstPortStart),
1144
if (HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) {
1145
if (printDataType(vars,
1146
portstr, sizeof(portstr),
1147
&portData->dataDstPortEnd) < 0)
1150
virBufferAsprintf(buf,
1164
iptablesEnforceDirection(int directionIn,
1165
virNWFilterRuleDefPtr rule,
1168
if (rule->tt != VIR_NWFILTER_RULE_DIRECTION_INOUT)
1169
virBufferAsprintf(buf, " -m conntrack --ctdir %s",
1170
(directionIn) ? "Original"
1176
* _iptablesCreateRuleInstance:
1177
* @chainPrefix : The prefix to put in front of the name of the chain
1178
* @nwfilter : The filter
1179
* @rule: The rule of the filter to convert
1180
* @ifname : The name of the interface to apply the rule to
1181
* @vars : A map containing the variables to resolve
1182
* @res : The data structure to store the result(s) into
1183
* @match : optional string for state match
1184
* @accept_target : where to jump to on accepted traffic, i.e., "RETURN"
1186
* @isIPv6 : Whether this is an IPv6 rule
1187
* @maySkipICMP : whether this rule may under certain circumstances skip
1188
* the ICMP rule from being created
1190
* Convert a single rule into its representation for later instantiation
1192
* Returns 0 in case of success with the result stored in the data structure
1193
* pointed to by res, != 0 otherwise.
1196
_iptablesCreateRuleInstance(int directionIn,
1197
const char *chainPrefix,
1198
virNWFilterDefPtr nwfilter,
1199
virNWFilterRuleDefPtr rule,
1201
virNWFilterVarCombIterPtr vars,
1202
virNWFilterRuleInstPtr res,
1203
const char *match, bool defMatch,
1204
const char *accept_target,
1208
char chain[MAX_CHAINNAME_LENGTH];
1209
char number[MAX(INT_BUFSIZE_BOUND(uint32_t),
1210
INT_BUFSIZE_BOUND(int))];
1211
virBuffer prefix = VIR_BUFFER_INITIALIZER;
1212
virBuffer buf = VIR_BUFFER_INITIALIZER;
1213
virBuffer afterStateMatch = VIR_BUFFER_INITIALIZER;
1214
virBufferPtr final = NULL;
1216
const char *iptables_cmd = (isIPv6) ? ip6tables_cmd_path
1217
: iptables_cmd_path;
1218
unsigned int bufUsed;
1219
bool srcMacSkipped = false;
1220
bool skipRule = false;
1221
bool skipMatch = false;
1222
bool hasICMPType = false;
1224
if (!iptables_cmd) {
1225
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
1226
_("cannot create rule since %s tool is "
1228
isIPv6 ? "ip6tables" : "iptables");
1232
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
1234
switch (rule->prtclType) {
1235
case VIR_NWFILTER_RULE_PROTOCOL_TCP:
1236
case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
1237
virBufferAsprintf(&buf,
1238
CMD_DEF_PRE "$IPT -%%c %s %%s",
1241
virBufferAddLit(&buf, " -p tcp");
1243
bufUsed = virBufferUse(&buf);
1245
if (iptablesHandleSrcMacAddr(&buf,
1247
&rule->p.tcpHdrFilter.dataSrcMACAddr,
1249
&srcMacSkipped) < 0)
1252
if (iptablesHandleIpHdr(&buf,
1255
&rule->p.tcpHdrFilter.ipHdr,
1257
&skipRule, &skipMatch,
1261
if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPFlags)) {
1262
virBufferAsprintf(&buf, " %s --tcp-flags ",
1263
ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPFlags));
1264
virNWFilterPrintTCPFlags(&buf,
1265
rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.mask,
1267
rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.flags);
1270
if (iptablesHandlePortData(&buf,
1272
&rule->p.tcpHdrFilter.portData,
1276
if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPOption)) {
1277
if (printDataType(vars,
1278
number, sizeof(number),
1279
&rule->p.tcpHdrFilter.dataTCPOption) < 0)
1282
virBufferAsprintf(&buf,
1283
" %s --tcp-option %s",
1284
ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPOption),
1290
case VIR_NWFILTER_RULE_PROTOCOL_UDP:
1291
case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
1292
virBufferAsprintf(&buf,
1293
CMD_DEF_PRE "$IPT -%%c %s %%s",
1296
virBufferAddLit(&buf, " -p udp");
1298
bufUsed = virBufferUse(&buf);
1300
if (iptablesHandleSrcMacAddr(&buf,
1302
&rule->p.udpHdrFilter.dataSrcMACAddr,
1304
&srcMacSkipped) < 0)
1307
if (iptablesHandleIpHdr(&buf,
1310
&rule->p.udpHdrFilter.ipHdr,
1312
&skipRule, &skipMatch,
1316
if (iptablesHandlePortData(&buf,
1318
&rule->p.udpHdrFilter.portData,
1323
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
1324
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
1325
virBufferAsprintf(&buf,
1326
CMD_DEF_PRE "$IPT -%%c %s %%s",
1329
virBufferAddLit(&buf, " -p udplite");
1331
bufUsed = virBufferUse(&buf);
1333
if (iptablesHandleSrcMacAddr(&buf,
1335
&rule->p.udpliteHdrFilter.dataSrcMACAddr,
1337
&srcMacSkipped) < 0)
1340
if (iptablesHandleIpHdr(&buf,
1343
&rule->p.udpliteHdrFilter.ipHdr,
1345
&skipRule, &skipMatch,
1351
case VIR_NWFILTER_RULE_PROTOCOL_ESP:
1352
case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
1353
virBufferAsprintf(&buf,
1354
CMD_DEF_PRE "$IPT -%%c %s %%s",
1357
virBufferAddLit(&buf, " -p esp");
1359
bufUsed = virBufferUse(&buf);
1361
if (iptablesHandleSrcMacAddr(&buf,
1363
&rule->p.espHdrFilter.dataSrcMACAddr,
1365
&srcMacSkipped) < 0)
1368
if (iptablesHandleIpHdr(&buf,
1371
&rule->p.espHdrFilter.ipHdr,
1373
&skipRule, &skipMatch,
1379
case VIR_NWFILTER_RULE_PROTOCOL_AH:
1380
case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
1381
virBufferAsprintf(&buf,
1382
CMD_DEF_PRE "$IPT -%%c %s %%s",
1385
virBufferAddLit(&buf, " -p ah");
1387
bufUsed = virBufferUse(&buf);
1389
if (iptablesHandleSrcMacAddr(&buf,
1391
&rule->p.ahHdrFilter.dataSrcMACAddr,
1393
&srcMacSkipped) < 0)
1396
if (iptablesHandleIpHdr(&buf,
1399
&rule->p.ahHdrFilter.ipHdr,
1401
&skipRule, &skipMatch,
1407
case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
1408
case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
1409
virBufferAsprintf(&buf,
1410
CMD_DEF_PRE "$IPT -%%c %s %%s",
1413
virBufferAddLit(&buf, " -p sctp");
1415
bufUsed = virBufferUse(&buf);
1417
if (iptablesHandleSrcMacAddr(&buf,
1419
&rule->p.sctpHdrFilter.dataSrcMACAddr,
1421
&srcMacSkipped) < 0)
1424
if (iptablesHandleIpHdr(&buf,
1427
&rule->p.sctpHdrFilter.ipHdr,
1429
&skipRule, &skipMatch,
1433
if (iptablesHandlePortData(&buf,
1435
&rule->p.sctpHdrFilter.portData,
1440
case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
1441
case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
1442
virBufferAsprintf(&buf,
1443
CMD_DEF_PRE "$IPT -%%c %s %%s",
1446
if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
1447
virBufferAddLit(&buf, " -p icmp");
1449
virBufferAddLit(&buf, " -p icmpv6");
1451
bufUsed = virBufferUse(&buf);
1453
if (iptablesHandleSrcMacAddr(&buf,
1455
&rule->p.icmpHdrFilter.dataSrcMACAddr,
1457
&srcMacSkipped) < 0)
1460
if (iptablesHandleIpHdr(&buf,
1463
&rule->p.icmpHdrFilter.ipHdr,
1465
&skipRule, &skipMatch,
1469
if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPType)) {
1477
if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
1478
parm = "--icmp-type";
1480
parm = "--icmpv6-type";
1482
if (printDataType(vars,
1483
number, sizeof(number),
1484
&rule->p.icmpHdrFilter.dataICMPType) < 0)
1487
virBufferAsprintf(&buf,
1489
ENTRY_GET_NEG_SIGN(&rule->p.icmpHdrFilter.dataICMPType),
1493
if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPCode)) {
1494
if (printDataType(vars,
1495
number, sizeof(number),
1496
&rule->p.icmpHdrFilter.dataICMPCode) < 0)
1499
virBufferAsprintf(&buf,
1506
case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
1507
virBufferAsprintf(&buf,
1508
CMD_DEF_PRE "$IPT -%%c %s %%s",
1511
virBufferAddLit(&buf, " -p igmp");
1513
bufUsed = virBufferUse(&buf);
1515
if (iptablesHandleSrcMacAddr(&buf,
1517
&rule->p.igmpHdrFilter.dataSrcMACAddr,
1519
&srcMacSkipped) < 0)
1522
if (iptablesHandleIpHdr(&buf,
1525
&rule->p.igmpHdrFilter.ipHdr,
1527
&skipRule, &skipMatch,
1533
case VIR_NWFILTER_RULE_PROTOCOL_ALL:
1534
case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
1535
virBufferAsprintf(&buf,
1536
CMD_DEF_PRE "$IPT -%%c %s %%s",
1539
virBufferAddLit(&buf, " -p all");
1541
bufUsed = virBufferUse(&buf);
1543
if (iptablesHandleSrcMacAddr(&buf,
1545
&rule->p.allHdrFilter.dataSrcMACAddr,
1547
&srcMacSkipped) < 0)
1550
if (iptablesHandleIpHdr(&buf,
1553
&rule->p.allHdrFilter.ipHdr,
1555
&skipRule, &skipMatch,
1565
if ((srcMacSkipped && bufUsed == virBufferUse(&buf)) ||
1567
virBufferFreeAndReset(&buf);
1568
virBufferFreeAndReset(&prefix);
1572
if (rule->action == VIR_NWFILTER_RULE_ACTION_ACCEPT)
1573
target = accept_target;
1575
target = virNWFilterJumpTargetTypeToString(rule->action);
1576
skipMatch = defMatch;
1579
if (match && !skipMatch)
1580
virBufferAsprintf(&buf, " %s", match);
1582
if (defMatch && match != NULL && !skipMatch && !hasICMPType)
1583
iptablesEnforceDirection(directionIn,
1587
if (virBufferError(&afterStateMatch)) {
1588
virBufferFreeAndReset(&buf);
1589
virBufferFreeAndReset(&prefix);
1590
virBufferFreeAndReset(&afterStateMatch);
1591
virReportOOMError();
1595
if (virBufferUse(&afterStateMatch)) {
1596
char *s = virBufferContentAndReset(&afterStateMatch);
1598
virBufferAdd(&buf, s, -1);
1603
virBufferAsprintf(&buf,
1604
" -j %s" CMD_DEF_POST CMD_SEPARATOR
1608
if (virBufferError(&buf) || virBufferError(&prefix)) {
1609
virBufferFreeAndReset(&buf);
1610
virBufferFreeAndReset(&prefix);
1611
virReportOOMError();
1615
if (virBufferUse(&prefix)) {
1616
char *s = virBufferContentAndReset(&buf);
1618
virBufferAdd(&prefix, s, -1);
1624
if (virBufferError(&prefix)) {
1625
virBufferFreeAndReset(&prefix);
1626
virReportOOMError();
1633
return ebiptablesAddRuleInst(res,
1634
virBufferContentAndReset(final),
1635
nwfilter->chainsuffix,
1636
nwfilter->chainPriority,
1639
(isIPv6) ? RT_IP6TABLES : RT_IPTABLES);
1643
virBufferFreeAndReset(&buf);
1644
virBufferFreeAndReset(&prefix);
1645
virBufferFreeAndReset(&afterStateMatch);
1650
virBufferFreeAndReset(&buf);
1651
virBufferFreeAndReset(&prefix);
1652
virBufferFreeAndReset(&afterStateMatch);
1659
printStateMatchFlags(int32_t flags, char **bufptr)
1661
virBuffer buf = VIR_BUFFER_INITIALIZER;
1662
virNWFilterPrintStateMatchFlags(&buf,
1663
"-m state --state ",
1666
if (virBufferError(&buf)) {
1667
virBufferFreeAndReset(&buf);
1668
virReportOOMError();
1671
*bufptr = virBufferContentAndReset(&buf);
1676
iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter,
1677
virNWFilterRuleDefPtr rule,
1679
virNWFilterVarCombIterPtr vars,
1680
virNWFilterRuleInstPtr res,
1684
int directionIn = 0;
1685
char chainPrefix[2];
1686
bool maySkipICMP, inout = false;
1687
char *matchState = NULL;
1690
if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
1691
(rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
1693
inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
1696
chainPrefix[0] = 'F';
1698
maySkipICMP = directionIn || inout;
1703
if (directionIn && !inout) {
1704
if ((rule->flags & IPTABLES_STATE_FLAGS))
1708
if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
1709
if (printStateMatchFlags(rule->flags, &matchState) < 0)
1713
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1715
rc = _iptablesCreateRuleInstance(directionIn,
1727
VIR_FREE(matchState);
1732
maySkipICMP = !directionIn || inout;
1736
if ((rule->flags & IPTABLES_STATE_FLAGS))
1740
if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
1741
if (printStateMatchFlags(rule->flags, &matchState) < 0)
1745
chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
1747
rc = _iptablesCreateRuleInstance(!directionIn,
1759
VIR_FREE(matchState);
1765
maySkipICMP = directionIn;
1769
if (directionIn && !inout) {
1770
if ((rule->flags & IPTABLES_STATE_FLAGS))
1773
if ((rule->flags & IPTABLES_STATE_FLAGS)) {
1774
if (printStateMatchFlags(rule->flags, &matchState) < 0)
1780
chainPrefix[0] = 'H';
1781
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1782
rc = _iptablesCreateRuleInstance(directionIn,
1793
VIR_FREE(matchState);
1801
iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
1802
virNWFilterRuleDefPtr rule,
1804
virNWFilterVarCombIterPtr vars,
1805
virNWFilterRuleInstPtr res,
1809
int directionIn = 0;
1810
char chainPrefix[2];
1812
bool maySkipICMP, inout = false;
1813
const char *matchState;
1815
if (!(rule->flags & RULE_FLAG_NO_STATEMATCH) &&
1816
(rule->flags & IPTABLES_STATE_FLAGS)) {
1817
return iptablesCreateRuleInstanceStateCtrl(nwfilter,
1825
if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
1826
(rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
1828
inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
1833
if ((rule->flags & RULE_FLAG_NO_STATEMATCH))
1836
chainPrefix[0] = 'F';
1838
maySkipICMP = directionIn || inout;
1841
matchState = directionIn ? MATCH_STATE_IN : MATCH_STATE_OUT;
1845
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1846
rc = _iptablesCreateRuleInstance(directionIn,
1861
maySkipICMP = !directionIn || inout;
1863
matchState = directionIn ? MATCH_STATE_OUT : MATCH_STATE_IN;
1867
chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
1868
rc = _iptablesCreateRuleInstance(!directionIn,
1882
maySkipICMP = directionIn;
1884
matchState = directionIn ? MATCH_STATE_IN : MATCH_STATE_OUT;
1888
chainPrefix[0] = 'H';
1889
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1890
rc = _iptablesCreateRuleInstance(directionIn,
1909
* ebtablesCreateRuleInstance:
1910
* @chainPrefix : The prefix to put in front of the name of the chain
1911
* @nwfilter : The filter
1912
* @rule: The rule of the filter to convert
1913
* @ifname : The name of the interface to apply the rule to
1914
* @vars : A map containing the variables to resolve
1915
* @res : The data structure to store the result(s) into
1916
* @reverse : Whether to reverse src and dst attributes
1918
* Convert a single rule into its representation for later instantiation
1920
* Returns 0 in case of success with the result stored in the data structure
1921
* pointed to by res, != 0 otherwise.
1924
ebtablesCreateRuleInstance(char chainPrefix,
1925
virNWFilterDefPtr nwfilter,
1926
virNWFilterRuleDefPtr rule,
1928
virNWFilterVarCombIterPtr vars,
1929
virNWFilterRuleInstPtr res,
1932
char macaddr[VIR_MAC_STRING_BUFLEN],
1933
ipaddr[INET_ADDRSTRLEN],
1934
ipv6addr[INET6_ADDRSTRLEN],
1935
number[MAX(INT_BUFSIZE_BOUND(uint32_t),
1936
INT_BUFSIZE_BOUND(int))],
1937
field[MAX(VIR_MAC_STRING_BUFLEN, INET6_ADDRSTRLEN)];
1938
char chain[MAX_CHAINNAME_LENGTH];
1939
virBuffer buf = VIR_BUFFER_INITIALIZER;
1942
if (!ebtables_cmd_path) {
1943
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1944
_("cannot create rule since ebtables tool is "
1949
if (STREQ(nwfilter->chainsuffix,
1950
virNWFilterChainSuffixTypeToString(
1951
VIR_NWFILTER_CHAINSUFFIX_ROOT)))
1952
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
1954
PRINT_CHAIN(chain, chainPrefix, ifname,
1955
nwfilter->chainsuffix);
1958
switch (rule->prtclType) {
1959
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
1961
virBufferAsprintf(&buf,
1962
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
1965
if (ebtablesHandleEthHdr(&buf,
1967
&rule->p.ethHdrFilter.ethHdr,
1971
if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
1972
if (printDataTypeAsHex(vars,
1973
number, sizeof(number),
1974
&rule->p.ethHdrFilter.dataProtocolID) < 0)
1976
virBufferAsprintf(&buf,
1978
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
1983
case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
1985
virBufferAsprintf(&buf,
1986
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
1990
if (ebtablesHandleEthHdr(&buf,
1992
&rule->p.vlanHdrFilter.ethHdr,
1996
virBufferAddLit(&buf,
1999
#define INST_ITEM(STRUCT, ITEM, CLI) \
2000
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
2001
if (printDataType(vars, \
2002
field, sizeof(field), \
2003
&rule->p.STRUCT.ITEM) < 0) \
2005
virBufferAsprintf(&buf, \
2007
ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
2011
#define INST_ITEM_2PARMS(STRUCT, ITEM, ITEM_HI, CLI, SEP) \
2012
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
2013
if (printDataType(vars, \
2014
field, sizeof(field), \
2015
&rule->p.STRUCT.ITEM) < 0) \
2017
virBufferAsprintf(&buf, \
2019
ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
2021
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM_HI)) { \
2022
if (printDataType(vars, \
2023
field, sizeof(field), \
2024
&rule->p.STRUCT.ITEM_HI) < 0) \
2026
virBufferAsprintf(&buf, SEP "%s", field); \
2029
#define INST_ITEM_RANGE(S, I, I_HI, C) \
2030
INST_ITEM_2PARMS(S, I, I_HI, C, ":")
2031
#define INST_ITEM_MASK(S, I, MASK, C) \
2032
INST_ITEM_2PARMS(S, I, MASK, C, "/")
2034
INST_ITEM(vlanHdrFilter, dataVlanID, "--vlan-id")
2035
INST_ITEM(vlanHdrFilter, dataVlanEncap, "--vlan-encap")
2038
case VIR_NWFILTER_RULE_PROTOCOL_STP:
2040
/* cannot handle inout direction with srcmask set in reverse dir.
2041
since this clashes with -d below... */
2043
HAS_ENTRY_ITEM(&rule->p.stpHdrFilter.ethHdr.dataSrcMACAddr)) {
2044
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
2045
_("STP filtering in %s direction with "
2046
"source MAC address set is not supported"),
2047
virNWFilterRuleDirectionTypeToString(
2048
VIR_NWFILTER_RULE_DIRECTION_INOUT));
2052
virBufferAsprintf(&buf,
2053
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2057
if (ebtablesHandleEthHdr(&buf,
2059
&rule->p.stpHdrFilter.ethHdr,
2063
virBufferAddLit(&buf, " -d " NWFILTER_MAC_BGA);
2065
INST_ITEM(stpHdrFilter, dataType, "--stp-type")
2066
INST_ITEM(stpHdrFilter, dataFlags, "--stp-flags")
2067
INST_ITEM_RANGE(stpHdrFilter, dataRootPri, dataRootPriHi,
2069
INST_ITEM_MASK( stpHdrFilter, dataRootAddr, dataRootAddrMask,
2071
INST_ITEM_RANGE(stpHdrFilter, dataRootCost, dataRootCostHi,
2073
INST_ITEM_RANGE(stpHdrFilter, dataSndrPrio, dataSndrPrioHi,
2074
"--stp-sender-prio");
2075
INST_ITEM_MASK( stpHdrFilter, dataSndrAddr, dataSndrAddrMask,
2076
"--stp-sender-addr");
2077
INST_ITEM_RANGE(stpHdrFilter, dataPort, dataPortHi, "--stp-port");
2078
INST_ITEM_RANGE(stpHdrFilter, dataAge, dataAgeHi, "--stp-msg-age");
2079
INST_ITEM_RANGE(stpHdrFilter, dataMaxAge, dataMaxAgeHi,
2081
INST_ITEM_RANGE(stpHdrFilter, dataHelloTime, dataHelloTimeHi,
2082
"--stp-hello-time");
2083
INST_ITEM_RANGE(stpHdrFilter, dataFwdDelay, dataFwdDelayHi,
2084
"--stp-forward-delay");
2087
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
2088
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
2090
virBufferAsprintf(&buf,
2091
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2094
if (ebtablesHandleEthHdr(&buf,
2096
&rule->p.arpHdrFilter.ethHdr,
2100
virBufferAsprintf(&buf, " -p 0x%x",
2101
(rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ARP)
2102
? l3_protocols[L3_PROTO_ARP_IDX].attr
2103
: l3_protocols[L3_PROTO_RARP_IDX].attr);
2105
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
2106
if (printDataType(vars,
2107
number, sizeof(number),
2108
&rule->p.arpHdrFilter.dataHWType) < 0)
2110
virBufferAsprintf(&buf,
2111
" --arp-htype %s %s",
2112
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
2116
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
2117
if (printDataType(vars,
2118
number, sizeof(number),
2119
&rule->p.arpHdrFilter.dataOpcode) < 0)
2121
virBufferAsprintf(&buf,
2122
" --arp-opcode %s %s",
2123
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
2127
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
2128
if (printDataTypeAsHex(vars,
2129
number, sizeof(number),
2130
&rule->p.arpHdrFilter.dataProtocolType) < 0)
2132
virBufferAsprintf(&buf,
2133
" --arp-ptype %s %s",
2134
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
2138
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
2139
if (printDataType(vars,
2140
ipaddr, sizeof(ipaddr),
2141
&rule->p.arpHdrFilter.dataARPSrcIPAddr) < 0)
2144
virBufferAsprintf(&buf,
2146
reverse ? "--arp-ip-dst" : "--arp-ip-src",
2147
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcIPAddr),
2151
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPAddr)) {
2152
if (printDataType(vars,
2153
ipaddr, sizeof(ipaddr),
2154
&rule->p.arpHdrFilter.dataARPDstIPAddr) < 0)
2157
virBufferAsprintf(&buf,
2159
reverse ? "--arp-ip-src" : "--arp-ip-dst",
2160
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstIPAddr),
2164
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcMACAddr)) {
2165
if (printDataType(vars,
2166
macaddr, sizeof(macaddr),
2167
&rule->p.arpHdrFilter.dataARPSrcMACAddr) < 0)
2170
virBufferAsprintf(&buf,
2172
reverse ? "--arp-mac-dst" : "--arp-mac-src",
2173
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcMACAddr),
2177
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstMACAddr)) {
2178
if (printDataType(vars,
2179
macaddr, sizeof(macaddr),
2180
&rule->p.arpHdrFilter.dataARPDstMACAddr) < 0)
2183
virBufferAsprintf(&buf,
2185
reverse ? "--arp-mac-src" : "--arp-mac-dst",
2186
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstMACAddr),
2190
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataGratuitousARP) &&
2191
rule->p.arpHdrFilter.dataGratuitousARP.u.boolean) {
2192
virBufferAsprintf(&buf,
2193
" %s --arp-gratuitous",
2194
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataGratuitousARP));
2198
case VIR_NWFILTER_RULE_PROTOCOL_IP:
2199
virBufferAsprintf(&buf,
2200
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2203
if (ebtablesHandleEthHdr(&buf,
2205
&rule->p.ipHdrFilter.ethHdr,
2209
virBufferAddLit(&buf,
2212
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr)) {
2213
if (printDataType(vars,
2214
ipaddr, sizeof(ipaddr),
2215
&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr) < 0)
2218
virBufferAsprintf(&buf,
2220
reverse ? "--ip-destination" : "--ip-source",
2221
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr),
2224
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)) {
2225
if (printDataType(vars,
2226
number, sizeof(number),
2227
&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)
2230
virBufferAsprintf(&buf,
2236
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr)) {
2238
if (printDataType(vars,
2239
ipaddr, sizeof(ipaddr),
2240
&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr) < 0)
2243
virBufferAsprintf(&buf,
2245
reverse ? "--ip-source" : "--ip-destination",
2246
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr),
2249
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)) {
2250
if (printDataType(vars,
2251
number, sizeof(number),
2252
&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)
2255
virBufferAsprintf(&buf,
2261
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID)) {
2262
if (printDataType(vars,
2263
number, sizeof(number),
2264
&rule->p.ipHdrFilter.ipHdr.dataProtocolID) < 0)
2267
virBufferAsprintf(&buf,
2268
" --ip-protocol %s %s",
2269
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
2273
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
2275
if (printDataType(vars,
2276
number, sizeof(number),
2277
&rule->p.ipHdrFilter.portData.dataSrcPortStart)
2281
virBufferAsprintf(&buf,
2283
reverse ? "--ip-destination-port" : "--ip-source-port",
2284
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
2287
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
2288
if (printDataType(vars,
2289
number, sizeof(number),
2290
&rule->p.ipHdrFilter.portData.dataSrcPortEnd)
2294
virBufferAsprintf(&buf,
2300
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
2302
if (printDataType(vars,
2303
number, sizeof(number),
2304
&rule->p.ipHdrFilter.portData.dataDstPortStart)
2308
virBufferAsprintf(&buf,
2310
reverse ? "--ip-source-port" : "--ip-destination-port",
2311
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
2314
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
2315
if (printDataType(vars,
2316
number, sizeof(number),
2317
&rule->p.ipHdrFilter.portData.dataDstPortEnd)
2321
virBufferAsprintf(&buf,
2327
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDSCP)) {
2328
if (printDataTypeAsHex(vars,
2329
number, sizeof(number),
2330
&rule->p.ipHdrFilter.ipHdr.dataDSCP) < 0)
2333
virBufferAsprintf(&buf,
2335
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDSCP),
2340
case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
2341
virBufferAsprintf(&buf,
2342
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2345
if (ebtablesHandleEthHdr(&buf,
2347
&rule->p.ipv6HdrFilter.ethHdr,
2351
virBufferAddLit(&buf,
2354
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr)) {
2355
if (printDataType(vars,
2356
ipv6addr, sizeof(ipv6addr),
2357
&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr) < 0)
2360
virBufferAsprintf(&buf,
2362
reverse ? "--ip6-destination" : "--ip6-source",
2363
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr),
2366
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)) {
2367
if (printDataType(vars,
2368
number, sizeof(number),
2369
&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)
2372
virBufferAsprintf(&buf,
2378
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr)) {
2380
if (printDataType(vars,
2381
ipv6addr, sizeof(ipv6addr),
2382
&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr) < 0)
2385
virBufferAsprintf(&buf,
2387
reverse ? "--ip6-source" : "--ip6-destination",
2388
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr),
2391
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)) {
2392
if (printDataType(vars,
2393
number, sizeof(number),
2394
&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)
2397
virBufferAsprintf(&buf,
2403
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID)) {
2404
if (printDataType(vars,
2405
number, sizeof(number),
2406
&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID) < 0)
2409
virBufferAsprintf(&buf,
2410
" --ip6-protocol %s %s",
2411
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID),
2415
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart)) {
2417
if (printDataType(vars,
2418
number, sizeof(number),
2419
&rule->p.ipv6HdrFilter.portData.dataSrcPortStart)
2423
virBufferAsprintf(&buf,
2425
reverse ? "--ip6-destination-port" : "--ip6-source-port",
2426
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart),
2429
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)) {
2430
if (printDataType(vars,
2431
number, sizeof(number),
2432
&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)
2436
virBufferAsprintf(&buf,
2442
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortStart)) {
2444
if (printDataType(vars,
2445
number, sizeof(number),
2446
&rule->p.ipv6HdrFilter.portData.dataDstPortStart)
2450
virBufferAsprintf(&buf,
2452
reverse ? "--ip6-source-port" : "--ip6-destination-port",
2453
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataDstPortStart),
2456
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortEnd)) {
2457
if (printDataType(vars,
2458
number, sizeof(number),
2459
&rule->p.ipv6HdrFilter.portData.dataDstPortEnd)
2463
virBufferAsprintf(&buf,
2470
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
2471
virBufferAsprintf(&buf,
2472
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2480
switch (rule->action) {
2481
case VIR_NWFILTER_RULE_ACTION_REJECT:
2482
/* REJECT not supported */
2483
target = virNWFilterJumpTargetTypeToString(
2484
VIR_NWFILTER_RULE_ACTION_DROP);
2487
target = virNWFilterJumpTargetTypeToString(rule->action);
2490
virBufferAsprintf(&buf,
2491
" -j %s" CMD_DEF_POST CMD_SEPARATOR
2495
if (virBufferError(&buf)) {
2496
virBufferFreeAndReset(&buf);
2497
virReportOOMError();
2501
return ebiptablesAddRuleInst(res,
2502
virBufferContentAndReset(&buf),
2503
nwfilter->chainsuffix,
2504
nwfilter->chainPriority,
2510
virBufferFreeAndReset(&buf);
2517
* ebiptablesCreateRuleInstance:
2518
* @nwfilter : The filter
2519
* @rule: The rule of the filter to convert
2520
* @ifname : The name of the interface to apply the rule to
2521
* @vars : A map containing the variables to resolve
2522
* @res : The data structure to store the result(s) into
2524
* Convert a single rule into its representation for later instantiation
2526
* Returns 0 in case of success with the result stored in the data structure
2527
* pointed to by res, -1 otherwise
2530
ebiptablesCreateRuleInstance(enum virDomainNetType nettype ATTRIBUTE_UNUSED,
2531
virNWFilterDefPtr nwfilter,
2532
virNWFilterRuleDefPtr rule,
2534
virNWFilterVarCombIterPtr vars,
2535
virNWFilterRuleInstPtr res)
2540
switch (rule->prtclType) {
2541
case VIR_NWFILTER_RULE_PROTOCOL_IP:
2542
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
2543
case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
2544
case VIR_NWFILTER_RULE_PROTOCOL_STP:
2545
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
2546
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
2547
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
2548
case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
2550
if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
2551
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
2552
rc = ebtablesCreateRuleInstance(CHAINPREFIX_HOST_IN_TEMP,
2558
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
2563
if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
2564
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
2565
rc = ebtablesCreateRuleInstance(CHAINPREFIX_HOST_OUT_TEMP,
2575
case VIR_NWFILTER_RULE_PROTOCOL_TCP:
2576
case VIR_NWFILTER_RULE_PROTOCOL_UDP:
2577
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
2578
case VIR_NWFILTER_RULE_PROTOCOL_ESP:
2579
case VIR_NWFILTER_RULE_PROTOCOL_AH:
2580
case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
2581
case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
2582
case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
2583
case VIR_NWFILTER_RULE_PROTOCOL_ALL:
2585
rc = iptablesCreateRuleInstance(nwfilter,
2593
case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
2594
case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
2595
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
2596
case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
2597
case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
2598
case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
2599
case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
2600
case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
2602
rc = iptablesCreateRuleInstance(nwfilter,
2610
case VIR_NWFILTER_RULE_PROTOCOL_LAST:
2611
virNWFilterReportError(VIR_ERR_OPERATION_FAILED,
2612
"%s", _("illegal protocol type"));
2621
ebiptablesCreateRuleInstanceIterate(
2622
enum virDomainNetType nettype ATTRIBUTE_UNUSED,
2623
virNWFilterDefPtr nwfilter,
2624
virNWFilterRuleDefPtr rule,
2626
virNWFilterHashTablePtr vars,
2627
virNWFilterRuleInstPtr res)
2630
virNWFilterVarCombIterPtr vciter;
2632
/* rule->vars holds all the variables names that this rule will access.
2633
* iterate over all combinations of the variables' values and instantiate
2634
* the filtering rule with each combination.
2636
vciter = virNWFilterVarCombIterCreate(vars,
2637
rule->varAccess, rule->nVarAccess);
2642
rc = ebiptablesCreateRuleInstance(nettype,
2650
vciter = virNWFilterVarCombIterNext(vciter);
2651
} while (vciter != NULL);
2653
virNWFilterVarCombIterFree(vciter);
2659
ebiptablesFreeRuleInstance(void *_inst)
2661
ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
2667
ebiptablesDisplayRuleInstance(void *_inst)
2669
ebiptablesRuleInstPtr inst = (ebiptablesRuleInstPtr)_inst;
2670
VIR_INFO("Command Template: '%s', Needed protocol: '%s'",
2671
inst->commandTemplate,
2672
inst->neededProtocolChain);
2678
* ebiptablesExecCLI:
2679
* @buf : pointer to virBuffer containing the string with the commands to
2681
* @status: Pointer to an integer for returning the WEXITSTATUS of the
2682
* commands executed via the script the was run.
2683
* @outbuf: Optional pointer to a string that will hold the buffer with
2684
* output of the executed command. The actual buffer holding
2685
* the message will be newly allocated by this function and
2686
* any passed in buffer freed first.
2688
* Returns 0 in case of success, < 0 in case of an error. The returned
2689
* value is NOT the result of running the commands inside the shell
2692
* Execute a sequence of commands (held in the given buffer) as a /bin/sh
2693
* script and return the status of the execution in *status (if status is
2694
* NULL, then the script must exit with status 0).
2697
ebiptablesExecCLI(virBufferPtr buf,
2698
int *status, char **outbuf)
2706
if (!virBufferError(buf) && !virBufferUse(buf))
2712
cmd = virCommandNewArgList("/bin/sh", "-c", NULL);
2713
virCommandAddArgBuffer(cmd, buf);
2715
virCommandSetOutputBuffer(cmd, outbuf);
2717
virMutexLock(&execCLIMutex);
2719
rc = virCommandRun(cmd, status);
2721
virMutexUnlock(&execCLIMutex);
2723
virCommandFree(cmd);
2730
ebtablesCreateTmpRootChain(virBufferPtr buf,
2731
int incoming, const char *ifname,
2734
char chain[MAX_CHAINNAME_LENGTH];
2735
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2736
: CHAINPREFIX_HOST_OUT_TEMP;
2738
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2740
virBufferAsprintf(buf,
2741
CMD_DEF("$EBT -t nat -N %s") CMD_SEPARATOR
2745
CMD_STOPONERR(stopOnError));
2752
ebtablesLinkTmpRootChain(virBufferPtr buf,
2753
int incoming, const char *ifname,
2756
char chain[MAX_CHAINNAME_LENGTH];
2757
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2758
: CHAINPREFIX_HOST_OUT_TEMP;
2759
char iodev = (incoming) ? 'i' : 'o';
2761
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2763
virBufferAsprintf(buf,
2764
CMD_DEF("$EBT -t nat -A %s -%c %s -j %s") CMD_SEPARATOR
2767
(incoming) ? EBTABLES_CHAIN_INCOMING
2768
: EBTABLES_CHAIN_OUTGOING,
2769
iodev, ifname, chain,
2771
CMD_STOPONERR(stopOnError));
2778
_ebtablesRemoveRootChain(virBufferPtr buf,
2779
int incoming, const char *ifname,
2782
char chain[MAX_CHAINNAME_LENGTH];
2785
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2786
: CHAINPREFIX_HOST_OUT_TEMP;
2788
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
2789
: CHAINPREFIX_HOST_OUT;
2791
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2793
virBufferAsprintf(buf,
2794
"$EBT -t nat -F %s" CMD_SEPARATOR
2795
"$EBT -t nat -X %s" CMD_SEPARATOR,
2804
ebtablesRemoveRootChain(virBufferPtr buf,
2805
int incoming, const char *ifname)
2807
return _ebtablesRemoveRootChain(buf, incoming, ifname, 0);
2812
ebtablesRemoveTmpRootChain(virBufferPtr buf,
2813
int incoming, const char *ifname)
2815
return _ebtablesRemoveRootChain(buf, incoming, ifname, 1);
2820
_ebtablesUnlinkRootChain(virBufferPtr buf,
2821
int incoming, const char *ifname,
2824
char chain[MAX_CHAINNAME_LENGTH];
2825
char iodev = (incoming) ? 'i' : 'o';
2829
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2830
: CHAINPREFIX_HOST_OUT_TEMP;
2832
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
2833
: CHAINPREFIX_HOST_OUT;
2836
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2838
virBufferAsprintf(buf,
2839
"$EBT -t nat -D %s -%c %s -j %s" CMD_SEPARATOR,
2840
(incoming) ? EBTABLES_CHAIN_INCOMING
2841
: EBTABLES_CHAIN_OUTGOING,
2842
iodev, ifname, chain);
2849
ebtablesUnlinkRootChain(virBufferPtr buf,
2850
int incoming, const char *ifname)
2852
return _ebtablesUnlinkRootChain(buf, incoming, ifname, 0);
2857
ebtablesUnlinkTmpRootChain(virBufferPtr buf,
2858
int incoming, const char *ifname)
2860
return _ebtablesUnlinkRootChain(buf, incoming, ifname, 1);
2865
ebtablesCreateTmpSubChain(ebiptablesRuleInstPtr *inst,
2866
int *nRuleInstances,
2869
enum l3_proto_idx protoidx,
2870
const char *filtername,
2872
virNWFilterChainPriority priority)
2874
virBuffer buf = VIR_BUFFER_INITIALIZER;
2875
ebiptablesRuleInstPtr tmp = *inst;
2876
size_t count = *nRuleInstances;
2877
char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
2878
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2879
: CHAINPREFIX_HOST_OUT_TEMP;
2880
char *protostr = NULL;
2882
PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
2883
PRINT_CHAIN(chain, chainPrefix, ifname,
2884
(filtername) ? filtername : l3_protocols[protoidx].val);
2887
case L2_PROTO_MAC_IDX:
2888
protostr = strdup("");
2890
case L2_PROTO_STP_IDX:
2891
ignore_value(virAsprintf(&protostr, "-d " NWFILTER_MAC_BGA " "));
2894
ignore_value(virAsprintf(&protostr, "-p 0x%04x ",
2895
l3_protocols[protoidx].attr));
2900
virReportOOMError();
2904
virBufferAsprintf(&buf,
2905
CMD_DEF("$EBT -t nat -F %s") CMD_SEPARATOR
2907
CMD_DEF("$EBT -t nat -X %s") CMD_SEPARATOR
2909
CMD_DEF("$EBT -t nat -N %s") CMD_SEPARATOR
2912
CMD_DEF("$EBT -t nat -%%c %s %%s %s-j %s")
2921
CMD_STOPONERR(stopOnError),
2923
rootchain, protostr, chain,
2925
CMD_STOPONERR(stopOnError));
2929
if (virBufferError(&buf) ||
2930
VIR_EXPAND_N(tmp, count, 1) < 0) {
2931
virReportOOMError();
2932
virBufferFreeAndReset(&buf);
2936
*nRuleInstances = count;
2939
tmp[*nRuleInstances - 1].priority = priority;
2940
tmp[*nRuleInstances - 1].commandTemplate =
2941
virBufferContentAndReset(&buf);
2942
tmp[*nRuleInstances - 1].neededProtocolChain =
2943
virNWFilterChainSuffixTypeToString(VIR_NWFILTER_CHAINSUFFIX_ROOT);
2949
_ebtablesRemoveSubChains(virBufferPtr buf,
2953
char rootchain[MAX_CHAINNAME_LENGTH];
2956
NWFILTER_SET_EBTABLES_SHELLVAR(buf);
2958
virBufferAsprintf(buf, NWFILTER_FUNC_COLLECT_CHAINS,
2960
virBufferAdd(buf, NWFILTER_FUNC_RM_CHAINS, -1);
2962
virBufferAsprintf(buf, NWFILTER_FUNC_SET_IFS);
2963
virBufferAddLit(buf, "chains=\"$(collect_chains");
2964
for (i = 0; chains[i] != 0; i++) {
2965
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
2966
virBufferAsprintf(buf, " %s", rootchain);
2968
virBufferAddLit(buf, ")\"\n");
2970
for (i = 0; chains[i] != 0; i++) {
2971
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
2972
virBufferAsprintf(buf,
2973
"$EBT -t nat -F %s\n",
2976
virBufferAddLit(buf, "rm_chains $chains\n");
2982
ebtablesRemoveSubChains(virBufferPtr buf,
2986
CHAINPREFIX_HOST_IN,
2987
CHAINPREFIX_HOST_OUT,
2991
return _ebtablesRemoveSubChains(buf, ifname, chains);
2995
ebtablesRemoveTmpSubChains(virBufferPtr buf,
2999
CHAINPREFIX_HOST_IN_TEMP,
3000
CHAINPREFIX_HOST_OUT_TEMP,
3004
return _ebtablesRemoveSubChains(buf, ifname, chains);
3008
ebtablesRenameTmpSubChain(virBufferPtr buf,
3011
const char *protocol)
3013
char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
3014
char tmpChainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
3015
: CHAINPREFIX_HOST_OUT_TEMP;
3016
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
3017
: CHAINPREFIX_HOST_OUT;
3020
PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
3021
PRINT_CHAIN( chain, chainPrefix, ifname, protocol);
3023
PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
3024
PRINT_ROOT_CHAIN( chain, chainPrefix, ifname);
3027
virBufferAsprintf(buf,
3028
"$EBT -t nat -E %s %s" CMD_SEPARATOR,
3034
ebtablesRenameTmpRootChain(virBufferPtr buf,
3038
return ebtablesRenameTmpSubChain(buf, incoming, ifname, NULL);
3042
ebtablesRenameTmpSubAndRootChains(virBufferPtr buf,
3045
char rootchain[MAX_CHAINNAME_LENGTH];
3048
CHAINPREFIX_HOST_IN_TEMP,
3049
CHAINPREFIX_HOST_OUT_TEMP,
3052
NWFILTER_SET_EBTABLES_SHELLVAR(buf);
3054
virBufferAsprintf(buf, NWFILTER_FUNC_COLLECT_CHAINS,
3056
virBufferAsprintf(buf, NWFILTER_FUNC_RENAME_CHAINS,
3057
CHAINPREFIX_HOST_IN_TEMP,
3058
CHAINPREFIX_HOST_IN,
3059
CHAINPREFIX_HOST_OUT_TEMP,
3060
CHAINPREFIX_HOST_OUT);
3062
virBufferAsprintf(buf, NWFILTER_FUNC_SET_IFS);
3063
virBufferAddLit(buf, "chains=\"$(collect_chains");
3064
for (i = 0; chains[i] != 0; i++) {
3065
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
3066
virBufferAsprintf(buf, " %s", rootchain);
3068
virBufferAddLit(buf, ")\"\n");
3070
virBufferAddLit(buf, "rename_chains $chains\n");
3072
ebtablesRenameTmpRootChain(buf, 1, ifname);
3073
ebtablesRenameTmpRootChain(buf, 0, ifname);
3079
ebiptablesInstCommand(virBufferPtr buf,
3080
const char *templ, char cmd, int pos,
3083
char position[10] = { 0 };
3085
snprintf(position, sizeof(position), "%d", pos);
3086
virBufferAsprintf(buf, templ, cmd, position);
3087
virBufferAsprintf(buf, CMD_SEPARATOR "%s",
3088
CMD_STOPONERR(stopOnError));
3093
* ebiptablesCanApplyBasicRules
3095
* Determine whether this driver can apply the basic rules, meaning
3096
* run ebtablesApplyBasicRules and ebtablesApplyDHCPOnlyRules.
3097
* In case of this driver we need the ebtables tool available.
3100
ebiptablesCanApplyBasicRules(void) {
3101
return ebtables_cmd_path != NULL;
3105
* ebtablesApplyBasicRules
3107
* @ifname: name of the backend-interface to which to apply the rules
3108
* @macaddr: MAC address the VM is using in packets sent through the
3111
* Returns 0 on success, -1 on failure with the rules removed
3113
* Apply basic filtering rules on the given interface
3114
* - filtering for MAC address spoofing
3115
* - allowing IPv4 & ARP traffic
3118
ebtablesApplyBasicRules(const char *ifname,
3119
const unsigned char *macaddr)
3121
virBuffer buf = VIR_BUFFER_INITIALIZER;
3122
char chain[MAX_CHAINNAME_LENGTH];
3123
char chainPrefix = CHAINPREFIX_HOST_IN_TEMP;
3124
char macaddr_str[VIR_MAC_STRING_BUFLEN];
3126
if (!ebtables_cmd_path) {
3127
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3128
_("cannot create rules since ebtables tool is "
3133
virMacAddrFormat(macaddr, macaddr_str);
3135
ebiptablesAllTeardown(ifname);
3137
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3139
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
3141
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
3142
virBufferAsprintf(&buf,
3143
CMD_DEF("$EBT -t nat -A %s -s ! %s -j DROP") CMD_SEPARATOR
3150
virBufferAsprintf(&buf,
3151
CMD_DEF("$EBT -t nat -A %s -p IPv4 -j ACCEPT") CMD_SEPARATOR
3158
virBufferAsprintf(&buf,
3159
CMD_DEF("$EBT -t nat -A %s -p ARP -j ACCEPT") CMD_SEPARATOR
3166
virBufferAsprintf(&buf,
3167
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3174
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3175
ebtablesRenameTmpRootChain(&buf, 1, ifname);
3177
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
3178
goto tear_down_tmpebchains;
3182
tear_down_tmpebchains:
3183
ebtablesCleanAll(ifname);
3185
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3187
_("Some rules could not be created."));
3194
* ebtablesApplyDHCPOnlyRules
3196
* @ifname: name of the backend-interface to which to apply the rules
3197
* @macaddr: MAC address the VM is using in packets sent through the
3199
* @dhcpsrvrs: The DHCP server(s) from which the VM may receive traffic
3201
* @leaveTemporary: Whether to leave the table names with their temporary
3202
* names (true) or also perform the renaming to their final names as
3203
* part of this call (false)
3205
* Returns 0 on success, -1 on failure with the rules removed
3207
* Apply filtering rules so that the VM can only send and receive
3208
* DHCP traffic and nothing else.
3211
ebtablesApplyDHCPOnlyRules(const char *ifname,
3212
const unsigned char *macaddr,
3213
virNWFilterVarValuePtr dhcpsrvrs,
3214
bool leaveTemporary)
3216
virBuffer buf = VIR_BUFFER_INITIALIZER;
3217
char chain_in [MAX_CHAINNAME_LENGTH],
3218
chain_out[MAX_CHAINNAME_LENGTH];
3219
char macaddr_str[VIR_MAC_STRING_BUFLEN];
3220
unsigned int idx = 0;
3221
unsigned int num_dhcpsrvrs;
3223
if (!ebtables_cmd_path) {
3224
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3225
_("cannot create rules since ebtables tool is "
3230
virMacAddrFormat(macaddr, macaddr_str);
3232
ebiptablesAllTeardown(ifname);
3234
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3236
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
3237
ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
3239
PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
3240
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
3242
virBufferAsprintf(&buf,
3243
CMD_DEF("$EBT -t nat -A %s"
3245
" -p ipv4 --ip-protocol udp"
3246
" --ip-sport 68 --ip-dport 67"
3247
" -j ACCEPT") CMD_SEPARATOR
3255
virBufferAsprintf(&buf,
3256
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3263
num_dhcpsrvrs = (dhcpsrvrs != NULL)
3264
? virNWFilterVarValueGetCardinality(dhcpsrvrs)
3268
char *srcIPParam = NULL;
3270
if (idx < num_dhcpsrvrs) {
3271
const char *dhcpserver;
3273
dhcpserver = virNWFilterVarValueGetNthValue(dhcpsrvrs, idx);
3275
if (virAsprintf(&srcIPParam, "--ip-src %s", dhcpserver) < 0) {
3276
virReportOOMError();
3277
goto tear_down_tmpebchains;
3281
virBufferAsprintf(&buf,
3282
CMD_DEF("$EBT -t nat -A %s"
3284
" -p ipv4 --ip-protocol udp"
3286
" --ip-sport 67 --ip-dport 68"
3287
" -j ACCEPT") CMD_SEPARATOR
3293
srcIPParam != NULL ? srcIPParam : "",
3296
VIR_FREE(srcIPParam);
3298
if (idx == num_dhcpsrvrs)
3304
virBufferAsprintf(&buf,
3305
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3312
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3313
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
3315
if (!leaveTemporary) {
3316
ebtablesRenameTmpRootChain(&buf, 1, ifname);
3317
ebtablesRenameTmpRootChain(&buf, 0, ifname);
3320
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
3321
goto tear_down_tmpebchains;
3325
tear_down_tmpebchains:
3326
ebtablesCleanAll(ifname);
3328
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3330
_("Some rules could not be created."));
3337
* ebtablesApplyDropAllRules
3339
* @ifname: name of the backend-interface to which to apply the rules
3341
* Returns 0 on success, -1 on failure with the rules removed
3343
* Apply filtering rules so that the VM cannot receive or send traffic.
3346
ebtablesApplyDropAllRules(const char *ifname)
3348
virBuffer buf = VIR_BUFFER_INITIALIZER;
3349
char chain_in [MAX_CHAINNAME_LENGTH],
3350
chain_out[MAX_CHAINNAME_LENGTH];
3352
if (!ebtables_cmd_path) {
3353
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3354
_("cannot create rules since ebtables tool is "
3359
ebiptablesAllTeardown(ifname);
3361
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3363
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
3364
ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
3366
PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
3367
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
3369
virBufferAsprintf(&buf,
3370
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3377
virBufferAsprintf(&buf,
3378
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3385
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3386
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
3387
ebtablesRenameTmpRootChain(&buf, 1, ifname);
3388
ebtablesRenameTmpRootChain(&buf, 0, ifname);
3390
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
3391
goto tear_down_tmpebchains;
3395
tear_down_tmpebchains:
3396
ebtablesCleanAll(ifname);
3398
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3400
_("Some rules could not be created."));
3407
ebtablesRemoveBasicRules(const char *ifname)
3409
return ebtablesCleanAll(ifname);
3413
static int ebtablesCleanAll(const char *ifname)
3415
virBuffer buf = VIR_BUFFER_INITIALIZER;
3418
if (!ebtables_cmd_path)
3421
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3423
ebtablesUnlinkRootChain(&buf, 1, ifname);
3424
ebtablesUnlinkRootChain(&buf, 0, ifname);
3425
ebtablesRemoveSubChains(&buf, ifname);
3426
ebtablesRemoveRootChain(&buf, 1, ifname);
3427
ebtablesRemoveRootChain(&buf, 0, ifname);
3429
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3430
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3431
ebtablesRemoveTmpSubChains(&buf, ifname);
3432
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3433
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3435
ebiptablesExecCLI(&buf, &cli_status, NULL);
3441
ebiptablesRuleOrderSort(const void *a, const void *b)
3443
const ebiptablesRuleInstPtr insta = (const ebiptablesRuleInstPtr)a;
3444
const ebiptablesRuleInstPtr instb = (const ebiptablesRuleInstPtr)b;
3445
const char *root = virNWFilterChainSuffixTypeToString(
3446
VIR_NWFILTER_CHAINSUFFIX_ROOT);
3447
bool root_a = STREQ(insta->neededProtocolChain, root);
3448
bool root_b = STREQ(instb->neededProtocolChain, root);
3450
/* ensure root chain commands appear before all others since
3451
we will need them to create the child chains */
3456
return -1; /* a before b */
3459
return 1; /* b before a */
3462
/* priorities are limited to range [-1000, 1000] */
3463
return insta->priority - instb->priority;
3467
ebiptablesRuleOrderSortPtr(const void *a, const void *b)
3469
const ebiptablesRuleInstPtr *insta = a;
3470
const ebiptablesRuleInstPtr *instb = b;
3471
return ebiptablesRuleOrderSort(*insta, *instb);
3475
ebiptablesFilterOrderSort(const virHashKeyValuePairPtr a,
3476
const virHashKeyValuePairPtr b)
3478
/* elements' values has been limited to range [-1000, 1000] */
3479
return *(virNWFilterChainPriority *)a->value -
3480
*(virNWFilterChainPriority *)b->value;
3484
iptablesCheckBridgeNFCallEnabled(bool isIPv6)
3486
static time_t lastReport, lastReportIPv6;
3487
const char *pathname = NULL;
3489
time_t now = time(NULL);
3492
(now - lastReportIPv6) > BRIDGE_NF_CALL_ALERT_INTERVAL ) {
3493
pathname = PROC_BRIDGE_NF_CALL_IP6TABLES;
3494
} else if (now - lastReport > BRIDGE_NF_CALL_ALERT_INTERVAL) {
3495
pathname = PROC_BRIDGE_NF_CALL_IPTABLES;
3499
int fd = open(pathname, O_RDONLY);
3501
if (read(fd, buffer, 1) == 1) {
3502
if (buffer[0] == '0') {
3504
snprintf(msg, sizeof(msg),
3505
_("To enable ip%stables filtering for the VM do "
3509
VIR_WARN("%s", msg);
3511
lastReportIPv6 = now;
3516
VIR_FORCE_CLOSE(fd);
3522
* Given a filtername determine the protocol it is used for evaluating
3523
* We do prefix-matching to determine the protocol.
3525
static enum l3_proto_idx
3526
ebtablesGetProtoIdxByFiltername(const char *filtername)
3528
enum l3_proto_idx idx;
3530
for (idx = 0; idx < L3_PROTO_LAST_IDX; idx++) {
3531
if (STRPREFIX(filtername, l3_protocols[idx].val)) {
3540
ebtablesCreateTmpRootAndSubChains(virBufferPtr buf,
3542
virHashTablePtr chains, int direction,
3543
ebiptablesRuleInstPtr *inst,
3544
int *nRuleInstances)
3547
virHashKeyValuePairPtr filter_names;
3548
const virNWFilterChainPriority *priority;
3550
if (ebtablesCreateTmpRootChain(buf, direction, ifname, 1) < 0)
3553
filter_names = virHashGetItems(chains,
3554
ebiptablesFilterOrderSort);
3555
if (filter_names == NULL)
3558
for (i = 0; filter_names[i].key; i++) {
3559
enum l3_proto_idx idx = ebtablesGetProtoIdxByFiltername(
3560
filter_names[i].key);
3563
priority = (const virNWFilterChainPriority *)filter_names[i].value;
3564
rc = ebtablesCreateTmpSubChain(inst, nRuleInstances,
3565
direction, ifname, idx,
3566
filter_names[i].key, 1,
3572
VIR_FREE(filter_names);
3577
ebiptablesApplyNewRules(const char *ifname,
3583
ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
3584
virBuffer buf = VIR_BUFFER_INITIALIZER;
3585
virHashTablePtr chains_in_set = virHashCreate(10, NULL);
3586
virHashTablePtr chains_out_set = virHashCreate(10, NULL);
3587
bool haveIptables = false;
3588
bool haveIp6tables = false;
3589
ebiptablesRuleInstPtr ebtChains = NULL;
3591
char *errmsg = NULL;
3596
if (!chains_in_set || !chains_out_set) {
3597
virReportOOMError();
3598
goto exit_free_sets;
3601
if (nruleInstances > 1 && inst)
3602
qsort(inst, nruleInstances, sizeof(inst[0]),
3603
ebiptablesRuleOrderSortPtr);
3605
/* scan the rules to see which chains need to be created */
3606
for (i = 0; i < nruleInstances; i++) {
3608
if (inst[i]->ruleType == RT_EBTABLES) {
3609
const char *name = inst[i]->neededProtocolChain;
3610
if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP) {
3611
if (virHashUpdateEntry(chains_in_set, name,
3612
&inst[i]->chainPriority) < 0) {
3613
virReportOOMError();
3614
goto exit_free_sets;
3617
if (virHashUpdateEntry(chains_out_set, name,
3618
&inst[i]->chainPriority) < 0) {
3619
virReportOOMError();
3620
goto exit_free_sets;
3627
/* cleanup whatever may exist */
3628
if (ebtables_cmd_path) {
3629
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3631
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3632
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3633
ebtablesRemoveTmpSubChains(&buf, ifname);
3634
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3635
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3636
ebiptablesExecCLI(&buf, &cli_status, NULL);
3639
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3641
/* create needed chains */
3642
if ((virHashSize(chains_in_set) > 0 &&
3643
ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_in_set , 1,
3644
&ebtChains, &nEbtChains) < 0) ||
3645
(virHashSize(chains_out_set) > 0 &&
3646
ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_out_set, 0,
3647
&ebtChains, &nEbtChains) < 0)) {
3648
goto tear_down_tmpebchains;
3652
qsort(&ebtChains[0], nEbtChains, sizeof(ebtChains[0]),
3653
ebiptablesRuleOrderSort);
3655
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3656
goto tear_down_tmpebchains;
3658
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3660
/* process ebtables commands; interleave commands from filters with
3661
commands for creating and connecting ebtables chains */
3663
for (i = 0; i < nruleInstances; i++) {
3665
switch (inst[i]->ruleType) {
3667
while (j < nEbtChains &&
3668
ebtChains[j].priority <= inst[i]->priority) {
3669
ebiptablesInstCommand(&buf,
3670
ebtChains[j++].commandTemplate,
3673
ebiptablesInstCommand(&buf,
3674
inst[i]->commandTemplate,
3678
haveIptables = true;
3681
haveIp6tables = true;
3686
while (j < nEbtChains)
3687
ebiptablesInstCommand(&buf,
3688
ebtChains[j++].commandTemplate,
3691
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3692
goto tear_down_tmpebchains;
3695
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3697
iptablesUnlinkTmpRootChains(&buf, ifname);
3698
iptablesRemoveTmpRootChains(&buf, ifname);
3700
iptablesCreateBaseChains(&buf);
3702
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3703
goto tear_down_tmpebchains;
3705
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3707
iptablesCreateTmpRootChains(&buf, ifname);
3709
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3710
goto tear_down_tmpiptchains;
3712
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3714
iptablesLinkTmpRootChains(&buf, ifname);
3715
iptablesSetupVirtInPost(&buf, ifname);
3716
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3717
goto tear_down_tmpiptchains;
3719
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3721
for (i = 0; i < nruleInstances; i++) {
3723
if (inst[i]->ruleType == RT_IPTABLES)
3724
iptablesInstCommand(&buf,
3725
inst[i]->commandTemplate,
3729
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3730
goto tear_down_tmpiptchains;
3732
iptablesCheckBridgeNFCallEnabled(false);
3735
if (haveIp6tables) {
3736
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3738
iptablesUnlinkTmpRootChains(&buf, ifname);
3739
iptablesRemoveTmpRootChains(&buf, ifname);
3741
iptablesCreateBaseChains(&buf);
3743
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3744
goto tear_down_tmpiptchains;
3746
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3748
iptablesCreateTmpRootChains(&buf, ifname);
3750
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3751
goto tear_down_tmpip6tchains;
3753
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3755
iptablesLinkTmpRootChains(&buf, ifname);
3756
iptablesSetupVirtInPost(&buf, ifname);
3757
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3758
goto tear_down_tmpip6tchains;
3760
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3762
for (i = 0; i < nruleInstances; i++) {
3763
if (inst[i]->ruleType == RT_IP6TABLES)
3764
iptablesInstCommand(&buf,
3765
inst[i]->commandTemplate,
3769
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3770
goto tear_down_tmpip6tchains;
3772
iptablesCheckBridgeNFCallEnabled(true);
3775
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3777
if (virHashSize(chains_in_set) != 0)
3778
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3779
if (virHashSize(chains_out_set) != 0)
3780
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
3782
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3783
goto tear_down_ebsubchains_and_unlink;
3785
virHashFree(chains_in_set);
3786
virHashFree(chains_out_set);
3788
for (i = 0; i < nEbtChains; i++)
3789
VIR_FREE(ebtChains[i].commandTemplate);
3790
VIR_FREE(ebtChains);
3796
tear_down_ebsubchains_and_unlink:
3797
if (ebtables_cmd_path) {
3798
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3800
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3801
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3804
tear_down_tmpip6tchains:
3805
if (haveIp6tables) {
3806
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3808
iptablesUnlinkTmpRootChains(&buf, ifname);
3809
iptablesRemoveTmpRootChains(&buf, ifname);
3812
tear_down_tmpiptchains:
3814
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3816
iptablesUnlinkTmpRootChains(&buf, ifname);
3817
iptablesRemoveTmpRootChains(&buf, ifname);
3820
tear_down_tmpebchains:
3821
if (ebtables_cmd_path) {
3822
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3824
ebtablesRemoveTmpSubChains(&buf, ifname);
3825
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3826
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3829
ebiptablesExecCLI(&buf, &cli_status, NULL);
3831
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3832
_("Some rules could not be created for "
3833
"interface %s%s%s"),
3836
errmsg ? errmsg : "");
3839
virHashFree(chains_in_set);
3840
virHashFree(chains_out_set);
3842
for (i = 0; i < nEbtChains; i++)
3843
VIR_FREE(ebtChains[i].commandTemplate);
3844
VIR_FREE(ebtChains);
3853
ebiptablesTearNewRules(const char *ifname)
3856
virBuffer buf = VIR_BUFFER_INITIALIZER;
3858
if (iptables_cmd_path) {
3859
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3861
iptablesUnlinkTmpRootChains(&buf, ifname);
3862
iptablesRemoveTmpRootChains(&buf, ifname);
3865
if (ip6tables_cmd_path) {
3866
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3868
iptablesUnlinkTmpRootChains(&buf, ifname);
3869
iptablesRemoveTmpRootChains(&buf, ifname);
3872
if (ebtables_cmd_path) {
3873
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3875
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3876
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3878
ebtablesRemoveTmpSubChains(&buf, ifname);
3879
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3880
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3883
ebiptablesExecCLI(&buf, &cli_status, NULL);
3890
ebiptablesTearOldRules(const char *ifname)
3893
virBuffer buf = VIR_BUFFER_INITIALIZER;
3895
/* switch to new iptables user defined chains */
3896
if (iptables_cmd_path) {
3897
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3899
iptablesUnlinkRootChains(&buf, ifname);
3900
iptablesRemoveRootChains(&buf, ifname);
3902
iptablesRenameTmpRootChains(&buf, ifname);
3903
ebiptablesExecCLI(&buf, &cli_status, NULL);
3906
if (ip6tables_cmd_path) {
3907
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3909
iptablesUnlinkRootChains(&buf, ifname);
3910
iptablesRemoveRootChains(&buf, ifname);
3912
iptablesRenameTmpRootChains(&buf, ifname);
3913
ebiptablesExecCLI(&buf, &cli_status, NULL);
3916
if (ebtables_cmd_path) {
3917
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3919
ebtablesUnlinkRootChain(&buf, 1, ifname);
3920
ebtablesUnlinkRootChain(&buf, 0, ifname);
3922
ebtablesRemoveSubChains(&buf, ifname);
3924
ebtablesRemoveRootChain(&buf, 1, ifname);
3925
ebtablesRemoveRootChain(&buf, 0, ifname);
3927
ebtablesRenameTmpSubAndRootChains(&buf, ifname);
3929
ebiptablesExecCLI(&buf, &cli_status, NULL);
3937
* ebiptablesRemoveRules:
3938
* @ifname : the name of the interface to which the rules apply
3939
* @nRuleInstance : the number of given rules
3940
* @_inst : array of rule instantiation data
3942
* Remove all rules one after the other
3944
* Return 0 on success, -1 if execution of one or more cleanup
3948
ebiptablesRemoveRules(const char *ifname ATTRIBUTE_UNUSED,
3955
virBuffer buf = VIR_BUFFER_INITIALIZER;
3956
ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
3958
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3960
for (i = 0; i < nruleInstances; i++)
3961
ebiptablesInstCommand(&buf,
3962
inst[i]->commandTemplate,
3966
if (ebiptablesExecCLI(&buf, &cli_status, NULL) < 0)
3970
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3972
_("error while executing CLI commands"));
3982
* ebiptablesAllTeardown:
3983
* @ifname : the name of the interface to which the rules apply
3985
* Unconditionally remove all possible user defined tables and rules
3986
* that were created for the given interface (ifname).
3991
ebiptablesAllTeardown(const char *ifname)
3993
virBuffer buf = VIR_BUFFER_INITIALIZER;
3996
if (iptables_cmd_path) {
3997
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3999
iptablesUnlinkRootChains(&buf, ifname);
4000
iptablesClearVirtInPost (&buf, ifname);
4001
iptablesRemoveRootChains(&buf, ifname);
4004
if (ip6tables_cmd_path) {
4005
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
4007
iptablesUnlinkRootChains(&buf, ifname);
4008
iptablesClearVirtInPost (&buf, ifname);
4009
iptablesRemoveRootChains(&buf, ifname);
4012
if (ebtables_cmd_path) {
4013
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
4015
ebtablesUnlinkRootChain(&buf, 1, ifname);
4016
ebtablesUnlinkRootChain(&buf, 0, ifname);
4018
ebtablesRemoveSubChains(&buf, ifname);
4020
ebtablesRemoveRootChain(&buf, 1, ifname);
4021
ebtablesRemoveRootChain(&buf, 0, ifname);
4023
ebiptablesExecCLI(&buf, &cli_status, NULL);
4029
virNWFilterTechDriver ebiptables_driver = {
4030
.name = EBIPTABLES_DRIVER_ID,
4033
.init = ebiptablesDriverInit,
4034
.shutdown = ebiptablesDriverShutdown,
4036
.createRuleInstance = ebiptablesCreateRuleInstanceIterate,
4037
.applyNewRules = ebiptablesApplyNewRules,
4038
.tearNewRules = ebiptablesTearNewRules,
4039
.tearOldRules = ebiptablesTearOldRules,
4040
.allTeardown = ebiptablesAllTeardown,
4041
.removeRules = ebiptablesRemoveRules,
4042
.freeRuleInstance = ebiptablesFreeRuleInstance,
4043
.displayRuleInstance = ebiptablesDisplayRuleInstance,
4045
.canApplyBasicRules = ebiptablesCanApplyBasicRules,
4046
.applyBasicRules = ebtablesApplyBasicRules,
4047
.applyDHCPOnlyRules = ebtablesApplyDHCPOnlyRules,
4048
.applyDropAllRules = ebtablesApplyDropAllRules,
4049
.removeBasicRules = ebtablesRemoveBasicRules,
4054
ebiptablesDriverInit(bool privileged)
4056
virBuffer buf = VIR_BUFFER_INITIALIZER;
4057
char *errmsg = NULL;
4062
if (virMutexInit(&execCLIMutex) < 0)
4065
gawk_cmd_path = virFindFileInPath("gawk");
4066
grep_cmd_path = virFindFileInPath("grep");
4068
ebtables_cmd_path = virFindFileInPath("ebtables");
4069
if (ebtables_cmd_path) {
4070
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
4072
virBufferAsprintf(&buf,
4073
CMD_DEF("$EBT -t nat -L") CMD_SEPARATOR
4078
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
4079
VIR_FREE(ebtables_cmd_path);
4080
VIR_ERROR(_("Testing of ebtables command failed: %s"),
4084
VIR_WARN("Could not find 'ebtables' executable");
4087
iptables_cmd_path = virFindFileInPath("iptables");
4088
if (iptables_cmd_path) {
4089
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
4091
virBufferAsprintf(&buf,
4092
CMD_DEF("$IPT -n -L FORWARD") CMD_SEPARATOR
4097
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
4098
VIR_FREE(iptables_cmd_path);
4099
VIR_ERROR(_("Testing of iptables command failed: %s"),
4103
VIR_WARN("Could not find 'iptables' executable");
4106
ip6tables_cmd_path = virFindFileInPath("ip6tables");
4107
if (ip6tables_cmd_path) {
4108
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
4110
virBufferAsprintf(&buf,
4111
CMD_DEF("$IPT -n -L FORWARD") CMD_SEPARATOR
4116
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
4117
VIR_FREE(ip6tables_cmd_path);
4118
VIR_ERROR(_("Testing of ip6tables command failed: %s"),
4122
VIR_WARN("Could not find 'ip6tables' executable");
4125
/* ip(6)tables support needs gawk & grep, ebtables doesn't */
4126
if ((iptables_cmd_path != NULL || ip6tables_cmd_path != NULL) &&
4127
(!grep_cmd_path || !gawk_cmd_path)) {
4128
VIR_ERROR(_("essential tools to support ip(6)tables "
4129
"firewalls could not be located"));
4130
VIR_FREE(iptables_cmd_path);
4131
VIR_FREE(ip6tables_cmd_path);
4136
if (!ebtables_cmd_path && !iptables_cmd_path && !ip6tables_cmd_path) {
4137
VIR_ERROR(_("firewall tools were not found or cannot be used"));
4138
ebiptablesDriverShutdown();
4142
ebiptables_driver.flags = TECHDRV_FLAG_INITIALIZED;
4149
ebiptablesDriverShutdown(void)
4151
VIR_FREE(gawk_cmd_path);
4152
VIR_FREE(grep_cmd_path);
4153
VIR_FREE(ebtables_cmd_path);
4154
VIR_FREE(iptables_cmd_path);
4155
VIR_FREE(ip6tables_cmd_path);
4156
ebiptables_driver.flags = 0;