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->var);
235
/* error has been reported */
239
if (!virStrcpy(buf, val, bufsize)) {
240
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
241
_("Buffer to small to print MAC address "
254
_printDataType(virNWFilterVarCombIterPtr vars,
255
char *buf, int bufsize,
262
if (printVar(vars, buf, bufsize, item, &done))
268
switch (item->datatype) {
269
case DATATYPE_IPADDR:
270
data = virSocketAddrFormat(&item->u.ipaddr);
273
if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
274
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
275
_("buffer too small for IP address"));
282
case DATATYPE_IPV6ADDR:
283
data = virSocketAddrFormat(&item->u.ipaddr);
287
if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
288
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
289
_("buffer too small for IPv6 address"));
296
case DATATYPE_MACADDR:
297
case DATATYPE_MACMASK:
298
if (bufsize < VIR_MAC_STRING_BUFLEN) {
299
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
300
_("Buffer too small for MAC address"));
304
virFormatMacAddr(item->u.macaddr.addr, buf);
307
case DATATYPE_IPV6MASK:
308
case DATATYPE_IPMASK:
309
if (snprintf(buf, bufsize, "%d",
310
item->u.u8) >= bufsize) {
311
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
312
_("Buffer too small for uint8 type"));
317
case DATATYPE_UINT32:
318
case DATATYPE_UINT32_HEX:
319
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%u",
320
item->u.u32) >= bufsize) {
321
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
322
_("Buffer too small for uint32 type"));
327
case DATATYPE_UINT16:
328
case DATATYPE_UINT16_HEX:
329
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
330
item->u.u16) >= bufsize) {
331
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
332
_("Buffer too small for uint16 type"));
338
case DATATYPE_UINT8_HEX:
339
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
340
item->u.u8) >= bufsize) {
341
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
342
_("Buffer too small for uint8 type"));
348
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
349
_("Unhandled datatype %x"), item->datatype);
359
printDataType(virNWFilterVarCombIterPtr vars,
360
char *buf, int bufsize,
363
return _printDataType(vars, buf, bufsize, item, 0);
368
printDataTypeAsHex(virNWFilterVarCombIterPtr vars,
369
char *buf, int bufsize,
372
return _printDataType(vars, buf, bufsize, item, 1);
377
printCommentVar(virBufferPtr dest, const char *buf)
379
size_t i, len = strlen(buf);
381
virBufferAddLit(dest, COMMENT_VARNAME "='");
383
if (len > IPTABLES_MAX_COMMENT_LENGTH)
384
len = IPTABLES_MAX_COMMENT_LENGTH;
386
for (i = 0; i < len; i++) {
388
virBufferAddLit(dest, "'\\''");
390
virBufferAddChar(dest, buf[i]);
392
virBufferAddLit(dest,"'" CMD_SEPARATOR);
397
ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
402
VIR_FREE(inst->commandTemplate);
408
ebiptablesAddRuleInst(virNWFilterRuleInstPtr res,
409
char *commandTemplate,
410
const char *neededChain,
411
virNWFilterChainPriority chainPriority,
413
virNWFilterRulePriority priority,
414
enum RuleType ruleType)
416
ebiptablesRuleInstPtr inst;
418
if (VIR_ALLOC(inst) < 0) {
423
inst->commandTemplate = commandTemplate;
424
inst->neededProtocolChain = neededChain;
425
inst->chainPriority = chainPriority;
426
inst->chainprefix = chainprefix;
427
inst->priority = priority;
428
inst->ruleType = ruleType;
430
return virNWFilterRuleInstAddData(res, inst);
435
ebtablesHandleEthHdr(virBufferPtr buf,
436
virNWFilterVarCombIterPtr vars,
437
ethHdrDataDefPtr ethHdr,
440
char macaddr[VIR_MAC_STRING_BUFLEN];
442
if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACAddr)) {
443
if (printDataType(vars,
444
macaddr, sizeof(macaddr),
445
ðHdr->dataSrcMACAddr))
448
virBufferAsprintf(buf,
450
reverse ? "-d" : "-s",
451
ENTRY_GET_NEG_SIGN(ðHdr->dataSrcMACAddr),
454
if (HAS_ENTRY_ITEM(ðHdr->dataSrcMACMask)) {
455
if (printDataType(vars,
456
macaddr, sizeof(macaddr),
457
ðHdr->dataSrcMACMask))
460
virBufferAsprintf(buf,
466
if (HAS_ENTRY_ITEM(ðHdr->dataDstMACAddr)) {
467
if (printDataType(vars,
468
macaddr, sizeof(macaddr),
469
ðHdr->dataDstMACAddr))
472
virBufferAsprintf(buf,
474
reverse ? "-s" : "-d",
475
ENTRY_GET_NEG_SIGN(ðHdr->dataDstMACAddr),
478
if (HAS_ENTRY_ITEM(ðHdr->dataDstMACMask)) {
479
if (printDataType(vars,
480
macaddr, sizeof(macaddr),
481
ðHdr->dataDstMACMask))
484
virBufferAsprintf(buf,
493
virBufferFreeAndReset(buf);
499
/************************ iptables support ************************/
501
static int iptablesLinkIPTablesBaseChain(virBufferPtr buf,
503
const char *syschain,
507
virBufferAsprintf(buf,
508
"res=$($IPT -L %s -n --line-number | "
510
"if [ $? -ne 0 ]; then\n"
511
" $IPT -I %s %d -j %s\n"
513
" r=$(echo $res | %s '{print $1}')\n"
514
" if [ \"${r}\" != \"%d\" ]; then\n"
515
" " CMD_DEF("$IPT -I %s %d -j %s") CMD_SEPARATOR
519
" " CMD_DEF("$IPT -D %s ${r}") CMD_SEPARATOR
526
grep_cmd_path, udchain,
528
syschain, pos, udchain,
533
syschain, pos, udchain,
534
CMD_STOPONERR(stopOnError),
537
CMD_STOPONERR(stopOnError));
542
static int iptablesCreateBaseChains(virBufferPtr buf)
544
virBufferAddLit(buf, "$IPT -N " VIRT_IN_CHAIN CMD_SEPARATOR
545
"$IPT -N " VIRT_OUT_CHAIN CMD_SEPARATOR
546
"$IPT -N " VIRT_IN_POST_CHAIN CMD_SEPARATOR
547
"$IPT -N " HOST_IN_CHAIN CMD_SEPARATOR);
548
iptablesLinkIPTablesBaseChain(buf,
549
VIRT_IN_CHAIN , "FORWARD", 1, 1);
550
iptablesLinkIPTablesBaseChain(buf,
551
VIRT_OUT_CHAIN , "FORWARD", 2, 1);
552
iptablesLinkIPTablesBaseChain(buf,
553
VIRT_IN_POST_CHAIN, "FORWARD", 3, 1);
554
iptablesLinkIPTablesBaseChain(buf,
555
HOST_IN_CHAIN , "INPUT" , 1, 1);
562
iptablesCreateTmpRootChain(virBufferPtr buf,
564
int incoming, const char *ifname,
567
char chain[MAX_CHAINNAME_LENGTH];
568
char chainPrefix[2] = {
570
(incoming) ? CHAINPREFIX_HOST_IN_TEMP
571
: CHAINPREFIX_HOST_OUT_TEMP
574
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
576
virBufferAsprintf(buf,
577
CMD_DEF("$IPT -N %s") CMD_SEPARATOR
581
CMD_STOPONERR(stopOnError));
588
iptablesCreateTmpRootChains(virBufferPtr buf,
591
iptablesCreateTmpRootChain(buf, 'F', 0, ifname, 1);
592
iptablesCreateTmpRootChain(buf, 'F', 1, ifname, 1);
593
iptablesCreateTmpRootChain(buf, 'H', 1, ifname, 1);
599
_iptablesRemoveRootChain(virBufferPtr buf,
601
int incoming, const char *ifname,
604
char chain[MAX_CHAINNAME_LENGTH];
605
char chainPrefix[2] = {
610
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
611
: CHAINPREFIX_HOST_OUT_TEMP;
613
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
614
: CHAINPREFIX_HOST_OUT;
616
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
618
virBufferAsprintf(buf,
619
"$IPT -F %s" CMD_SEPARATOR
620
"$IPT -X %s" CMD_SEPARATOR,
629
iptablesRemoveRootChain(virBufferPtr buf,
634
return _iptablesRemoveRootChain(buf, prefix, incoming, ifname, 0);
639
iptablesRemoveTmpRootChain(virBufferPtr buf,
644
return _iptablesRemoveRootChain(buf, prefix,
645
incoming, ifname, 1);
650
iptablesRemoveTmpRootChains(virBufferPtr buf,
653
iptablesRemoveTmpRootChain(buf, 'F', 0, ifname);
654
iptablesRemoveTmpRootChain(buf, 'F', 1, ifname);
655
iptablesRemoveTmpRootChain(buf, 'H', 1, ifname);
661
iptablesRemoveRootChains(virBufferPtr buf,
664
iptablesRemoveRootChain(buf, 'F', 0, ifname);
665
iptablesRemoveRootChain(buf, 'F', 1, ifname);
666
iptablesRemoveRootChain(buf, 'H', 1, ifname);
672
iptablesLinkTmpRootChain(virBufferPtr buf,
673
const char *basechain,
675
int incoming, const char *ifname,
678
char chain[MAX_CHAINNAME_LENGTH];
679
char chainPrefix[2] = {
681
(incoming) ? CHAINPREFIX_HOST_IN_TEMP
682
: CHAINPREFIX_HOST_OUT_TEMP
684
const char *match = (incoming) ? MATCH_PHYSDEV_IN
687
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
689
virBufferAsprintf(buf,
690
CMD_DEF("$IPT -A %s "
691
"%s %s -g %s") CMD_SEPARATOR
695
match, ifname, chain,
697
CMD_STOPONERR(stopOnError));
704
iptablesLinkTmpRootChains(virBufferPtr buf,
707
iptablesLinkTmpRootChain(buf, VIRT_OUT_CHAIN, 'F', 0, ifname, 1);
708
iptablesLinkTmpRootChain(buf, VIRT_IN_CHAIN , 'F', 1, ifname, 1);
709
iptablesLinkTmpRootChain(buf, HOST_IN_CHAIN , 'H', 1, ifname, 1);
716
iptablesSetupVirtInPost(virBufferPtr buf,
719
const char *match = MATCH_PHYSDEV_IN;
720
virBufferAsprintf(buf,
721
"res=$($IPT -n -L " VIRT_IN_POST_CHAIN
722
" | grep \"\\%s %s\")\n"
723
"if [ \"${res}\" = \"\" ]; then "
725
" -A " VIRT_IN_POST_CHAIN
726
" %s %s -j ACCEPT") CMD_SEPARATOR
738
iptablesClearVirtInPost(virBufferPtr buf,
741
const char *match = MATCH_PHYSDEV_IN;
742
virBufferAsprintf(buf,
743
"$IPT -D " VIRT_IN_POST_CHAIN
744
" %s %s -j ACCEPT" CMD_SEPARATOR,
750
_iptablesUnlinkRootChain(virBufferPtr buf,
751
const char *basechain,
753
int incoming, const char *ifname,
756
char chain[MAX_CHAINNAME_LENGTH];
757
char chainPrefix[2] = {
761
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
762
: CHAINPREFIX_HOST_OUT_TEMP;
764
chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
765
: CHAINPREFIX_HOST_OUT;
766
const char *match = (incoming) ? MATCH_PHYSDEV_IN
769
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
771
virBufferAsprintf(buf,
773
"%s %s -g %s" CMD_SEPARATOR,
775
match, ifname, chain);
782
iptablesUnlinkRootChain(virBufferPtr buf,
783
const char *basechain,
785
int incoming, const char *ifname)
787
return _iptablesUnlinkRootChain(buf,
788
basechain, prefix, incoming, ifname, 0);
793
iptablesUnlinkTmpRootChain(virBufferPtr buf,
794
const char *basechain,
796
int incoming, const char *ifname)
798
return _iptablesUnlinkRootChain(buf,
799
basechain, prefix, incoming, ifname, 1);
804
iptablesUnlinkRootChains(virBufferPtr buf,
807
iptablesUnlinkRootChain(buf, VIRT_OUT_CHAIN, 'F', 0, ifname);
808
iptablesUnlinkRootChain(buf, VIRT_IN_CHAIN , 'F', 1, ifname);
809
iptablesUnlinkRootChain(buf, HOST_IN_CHAIN , 'H', 1, ifname);
816
iptablesUnlinkTmpRootChains(virBufferPtr buf,
819
iptablesUnlinkTmpRootChain(buf, VIRT_OUT_CHAIN, 'F', 0, ifname);
820
iptablesUnlinkTmpRootChain(buf, VIRT_IN_CHAIN , 'F', 1, ifname);
821
iptablesUnlinkTmpRootChain(buf, HOST_IN_CHAIN , 'H', 1, ifname);
827
iptablesRenameTmpRootChain(virBufferPtr buf,
832
char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
833
char tmpChainPrefix[2] = {
835
(incoming) ? CHAINPREFIX_HOST_IN_TEMP
836
: CHAINPREFIX_HOST_OUT_TEMP
838
char chainPrefix[2] = {
840
(incoming) ? CHAINPREFIX_HOST_IN
841
: CHAINPREFIX_HOST_OUT
844
PRINT_IPT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
845
PRINT_IPT_ROOT_CHAIN( chain, chainPrefix, ifname);
847
virBufferAsprintf(buf,
848
"$IPT -E %s %s" CMD_SEPARATOR,
856
iptablesRenameTmpRootChains(virBufferPtr buf,
859
iptablesRenameTmpRootChain(buf, 'F', 0, ifname);
860
iptablesRenameTmpRootChain(buf, 'F', 1, ifname);
861
iptablesRenameTmpRootChain(buf, 'H', 1, ifname);
867
iptablesInstCommand(virBufferPtr buf,
868
const char *templ, char cmd, int pos,
871
char position[10] = { 0 };
873
snprintf(position, sizeof(position), "%d", pos);
874
virBufferAsprintf(buf, templ, cmd, position);
875
virBufferAsprintf(buf, CMD_SEPARATOR "%s",
876
CMD_STOPONERR(stopOnError));
881
iptablesHandleSrcMacAddr(virBufferPtr buf,
882
virNWFilterVarCombIterPtr vars,
883
nwItemDescPtr srcMacAddr,
887
char macaddr[VIR_MAC_STRING_BUFLEN];
888
*srcmacskipped = false;
890
if (HAS_ENTRY_ITEM(srcMacAddr)) {
892
*srcmacskipped = true;
896
if (printDataType(vars,
897
macaddr, sizeof(macaddr),
901
virBufferAsprintf(buf,
902
" -m mac %s --mac-source %s",
903
ENTRY_GET_NEG_SIGN(srcMacAddr),
910
virBufferFreeAndReset(buf);
917
iptablesHandleIpHdr(virBufferPtr buf,
918
virBufferPtr afterStateMatch,
919
virNWFilterVarCombIterPtr vars,
920
ipHdrDataDefPtr ipHdr,
922
bool *skipRule, bool *skipMatch,
925
char ipaddr[INET6_ADDRSTRLEN],
926
number[MAX(INT_BUFSIZE_BOUND(uint32_t),
927
INT_BUFSIZE_BOUND(int))];
928
const char *src = "--source";
929
const char *dst = "--destination";
930
const char *srcrange = "--src-range";
931
const char *dstrange = "--dst-range";
933
src = "--destination";
935
srcrange = "--dst-range";
936
dstrange = "--src-range";
939
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPAddr)) {
941
if (printDataType(vars,
942
ipaddr, sizeof(ipaddr),
943
&ipHdr->dataSrcIPAddr))
946
virBufferAsprintf(buf,
948
ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPAddr),
952
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPMask)) {
954
if (printDataType(vars,
955
number, sizeof(number),
956
&ipHdr->dataSrcIPMask))
959
virBufferAsprintf(buf,
963
} else if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPFrom)) {
965
if (printDataType(vars,
966
ipaddr, sizeof(ipaddr),
967
&ipHdr->dataSrcIPFrom))
970
virBufferAsprintf(buf,
971
" -m iprange %s %s %s",
972
ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPFrom),
976
if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPTo)) {
978
if (printDataType(vars,
979
ipaddr, sizeof(ipaddr),
980
&ipHdr->dataSrcIPTo))
983
virBufferAsprintf(buf,
989
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPAddr)) {
991
if (printDataType(vars,
992
ipaddr, sizeof(ipaddr),
993
&ipHdr->dataDstIPAddr))
996
virBufferAsprintf(buf,
998
ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPAddr),
1002
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPMask)) {
1004
if (printDataType(vars,
1005
number, sizeof(number),
1006
&ipHdr->dataDstIPMask))
1009
virBufferAsprintf(buf,
1014
} else if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPFrom)) {
1016
if (printDataType(vars,
1017
ipaddr, sizeof(ipaddr),
1018
&ipHdr->dataDstIPFrom))
1021
virBufferAsprintf(buf,
1022
" -m iprange %s %s %s",
1023
ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPFrom),
1027
if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPTo)) {
1029
if (printDataType(vars,
1030
ipaddr, sizeof(ipaddr),
1031
&ipHdr->dataDstIPTo))
1034
virBufferAsprintf(buf,
1040
if (HAS_ENTRY_ITEM(&ipHdr->dataDSCP)) {
1042
if (printDataType(vars,
1043
number, sizeof(number),
1047
virBufferAsprintf(buf,
1048
" -m dscp %s --dscp %s",
1049
ENTRY_GET_NEG_SIGN(&ipHdr->dataDSCP),
1053
if (HAS_ENTRY_ITEM(&ipHdr->dataConnlimitAbove)) {
1055
/* only support for limit in outgoing dir. */
1058
if (printDataType(vars,
1059
number, sizeof(number),
1060
&ipHdr->dataConnlimitAbove))
1063
/* place connlimit after potential -m state --state ...
1064
since this is the most useful order */
1065
virBufferAsprintf(afterStateMatch,
1066
" -m connlimit %s --connlimit-above %s",
1067
ENTRY_GET_NEG_SIGN(&ipHdr->dataConnlimitAbove),
1073
if (HAS_ENTRY_ITEM(&ipHdr->dataComment)) {
1074
printCommentVar(prefix, ipHdr->dataComment.u.string);
1076
/* keep comments behind everything else -- they are packet eval.
1078
virBufferAddLit(afterStateMatch,
1079
" -m comment --comment \"$" COMMENT_VARNAME "\"");
1085
virBufferFreeAndReset(buf);
1086
virBufferFreeAndReset(afterStateMatch);
1093
iptablesHandlePortData(virBufferPtr buf,
1094
virNWFilterVarCombIterPtr vars,
1095
portDataDefPtr portData,
1099
const char *sport = "--sport";
1100
const char *dport = "--dport";
1106
if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart)) {
1107
if (printDataType(vars,
1108
portstr, sizeof(portstr),
1109
&portData->dataSrcPortStart))
1112
virBufferAsprintf(buf,
1114
ENTRY_GET_NEG_SIGN(&portData->dataSrcPortStart),
1118
if (HAS_ENTRY_ITEM(&portData->dataSrcPortEnd)) {
1119
if (printDataType(vars,
1120
portstr, sizeof(portstr),
1121
&portData->dataSrcPortEnd))
1124
virBufferAsprintf(buf,
1130
if (HAS_ENTRY_ITEM(&portData->dataDstPortStart)) {
1131
if (printDataType(vars,
1132
portstr, sizeof(portstr),
1133
&portData->dataDstPortStart))
1136
virBufferAsprintf(buf,
1138
ENTRY_GET_NEG_SIGN(&portData->dataDstPortStart),
1142
if (HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) {
1143
if (printDataType(vars,
1144
portstr, sizeof(portstr),
1145
&portData->dataDstPortEnd))
1148
virBufferAsprintf(buf,
1162
iptablesEnforceDirection(int directionIn,
1163
virNWFilterRuleDefPtr rule,
1166
if (rule->tt != VIR_NWFILTER_RULE_DIRECTION_INOUT)
1167
virBufferAsprintf(buf, " -m conntrack --ctdir %s",
1168
(directionIn) ? "Original"
1174
* _iptablesCreateRuleInstance:
1175
* @chainPrefix : The prefix to put in front of the name of the chain
1176
* @nwfilter : The filter
1177
* @rule: The rule of the filter to convert
1178
* @ifname : The name of the interface to apply the rule to
1179
* @vars : A map containing the variables to resolve
1180
* @res : The data structure to store the result(s) into
1181
* @match : optional string for state match
1182
* @accept_target : where to jump to on accepted traffic, i.e., "RETURN"
1184
* @isIPv6 : Whether this is an IPv6 rule
1185
* @maySkipICMP : whether this rule may under certain circumstances skip
1186
* the ICMP rule from being created
1188
* Convert a single rule into its representation for later instantiation
1190
* Returns 0 in case of success with the result stored in the data structure
1191
* pointed to by res, != 0 otherwise.
1194
_iptablesCreateRuleInstance(int directionIn,
1195
const char *chainPrefix,
1196
virNWFilterDefPtr nwfilter,
1197
virNWFilterRuleDefPtr rule,
1199
virNWFilterVarCombIterPtr vars,
1200
virNWFilterRuleInstPtr res,
1201
const char *match, bool defMatch,
1202
const char *accept_target,
1206
char chain[MAX_CHAINNAME_LENGTH];
1207
char number[MAX(INT_BUFSIZE_BOUND(uint32_t),
1208
INT_BUFSIZE_BOUND(int))];
1209
virBuffer prefix = VIR_BUFFER_INITIALIZER;
1210
virBuffer buf = VIR_BUFFER_INITIALIZER;
1211
virBuffer afterStateMatch = VIR_BUFFER_INITIALIZER;
1212
virBufferPtr final = NULL;
1214
const char *iptables_cmd = (isIPv6) ? ip6tables_cmd_path
1215
: iptables_cmd_path;
1216
unsigned int bufUsed;
1217
bool srcMacSkipped = false;
1218
bool skipRule = false;
1219
bool skipMatch = false;
1220
bool hasICMPType = false;
1222
if (!iptables_cmd) {
1223
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
1224
_("cannot create rule since %s tool is "
1226
isIPv6 ? "ip6tables" : "iptables");
1230
PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
1232
switch (rule->prtclType) {
1233
case VIR_NWFILTER_RULE_PROTOCOL_TCP:
1234
case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
1235
virBufferAsprintf(&buf,
1236
CMD_DEF_PRE "$IPT -%%c %s %%s",
1239
virBufferAddLit(&buf, " -p tcp");
1241
bufUsed = virBufferUse(&buf);
1243
if (iptablesHandleSrcMacAddr(&buf,
1245
&rule->p.tcpHdrFilter.dataSrcMACAddr,
1250
if (iptablesHandleIpHdr(&buf,
1253
&rule->p.tcpHdrFilter.ipHdr,
1255
&skipRule, &skipMatch,
1259
if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPFlags)) {
1260
virBufferAsprintf(&buf, " %s --tcp-flags ",
1261
ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPFlags));
1262
virNWFilterPrintTCPFlags(&buf,
1263
rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.mask,
1265
rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.flags);
1268
if (iptablesHandlePortData(&buf,
1270
&rule->p.tcpHdrFilter.portData,
1274
if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPOption)) {
1275
if (printDataType(vars,
1276
number, sizeof(number),
1277
&rule->p.tcpHdrFilter.dataTCPOption))
1280
virBufferAsprintf(&buf,
1281
" %s --tcp-option %s",
1282
ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPOption),
1288
case VIR_NWFILTER_RULE_PROTOCOL_UDP:
1289
case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
1290
virBufferAsprintf(&buf,
1291
CMD_DEF_PRE "$IPT -%%c %s %%s",
1294
virBufferAddLit(&buf, " -p udp");
1296
bufUsed = virBufferUse(&buf);
1298
if (iptablesHandleSrcMacAddr(&buf,
1300
&rule->p.udpHdrFilter.dataSrcMACAddr,
1305
if (iptablesHandleIpHdr(&buf,
1308
&rule->p.udpHdrFilter.ipHdr,
1310
&skipRule, &skipMatch,
1314
if (iptablesHandlePortData(&buf,
1316
&rule->p.udpHdrFilter.portData,
1321
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
1322
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
1323
virBufferAsprintf(&buf,
1324
CMD_DEF_PRE "$IPT -%%c %s %%s",
1327
virBufferAddLit(&buf, " -p udplite");
1329
bufUsed = virBufferUse(&buf);
1331
if (iptablesHandleSrcMacAddr(&buf,
1333
&rule->p.udpliteHdrFilter.dataSrcMACAddr,
1338
if (iptablesHandleIpHdr(&buf,
1341
&rule->p.udpliteHdrFilter.ipHdr,
1343
&skipRule, &skipMatch,
1349
case VIR_NWFILTER_RULE_PROTOCOL_ESP:
1350
case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
1351
virBufferAsprintf(&buf,
1352
CMD_DEF_PRE "$IPT -%%c %s %%s",
1355
virBufferAddLit(&buf, " -p esp");
1357
bufUsed = virBufferUse(&buf);
1359
if (iptablesHandleSrcMacAddr(&buf,
1361
&rule->p.espHdrFilter.dataSrcMACAddr,
1366
if (iptablesHandleIpHdr(&buf,
1369
&rule->p.espHdrFilter.ipHdr,
1371
&skipRule, &skipMatch,
1377
case VIR_NWFILTER_RULE_PROTOCOL_AH:
1378
case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
1379
virBufferAsprintf(&buf,
1380
CMD_DEF_PRE "$IPT -%%c %s %%s",
1383
virBufferAddLit(&buf, " -p ah");
1385
bufUsed = virBufferUse(&buf);
1387
if (iptablesHandleSrcMacAddr(&buf,
1389
&rule->p.ahHdrFilter.dataSrcMACAddr,
1394
if (iptablesHandleIpHdr(&buf,
1397
&rule->p.ahHdrFilter.ipHdr,
1399
&skipRule, &skipMatch,
1405
case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
1406
case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
1407
virBufferAsprintf(&buf,
1408
CMD_DEF_PRE "$IPT -%%c %s %%s",
1411
virBufferAddLit(&buf, " -p sctp");
1413
bufUsed = virBufferUse(&buf);
1415
if (iptablesHandleSrcMacAddr(&buf,
1417
&rule->p.sctpHdrFilter.dataSrcMACAddr,
1422
if (iptablesHandleIpHdr(&buf,
1425
&rule->p.sctpHdrFilter.ipHdr,
1427
&skipRule, &skipMatch,
1431
if (iptablesHandlePortData(&buf,
1433
&rule->p.sctpHdrFilter.portData,
1438
case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
1439
case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
1440
virBufferAsprintf(&buf,
1441
CMD_DEF_PRE "$IPT -%%c %s %%s",
1444
if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
1445
virBufferAddLit(&buf, " -p icmp");
1447
virBufferAddLit(&buf, " -p icmpv6");
1449
bufUsed = virBufferUse(&buf);
1451
if (iptablesHandleSrcMacAddr(&buf,
1453
&rule->p.icmpHdrFilter.dataSrcMACAddr,
1458
if (iptablesHandleIpHdr(&buf,
1461
&rule->p.icmpHdrFilter.ipHdr,
1463
&skipRule, &skipMatch,
1467
if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPType)) {
1475
if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
1476
parm = "--icmp-type";
1478
parm = "--icmpv6-type";
1480
if (printDataType(vars,
1481
number, sizeof(number),
1482
&rule->p.icmpHdrFilter.dataICMPType))
1485
virBufferAsprintf(&buf,
1487
ENTRY_GET_NEG_SIGN(&rule->p.icmpHdrFilter.dataICMPType),
1491
if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPCode)) {
1492
if (printDataType(vars,
1493
number, sizeof(number),
1494
&rule->p.icmpHdrFilter.dataICMPCode))
1497
virBufferAsprintf(&buf,
1504
case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
1505
virBufferAsprintf(&buf,
1506
CMD_DEF_PRE "$IPT -%%c %s %%s",
1509
virBufferAddLit(&buf, " -p igmp");
1511
bufUsed = virBufferUse(&buf);
1513
if (iptablesHandleSrcMacAddr(&buf,
1515
&rule->p.igmpHdrFilter.dataSrcMACAddr,
1520
if (iptablesHandleIpHdr(&buf,
1523
&rule->p.igmpHdrFilter.ipHdr,
1525
&skipRule, &skipMatch,
1531
case VIR_NWFILTER_RULE_PROTOCOL_ALL:
1532
case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
1533
virBufferAsprintf(&buf,
1534
CMD_DEF_PRE "$IPT -%%c %s %%s",
1537
virBufferAddLit(&buf, " -p all");
1539
bufUsed = virBufferUse(&buf);
1541
if (iptablesHandleSrcMacAddr(&buf,
1543
&rule->p.allHdrFilter.dataSrcMACAddr,
1548
if (iptablesHandleIpHdr(&buf,
1551
&rule->p.allHdrFilter.ipHdr,
1553
&skipRule, &skipMatch,
1563
if ((srcMacSkipped && bufUsed == virBufferUse(&buf)) ||
1565
virBufferFreeAndReset(&buf);
1566
virBufferFreeAndReset(&prefix);
1570
if (rule->action == VIR_NWFILTER_RULE_ACTION_ACCEPT)
1571
target = accept_target;
1573
target = virNWFilterJumpTargetTypeToString(rule->action);
1574
skipMatch = defMatch;
1577
if (match && !skipMatch)
1578
virBufferAsprintf(&buf, " %s", match);
1580
if (defMatch && match != NULL && !skipMatch && !hasICMPType)
1581
iptablesEnforceDirection(directionIn,
1585
if (virBufferError(&afterStateMatch)) {
1586
virBufferFreeAndReset(&buf);
1587
virBufferFreeAndReset(&prefix);
1588
virBufferFreeAndReset(&afterStateMatch);
1589
virReportOOMError();
1593
if (virBufferUse(&afterStateMatch)) {
1594
char *s = virBufferContentAndReset(&afterStateMatch);
1596
virBufferAdd(&buf, s, -1);
1601
virBufferAsprintf(&buf,
1602
" -j %s" CMD_DEF_POST CMD_SEPARATOR
1606
if (virBufferError(&buf) || virBufferError(&prefix)) {
1607
virBufferFreeAndReset(&buf);
1608
virBufferFreeAndReset(&prefix);
1609
virReportOOMError();
1613
if (virBufferUse(&prefix)) {
1614
char *s = virBufferContentAndReset(&buf);
1616
virBufferAdd(&prefix, s, -1);
1622
if (virBufferError(&prefix)) {
1623
virBufferFreeAndReset(&prefix);
1624
virReportOOMError();
1631
return ebiptablesAddRuleInst(res,
1632
virBufferContentAndReset(final),
1633
nwfilter->chainsuffix,
1634
nwfilter->chainPriority,
1637
(isIPv6) ? RT_IP6TABLES : RT_IPTABLES);
1641
virBufferFreeAndReset(&buf);
1642
virBufferFreeAndReset(&prefix);
1643
virBufferFreeAndReset(&afterStateMatch);
1648
virBufferFreeAndReset(&buf);
1649
virBufferFreeAndReset(&prefix);
1650
virBufferFreeAndReset(&afterStateMatch);
1657
printStateMatchFlags(int32_t flags, char **bufptr)
1659
virBuffer buf = VIR_BUFFER_INITIALIZER;
1660
virNWFilterPrintStateMatchFlags(&buf,
1661
"-m state --state ",
1664
if (virBufferError(&buf)) {
1665
virBufferFreeAndReset(&buf);
1666
virReportOOMError();
1669
*bufptr = virBufferContentAndReset(&buf);
1674
iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter,
1675
virNWFilterRuleDefPtr rule,
1677
virNWFilterVarCombIterPtr vars,
1678
virNWFilterRuleInstPtr res,
1682
int directionIn = 0;
1683
char chainPrefix[2];
1684
bool maySkipICMP, inout = false;
1685
char *matchState = NULL;
1688
if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
1689
(rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
1691
inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
1694
chainPrefix[0] = 'F';
1696
maySkipICMP = directionIn || inout;
1701
if (directionIn && !inout) {
1702
if ((rule->flags & IPTABLES_STATE_FLAGS))
1706
if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
1707
if (printStateMatchFlags(rule->flags, &matchState))
1711
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1713
rc = _iptablesCreateRuleInstance(directionIn,
1725
VIR_FREE(matchState);
1730
maySkipICMP = !directionIn || inout;
1734
if ((rule->flags & IPTABLES_STATE_FLAGS))
1738
if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
1739
if (printStateMatchFlags(rule->flags, &matchState))
1743
chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
1745
rc = _iptablesCreateRuleInstance(!directionIn,
1757
VIR_FREE(matchState);
1763
maySkipICMP = directionIn;
1767
if (directionIn && !inout) {
1768
if ((rule->flags & IPTABLES_STATE_FLAGS))
1771
if ((rule->flags & IPTABLES_STATE_FLAGS)) {
1772
if (printStateMatchFlags(rule->flags, &matchState))
1778
chainPrefix[0] = 'H';
1779
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1780
rc = _iptablesCreateRuleInstance(directionIn,
1791
VIR_FREE(matchState);
1799
iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
1800
virNWFilterRuleDefPtr rule,
1802
virNWFilterVarCombIterPtr vars,
1803
virNWFilterRuleInstPtr res,
1807
int directionIn = 0;
1808
char chainPrefix[2];
1810
bool maySkipICMP, inout = false;
1811
const char *matchState;
1813
if (!(rule->flags & RULE_FLAG_NO_STATEMATCH) &&
1814
(rule->flags & IPTABLES_STATE_FLAGS)) {
1815
return iptablesCreateRuleInstanceStateCtrl(nwfilter,
1823
if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
1824
(rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
1826
inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
1831
if ((rule->flags & RULE_FLAG_NO_STATEMATCH))
1834
chainPrefix[0] = 'F';
1836
maySkipICMP = directionIn || inout;
1839
matchState = directionIn ? MATCH_STATE_IN : MATCH_STATE_OUT;
1843
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1844
rc = _iptablesCreateRuleInstance(directionIn,
1859
maySkipICMP = !directionIn || inout;
1861
matchState = directionIn ? MATCH_STATE_OUT : MATCH_STATE_IN;
1865
chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
1866
rc = _iptablesCreateRuleInstance(!directionIn,
1880
maySkipICMP = directionIn;
1882
matchState = directionIn ? MATCH_STATE_IN : MATCH_STATE_OUT;
1886
chainPrefix[0] = 'H';
1887
chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
1888
rc = _iptablesCreateRuleInstance(directionIn,
1907
* ebtablesCreateRuleInstance:
1908
* @chainPrefix : The prefix to put in front of the name of the chain
1909
* @nwfilter : The filter
1910
* @rule: The rule of the filter to convert
1911
* @ifname : The name of the interface to apply the rule to
1912
* @vars : A map containing the variables to resolve
1913
* @res : The data structure to store the result(s) into
1914
* @reverse : Whether to reverse src and dst attributes
1916
* Convert a single rule into its representation for later instantiation
1918
* Returns 0 in case of success with the result stored in the data structure
1919
* pointed to by res, != 0 otherwise.
1922
ebtablesCreateRuleInstance(char chainPrefix,
1923
virNWFilterDefPtr nwfilter,
1924
virNWFilterRuleDefPtr rule,
1926
virNWFilterVarCombIterPtr vars,
1927
virNWFilterRuleInstPtr res,
1930
char macaddr[VIR_MAC_STRING_BUFLEN],
1931
ipaddr[INET_ADDRSTRLEN],
1932
ipv6addr[INET6_ADDRSTRLEN],
1933
number[MAX(INT_BUFSIZE_BOUND(uint32_t),
1934
INT_BUFSIZE_BOUND(int))],
1935
field[MAX(VIR_MAC_STRING_BUFLEN, INET6_ADDRSTRLEN)];
1936
char chain[MAX_CHAINNAME_LENGTH];
1937
virBuffer buf = VIR_BUFFER_INITIALIZER;
1940
if (!ebtables_cmd_path) {
1941
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
1942
_("cannot create rule since ebtables tool is "
1947
if (STREQ(nwfilter->chainsuffix,
1948
virNWFilterChainSuffixTypeToString(
1949
VIR_NWFILTER_CHAINSUFFIX_ROOT)))
1950
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
1952
PRINT_CHAIN(chain, chainPrefix, ifname,
1953
nwfilter->chainsuffix);
1956
switch (rule->prtclType) {
1957
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
1959
virBufferAsprintf(&buf,
1960
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
1963
if (ebtablesHandleEthHdr(&buf,
1965
&rule->p.ethHdrFilter.ethHdr,
1969
if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
1970
if (printDataTypeAsHex(vars,
1971
number, sizeof(number),
1972
&rule->p.ethHdrFilter.dataProtocolID))
1974
virBufferAsprintf(&buf,
1976
ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
1981
case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
1983
virBufferAsprintf(&buf,
1984
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
1988
if (ebtablesHandleEthHdr(&buf,
1990
&rule->p.vlanHdrFilter.ethHdr,
1994
virBufferAddLit(&buf,
1997
#define INST_ITEM(STRUCT, ITEM, CLI) \
1998
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
1999
if (printDataType(vars, \
2000
field, sizeof(field), \
2001
&rule->p.STRUCT.ITEM)) \
2003
virBufferAsprintf(&buf, \
2005
ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
2009
#define INST_ITEM_2PARMS(STRUCT, ITEM, ITEM_HI, CLI, SEP) \
2010
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM)) { \
2011
if (printDataType(vars, \
2012
field, sizeof(field), \
2013
&rule->p.STRUCT.ITEM)) \
2015
virBufferAsprintf(&buf, \
2017
ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
2019
if (HAS_ENTRY_ITEM(&rule->p.STRUCT.ITEM_HI)) { \
2020
if (printDataType(vars, \
2021
field, sizeof(field), \
2022
&rule->p.STRUCT.ITEM_HI)) \
2024
virBufferAsprintf(&buf, SEP "%s", field); \
2027
#define INST_ITEM_RANGE(S, I, I_HI, C) \
2028
INST_ITEM_2PARMS(S, I, I_HI, C, ":")
2029
#define INST_ITEM_MASK(S, I, MASK, C) \
2030
INST_ITEM_2PARMS(S, I, MASK, C, "/")
2032
INST_ITEM(vlanHdrFilter, dataVlanID, "--vlan-id")
2033
INST_ITEM(vlanHdrFilter, dataVlanEncap, "--vlan-encap")
2036
case VIR_NWFILTER_RULE_PROTOCOL_STP:
2038
/* cannot handle inout direction with srcmask set in reverse dir.
2039
since this clashes with -d below... */
2041
HAS_ENTRY_ITEM(&rule->p.stpHdrFilter.ethHdr.dataSrcMACAddr)) {
2042
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
2043
_("STP filtering in %s direction with "
2044
"source MAC address set is not supported"),
2045
virNWFilterRuleDirectionTypeToString(
2046
VIR_NWFILTER_RULE_DIRECTION_INOUT));
2050
virBufferAsprintf(&buf,
2051
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2055
if (ebtablesHandleEthHdr(&buf,
2057
&rule->p.stpHdrFilter.ethHdr,
2061
virBufferAddLit(&buf, " -d " NWFILTER_MAC_BGA);
2063
INST_ITEM(stpHdrFilter, dataType, "--stp-type")
2064
INST_ITEM(stpHdrFilter, dataFlags, "--stp-flags")
2065
INST_ITEM_RANGE(stpHdrFilter, dataRootPri, dataRootPriHi,
2067
INST_ITEM_MASK( stpHdrFilter, dataRootAddr, dataRootAddrMask,
2069
INST_ITEM_RANGE(stpHdrFilter, dataRootCost, dataRootCostHi,
2071
INST_ITEM_RANGE(stpHdrFilter, dataSndrPrio, dataSndrPrioHi,
2072
"--stp-sender-prio");
2073
INST_ITEM_MASK( stpHdrFilter, dataSndrAddr, dataSndrAddrMask,
2074
"--stp-sender-addr");
2075
INST_ITEM_RANGE(stpHdrFilter, dataPort, dataPortHi, "--stp-port");
2076
INST_ITEM_RANGE(stpHdrFilter, dataAge, dataAgeHi, "--stp-msg-age");
2077
INST_ITEM_RANGE(stpHdrFilter, dataMaxAge, dataMaxAgeHi,
2079
INST_ITEM_RANGE(stpHdrFilter, dataHelloTime, dataHelloTimeHi,
2080
"--stp-hello-time");
2081
INST_ITEM_RANGE(stpHdrFilter, dataFwdDelay, dataFwdDelayHi,
2082
"--stp-forward-delay");
2085
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
2086
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
2088
virBufferAsprintf(&buf,
2089
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2092
if (ebtablesHandleEthHdr(&buf,
2094
&rule->p.arpHdrFilter.ethHdr,
2098
virBufferAsprintf(&buf, " -p 0x%x",
2099
(rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ARP)
2100
? l3_protocols[L3_PROTO_ARP_IDX].attr
2101
: l3_protocols[L3_PROTO_RARP_IDX].attr);
2103
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
2104
if (printDataType(vars,
2105
number, sizeof(number),
2106
&rule->p.arpHdrFilter.dataHWType))
2108
virBufferAsprintf(&buf,
2109
" --arp-htype %s %s",
2110
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
2114
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
2115
if (printDataType(vars,
2116
number, sizeof(number),
2117
&rule->p.arpHdrFilter.dataOpcode))
2119
virBufferAsprintf(&buf,
2120
" --arp-opcode %s %s",
2121
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
2125
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
2126
if (printDataTypeAsHex(vars,
2127
number, sizeof(number),
2128
&rule->p.arpHdrFilter.dataProtocolType))
2130
virBufferAsprintf(&buf,
2131
" --arp-ptype %s %s",
2132
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
2136
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
2137
if (printDataType(vars,
2138
ipaddr, sizeof(ipaddr),
2139
&rule->p.arpHdrFilter.dataARPSrcIPAddr))
2142
virBufferAsprintf(&buf,
2144
reverse ? "--arp-ip-dst" : "--arp-ip-src",
2145
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcIPAddr),
2149
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPAddr)) {
2150
if (printDataType(vars,
2151
ipaddr, sizeof(ipaddr),
2152
&rule->p.arpHdrFilter.dataARPDstIPAddr))
2155
virBufferAsprintf(&buf,
2157
reverse ? "--arp-ip-src" : "--arp-ip-dst",
2158
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstIPAddr),
2162
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcMACAddr)) {
2163
if (printDataType(vars,
2164
macaddr, sizeof(macaddr),
2165
&rule->p.arpHdrFilter.dataARPSrcMACAddr))
2168
virBufferAsprintf(&buf,
2170
reverse ? "--arp-mac-dst" : "--arp-mac-src",
2171
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcMACAddr),
2175
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstMACAddr)) {
2176
if (printDataType(vars,
2177
macaddr, sizeof(macaddr),
2178
&rule->p.arpHdrFilter.dataARPDstMACAddr))
2181
virBufferAsprintf(&buf,
2183
reverse ? "--arp-mac-src" : "--arp-mac-dst",
2184
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstMACAddr),
2188
if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataGratuitousARP) &&
2189
rule->p.arpHdrFilter.dataGratuitousARP.u.boolean) {
2190
virBufferAsprintf(&buf,
2191
" %s --arp-gratuitous",
2192
ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataGratuitousARP));
2196
case VIR_NWFILTER_RULE_PROTOCOL_IP:
2197
virBufferAsprintf(&buf,
2198
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2201
if (ebtablesHandleEthHdr(&buf,
2203
&rule->p.ipHdrFilter.ethHdr,
2207
virBufferAddLit(&buf,
2210
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr)) {
2211
if (printDataType(vars,
2212
ipaddr, sizeof(ipaddr),
2213
&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr))
2216
virBufferAsprintf(&buf,
2218
reverse ? "--ip-destination" : "--ip-source",
2219
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr),
2222
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)) {
2223
if (printDataType(vars,
2224
number, sizeof(number),
2225
&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask))
2227
virBufferAsprintf(&buf,
2233
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr)) {
2235
if (printDataType(vars,
2236
ipaddr, sizeof(ipaddr),
2237
&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr))
2240
virBufferAsprintf(&buf,
2242
reverse ? "--ip-source" : "--ip-destination",
2243
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr),
2246
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)) {
2247
if (printDataType(vars,
2248
number, sizeof(number),
2249
&rule->p.ipHdrFilter.ipHdr.dataDstIPMask))
2251
virBufferAsprintf(&buf,
2257
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataProtocolID)) {
2258
if (printDataType(vars,
2259
number, sizeof(number),
2260
&rule->p.ipHdrFilter.ipHdr.dataProtocolID))
2263
virBufferAsprintf(&buf,
2264
" --ip-protocol %s %s",
2265
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
2269
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
2271
if (printDataType(vars,
2272
number, sizeof(number),
2273
&rule->p.ipHdrFilter.portData.dataSrcPortStart))
2276
virBufferAsprintf(&buf,
2278
reverse ? "--ip-destination-port" : "--ip-source-port",
2279
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
2282
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
2283
if (printDataType(vars,
2284
number, sizeof(number),
2285
&rule->p.ipHdrFilter.portData.dataSrcPortEnd))
2288
virBufferAsprintf(&buf,
2294
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
2296
if (printDataType(vars,
2297
number, sizeof(number),
2298
&rule->p.ipHdrFilter.portData.dataDstPortStart))
2301
virBufferAsprintf(&buf,
2303
reverse ? "--ip-source-port" : "--ip-destination-port",
2304
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
2307
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
2308
if (printDataType(vars,
2309
number, sizeof(number),
2310
&rule->p.ipHdrFilter.portData.dataDstPortEnd))
2313
virBufferAsprintf(&buf,
2319
if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDSCP)) {
2320
if (printDataTypeAsHex(vars,
2321
number, sizeof(number),
2322
&rule->p.ipHdrFilter.ipHdr.dataDSCP))
2325
virBufferAsprintf(&buf,
2327
ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDSCP),
2332
case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
2333
virBufferAsprintf(&buf,
2334
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2337
if (ebtablesHandleEthHdr(&buf,
2339
&rule->p.ipv6HdrFilter.ethHdr,
2343
virBufferAddLit(&buf,
2346
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr)) {
2347
if (printDataType(vars,
2348
ipv6addr, sizeof(ipv6addr),
2349
&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr))
2352
virBufferAsprintf(&buf,
2354
reverse ? "--ip6-destination" : "--ip6-source",
2355
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr),
2358
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)) {
2359
if (printDataType(vars,
2360
number, sizeof(number),
2361
&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask))
2363
virBufferAsprintf(&buf,
2369
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr)) {
2371
if (printDataType(vars,
2372
ipv6addr, sizeof(ipv6addr),
2373
&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr))
2376
virBufferAsprintf(&buf,
2378
reverse ? "--ip6-source" : "--ip6-destination",
2379
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr),
2382
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)) {
2383
if (printDataType(vars,
2384
number, sizeof(number),
2385
&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask))
2387
virBufferAsprintf(&buf,
2393
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID)) {
2394
if (printDataType(vars,
2395
number, sizeof(number),
2396
&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID))
2399
virBufferAsprintf(&buf,
2400
" --ip6-protocol %s %s",
2401
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID),
2405
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart)) {
2407
if (printDataType(vars,
2408
number, sizeof(number),
2409
&rule->p.ipv6HdrFilter.portData.dataSrcPortStart))
2412
virBufferAsprintf(&buf,
2414
reverse ? "--ip6-destination-port" : "--ip6-source-port",
2415
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart),
2418
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)) {
2419
if (printDataType(vars,
2420
number, sizeof(number),
2421
&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd))
2424
virBufferAsprintf(&buf,
2430
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortStart)) {
2432
if (printDataType(vars,
2433
number, sizeof(number),
2434
&rule->p.ipv6HdrFilter.portData.dataDstPortStart))
2437
virBufferAsprintf(&buf,
2439
reverse ? "--ip6-source-port" : "--ip6-destination-port",
2440
ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataDstPortStart),
2443
if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortEnd)) {
2444
if (printDataType(vars,
2445
number, sizeof(number),
2446
&rule->p.ipv6HdrFilter.portData.dataDstPortEnd))
2449
virBufferAsprintf(&buf,
2456
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
2457
virBufferAsprintf(&buf,
2458
CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
2466
switch (rule->action) {
2467
case VIR_NWFILTER_RULE_ACTION_REJECT:
2468
/* REJECT not supported */
2469
target = virNWFilterJumpTargetTypeToString(
2470
VIR_NWFILTER_RULE_ACTION_DROP);
2473
target = virNWFilterJumpTargetTypeToString(rule->action);
2476
virBufferAsprintf(&buf,
2477
" -j %s" CMD_DEF_POST CMD_SEPARATOR
2481
if (virBufferError(&buf)) {
2482
virBufferFreeAndReset(&buf);
2483
virReportOOMError();
2487
return ebiptablesAddRuleInst(res,
2488
virBufferContentAndReset(&buf),
2489
nwfilter->chainsuffix,
2490
nwfilter->chainPriority,
2496
virBufferFreeAndReset(&buf);
2503
* ebiptablesCreateRuleInstance:
2504
* @nwfilter : The filter
2505
* @rule: The rule of the filter to convert
2506
* @ifname : The name of the interface to apply the rule to
2507
* @vars : A map containing the variables to resolve
2508
* @res : The data structure to store the result(s) into
2510
* Convert a single rule into its representation for later instantiation
2512
* Returns 0 in case of success with the result stored in the data structure
2513
* pointed to by res, != 0 otherwise.
2516
ebiptablesCreateRuleInstance(enum virDomainNetType nettype ATTRIBUTE_UNUSED,
2517
virNWFilterDefPtr nwfilter,
2518
virNWFilterRuleDefPtr rule,
2520
virNWFilterVarCombIterPtr vars,
2521
virNWFilterRuleInstPtr res)
2526
switch (rule->prtclType) {
2527
case VIR_NWFILTER_RULE_PROTOCOL_IP:
2528
case VIR_NWFILTER_RULE_PROTOCOL_MAC:
2529
case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
2530
case VIR_NWFILTER_RULE_PROTOCOL_STP:
2531
case VIR_NWFILTER_RULE_PROTOCOL_ARP:
2532
case VIR_NWFILTER_RULE_PROTOCOL_RARP:
2533
case VIR_NWFILTER_RULE_PROTOCOL_NONE:
2534
case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
2536
if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
2537
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
2538
rc = ebtablesCreateRuleInstance(CHAINPREFIX_HOST_IN_TEMP,
2544
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
2549
if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
2550
rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
2551
rc = ebtablesCreateRuleInstance(CHAINPREFIX_HOST_OUT_TEMP,
2561
case VIR_NWFILTER_RULE_PROTOCOL_TCP:
2562
case VIR_NWFILTER_RULE_PROTOCOL_UDP:
2563
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
2564
case VIR_NWFILTER_RULE_PROTOCOL_ESP:
2565
case VIR_NWFILTER_RULE_PROTOCOL_AH:
2566
case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
2567
case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
2568
case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
2569
case VIR_NWFILTER_RULE_PROTOCOL_ALL:
2571
rc = iptablesCreateRuleInstance(nwfilter,
2579
case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
2580
case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
2581
case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
2582
case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
2583
case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
2584
case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
2585
case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
2586
case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
2588
rc = iptablesCreateRuleInstance(nwfilter,
2596
case VIR_NWFILTER_RULE_PROTOCOL_LAST:
2597
virNWFilterReportError(VIR_ERR_OPERATION_FAILED,
2598
"%s", _("illegal protocol type"));
2607
ebiptablesCreateRuleInstanceIterate(
2608
enum virDomainNetType nettype ATTRIBUTE_UNUSED,
2609
virNWFilterDefPtr nwfilter,
2610
virNWFilterRuleDefPtr rule,
2612
virNWFilterHashTablePtr vars,
2613
virNWFilterRuleInstPtr res)
2616
virNWFilterVarCombIterPtr vciter;
2618
/* rule->vars holds all the variables names that this rule will access.
2619
* iterate over all combinations of the variables' values and instantiate
2620
* the filtering rule with each combination.
2622
vciter = virNWFilterVarCombIterCreate(vars, rule->vars, rule->nvars);
2627
rc = ebiptablesCreateRuleInstance(nettype,
2635
vciter = virNWFilterVarCombIterNext(vciter);
2636
} while (vciter != NULL);
2638
virNWFilterVarCombIterFree(vciter);
2644
ebiptablesFreeRuleInstance(void *_inst)
2646
ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
2652
ebiptablesDisplayRuleInstance(void *_inst)
2654
ebiptablesRuleInstPtr inst = (ebiptablesRuleInstPtr)_inst;
2655
VIR_INFO("Command Template: '%s', Needed protocol: '%s'",
2656
inst->commandTemplate,
2657
inst->neededProtocolChain);
2663
* ebiptablesExecCLI:
2664
* @buf : pointer to virBuffer containing the string with the commands to
2666
* @status: Pointer to an integer for returning the WEXITSTATUS of the
2667
* commands executed via the script the was run.
2668
* @outbuf: Optional pointer to a string that will hold the buffer with
2669
* output of the executed command. The actual buffer holding
2670
* the message will be newly allocated by this function and
2671
* any passed in buffer freed first.
2673
* Returns 0 in case of success, < 0 in case of an error. The returned
2674
* value is NOT the result of running the commands inside the shell
2677
* Execute a sequence of commands (held in the given buffer) as a /bin/sh
2678
* script and return the status of the execution in *status (if status is
2679
* NULL, then the script must exit with status 0).
2682
ebiptablesExecCLI(virBufferPtr buf,
2683
int *status, char **outbuf)
2691
if (!virBufferError(buf) && !virBufferUse(buf))
2697
cmd = virCommandNewArgList("/bin/sh", "-c", NULL);
2698
virCommandAddArgBuffer(cmd, buf);
2700
virCommandSetOutputBuffer(cmd, outbuf);
2702
virMutexLock(&execCLIMutex);
2704
rc = virCommandRun(cmd, status);
2706
virMutexUnlock(&execCLIMutex);
2708
virCommandFree(cmd);
2715
ebtablesCreateTmpRootChain(virBufferPtr buf,
2716
int incoming, const char *ifname,
2719
char chain[MAX_CHAINNAME_LENGTH];
2720
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2721
: CHAINPREFIX_HOST_OUT_TEMP;
2723
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2725
virBufferAsprintf(buf,
2726
CMD_DEF("$EBT -t nat -N %s") CMD_SEPARATOR
2730
CMD_STOPONERR(stopOnError));
2737
ebtablesLinkTmpRootChain(virBufferPtr buf,
2738
int incoming, const char *ifname,
2741
char chain[MAX_CHAINNAME_LENGTH];
2742
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2743
: CHAINPREFIX_HOST_OUT_TEMP;
2744
char iodev = (incoming) ? 'i' : 'o';
2746
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2748
virBufferAsprintf(buf,
2749
CMD_DEF("$EBT -t nat -A %s -%c %s -j %s") CMD_SEPARATOR
2752
(incoming) ? EBTABLES_CHAIN_INCOMING
2753
: EBTABLES_CHAIN_OUTGOING,
2754
iodev, ifname, chain,
2756
CMD_STOPONERR(stopOnError));
2763
_ebtablesRemoveRootChain(virBufferPtr buf,
2764
int incoming, const char *ifname,
2767
char chain[MAX_CHAINNAME_LENGTH];
2770
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2771
: CHAINPREFIX_HOST_OUT_TEMP;
2773
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
2774
: CHAINPREFIX_HOST_OUT;
2776
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2778
virBufferAsprintf(buf,
2779
"$EBT -t nat -F %s" CMD_SEPARATOR
2780
"$EBT -t nat -X %s" CMD_SEPARATOR,
2789
ebtablesRemoveRootChain(virBufferPtr buf,
2790
int incoming, const char *ifname)
2792
return _ebtablesRemoveRootChain(buf, incoming, ifname, 0);
2797
ebtablesRemoveTmpRootChain(virBufferPtr buf,
2798
int incoming, const char *ifname)
2800
return _ebtablesRemoveRootChain(buf, incoming, ifname, 1);
2805
_ebtablesUnlinkRootChain(virBufferPtr buf,
2806
int incoming, const char *ifname,
2809
char chain[MAX_CHAINNAME_LENGTH];
2810
char iodev = (incoming) ? 'i' : 'o';
2814
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2815
: CHAINPREFIX_HOST_OUT_TEMP;
2817
chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
2818
: CHAINPREFIX_HOST_OUT;
2821
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
2823
virBufferAsprintf(buf,
2824
"$EBT -t nat -D %s -%c %s -j %s" CMD_SEPARATOR,
2825
(incoming) ? EBTABLES_CHAIN_INCOMING
2826
: EBTABLES_CHAIN_OUTGOING,
2827
iodev, ifname, chain);
2834
ebtablesUnlinkRootChain(virBufferPtr buf,
2835
int incoming, const char *ifname)
2837
return _ebtablesUnlinkRootChain(buf, incoming, ifname, 0);
2842
ebtablesUnlinkTmpRootChain(virBufferPtr buf,
2843
int incoming, const char *ifname)
2845
return _ebtablesUnlinkRootChain(buf, incoming, ifname, 1);
2850
ebtablesCreateTmpSubChain(ebiptablesRuleInstPtr *inst,
2851
int *nRuleInstances,
2854
enum l3_proto_idx protoidx,
2855
const char *filtername,
2857
virNWFilterChainPriority priority)
2859
virBuffer buf = VIR_BUFFER_INITIALIZER;
2860
ebiptablesRuleInstPtr tmp = *inst;
2861
size_t count = *nRuleInstances;
2862
char rootchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
2863
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2864
: CHAINPREFIX_HOST_OUT_TEMP;
2865
char *protostr = NULL;
2867
PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
2868
PRINT_CHAIN(chain, chainPrefix, ifname,
2869
(filtername) ? filtername : l3_protocols[protoidx].val);
2872
case L2_PROTO_MAC_IDX:
2873
protostr = strdup("");
2875
case L2_PROTO_STP_IDX:
2876
virAsprintf(&protostr, "-d " NWFILTER_MAC_BGA " ");
2879
virAsprintf(&protostr, "-p 0x%04x ", l3_protocols[protoidx].attr);
2884
virReportOOMError();
2888
virBufferAsprintf(&buf,
2889
CMD_DEF("$EBT -t nat -F %s") CMD_SEPARATOR
2891
CMD_DEF("$EBT -t nat -X %s") CMD_SEPARATOR
2893
CMD_DEF("$EBT -t nat -N %s") CMD_SEPARATOR
2896
CMD_DEF("$EBT -t nat -%%c %s %%s %s-j %s")
2905
CMD_STOPONERR(stopOnError),
2907
rootchain, protostr, chain,
2909
CMD_STOPONERR(stopOnError));
2913
if (virBufferError(&buf) ||
2914
VIR_EXPAND_N(tmp, count, 1) < 0) {
2915
virReportOOMError();
2916
virBufferFreeAndReset(&buf);
2920
*nRuleInstances = count;
2923
tmp[*nRuleInstances - 1].priority = priority;
2924
tmp[*nRuleInstances - 1].commandTemplate =
2925
virBufferContentAndReset(&buf);
2926
tmp[*nRuleInstances - 1].neededProtocolChain =
2927
virNWFilterChainSuffixTypeToString(VIR_NWFILTER_CHAINSUFFIX_ROOT);
2933
_ebtablesRemoveSubChains(virBufferPtr buf,
2937
char rootchain[MAX_CHAINNAME_LENGTH];
2940
NWFILTER_SET_EBTABLES_SHELLVAR(buf);
2942
virBufferAsprintf(buf, NWFILTER_FUNC_COLLECT_CHAINS,
2944
virBufferAdd(buf, NWFILTER_FUNC_RM_CHAINS, -1);
2946
virBufferAsprintf(buf, NWFILTER_FUNC_SET_IFS);
2947
virBufferAddLit(buf, "chains=\"$(collect_chains");
2948
for (i = 0; chains[i] != 0; i++) {
2949
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
2950
virBufferAsprintf(buf, " %s", rootchain);
2952
virBufferAddLit(buf, ")\"\n");
2954
for (i = 0; chains[i] != 0; i++) {
2955
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
2956
virBufferAsprintf(buf,
2957
"$EBT -t nat -F %s\n",
2960
virBufferAddLit(buf, "rm_chains $chains\n");
2966
ebtablesRemoveSubChains(virBufferPtr buf,
2970
CHAINPREFIX_HOST_IN,
2971
CHAINPREFIX_HOST_OUT,
2975
return _ebtablesRemoveSubChains(buf, ifname, chains);
2979
ebtablesRemoveTmpSubChains(virBufferPtr buf,
2983
CHAINPREFIX_HOST_IN_TEMP,
2984
CHAINPREFIX_HOST_OUT_TEMP,
2988
return _ebtablesRemoveSubChains(buf, ifname, chains);
2992
ebtablesRenameTmpSubChain(virBufferPtr buf,
2995
const char *protocol)
2997
char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
2998
char tmpChainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
2999
: CHAINPREFIX_HOST_OUT_TEMP;
3000
char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
3001
: CHAINPREFIX_HOST_OUT;
3004
PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
3005
PRINT_CHAIN( chain, chainPrefix, ifname, protocol);
3007
PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
3008
PRINT_ROOT_CHAIN( chain, chainPrefix, ifname);
3011
virBufferAsprintf(buf,
3012
"$EBT -t nat -E %s %s" CMD_SEPARATOR,
3018
ebtablesRenameTmpRootChain(virBufferPtr buf,
3022
return ebtablesRenameTmpSubChain(buf, incoming, ifname, NULL);
3026
ebtablesRenameTmpSubAndRootChains(virBufferPtr buf,
3029
char rootchain[MAX_CHAINNAME_LENGTH];
3032
CHAINPREFIX_HOST_IN_TEMP,
3033
CHAINPREFIX_HOST_OUT_TEMP,
3036
NWFILTER_SET_EBTABLES_SHELLVAR(buf);
3038
virBufferAsprintf(buf, NWFILTER_FUNC_COLLECT_CHAINS,
3040
virBufferAsprintf(buf, NWFILTER_FUNC_RENAME_CHAINS,
3041
CHAINPREFIX_HOST_IN_TEMP,
3042
CHAINPREFIX_HOST_IN,
3043
CHAINPREFIX_HOST_OUT_TEMP,
3044
CHAINPREFIX_HOST_OUT);
3046
virBufferAsprintf(buf, NWFILTER_FUNC_SET_IFS);
3047
virBufferAddLit(buf, "chains=\"$(collect_chains");
3048
for (i = 0; chains[i] != 0; i++) {
3049
PRINT_ROOT_CHAIN(rootchain, chains[i], ifname);
3050
virBufferAsprintf(buf, " %s", rootchain);
3052
virBufferAddLit(buf, ")\"\n");
3054
virBufferAddLit(buf, "rename_chains $chains\n");
3056
ebtablesRenameTmpRootChain(buf, 1, ifname);
3057
ebtablesRenameTmpRootChain(buf, 0, ifname);
3063
ebiptablesInstCommand(virBufferPtr buf,
3064
const char *templ, char cmd, int pos,
3067
char position[10] = { 0 };
3069
snprintf(position, sizeof(position), "%d", pos);
3070
virBufferAsprintf(buf, templ, cmd, position);
3071
virBufferAsprintf(buf, CMD_SEPARATOR "%s",
3072
CMD_STOPONERR(stopOnError));
3077
* ebiptablesCanApplyBasicRules
3079
* Determine whether this driver can apply the basic rules, meaning
3080
* run ebtablesApplyBasicRules and ebtablesApplyDHCPOnlyRules.
3081
* In case of this driver we need the ebtables tool available.
3084
ebiptablesCanApplyBasicRules(void) {
3085
return (ebtables_cmd_path != NULL);
3089
* ebtablesApplyBasicRules
3091
* @ifname: name of the backend-interface to which to apply the rules
3092
* @macaddr: MAC address the VM is using in packets sent through the
3095
* Returns 0 on success, 1 on failure with the rules removed
3097
* Apply basic filtering rules on the given interface
3098
* - filtering for MAC address spoofing
3099
* - allowing IPv4 & ARP traffic
3102
ebtablesApplyBasicRules(const char *ifname,
3103
const unsigned char *macaddr)
3105
virBuffer buf = VIR_BUFFER_INITIALIZER;
3106
char chain[MAX_CHAINNAME_LENGTH];
3107
char chainPrefix = CHAINPREFIX_HOST_IN_TEMP;
3108
char macaddr_str[VIR_MAC_STRING_BUFLEN];
3110
if (!ebtables_cmd_path) {
3111
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3112
_("cannot create rules since ebtables tool is "
3117
virFormatMacAddr(macaddr, macaddr_str);
3119
ebiptablesAllTeardown(ifname);
3121
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3123
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
3125
PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
3126
virBufferAsprintf(&buf,
3127
CMD_DEF("$EBT -t nat -A %s -s ! %s -j DROP") CMD_SEPARATOR
3134
virBufferAsprintf(&buf,
3135
CMD_DEF("$EBT -t nat -A %s -p IPv4 -j ACCEPT") CMD_SEPARATOR
3142
virBufferAsprintf(&buf,
3143
CMD_DEF("$EBT -t nat -A %s -p ARP -j ACCEPT") CMD_SEPARATOR
3150
virBufferAsprintf(&buf,
3151
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3158
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3159
ebtablesRenameTmpRootChain(&buf, 1, ifname);
3161
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
3162
goto tear_down_tmpebchains;
3166
tear_down_tmpebchains:
3167
ebtablesCleanAll(ifname);
3169
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3171
_("Some rules could not be created."));
3178
* ebtablesApplyDHCPOnlyRules
3180
* @ifname: name of the backend-interface to which to apply the rules
3181
* @macaddr: MAC address the VM is using in packets sent through the
3183
* @dhcpserver: The DHCP server from which the VM may receive traffic
3185
* @leaveTemporary: Whether to leave the table names with their temporary
3186
* names (true) or also perform the renaming to their final names as
3187
* part of this call (false)
3189
* Returns 0 on success, 1 on failure with the rules removed
3191
* Apply filtering rules so that the VM can only send and receive
3192
* DHCP traffic and nothing else.
3195
ebtablesApplyDHCPOnlyRules(const char *ifname,
3196
const unsigned char *macaddr,
3197
const char *dhcpserver,
3198
bool leaveTemporary)
3200
virBuffer buf = VIR_BUFFER_INITIALIZER;
3201
char chain_in [MAX_CHAINNAME_LENGTH],
3202
chain_out[MAX_CHAINNAME_LENGTH];
3203
char macaddr_str[VIR_MAC_STRING_BUFLEN];
3204
char *srcIPParam = NULL;
3206
if (!ebtables_cmd_path) {
3207
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3208
_("cannot create rules since ebtables tool is "
3214
virBufferAsprintf(&buf, " --ip-src %s", dhcpserver);
3215
if (virBufferError(&buf))
3217
srcIPParam = virBufferContentAndReset(&buf);
3220
virFormatMacAddr(macaddr, macaddr_str);
3222
ebiptablesAllTeardown(ifname);
3224
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3226
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
3227
ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
3229
PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
3230
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
3232
virBufferAsprintf(&buf,
3233
CMD_DEF("$EBT -t nat -A %s"
3234
" -s %s -d Broadcast "
3235
" -p ipv4 --ip-protocol udp"
3236
" --ip-src 0.0.0.0 --ip-dst 255.255.255.255"
3237
" --ip-sport 68 --ip-dport 67"
3238
" -j ACCEPT") CMD_SEPARATOR
3246
virBufferAsprintf(&buf,
3247
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3254
virBufferAsprintf(&buf,
3255
CMD_DEF("$EBT -t nat -A %s"
3257
" -p ipv4 --ip-protocol udp"
3259
" --ip-sport 67 --ip-dport 68"
3260
" -j ACCEPT") CMD_SEPARATOR
3266
srcIPParam != NULL ? srcIPParam : "",
3269
virBufferAsprintf(&buf,
3270
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3277
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3278
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
3280
if (!leaveTemporary) {
3281
ebtablesRenameTmpRootChain(&buf, 1, ifname);
3282
ebtablesRenameTmpRootChain(&buf, 0, ifname);
3285
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
3286
goto tear_down_tmpebchains;
3288
VIR_FREE(srcIPParam);
3292
tear_down_tmpebchains:
3293
ebtablesCleanAll(ifname);
3295
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3297
_("Some rules could not be created."));
3299
VIR_FREE(srcIPParam);
3306
* ebtablesApplyDropAllRules
3308
* @ifname: name of the backend-interface to which to apply the rules
3310
* Returns 0 on success, 1 on failure with the rules removed
3312
* Apply filtering rules so that the VM cannot receive or send traffic.
3315
ebtablesApplyDropAllRules(const char *ifname)
3317
virBuffer buf = VIR_BUFFER_INITIALIZER;
3318
char chain_in [MAX_CHAINNAME_LENGTH],
3319
chain_out[MAX_CHAINNAME_LENGTH];
3321
if (!ebtables_cmd_path) {
3322
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
3323
_("cannot create rules since ebtables tool is "
3328
ebiptablesAllTeardown(ifname);
3330
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3332
ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
3333
ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
3335
PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
3336
PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
3338
virBufferAsprintf(&buf,
3339
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3346
virBufferAsprintf(&buf,
3347
CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
3354
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3355
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
3356
ebtablesRenameTmpRootChain(&buf, 1, ifname);
3357
ebtablesRenameTmpRootChain(&buf, 0, ifname);
3359
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
3360
goto tear_down_tmpebchains;
3364
tear_down_tmpebchains:
3365
ebtablesCleanAll(ifname);
3367
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3369
_("Some rules could not be created."));
3376
ebtablesRemoveBasicRules(const char *ifname)
3378
return ebtablesCleanAll(ifname);
3382
static int ebtablesCleanAll(const char *ifname)
3384
virBuffer buf = VIR_BUFFER_INITIALIZER;
3387
if (!ebtables_cmd_path)
3390
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3392
ebtablesUnlinkRootChain(&buf, 1, ifname);
3393
ebtablesUnlinkRootChain(&buf, 0, ifname);
3394
ebtablesRemoveSubChains(&buf, ifname);
3395
ebtablesRemoveRootChain(&buf, 1, ifname);
3396
ebtablesRemoveRootChain(&buf, 0, ifname);
3398
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3399
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3400
ebtablesRemoveTmpSubChains(&buf, ifname);
3401
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3402
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3404
ebiptablesExecCLI(&buf, &cli_status, NULL);
3410
ebiptablesRuleOrderSort(const void *a, const void *b)
3412
const ebiptablesRuleInstPtr insta = (const ebiptablesRuleInstPtr)a;
3413
const ebiptablesRuleInstPtr instb = (const ebiptablesRuleInstPtr)b;
3414
const char *root = virNWFilterChainSuffixTypeToString(
3415
VIR_NWFILTER_CHAINSUFFIX_ROOT);
3416
bool root_a = STREQ(insta->neededProtocolChain, root);
3417
bool root_b = STREQ(instb->neededProtocolChain, root);
3419
/* ensure root chain commands appear before all others since
3420
we will need them to create the child chains */
3425
return -1; /* a before b */
3428
return 1; /* b before a */
3431
/* priorities are limited to range [-1000, 1000] */
3432
return (insta->priority - instb->priority);
3436
ebiptablesRuleOrderSortPtr(const void *a, const void *b)
3438
const ebiptablesRuleInstPtr *insta = a;
3439
const ebiptablesRuleInstPtr *instb = b;
3440
return ebiptablesRuleOrderSort(*insta, *instb);
3444
ebiptablesFilterOrderSort(const virHashKeyValuePairPtr a,
3445
const virHashKeyValuePairPtr b)
3447
/* elements' values has been limited to range [-1000, 1000] */
3448
return *(virNWFilterChainPriority *)a->value -
3449
*(virNWFilterChainPriority *)b->value;
3453
iptablesCheckBridgeNFCallEnabled(bool isIPv6)
3455
static time_t lastReport, lastReportIPv6;
3456
const char *pathname = NULL;
3458
time_t now = time(NULL);
3461
(now - lastReportIPv6) > BRIDGE_NF_CALL_ALERT_INTERVAL ) {
3462
pathname = PROC_BRIDGE_NF_CALL_IP6TABLES;
3463
} else if (now - lastReport > BRIDGE_NF_CALL_ALERT_INTERVAL) {
3464
pathname = PROC_BRIDGE_NF_CALL_IPTABLES;
3468
int fd = open(pathname, O_RDONLY);
3470
if (read(fd, buffer, 1) == 1) {
3471
if (buffer[0] == '0') {
3473
snprintf(msg, sizeof(msg),
3474
_("To enable ip%stables filtering for the VM do "
3478
VIR_WARN("%s", msg);
3480
lastReportIPv6 = now;
3485
VIR_FORCE_CLOSE(fd);
3491
* Given a filtername determine the protocol it is used for evaluating
3492
* We do prefix-matching to determine the protocol.
3494
static enum l3_proto_idx
3495
ebtablesGetProtoIdxByFiltername(const char *filtername)
3497
enum l3_proto_idx idx;
3499
for (idx = 0; idx < L3_PROTO_LAST_IDX; idx++) {
3500
if (STRPREFIX(filtername, l3_protocols[idx].val)) {
3509
ebtablesCreateTmpRootAndSubChains(virBufferPtr buf,
3511
virHashTablePtr chains, int direction,
3512
ebiptablesRuleInstPtr *inst,
3513
int *nRuleInstances)
3516
virHashKeyValuePairPtr filter_names;
3517
const virNWFilterChainPriority *priority;
3519
if (ebtablesCreateTmpRootChain(buf, direction, ifname, 1) < 0)
3522
filter_names = virHashGetItems(chains,
3523
ebiptablesFilterOrderSort);
3524
if (filter_names == NULL)
3527
for (i = 0; filter_names[i].key; i++) {
3528
enum l3_proto_idx idx = ebtablesGetProtoIdxByFiltername(
3529
filter_names[i].key);
3532
priority = (const virNWFilterChainPriority *)filter_names[i].value;
3533
rc = ebtablesCreateTmpSubChain(inst, nRuleInstances,
3534
direction, ifname, idx,
3535
filter_names[i].key, 1,
3541
VIR_FREE(filter_names);
3546
ebiptablesApplyNewRules(const char *ifname,
3552
ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
3553
virBuffer buf = VIR_BUFFER_INITIALIZER;
3554
virHashTablePtr chains_in_set = virHashCreate(10, NULL);
3555
virHashTablePtr chains_out_set = virHashCreate(10, NULL);
3556
bool haveIptables = false;
3557
bool haveIp6tables = false;
3558
ebiptablesRuleInstPtr ebtChains = NULL;
3560
char *errmsg = NULL;
3562
if (!chains_in_set || !chains_out_set) {
3563
virReportOOMError();
3564
goto exit_free_sets;
3567
if (nruleInstances > 1 && inst)
3568
qsort(inst, nruleInstances, sizeof(inst[0]),
3569
ebiptablesRuleOrderSortPtr);
3571
/* scan the rules to see which chains need to be created */
3572
for (i = 0; i < nruleInstances; i++) {
3574
if (inst[i]->ruleType == RT_EBTABLES) {
3575
const char *name = inst[i]->neededProtocolChain;
3576
if (inst[i]->chainprefix == CHAINPREFIX_HOST_IN_TEMP) {
3577
if (virHashUpdateEntry(chains_in_set, name,
3578
&inst[i]->chainPriority)) {
3579
virReportOOMError();
3580
goto exit_free_sets;
3583
if (virHashUpdateEntry(chains_out_set, name,
3584
&inst[i]->chainPriority)) {
3585
virReportOOMError();
3586
goto exit_free_sets;
3593
/* cleanup whatever may exist */
3594
if (ebtables_cmd_path) {
3595
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3597
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3598
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3599
ebtablesRemoveTmpSubChains(&buf, ifname);
3600
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3601
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3602
ebiptablesExecCLI(&buf, &cli_status, NULL);
3605
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3607
/* create needed chains */
3608
if (ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_in_set , 1,
3609
&ebtChains, &nEbtChains) ||
3610
ebtablesCreateTmpRootAndSubChains(&buf, ifname, chains_out_set, 0,
3611
&ebtChains, &nEbtChains)) {
3612
goto tear_down_tmpebchains;
3616
qsort(&ebtChains[0], nEbtChains, sizeof(ebtChains[0]),
3617
ebiptablesRuleOrderSort);
3619
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3620
goto tear_down_tmpebchains;
3622
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3624
/* process ebtables commands; interleave commands from filters with
3625
commands for creating and connecting ebtables chains */
3627
for (i = 0; i < nruleInstances; i++) {
3629
switch (inst[i]->ruleType) {
3631
while (j < nEbtChains &&
3632
ebtChains[j].priority <= inst[i]->priority) {
3633
ebiptablesInstCommand(&buf,
3634
ebtChains[j++].commandTemplate,
3637
ebiptablesInstCommand(&buf,
3638
inst[i]->commandTemplate,
3642
haveIptables = true;
3645
haveIp6tables = true;
3650
while (j < nEbtChains)
3651
ebiptablesInstCommand(&buf,
3652
ebtChains[j++].commandTemplate,
3655
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3656
goto tear_down_tmpebchains;
3659
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3661
iptablesUnlinkTmpRootChains(&buf, ifname);
3662
iptablesRemoveTmpRootChains(&buf, ifname);
3664
iptablesCreateBaseChains(&buf);
3666
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3667
goto tear_down_tmpebchains;
3669
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3671
iptablesCreateTmpRootChains(&buf, ifname);
3673
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3674
goto tear_down_tmpiptchains;
3676
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3678
iptablesLinkTmpRootChains(&buf, ifname);
3679
iptablesSetupVirtInPost(&buf, ifname);
3680
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3681
goto tear_down_tmpiptchains;
3683
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3685
for (i = 0; i < nruleInstances; i++) {
3687
if (inst[i]->ruleType == RT_IPTABLES)
3688
iptablesInstCommand(&buf,
3689
inst[i]->commandTemplate,
3693
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3694
goto tear_down_tmpiptchains;
3696
iptablesCheckBridgeNFCallEnabled(false);
3699
if (haveIp6tables) {
3700
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3702
iptablesUnlinkTmpRootChains(&buf, ifname);
3703
iptablesRemoveTmpRootChains(&buf, ifname);
3705
iptablesCreateBaseChains(&buf);
3707
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3708
goto tear_down_tmpiptchains;
3710
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3712
iptablesCreateTmpRootChains(&buf, ifname);
3714
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3715
goto tear_down_tmpip6tchains;
3717
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3719
iptablesLinkTmpRootChains(&buf, ifname);
3720
iptablesSetupVirtInPost(&buf, ifname);
3721
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3722
goto tear_down_tmpip6tchains;
3724
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3726
for (i = 0; i < nruleInstances; i++) {
3727
if (inst[i]->ruleType == RT_IP6TABLES)
3728
iptablesInstCommand(&buf,
3729
inst[i]->commandTemplate,
3733
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3734
goto tear_down_tmpip6tchains;
3736
iptablesCheckBridgeNFCallEnabled(true);
3739
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3741
if (virHashSize(chains_in_set) != 0)
3742
ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
3743
if (virHashSize(chains_out_set) != 0)
3744
ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
3746
if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
3747
goto tear_down_ebsubchains_and_unlink;
3749
virHashFree(chains_in_set);
3750
virHashFree(chains_out_set);
3752
for (i = 0; i < nEbtChains; i++)
3753
VIR_FREE(ebtChains[i].commandTemplate);
3754
VIR_FREE(ebtChains);
3760
tear_down_ebsubchains_and_unlink:
3761
if (ebtables_cmd_path) {
3762
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3764
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3765
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3768
tear_down_tmpip6tchains:
3769
if (haveIp6tables) {
3770
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3772
iptablesUnlinkTmpRootChains(&buf, ifname);
3773
iptablesRemoveTmpRootChains(&buf, ifname);
3776
tear_down_tmpiptchains:
3778
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3780
iptablesUnlinkTmpRootChains(&buf, ifname);
3781
iptablesRemoveTmpRootChains(&buf, ifname);
3784
tear_down_tmpebchains:
3785
if (ebtables_cmd_path) {
3786
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3788
ebtablesRemoveTmpSubChains(&buf, ifname);
3789
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3790
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3793
ebiptablesExecCLI(&buf, &cli_status, NULL);
3795
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3796
_("Some rules could not be created for "
3797
"interface %s%s%s"),
3800
errmsg ? errmsg : "");
3803
virHashFree(chains_in_set);
3804
virHashFree(chains_out_set);
3806
for (i = 0; i < nEbtChains; i++)
3807
VIR_FREE(ebtChains[i].commandTemplate);
3808
VIR_FREE(ebtChains);
3817
ebiptablesTearNewRules(const char *ifname)
3820
virBuffer buf = VIR_BUFFER_INITIALIZER;
3822
if (iptables_cmd_path) {
3823
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3825
iptablesUnlinkTmpRootChains(&buf, ifname);
3826
iptablesRemoveTmpRootChains(&buf, ifname);
3829
if (ip6tables_cmd_path) {
3830
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3832
iptablesUnlinkTmpRootChains(&buf, ifname);
3833
iptablesRemoveTmpRootChains(&buf, ifname);
3836
if (ebtables_cmd_path) {
3837
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3839
ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
3840
ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
3842
ebtablesRemoveTmpSubChains(&buf, ifname);
3843
ebtablesRemoveTmpRootChain(&buf, 1, ifname);
3844
ebtablesRemoveTmpRootChain(&buf, 0, ifname);
3847
ebiptablesExecCLI(&buf, &cli_status, NULL);
3854
ebiptablesTearOldRules(const char *ifname)
3857
virBuffer buf = VIR_BUFFER_INITIALIZER;
3859
/* switch to new iptables user defined chains */
3860
if (iptables_cmd_path) {
3861
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3863
iptablesUnlinkRootChains(&buf, ifname);
3864
iptablesRemoveRootChains(&buf, ifname);
3866
iptablesRenameTmpRootChains(&buf, ifname);
3867
ebiptablesExecCLI(&buf, &cli_status, NULL);
3870
if (ip6tables_cmd_path) {
3871
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3873
iptablesUnlinkRootChains(&buf, ifname);
3874
iptablesRemoveRootChains(&buf, ifname);
3876
iptablesRenameTmpRootChains(&buf, ifname);
3877
ebiptablesExecCLI(&buf, &cli_status, NULL);
3880
if (ebtables_cmd_path) {
3881
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3883
ebtablesUnlinkRootChain(&buf, 1, ifname);
3884
ebtablesUnlinkRootChain(&buf, 0, ifname);
3886
ebtablesRemoveSubChains(&buf, ifname);
3888
ebtablesRemoveRootChain(&buf, 1, ifname);
3889
ebtablesRemoveRootChain(&buf, 0, ifname);
3891
ebtablesRenameTmpSubAndRootChains(&buf, ifname);
3893
ebiptablesExecCLI(&buf, &cli_status, NULL);
3901
* ebiptablesRemoveRules:
3902
* @ifname : the name of the interface to which the rules apply
3903
* @nRuleInstance : the number of given rules
3904
* @_inst : array of rule instantiation data
3906
* Remove all rules one after the other
3908
* Return 0 on success, 1 if execution of one or more cleanup
3912
ebiptablesRemoveRules(const char *ifname ATTRIBUTE_UNUSED,
3919
virBuffer buf = VIR_BUFFER_INITIALIZER;
3920
ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
3922
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3924
for (i = 0; i < nruleInstances; i++)
3925
ebiptablesInstCommand(&buf,
3926
inst[i]->commandTemplate,
3930
if (ebiptablesExecCLI(&buf, &cli_status, NULL))
3934
virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
3936
_("error while executing CLI commands"));
3946
* ebiptablesAllTeardown:
3947
* @ifname : the name of the interface to which the rules apply
3949
* Unconditionally remove all possible user defined tables and rules
3950
* that were created for the given interface (ifname).
3955
ebiptablesAllTeardown(const char *ifname)
3957
virBuffer buf = VIR_BUFFER_INITIALIZER;
3960
if (iptables_cmd_path) {
3961
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
3963
iptablesUnlinkRootChains(&buf, ifname);
3964
iptablesClearVirtInPost (&buf, ifname);
3965
iptablesRemoveRootChains(&buf, ifname);
3968
if (ip6tables_cmd_path) {
3969
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
3971
iptablesUnlinkRootChains(&buf, ifname);
3972
iptablesClearVirtInPost (&buf, ifname);
3973
iptablesRemoveRootChains(&buf, ifname);
3976
if (ebtables_cmd_path) {
3977
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
3979
ebtablesUnlinkRootChain(&buf, 1, ifname);
3980
ebtablesUnlinkRootChain(&buf, 0, ifname);
3982
ebtablesRemoveSubChains(&buf, ifname);
3984
ebtablesRemoveRootChain(&buf, 1, ifname);
3985
ebtablesRemoveRootChain(&buf, 0, ifname);
3987
ebiptablesExecCLI(&buf, &cli_status, NULL);
3993
virNWFilterTechDriver ebiptables_driver = {
3994
.name = EBIPTABLES_DRIVER_ID,
3997
.init = ebiptablesDriverInit,
3998
.shutdown = ebiptablesDriverShutdown,
4000
.createRuleInstance = ebiptablesCreateRuleInstanceIterate,
4001
.applyNewRules = ebiptablesApplyNewRules,
4002
.tearNewRules = ebiptablesTearNewRules,
4003
.tearOldRules = ebiptablesTearOldRules,
4004
.allTeardown = ebiptablesAllTeardown,
4005
.removeRules = ebiptablesRemoveRules,
4006
.freeRuleInstance = ebiptablesFreeRuleInstance,
4007
.displayRuleInstance = ebiptablesDisplayRuleInstance,
4009
.canApplyBasicRules = ebiptablesCanApplyBasicRules,
4010
.applyBasicRules = ebtablesApplyBasicRules,
4011
.applyDHCPOnlyRules = ebtablesApplyDHCPOnlyRules,
4012
.applyDropAllRules = ebtablesApplyDropAllRules,
4013
.removeBasicRules = ebtablesRemoveBasicRules,
4018
ebiptablesDriverInit(bool privileged)
4020
virBuffer buf = VIR_BUFFER_INITIALIZER;
4025
if (virMutexInit(&execCLIMutex))
4028
gawk_cmd_path = virFindFileInPath("gawk");
4029
grep_cmd_path = virFindFileInPath("grep");
4031
ebtables_cmd_path = virFindFileInPath("ebtables");
4032
if (ebtables_cmd_path) {
4033
NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
4035
virBufferAsprintf(&buf,
4036
CMD_DEF("$EBT -t nat -L") CMD_SEPARATOR
4041
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
4042
VIR_FREE(ebtables_cmd_path);
4045
iptables_cmd_path = virFindFileInPath("iptables");
4046
if (iptables_cmd_path) {
4047
NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
4049
virBufferAsprintf(&buf,
4050
CMD_DEF("$IPT -n -L FORWARD") CMD_SEPARATOR
4055
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
4056
VIR_FREE(iptables_cmd_path);
4059
ip6tables_cmd_path = virFindFileInPath("ip6tables");
4060
if (ip6tables_cmd_path) {
4061
NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
4063
virBufferAsprintf(&buf,
4064
CMD_DEF("$IPT -n -L FORWARD") CMD_SEPARATOR
4069
if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
4070
VIR_FREE(ip6tables_cmd_path);
4073
/* ip(6)tables support needs gawk & grep, ebtables doesn't */
4074
if ((iptables_cmd_path != NULL || ip6tables_cmd_path != NULL) &&
4075
(!grep_cmd_path || !gawk_cmd_path)) {
4076
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4077
_("essential tools to support ip(6)tables "
4078
"firewalls could not be located"));
4079
VIR_FREE(iptables_cmd_path);
4080
VIR_FREE(ip6tables_cmd_path);
4084
if (!ebtables_cmd_path && !iptables_cmd_path && !ip6tables_cmd_path) {
4085
virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
4086
_("firewall tools were not found or "
4088
ebiptablesDriverShutdown();
4092
ebiptables_driver.flags = TECHDRV_FLAG_INITIALIZED;
4099
ebiptablesDriverShutdown(void)
4101
VIR_FREE(gawk_cmd_path);
4102
VIR_FREE(grep_cmd_path);
4103
VIR_FREE(ebtables_cmd_path);
4104
VIR_FREE(iptables_cmd_path);
4105
VIR_FREE(ip6tables_cmd_path);
4106
ebiptables_driver.flags = 0;