~serge-hallyn/ubuntu/raring/libvirt/libvirt-hugepages

« back to all changes in this revision

Viewing changes to .pc/Don-t-require-gawk-for-a-simple-print-expression.patch/src/nwfilter/nwfilter_ebiptables_driver.c

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2012-05-13 15:44:12 UTC
  • mfrom: (1.2.13)
  • Revision ID: package-import@ubuntu.com-20120513154412-fgmn5sxqdzgnzlx3
Tags: 0.9.12-0ubuntu1
* New upstream version:
  * Synchronize with debian packaging:
    - debian/control: Update build depends.
    - debian/libvirt-bin.postrm: Cleanup /var/log/libvirt
      on purge.
    - Bump standards verson (no changes).
    - debian/patches/Don-t-fail-if-we-can-t-setup-avahi.patch: Added
  * Dropped patches:
    - debian/patches/Debianize-libvirt-guests.patch
    - debian/patches/rewrite-lxc-controller-eof-handling-yet-again
    - debian/patches/ubuntu/libnl13.patch
    - debian/patches/ubuntu/fix-lxc-startup-error.patch
    - debian/patches/ubuntu/fix-bridge-fd.patch
    - debian/patches/ubuntu/skip-labelling-network-disks.patch
    - debian/patches/ubuntu/xen-xend-shutdown-detection.patch
    - debian/patches/ubuntu/xen-config-no-vfb-for-hvm.patch
    - debian/patches/debian/Disable-daemon-start-test.patch
    - debian/patches/debian/Disable-gnulib-s-test-nonplocking-pipe.sh.patch
    - debian/patches/ubuntu/9006-default-config-test-case.patch
    - debian/patches/fix-block-migration.patch
    - debian/patches/ubuntu/9022-qemu-unescape-HMP-commands-before-converting-them-to.patch
    - debian/patches/ubuntu/9023-qemu-change-rbd-auth_supported-separation-character-.patch
    - debian/patches/ubuntu/9024-qemu-allow-snapshotting-of-sheepdog-and-rbd-disks.patch
    - debian/patches/9025-qemu-change-rbd-auth_supported-separation-character-.patch
    - debian/patches/ubuntu/arm-gcc-workaround.patch
  * Rediffed:
    - debian/patches/Allow-libvirt-group-to-access-the-socket.patch
    - debian/patches/Disable-failing-virnetsockettest.patch
    - debian/patches/dnsmasq-as-priv-user
    - debian/patches/9002-better_default_uri_virsh.patch
  * debian/control: Add libnl-route-3-dev ass a build depends.
  * debian/patches/libnl3-build-fix.patch: Fix build with libnl3.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
 
3
 *
 
4
 * Copyright (C) 2011 Red Hat, Inc.
 
5
 * Copyright (C) 2010 IBM Corp.
 
6
 * Copyright (C) 2010 Stefan Berger
 
7
 *
 
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.
 
12
 *
 
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.
 
17
 *
 
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
 
21
 *
 
22
 * Author: Stefan Berger <stefanb@us.ibm.com>
 
23
 */
 
24
 
 
25
#include <config.h>
 
26
 
 
27
#include <string.h>
 
28
#include <sys/stat.h>
 
29
#include <fcntl.h>
 
30
 
 
31
#include "internal.h"
 
32
 
 
33
#include "buf.h"
 
34
#include "memory.h"
 
35
#include "logging.h"
 
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"
 
41
#include "virfile.h"
 
42
#include "command.h"
 
43
#include "configmake.h"
 
44
#include "intprops.h"
 
45
 
 
46
 
 
47
#define VIR_FROM_THIS VIR_FROM_NWFILTER
 
48
 
 
49
 
 
50
#define EBTABLES_CHAIN_INCOMING "PREROUTING"
 
51
#define EBTABLES_CHAIN_OUTGOING "POSTROUTING"
 
52
 
 
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'
 
57
 
 
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.  */
 
62
 
 
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}'.\";" \
 
71
        "  exit 1;" \
 
72
        "fi" CMD_SEPARATOR \
 
73
      : ""
 
74
 
 
75
 
 
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"
 
80
 
 
81
#define BRIDGE_NF_CALL_ALERT_INTERVAL  10 /* seconds */
 
82
 
 
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;
 
88
 
 
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)
 
93
 
 
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:
 
97
 *
 
98
 * #> ebtables -t nat -L libvirt-I-tck-test205002
 
99
 * Bridge table: nat
 
100
 *
 
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
 
105
 * -p 0x835 -j ACCEPT
 
106
 * -j DROP
 
107
 */
 
108
static const char ebtables_script_func_collect_chains[] =
 
109
    "collect_chains()\n"
 
110
    "{\n"
 
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"
 
114
    "    do\n"
 
115
    "      echo $tmp\n"
 
116
    "      collect_chains $tmp\n"
 
117
    "    done\n"
 
118
    "  done\n"
 
119
    "}\n";
 
120
 
 
121
static const char ebiptables_script_func_rm_chains[] =
 
122
    "rm_chains()\n"
 
123
    "{\n"
 
124
    "  for tmp in $*; do $EBT -t nat -F $tmp; done\n"
 
125
    "  for tmp in $*; do $EBT -t nat -X $tmp; done\n"
 
126
    "}\n";
 
127
 
 
128
static const char ebiptables_script_func_rename_chains[] =
 
129
    "rename_chains()\n"
 
130
    "{\n"
 
131
    "  for tmp in $*; do\n"
 
132
    "    case $tmp in\n"
 
133
    "      %c*) $EBT -t nat -E $tmp %c${tmp#?} ;;\n"
 
134
    "      %c*) $EBT -t nat -E $tmp %c${tmp#?} ;;\n"
 
135
    "    esac\n"
 
136
    "  done\n"
 
137
    "}\n";
 
138
 
 
139
static const char ebiptables_script_set_ifs[] =
 
140
    "tmp='\n'\n"
 
141
    "IFS=' ''\t'$tmp\n";
 
142
 
 
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
 
147
 
 
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);
 
154
 
 
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"
 
159
 
 
160
#define PRINT_IPT_ROOT_CHAIN(buf, prefix, ifname) \
 
161
    snprintf(buf, sizeof(buf), "%c%c-%s", prefix[0], prefix[1], ifname)
 
162
 
 
163
#define PHYSDEV_IN  "--physdev-in"
 
164
#define PHYSDEV_OUT "--physdev-out"
 
165
 
 
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;
 
170
 
 
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
 
175
 
 
176
#define COMMENT_VARNAME "comment"
 
177
 
 
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);
 
183
 
 
184
static virMutex execCLIMutex;
 
185
 
 
186
struct ushort_map {
 
187
    unsigned short attr;
 
188
    const char *val;
 
189
};
 
190
 
 
191
 
 
192
enum l3_proto_idx {
 
193
    L3_PROTO_IPV4_IDX = 0,
 
194
    L3_PROTO_IPV6_IDX,
 
195
    L3_PROTO_ARP_IDX,
 
196
    L3_PROTO_RARP_IDX,
 
197
    L2_PROTO_MAC_IDX,
 
198
    L2_PROTO_VLAN_IDX,
 
199
    L2_PROTO_STP_IDX,
 
200
    L3_PROTO_LAST_IDX
 
201
};
 
202
 
 
203
#define USHORTMAP_ENTRY_IDX(IDX, ATT, VAL) [IDX] = { .attr = ATT, .val = VAL }
 
204
 
 
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.
 
209
 */
 
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),
 
219
};
 
220
 
 
221
 
 
222
static int
 
223
printVar(virNWFilterVarCombIterPtr vars,
 
224
         char *buf, int bufsize,
 
225
         nwItemDescPtr item,
 
226
         int *done)
 
227
{
 
228
    *done = 0;
 
229
 
 
230
    if ((item->flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
 
231
        const char *val;
 
232
 
 
233
        val = virNWFilterVarCombIterGetVarValue(vars, item->varAccess);
 
234
        if (!val) {
 
235
            /* error has been reported */
 
236
            return -1;
 
237
        }
 
238
 
 
239
        if (!virStrcpy(buf, val, bufsize)) {
 
240
            const char *varName;
 
241
 
 
242
            varName = virNWFilterVarAccessGetVarName(item->varAccess);
 
243
            virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
 
244
                                   _("Buffer too small to print variable "
 
245
                                   "'%s' into"), varName);
 
246
            return -1;
 
247
        }
 
248
 
 
249
        *done = 1;
 
250
    }
 
251
    return 0;
 
252
}
 
253
 
 
254
 
 
255
static int
 
256
_printDataType(virNWFilterVarCombIterPtr vars,
 
257
               char *buf, int bufsize,
 
258
               nwItemDescPtr item,
 
259
               bool asHex)
 
260
{
 
261
    int done;
 
262
    char *data;
 
263
 
 
264
    if (printVar(vars, buf, bufsize, item, &done) < 0)
 
265
        return -1;
 
266
 
 
267
    if (done)
 
268
        return 0;
 
269
 
 
270
    switch (item->datatype) {
 
271
    case DATATYPE_IPADDR:
 
272
        data = virSocketAddrFormat(&item->u.ipaddr);
 
273
        if (!data)
 
274
            return -1;
 
275
        if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
 
276
            virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
 
277
                                   _("buffer too small for IP address"));
 
278
            VIR_FREE(data);
 
279
            return -1;
 
280
        }
 
281
        VIR_FREE(data);
 
282
    break;
 
283
 
 
284
    case DATATYPE_IPV6ADDR:
 
285
        data = virSocketAddrFormat(&item->u.ipaddr);
 
286
        if (!data)
 
287
            return -1;
 
288
 
 
289
        if (snprintf(buf, bufsize, "%s", data) >= bufsize) {
 
290
            virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
 
291
                                   _("buffer too small for IPv6 address"));
 
292
            VIR_FREE(data);
 
293
            return -1;
 
294
        }
 
295
        VIR_FREE(data);
 
296
    break;
 
297
 
 
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"));
 
303
            return -1;
 
304
        }
 
305
 
 
306
        virMacAddrFormat(item->u.macaddr.addr, buf);
 
307
    break;
 
308
 
 
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"));
 
315
            return -1;
 
316
        }
 
317
    break;
 
318
 
 
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"));
 
325
            return -1;
 
326
        }
 
327
    break;
 
328
 
 
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"));
 
335
            return -1;
 
336
        }
 
337
    break;
 
338
 
 
339
    case DATATYPE_UINT8:
 
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"));
 
345
            return -1;
 
346
        }
 
347
    break;
 
348
 
 
349
    default:
 
350
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
 
351
                               _("Unhandled datatype %x"), item->datatype);
 
352
        return -1;
 
353
    break;
 
354
    }
 
355
 
 
356
    return 0;
 
357
}
 
358
 
 
359
 
 
360
static int
 
361
printDataType(virNWFilterVarCombIterPtr vars,
 
362
              char *buf, int bufsize,
 
363
              nwItemDescPtr item)
 
364
{
 
365
    return _printDataType(vars, buf, bufsize, item, 0);
 
366
}
 
367
 
 
368
 
 
369
static int
 
370
printDataTypeAsHex(virNWFilterVarCombIterPtr vars,
 
371
                   char *buf, int bufsize,
 
372
                   nwItemDescPtr item)
 
373
{
 
374
    return _printDataType(vars, buf, bufsize, item, 1);
 
375
}
 
376
 
 
377
 
 
378
static void
 
379
printCommentVar(virBufferPtr dest, const char *buf)
 
380
{
 
381
    size_t i, len = strlen(buf);
 
382
 
 
383
    virBufferAddLit(dest, COMMENT_VARNAME "='");
 
384
 
 
385
    if (len > IPTABLES_MAX_COMMENT_LENGTH)
 
386
        len = IPTABLES_MAX_COMMENT_LENGTH;
 
387
 
 
388
    for (i = 0; i < len; i++) {
 
389
        if (buf[i] == '\'')
 
390
            virBufferAddLit(dest, "'\\''");
 
391
        else
 
392
            virBufferAddChar(dest, buf[i]);
 
393
    }
 
394
    virBufferAddLit(dest,"'" CMD_SEPARATOR);
 
395
}
 
396
 
 
397
 
 
398
static void
 
399
ebiptablesRuleInstFree(ebiptablesRuleInstPtr inst)
 
400
{
 
401
    if (!inst)
 
402
        return;
 
403
 
 
404
    VIR_FREE(inst->commandTemplate);
 
405
    VIR_FREE(inst);
 
406
}
 
407
 
 
408
 
 
409
static int
 
410
ebiptablesAddRuleInst(virNWFilterRuleInstPtr res,
 
411
                      char *commandTemplate,
 
412
                      const char *neededChain,
 
413
                      virNWFilterChainPriority chainPriority,
 
414
                      char chainprefix,
 
415
                      virNWFilterRulePriority priority,
 
416
                      enum RuleType ruleType)
 
417
{
 
418
    ebiptablesRuleInstPtr inst;
 
419
 
 
420
    if (VIR_ALLOC(inst) < 0) {
 
421
        virReportOOMError();
 
422
        return -1;
 
423
    }
 
424
 
 
425
    inst->commandTemplate = commandTemplate;
 
426
    inst->neededProtocolChain = neededChain;
 
427
    inst->chainPriority = chainPriority;
 
428
    inst->chainprefix = chainprefix;
 
429
    inst->priority = priority;
 
430
    inst->ruleType = ruleType;
 
431
 
 
432
    return virNWFilterRuleInstAddData(res, inst);
 
433
}
 
434
 
 
435
 
 
436
static int
 
437
ebtablesHandleEthHdr(virBufferPtr buf,
 
438
                     virNWFilterVarCombIterPtr vars,
 
439
                     ethHdrDataDefPtr ethHdr,
 
440
                     bool reverse)
 
441
{
 
442
    char macaddr[VIR_MAC_STRING_BUFLEN];
 
443
 
 
444
    if (HAS_ENTRY_ITEM(&ethHdr->dataSrcMACAddr)) {
 
445
        if (printDataType(vars,
 
446
                          macaddr, sizeof(macaddr),
 
447
                          &ethHdr->dataSrcMACAddr) < 0)
 
448
            goto err_exit;
 
449
 
 
450
        virBufferAsprintf(buf,
 
451
                      " %s %s %s",
 
452
                      reverse ? "-d" : "-s",
 
453
                      ENTRY_GET_NEG_SIGN(&ethHdr->dataSrcMACAddr),
 
454
                      macaddr);
 
455
 
 
456
        if (HAS_ENTRY_ITEM(&ethHdr->dataSrcMACMask)) {
 
457
            if (printDataType(vars,
 
458
                              macaddr, sizeof(macaddr),
 
459
                              &ethHdr->dataSrcMACMask) < 0)
 
460
                goto err_exit;
 
461
 
 
462
            virBufferAsprintf(buf,
 
463
                              "/%s",
 
464
                              macaddr);
 
465
        }
 
466
    }
 
467
 
 
468
    if (HAS_ENTRY_ITEM(&ethHdr->dataDstMACAddr)) {
 
469
        if (printDataType(vars,
 
470
                          macaddr, sizeof(macaddr),
 
471
                          &ethHdr->dataDstMACAddr) < 0)
 
472
            goto err_exit;
 
473
 
 
474
        virBufferAsprintf(buf,
 
475
                      " %s %s %s",
 
476
                      reverse ? "-s" : "-d",
 
477
                      ENTRY_GET_NEG_SIGN(&ethHdr->dataDstMACAddr),
 
478
                      macaddr);
 
479
 
 
480
        if (HAS_ENTRY_ITEM(&ethHdr->dataDstMACMask)) {
 
481
            if (printDataType(vars,
 
482
                              macaddr, sizeof(macaddr),
 
483
                              &ethHdr->dataDstMACMask) < 0)
 
484
                goto err_exit;
 
485
 
 
486
            virBufferAsprintf(buf,
 
487
                              "/%s",
 
488
                              macaddr);
 
489
        }
 
490
    }
 
491
 
 
492
    return 0;
 
493
 
 
494
 err_exit:
 
495
    virBufferFreeAndReset(buf);
 
496
 
 
497
    return -1;
 
498
}
 
499
 
 
500
 
 
501
/************************ iptables support ************************/
 
502
 
 
503
static int iptablesLinkIPTablesBaseChain(virBufferPtr buf,
 
504
                                         const char *udchain,
 
505
                                         const char *syschain,
 
506
                                         unsigned int pos,
 
507
                                         int stopOnError)
 
508
{
 
509
    virBufferAsprintf(buf,
 
510
                      "res=$($IPT -L %s -n --line-number | "
 
511
                          "%s \" %s \")\n"
 
512
                      "if [ $? -ne 0 ]; then\n"
 
513
                      "  $IPT -I %s %d -j %s\n"
 
514
                      "else\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
 
518
                      "    " CMD_EXEC
 
519
                      "    %s"
 
520
                      "    r=$(( $r + 1 ))\n"
 
521
                      "    " CMD_DEF("$IPT -D %s ${r}") CMD_SEPARATOR
 
522
                      "    " CMD_EXEC
 
523
                      "    %s"
 
524
                      "  fi\n"
 
525
                      "fi\n",
 
526
 
 
527
                      syschain,
 
528
                      grep_cmd_path, udchain,
 
529
 
 
530
                      syschain, pos, udchain,
 
531
                      gawk_cmd_path,
 
532
 
 
533
                      pos,
 
534
 
 
535
                      syschain, pos, udchain,
 
536
                      CMD_STOPONERR(stopOnError),
 
537
 
 
538
                      syschain,
 
539
                      CMD_STOPONERR(stopOnError));
 
540
    return 0;
 
541
}
 
542
 
 
543
 
 
544
static int iptablesCreateBaseChains(virBufferPtr buf)
 
545
{
 
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);
 
558
 
 
559
    return 0;
 
560
}
 
561
 
 
562
 
 
563
static int
 
564
iptablesCreateTmpRootChain(virBufferPtr buf,
 
565
                           char prefix,
 
566
                           int incoming, const char *ifname,
 
567
                           int stopOnError)
 
568
{
 
569
    char chain[MAX_CHAINNAME_LENGTH];
 
570
    char chainPrefix[2] = {
 
571
       prefix,
 
572
       (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
573
                  : CHAINPREFIX_HOST_OUT_TEMP
 
574
    };
 
575
 
 
576
    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
577
 
 
578
    virBufferAsprintf(buf,
 
579
                      CMD_DEF("$IPT -N %s") CMD_SEPARATOR
 
580
                      CMD_EXEC
 
581
                      "%s",
 
582
                      chain,
 
583
                      CMD_STOPONERR(stopOnError));
 
584
 
 
585
    return 0;
 
586
}
 
587
 
 
588
 
 
589
static int
 
590
iptablesCreateTmpRootChains(virBufferPtr buf,
 
591
                            const char *ifname)
 
592
{
 
593
    iptablesCreateTmpRootChain(buf, 'F', 0, ifname, 1);
 
594
    iptablesCreateTmpRootChain(buf, 'F', 1, ifname, 1);
 
595
    iptablesCreateTmpRootChain(buf, 'H', 1, ifname, 1);
 
596
    return 0;
 
597
}
 
598
 
 
599
 
 
600
static int
 
601
_iptablesRemoveRootChain(virBufferPtr buf,
 
602
                         char prefix,
 
603
                         int incoming, const char *ifname,
 
604
                         int isTempChain)
 
605
{
 
606
    char chain[MAX_CHAINNAME_LENGTH];
 
607
    char chainPrefix[2] = {
 
608
        prefix,
 
609
    };
 
610
 
 
611
    if (isTempChain)
 
612
        chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
613
                                    : CHAINPREFIX_HOST_OUT_TEMP;
 
614
    else
 
615
        chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
 
616
                                    : CHAINPREFIX_HOST_OUT;
 
617
 
 
618
    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
619
 
 
620
    virBufferAsprintf(buf,
 
621
                      "$IPT -F %s" CMD_SEPARATOR
 
622
                      "$IPT -X %s" CMD_SEPARATOR,
 
623
                      chain,
 
624
                      chain);
 
625
 
 
626
    return 0;
 
627
}
 
628
 
 
629
 
 
630
static int
 
631
iptablesRemoveRootChain(virBufferPtr buf,
 
632
                        char prefix,
 
633
                        int incoming,
 
634
                        const char *ifname)
 
635
{
 
636
    return _iptablesRemoveRootChain(buf, prefix, incoming, ifname, 0);
 
637
}
 
638
 
 
639
 
 
640
static int
 
641
iptablesRemoveTmpRootChain(virBufferPtr buf,
 
642
                           char prefix,
 
643
                           int incoming,
 
644
                           const char *ifname)
 
645
{
 
646
    return _iptablesRemoveRootChain(buf, prefix,
 
647
                                    incoming, ifname, 1);
 
648
}
 
649
 
 
650
 
 
651
static int
 
652
iptablesRemoveTmpRootChains(virBufferPtr buf,
 
653
                            const char *ifname)
 
654
{
 
655
    iptablesRemoveTmpRootChain(buf, 'F', 0, ifname);
 
656
    iptablesRemoveTmpRootChain(buf, 'F', 1, ifname);
 
657
    iptablesRemoveTmpRootChain(buf, 'H', 1, ifname);
 
658
    return 0;
 
659
}
 
660
 
 
661
 
 
662
static int
 
663
iptablesRemoveRootChains(virBufferPtr buf,
 
664
                         const char *ifname)
 
665
{
 
666
    iptablesRemoveRootChain(buf, 'F', 0, ifname);
 
667
    iptablesRemoveRootChain(buf, 'F', 1, ifname);
 
668
    iptablesRemoveRootChain(buf, 'H', 1, ifname);
 
669
    return 0;
 
670
}
 
671
 
 
672
 
 
673
static int
 
674
iptablesLinkTmpRootChain(virBufferPtr buf,
 
675
                         const char *basechain,
 
676
                         char prefix,
 
677
                         int incoming, const char *ifname,
 
678
                         int stopOnError)
 
679
{
 
680
    char chain[MAX_CHAINNAME_LENGTH];
 
681
    char chainPrefix[2] = {
 
682
        prefix,
 
683
        (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
684
                   : CHAINPREFIX_HOST_OUT_TEMP
 
685
    };
 
686
    const char *match = (incoming) ? MATCH_PHYSDEV_IN
 
687
                                   : MATCH_PHYSDEV_OUT;
 
688
 
 
689
    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
690
 
 
691
    virBufferAsprintf(buf,
 
692
                      CMD_DEF("$IPT -A %s "
 
693
                              "%s %s -g %s") CMD_SEPARATOR
 
694
                      CMD_EXEC
 
695
                      "%s",
 
696
                      basechain,
 
697
                      match, ifname, chain,
 
698
 
 
699
                      CMD_STOPONERR(stopOnError));
 
700
 
 
701
    return 0;
 
702
}
 
703
 
 
704
 
 
705
static int
 
706
iptablesLinkTmpRootChains(virBufferPtr buf,
 
707
                          const char *ifname)
 
708
{
 
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);
 
712
 
 
713
    return 0;
 
714
}
 
715
 
 
716
 
 
717
static int
 
718
iptablesSetupVirtInPost(virBufferPtr buf,
 
719
                        const char *ifname)
 
720
{
 
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 "
 
726
                        CMD_DEF("$IPT"
 
727
                        " -A " VIRT_IN_POST_CHAIN
 
728
                        " %s %s -j ACCEPT") CMD_SEPARATOR
 
729
                        CMD_EXEC
 
730
                        "%s"
 
731
                      "fi\n",
 
732
                      PHYSDEV_IN, ifname,
 
733
                      match, ifname,
 
734
                      CMD_STOPONERR(1));
 
735
    return 0;
 
736
}
 
737
 
 
738
 
 
739
static int
 
740
iptablesClearVirtInPost(virBufferPtr buf,
 
741
                        const char *ifname)
 
742
{
 
743
    const char *match = MATCH_PHYSDEV_IN;
 
744
    virBufferAsprintf(buf,
 
745
                      "$IPT -D " VIRT_IN_POST_CHAIN
 
746
                      " %s %s -j ACCEPT" CMD_SEPARATOR,
 
747
                      match, ifname);
 
748
    return 0;
 
749
}
 
750
 
 
751
static int
 
752
_iptablesUnlinkRootChain(virBufferPtr buf,
 
753
                         const char *basechain,
 
754
                         char prefix,
 
755
                         int incoming, const char *ifname,
 
756
                         int isTempChain)
 
757
{
 
758
    char chain[MAX_CHAINNAME_LENGTH];
 
759
    char chainPrefix[2] = {
 
760
        prefix,
 
761
    };
 
762
    if (isTempChain)
 
763
        chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
764
                                    : CHAINPREFIX_HOST_OUT_TEMP;
 
765
    else
 
766
        chainPrefix[1] = (incoming) ? CHAINPREFIX_HOST_IN
 
767
                                    : CHAINPREFIX_HOST_OUT;
 
768
    const char *match = (incoming) ? MATCH_PHYSDEV_IN
 
769
                                   : MATCH_PHYSDEV_OUT;
 
770
 
 
771
    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
772
 
 
773
    virBufferAsprintf(buf,
 
774
                      "$IPT -D %s "
 
775
                      "%s %s -g %s" CMD_SEPARATOR,
 
776
                      basechain,
 
777
                      match, ifname, chain);
 
778
 
 
779
    return 0;
 
780
}
 
781
 
 
782
 
 
783
static int
 
784
iptablesUnlinkRootChain(virBufferPtr buf,
 
785
                        const char *basechain,
 
786
                        char prefix,
 
787
                        int incoming, const char *ifname)
 
788
{
 
789
    return _iptablesUnlinkRootChain(buf,
 
790
                                    basechain, prefix, incoming, ifname, 0);
 
791
}
 
792
 
 
793
 
 
794
static int
 
795
iptablesUnlinkTmpRootChain(virBufferPtr buf,
 
796
                           const char *basechain,
 
797
                           char prefix,
 
798
                           int incoming, const char *ifname)
 
799
{
 
800
    return _iptablesUnlinkRootChain(buf,
 
801
                                    basechain, prefix, incoming, ifname, 1);
 
802
}
 
803
 
 
804
 
 
805
static int
 
806
iptablesUnlinkRootChains(virBufferPtr buf,
 
807
                         const char *ifname)
 
808
{
 
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);
 
812
 
 
813
    return 0;
 
814
}
 
815
 
 
816
 
 
817
static int
 
818
iptablesUnlinkTmpRootChains(virBufferPtr buf,
 
819
                            const char *ifname)
 
820
{
 
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);
 
824
    return 0;
 
825
}
 
826
 
 
827
 
 
828
static int
 
829
iptablesRenameTmpRootChain(virBufferPtr buf,
 
830
                           char prefix,
 
831
                           int incoming,
 
832
                           const char *ifname)
 
833
{
 
834
    char tmpchain[MAX_CHAINNAME_LENGTH], chain[MAX_CHAINNAME_LENGTH];
 
835
    char tmpChainPrefix[2] = {
 
836
        prefix,
 
837
        (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
838
                   : CHAINPREFIX_HOST_OUT_TEMP
 
839
    };
 
840
    char chainPrefix[2] = {
 
841
        prefix,
 
842
        (incoming) ? CHAINPREFIX_HOST_IN
 
843
                   : CHAINPREFIX_HOST_OUT
 
844
    };
 
845
 
 
846
    PRINT_IPT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
 
847
    PRINT_IPT_ROOT_CHAIN(   chain,    chainPrefix, ifname);
 
848
 
 
849
    virBufferAsprintf(buf,
 
850
                      "$IPT -E %s %s" CMD_SEPARATOR,
 
851
                      tmpchain,
 
852
                      chain);
 
853
    return 0;
 
854
}
 
855
 
 
856
 
 
857
static int
 
858
iptablesRenameTmpRootChains(virBufferPtr buf,
 
859
                            const char *ifname)
 
860
{
 
861
    iptablesRenameTmpRootChain(buf, 'F', 0, ifname);
 
862
    iptablesRenameTmpRootChain(buf, 'F', 1, ifname);
 
863
    iptablesRenameTmpRootChain(buf, 'H', 1, ifname);
 
864
    return 0;
 
865
}
 
866
 
 
867
 
 
868
static void
 
869
iptablesInstCommand(virBufferPtr buf,
 
870
                    const char *templ, char cmd, int pos,
 
871
                    int stopOnError)
 
872
{
 
873
    char position[10] = { 0 };
 
874
    if (pos >= 0)
 
875
        snprintf(position, sizeof(position), "%d", pos);
 
876
    virBufferAsprintf(buf, templ, cmd, position);
 
877
    virBufferAsprintf(buf, CMD_SEPARATOR "%s",
 
878
                      CMD_STOPONERR(stopOnError));
 
879
}
 
880
 
 
881
 
 
882
static int
 
883
iptablesHandleSrcMacAddr(virBufferPtr buf,
 
884
                         virNWFilterVarCombIterPtr vars,
 
885
                         nwItemDescPtr srcMacAddr,
 
886
                         int directionIn,
 
887
                         bool *srcmacskipped)
 
888
{
 
889
    char macaddr[VIR_MAC_STRING_BUFLEN];
 
890
    *srcmacskipped = false;
 
891
 
 
892
    if (HAS_ENTRY_ITEM(srcMacAddr)) {
 
893
        if (directionIn) {
 
894
            *srcmacskipped = true;
 
895
            return 0;
 
896
        }
 
897
 
 
898
        if (printDataType(vars,
 
899
                          macaddr, sizeof(macaddr),
 
900
                          srcMacAddr) < 0)
 
901
            goto err_exit;
 
902
 
 
903
        virBufferAsprintf(buf,
 
904
                          " -m mac %s --mac-source %s",
 
905
                          ENTRY_GET_NEG_SIGN(srcMacAddr),
 
906
                          macaddr);
 
907
    }
 
908
 
 
909
    return 0;
 
910
 
 
911
err_exit:
 
912
    virBufferFreeAndReset(buf);
 
913
 
 
914
    return -1;
 
915
}
 
916
 
 
917
 
 
918
static int
 
919
iptablesHandleIpHdr(virBufferPtr buf,
 
920
                    virBufferPtr afterStateMatch,
 
921
                    virNWFilterVarCombIterPtr vars,
 
922
                    ipHdrDataDefPtr ipHdr,
 
923
                    int directionIn,
 
924
                    bool *skipRule, bool *skipMatch,
 
925
                    virBufferPtr prefix)
 
926
{
 
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";
 
934
    if (directionIn) {
 
935
        src = "--destination";
 
936
        dst = "--source";
 
937
        srcrange = "--dst-range";
 
938
        dstrange = "--src-range";
 
939
    }
 
940
 
 
941
    if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPAddr)) {
 
942
 
 
943
        if (printDataType(vars,
 
944
                          ipaddr, sizeof(ipaddr),
 
945
                          &ipHdr->dataSrcIPAddr) < 0)
 
946
            goto err_exit;
 
947
 
 
948
        virBufferAsprintf(buf,
 
949
                          " %s %s %s",
 
950
                          ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPAddr),
 
951
                          src,
 
952
                          ipaddr);
 
953
 
 
954
        if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPMask)) {
 
955
 
 
956
            if (printDataType(vars,
 
957
                              number, sizeof(number),
 
958
                              &ipHdr->dataSrcIPMask) < 0)
 
959
                goto err_exit;
 
960
 
 
961
            virBufferAsprintf(buf,
 
962
                              "/%s",
 
963
                              number);
 
964
        }
 
965
    } else if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPFrom)) {
 
966
 
 
967
        if (printDataType(vars,
 
968
                          ipaddr, sizeof(ipaddr),
 
969
                          &ipHdr->dataSrcIPFrom) < 0)
 
970
            goto err_exit;
 
971
 
 
972
        virBufferAsprintf(buf,
 
973
                          " -m iprange %s %s %s",
 
974
                          ENTRY_GET_NEG_SIGN(&ipHdr->dataSrcIPFrom),
 
975
                          srcrange,
 
976
                          ipaddr);
 
977
 
 
978
        if (HAS_ENTRY_ITEM(&ipHdr->dataSrcIPTo)) {
 
979
 
 
980
            if (printDataType(vars,
 
981
                              ipaddr, sizeof(ipaddr),
 
982
                              &ipHdr->dataSrcIPTo) < 0)
 
983
                goto err_exit;
 
984
 
 
985
            virBufferAsprintf(buf,
 
986
                              "-%s",
 
987
                              ipaddr);
 
988
        }
 
989
    }
 
990
 
 
991
    if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPAddr)) {
 
992
 
 
993
        if (printDataType(vars,
 
994
                          ipaddr, sizeof(ipaddr),
 
995
                          &ipHdr->dataDstIPAddr) < 0)
 
996
           goto err_exit;
 
997
 
 
998
        virBufferAsprintf(buf,
 
999
                          " %s %s %s",
 
1000
                          ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPAddr),
 
1001
                          dst,
 
1002
                          ipaddr);
 
1003
 
 
1004
        if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPMask)) {
 
1005
 
 
1006
            if (printDataType(vars,
 
1007
                              number, sizeof(number),
 
1008
                              &ipHdr->dataDstIPMask) < 0)
 
1009
                goto err_exit;
 
1010
 
 
1011
            virBufferAsprintf(buf,
 
1012
                              "/%s",
 
1013
                              number);
 
1014
 
 
1015
        }
 
1016
    } else if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPFrom)) {
 
1017
 
 
1018
        if (printDataType(vars,
 
1019
                          ipaddr, sizeof(ipaddr),
 
1020
                          &ipHdr->dataDstIPFrom) < 0)
 
1021
            goto err_exit;
 
1022
 
 
1023
        virBufferAsprintf(buf,
 
1024
                          " -m iprange %s %s %s",
 
1025
                          ENTRY_GET_NEG_SIGN(&ipHdr->dataDstIPFrom),
 
1026
                          dstrange,
 
1027
                          ipaddr);
 
1028
 
 
1029
        if (HAS_ENTRY_ITEM(&ipHdr->dataDstIPTo)) {
 
1030
 
 
1031
            if (printDataType(vars,
 
1032
                              ipaddr, sizeof(ipaddr),
 
1033
                              &ipHdr->dataDstIPTo) < 0)
 
1034
                goto err_exit;
 
1035
 
 
1036
            virBufferAsprintf(buf,
 
1037
                              "-%s",
 
1038
                              ipaddr);
 
1039
        }
 
1040
    }
 
1041
 
 
1042
    if (HAS_ENTRY_ITEM(&ipHdr->dataDSCP)) {
 
1043
 
 
1044
        if (printDataType(vars,
 
1045
                          number, sizeof(number),
 
1046
                          &ipHdr->dataDSCP) < 0)
 
1047
           goto err_exit;
 
1048
 
 
1049
        virBufferAsprintf(buf,
 
1050
                          " -m dscp %s --dscp %s",
 
1051
                          ENTRY_GET_NEG_SIGN(&ipHdr->dataDSCP),
 
1052
                          number);
 
1053
    }
 
1054
 
 
1055
    if (HAS_ENTRY_ITEM(&ipHdr->dataConnlimitAbove)) {
 
1056
        if (directionIn) {
 
1057
            /* only support for limit in outgoing dir. */
 
1058
            *skipRule = true;
 
1059
        } else {
 
1060
            if (printDataType(vars,
 
1061
                              number, sizeof(number),
 
1062
                              &ipHdr->dataConnlimitAbove) < 0)
 
1063
               goto err_exit;
 
1064
 
 
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),
 
1070
                              number);
 
1071
            *skipMatch = true;
 
1072
        }
 
1073
    }
 
1074
 
 
1075
    if (HAS_ENTRY_ITEM(&ipHdr->dataComment)) {
 
1076
        printCommentVar(prefix, ipHdr->dataComment.u.string);
 
1077
 
 
1078
        /* keep comments behind everything else -- they are packet eval.
 
1079
           no-ops */
 
1080
        virBufferAddLit(afterStateMatch,
 
1081
                        " -m comment --comment \"$" COMMENT_VARNAME "\"");
 
1082
    }
 
1083
 
 
1084
    return 0;
 
1085
 
 
1086
err_exit:
 
1087
    virBufferFreeAndReset(buf);
 
1088
    virBufferFreeAndReset(afterStateMatch);
 
1089
 
 
1090
    return -1;
 
1091
}
 
1092
 
 
1093
 
 
1094
static int
 
1095
iptablesHandlePortData(virBufferPtr buf,
 
1096
                       virNWFilterVarCombIterPtr vars,
 
1097
                       portDataDefPtr portData,
 
1098
                       int directionIn)
 
1099
{
 
1100
    char portstr[20];
 
1101
    const char *sport = "--sport";
 
1102
    const char *dport = "--dport";
 
1103
    if (directionIn) {
 
1104
        sport = "--dport";
 
1105
        dport = "--sport";
 
1106
    }
 
1107
 
 
1108
    if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart)) {
 
1109
        if (printDataType(vars,
 
1110
                          portstr, sizeof(portstr),
 
1111
                          &portData->dataSrcPortStart) < 0)
 
1112
            goto err_exit;
 
1113
 
 
1114
        virBufferAsprintf(buf,
 
1115
                          " %s %s %s",
 
1116
                          ENTRY_GET_NEG_SIGN(&portData->dataSrcPortStart),
 
1117
                          sport,
 
1118
                          portstr);
 
1119
 
 
1120
        if (HAS_ENTRY_ITEM(&portData->dataSrcPortEnd)) {
 
1121
            if (printDataType(vars,
 
1122
                              portstr, sizeof(portstr),
 
1123
                              &portData->dataSrcPortEnd) < 0)
 
1124
                goto err_exit;
 
1125
 
 
1126
             virBufferAsprintf(buf,
 
1127
                               ":%s",
 
1128
                               portstr);
 
1129
        }
 
1130
    }
 
1131
 
 
1132
    if (HAS_ENTRY_ITEM(&portData->dataDstPortStart)) {
 
1133
        if (printDataType(vars,
 
1134
                          portstr, sizeof(portstr),
 
1135
                          &portData->dataDstPortStart) < 0)
 
1136
            goto err_exit;
 
1137
 
 
1138
        virBufferAsprintf(buf,
 
1139
                          " %s %s %s",
 
1140
                          ENTRY_GET_NEG_SIGN(&portData->dataDstPortStart),
 
1141
                          dport,
 
1142
                          portstr);
 
1143
 
 
1144
        if (HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) {
 
1145
            if (printDataType(vars,
 
1146
                              portstr, sizeof(portstr),
 
1147
                              &portData->dataDstPortEnd) < 0)
 
1148
                goto err_exit;
 
1149
 
 
1150
             virBufferAsprintf(buf,
 
1151
                               ":%s",
 
1152
                               portstr);
 
1153
        }
 
1154
    }
 
1155
 
 
1156
    return 0;
 
1157
 
 
1158
err_exit:
 
1159
    return -1;
 
1160
}
 
1161
 
 
1162
 
 
1163
static void
 
1164
iptablesEnforceDirection(int directionIn,
 
1165
                         virNWFilterRuleDefPtr rule,
 
1166
                         virBufferPtr buf)
 
1167
{
 
1168
    if (rule->tt != VIR_NWFILTER_RULE_DIRECTION_INOUT)
 
1169
        virBufferAsprintf(buf, " -m conntrack --ctdir %s",
 
1170
                          (directionIn) ? "Original"
 
1171
                                        : "Reply");
 
1172
}
 
1173
 
 
1174
 
 
1175
/*
 
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"
 
1185
 *    "ACCEPT"
 
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
 
1189
 *
 
1190
 * Convert a single rule into its representation for later instantiation
 
1191
 *
 
1192
 * Returns 0 in case of success with the result stored in the data structure
 
1193
 * pointed to by res, != 0 otherwise.
 
1194
 */
 
1195
static int
 
1196
_iptablesCreateRuleInstance(int directionIn,
 
1197
                            const char *chainPrefix,
 
1198
                            virNWFilterDefPtr nwfilter,
 
1199
                            virNWFilterRuleDefPtr rule,
 
1200
                            const char *ifname,
 
1201
                            virNWFilterVarCombIterPtr vars,
 
1202
                            virNWFilterRuleInstPtr res,
 
1203
                            const char *match, bool defMatch,
 
1204
                            const char *accept_target,
 
1205
                            bool isIPv6,
 
1206
                            bool maySkipICMP)
 
1207
{
 
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;
 
1215
    const char *target;
 
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;
 
1223
 
 
1224
    if (!iptables_cmd) {
 
1225
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR,
 
1226
                               _("cannot create rule since %s tool is "
 
1227
                                 "missing."),
 
1228
                               isIPv6 ? "ip6tables" : "iptables");
 
1229
        goto err_exit;
 
1230
    }
 
1231
 
 
1232
    PRINT_IPT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
1233
 
 
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",
 
1239
                          chain);
 
1240
 
 
1241
        virBufferAddLit(&buf, " -p tcp");
 
1242
 
 
1243
        bufUsed = virBufferUse(&buf);
 
1244
 
 
1245
        if (iptablesHandleSrcMacAddr(&buf,
 
1246
                                     vars,
 
1247
                                     &rule->p.tcpHdrFilter.dataSrcMACAddr,
 
1248
                                     directionIn,
 
1249
                                     &srcMacSkipped) < 0)
 
1250
            goto err_exit;
 
1251
 
 
1252
        if (iptablesHandleIpHdr(&buf,
 
1253
                                &afterStateMatch,
 
1254
                                vars,
 
1255
                                &rule->p.tcpHdrFilter.ipHdr,
 
1256
                                directionIn,
 
1257
                                &skipRule, &skipMatch,
 
1258
                                &prefix) < 0)
 
1259
            goto err_exit;
 
1260
 
 
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,
 
1266
                      ' ',
 
1267
                      rule->p.tcpHdrFilter.dataTCPFlags.u.tcpFlags.flags);
 
1268
        }
 
1269
 
 
1270
        if (iptablesHandlePortData(&buf,
 
1271
                                   vars,
 
1272
                                   &rule->p.tcpHdrFilter.portData,
 
1273
                                   directionIn) < 0)
 
1274
            goto err_exit;
 
1275
 
 
1276
        if (HAS_ENTRY_ITEM(&rule->p.tcpHdrFilter.dataTCPOption)) {
 
1277
            if (printDataType(vars,
 
1278
                              number, sizeof(number),
 
1279
                              &rule->p.tcpHdrFilter.dataTCPOption) < 0)
 
1280
                goto err_exit;
 
1281
 
 
1282
            virBufferAsprintf(&buf,
 
1283
                              " %s --tcp-option %s",
 
1284
                              ENTRY_GET_NEG_SIGN(&rule->p.tcpHdrFilter.dataTCPOption),
 
1285
                              number);
 
1286
        }
 
1287
 
 
1288
    break;
 
1289
 
 
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",
 
1294
                          chain);
 
1295
 
 
1296
        virBufferAddLit(&buf, " -p udp");
 
1297
 
 
1298
        bufUsed = virBufferUse(&buf);
 
1299
 
 
1300
        if (iptablesHandleSrcMacAddr(&buf,
 
1301
                                     vars,
 
1302
                                     &rule->p.udpHdrFilter.dataSrcMACAddr,
 
1303
                                     directionIn,
 
1304
                                     &srcMacSkipped) < 0)
 
1305
            goto err_exit;
 
1306
 
 
1307
        if (iptablesHandleIpHdr(&buf,
 
1308
                                &afterStateMatch,
 
1309
                                vars,
 
1310
                                &rule->p.udpHdrFilter.ipHdr,
 
1311
                                directionIn,
 
1312
                                &skipRule, &skipMatch,
 
1313
                                &prefix) < 0)
 
1314
            goto err_exit;
 
1315
 
 
1316
        if (iptablesHandlePortData(&buf,
 
1317
                                   vars,
 
1318
                                   &rule->p.udpHdrFilter.portData,
 
1319
                                   directionIn) < 0)
 
1320
            goto err_exit;
 
1321
    break;
 
1322
 
 
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",
 
1327
                          chain);
 
1328
 
 
1329
        virBufferAddLit(&buf, " -p udplite");
 
1330
 
 
1331
        bufUsed = virBufferUse(&buf);
 
1332
 
 
1333
        if (iptablesHandleSrcMacAddr(&buf,
 
1334
                                     vars,
 
1335
                                     &rule->p.udpliteHdrFilter.dataSrcMACAddr,
 
1336
                                     directionIn,
 
1337
                                     &srcMacSkipped) < 0)
 
1338
            goto err_exit;
 
1339
 
 
1340
        if (iptablesHandleIpHdr(&buf,
 
1341
                                &afterStateMatch,
 
1342
                                vars,
 
1343
                                &rule->p.udpliteHdrFilter.ipHdr,
 
1344
                                directionIn,
 
1345
                                &skipRule, &skipMatch,
 
1346
                                &prefix) < 0)
 
1347
            goto err_exit;
 
1348
 
 
1349
    break;
 
1350
 
 
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",
 
1355
                          chain);
 
1356
 
 
1357
        virBufferAddLit(&buf, " -p esp");
 
1358
 
 
1359
        bufUsed = virBufferUse(&buf);
 
1360
 
 
1361
        if (iptablesHandleSrcMacAddr(&buf,
 
1362
                                     vars,
 
1363
                                     &rule->p.espHdrFilter.dataSrcMACAddr,
 
1364
                                     directionIn,
 
1365
                                     &srcMacSkipped) < 0)
 
1366
            goto err_exit;
 
1367
 
 
1368
        if (iptablesHandleIpHdr(&buf,
 
1369
                                &afterStateMatch,
 
1370
                                vars,
 
1371
                                &rule->p.espHdrFilter.ipHdr,
 
1372
                                directionIn,
 
1373
                                &skipRule, &skipMatch,
 
1374
                                &prefix) < 0)
 
1375
            goto err_exit;
 
1376
 
 
1377
    break;
 
1378
 
 
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",
 
1383
                          chain);
 
1384
 
 
1385
        virBufferAddLit(&buf, " -p ah");
 
1386
 
 
1387
        bufUsed = virBufferUse(&buf);
 
1388
 
 
1389
        if (iptablesHandleSrcMacAddr(&buf,
 
1390
                                     vars,
 
1391
                                     &rule->p.ahHdrFilter.dataSrcMACAddr,
 
1392
                                     directionIn,
 
1393
                                     &srcMacSkipped) < 0)
 
1394
            goto err_exit;
 
1395
 
 
1396
        if (iptablesHandleIpHdr(&buf,
 
1397
                                &afterStateMatch,
 
1398
                                vars,
 
1399
                                &rule->p.ahHdrFilter.ipHdr,
 
1400
                                directionIn,
 
1401
                                &skipRule, &skipMatch,
 
1402
                                &prefix) < 0)
 
1403
            goto err_exit;
 
1404
 
 
1405
    break;
 
1406
 
 
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",
 
1411
                          chain);
 
1412
 
 
1413
        virBufferAddLit(&buf, " -p sctp");
 
1414
 
 
1415
        bufUsed = virBufferUse(&buf);
 
1416
 
 
1417
        if (iptablesHandleSrcMacAddr(&buf,
 
1418
                                     vars,
 
1419
                                     &rule->p.sctpHdrFilter.dataSrcMACAddr,
 
1420
                                     directionIn,
 
1421
                                     &srcMacSkipped) < 0)
 
1422
            goto err_exit;
 
1423
 
 
1424
        if (iptablesHandleIpHdr(&buf,
 
1425
                                &afterStateMatch,
 
1426
                                vars,
 
1427
                                &rule->p.sctpHdrFilter.ipHdr,
 
1428
                                directionIn,
 
1429
                                &skipRule, &skipMatch,
 
1430
                                &prefix) < 0)
 
1431
            goto err_exit;
 
1432
 
 
1433
        if (iptablesHandlePortData(&buf,
 
1434
                                   vars,
 
1435
                                   &rule->p.sctpHdrFilter.portData,
 
1436
                                   directionIn) < 0)
 
1437
            goto err_exit;
 
1438
    break;
 
1439
 
 
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",
 
1444
                          chain);
 
1445
 
 
1446
        if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
 
1447
            virBufferAddLit(&buf, " -p icmp");
 
1448
        else
 
1449
            virBufferAddLit(&buf, " -p icmpv6");
 
1450
 
 
1451
        bufUsed = virBufferUse(&buf);
 
1452
 
 
1453
        if (iptablesHandleSrcMacAddr(&buf,
 
1454
                                     vars,
 
1455
                                     &rule->p.icmpHdrFilter.dataSrcMACAddr,
 
1456
                                     directionIn,
 
1457
                                     &srcMacSkipped) < 0)
 
1458
            goto err_exit;
 
1459
 
 
1460
        if (iptablesHandleIpHdr(&buf,
 
1461
                                &afterStateMatch,
 
1462
                                vars,
 
1463
                                &rule->p.icmpHdrFilter.ipHdr,
 
1464
                                directionIn,
 
1465
                                &skipRule, &skipMatch,
 
1466
                                &prefix) < 0)
 
1467
            goto err_exit;
 
1468
 
 
1469
        if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPType)) {
 
1470
            const char *parm;
 
1471
 
 
1472
            hasICMPType = true;
 
1473
 
 
1474
            if (maySkipICMP)
 
1475
                goto exit_no_error;
 
1476
 
 
1477
            if (rule->prtclType == VIR_NWFILTER_RULE_PROTOCOL_ICMP)
 
1478
                parm = "--icmp-type";
 
1479
            else
 
1480
                parm = "--icmpv6-type";
 
1481
 
 
1482
            if (printDataType(vars,
 
1483
                              number, sizeof(number),
 
1484
                              &rule->p.icmpHdrFilter.dataICMPType) < 0)
 
1485
                goto err_exit;
 
1486
 
 
1487
            virBufferAsprintf(&buf,
 
1488
                      " %s %s %s",
 
1489
                      ENTRY_GET_NEG_SIGN(&rule->p.icmpHdrFilter.dataICMPType),
 
1490
                      parm,
 
1491
                      number);
 
1492
 
 
1493
            if (HAS_ENTRY_ITEM(&rule->p.icmpHdrFilter.dataICMPCode)) {
 
1494
                if (printDataType(vars,
 
1495
                                  number, sizeof(number),
 
1496
                                  &rule->p.icmpHdrFilter.dataICMPCode) < 0)
 
1497
                    goto err_exit;
 
1498
 
 
1499
                 virBufferAsprintf(&buf,
 
1500
                                   "/%s",
 
1501
                                   number);
 
1502
            }
 
1503
        }
 
1504
    break;
 
1505
 
 
1506
    case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
 
1507
        virBufferAsprintf(&buf,
 
1508
                          CMD_DEF_PRE "$IPT -%%c %s %%s",
 
1509
                          chain);
 
1510
 
 
1511
        virBufferAddLit(&buf, " -p igmp");
 
1512
 
 
1513
        bufUsed = virBufferUse(&buf);
 
1514
 
 
1515
        if (iptablesHandleSrcMacAddr(&buf,
 
1516
                                     vars,
 
1517
                                     &rule->p.igmpHdrFilter.dataSrcMACAddr,
 
1518
                                     directionIn,
 
1519
                                     &srcMacSkipped) < 0)
 
1520
            goto err_exit;
 
1521
 
 
1522
        if (iptablesHandleIpHdr(&buf,
 
1523
                                &afterStateMatch,
 
1524
                                vars,
 
1525
                                &rule->p.igmpHdrFilter.ipHdr,
 
1526
                                directionIn,
 
1527
                                &skipRule, &skipMatch,
 
1528
                                &prefix) < 0)
 
1529
            goto err_exit;
 
1530
 
 
1531
    break;
 
1532
 
 
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",
 
1537
                          chain);
 
1538
 
 
1539
        virBufferAddLit(&buf, " -p all");
 
1540
 
 
1541
        bufUsed = virBufferUse(&buf);
 
1542
 
 
1543
        if (iptablesHandleSrcMacAddr(&buf,
 
1544
                                     vars,
 
1545
                                     &rule->p.allHdrFilter.dataSrcMACAddr,
 
1546
                                     directionIn,
 
1547
                                     &srcMacSkipped) < 0)
 
1548
            goto err_exit;
 
1549
 
 
1550
        if (iptablesHandleIpHdr(&buf,
 
1551
                                &afterStateMatch,
 
1552
                                vars,
 
1553
                                &rule->p.allHdrFilter.ipHdr,
 
1554
                                directionIn,
 
1555
                                &skipRule, &skipMatch,
 
1556
                                &prefix) < 0)
 
1557
            goto err_exit;
 
1558
 
 
1559
    break;
 
1560
 
 
1561
    default:
 
1562
        return -1;
 
1563
    }
 
1564
 
 
1565
    if ((srcMacSkipped && bufUsed == virBufferUse(&buf)) ||
 
1566
         skipRule) {
 
1567
        virBufferFreeAndReset(&buf);
 
1568
        virBufferFreeAndReset(&prefix);
 
1569
        return 0;
 
1570
    }
 
1571
 
 
1572
    if (rule->action == VIR_NWFILTER_RULE_ACTION_ACCEPT)
 
1573
        target = accept_target;
 
1574
    else {
 
1575
        target = virNWFilterJumpTargetTypeToString(rule->action);
 
1576
        skipMatch = defMatch;
 
1577
    }
 
1578
 
 
1579
    if (match && !skipMatch)
 
1580
        virBufferAsprintf(&buf, " %s", match);
 
1581
 
 
1582
    if (defMatch && match != NULL && !skipMatch && !hasICMPType)
 
1583
        iptablesEnforceDirection(directionIn,
 
1584
                                 rule,
 
1585
                                 &buf);
 
1586
 
 
1587
    if (virBufferError(&afterStateMatch)) {
 
1588
        virBufferFreeAndReset(&buf);
 
1589
        virBufferFreeAndReset(&prefix);
 
1590
        virBufferFreeAndReset(&afterStateMatch);
 
1591
        virReportOOMError();
 
1592
        return -1;
 
1593
    }
 
1594
 
 
1595
    if (virBufferUse(&afterStateMatch)) {
 
1596
        char *s = virBufferContentAndReset(&afterStateMatch);
 
1597
 
 
1598
        virBufferAdd(&buf, s, -1);
 
1599
 
 
1600
        VIR_FREE(s);
 
1601
    }
 
1602
 
 
1603
    virBufferAsprintf(&buf,
 
1604
                      " -j %s" CMD_DEF_POST CMD_SEPARATOR
 
1605
                      CMD_EXEC,
 
1606
                      target);
 
1607
 
 
1608
    if (virBufferError(&buf) || virBufferError(&prefix)) {
 
1609
        virBufferFreeAndReset(&buf);
 
1610
        virBufferFreeAndReset(&prefix);
 
1611
        virReportOOMError();
 
1612
        return -1;
 
1613
    }
 
1614
 
 
1615
    if (virBufferUse(&prefix)) {
 
1616
        char *s = virBufferContentAndReset(&buf);
 
1617
 
 
1618
        virBufferAdd(&prefix, s, -1);
 
1619
 
 
1620
        VIR_FREE(s);
 
1621
 
 
1622
        final = &prefix;
 
1623
 
 
1624
        if (virBufferError(&prefix)) {
 
1625
            virBufferFreeAndReset(&prefix);
 
1626
            virReportOOMError();
 
1627
            return -1;
 
1628
        }
 
1629
    } else
 
1630
        final = &buf;
 
1631
 
 
1632
 
 
1633
    return ebiptablesAddRuleInst(res,
 
1634
                                 virBufferContentAndReset(final),
 
1635
                                 nwfilter->chainsuffix,
 
1636
                                 nwfilter->chainPriority,
 
1637
                                 '\0',
 
1638
                                 rule->priority,
 
1639
                                 (isIPv6) ? RT_IP6TABLES : RT_IPTABLES);
 
1640
 
 
1641
 
 
1642
err_exit:
 
1643
    virBufferFreeAndReset(&buf);
 
1644
    virBufferFreeAndReset(&prefix);
 
1645
    virBufferFreeAndReset(&afterStateMatch);
 
1646
 
 
1647
    return -1;
 
1648
 
 
1649
exit_no_error:
 
1650
    virBufferFreeAndReset(&buf);
 
1651
    virBufferFreeAndReset(&prefix);
 
1652
    virBufferFreeAndReset(&afterStateMatch);
 
1653
 
 
1654
    return 0;
 
1655
}
 
1656
 
 
1657
 
 
1658
static int
 
1659
printStateMatchFlags(int32_t flags, char **bufptr)
 
1660
{
 
1661
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
1662
    virNWFilterPrintStateMatchFlags(&buf,
 
1663
                                    "-m state --state ",
 
1664
                                    flags,
 
1665
                                    false);
 
1666
    if (virBufferError(&buf)) {
 
1667
        virBufferFreeAndReset(&buf);
 
1668
        virReportOOMError();
 
1669
        return -1;
 
1670
    }
 
1671
    *bufptr = virBufferContentAndReset(&buf);
 
1672
    return 0;
 
1673
}
 
1674
 
 
1675
static int
 
1676
iptablesCreateRuleInstanceStateCtrl(virNWFilterDefPtr nwfilter,
 
1677
                                    virNWFilterRuleDefPtr rule,
 
1678
                                    const char *ifname,
 
1679
                                    virNWFilterVarCombIterPtr vars,
 
1680
                                    virNWFilterRuleInstPtr res,
 
1681
                                    bool isIPv6)
 
1682
{
 
1683
    int rc;
 
1684
    int directionIn = 0;
 
1685
    char chainPrefix[2];
 
1686
    bool maySkipICMP, inout = false;
 
1687
    char *matchState = NULL;
 
1688
    bool create;
 
1689
 
 
1690
    if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
 
1691
        (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
 
1692
        directionIn = 1;
 
1693
        inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
 
1694
    }
 
1695
 
 
1696
    chainPrefix[0] = 'F';
 
1697
 
 
1698
    maySkipICMP = directionIn || inout;
 
1699
 
 
1700
    create = true;
 
1701
    matchState = NULL;
 
1702
 
 
1703
    if (directionIn && !inout) {
 
1704
        if ((rule->flags & IPTABLES_STATE_FLAGS))
 
1705
            create = false;
 
1706
    }
 
1707
 
 
1708
    if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
 
1709
        if (printStateMatchFlags(rule->flags, &matchState) < 0)
 
1710
            return -1;
 
1711
    }
 
1712
 
 
1713
    chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
 
1714
    if (create) {
 
1715
        rc = _iptablesCreateRuleInstance(directionIn,
 
1716
                                         chainPrefix,
 
1717
                                         nwfilter,
 
1718
                                         rule,
 
1719
                                         ifname,
 
1720
                                         vars,
 
1721
                                         res,
 
1722
                                         matchState, false,
 
1723
                                         "RETURN",
 
1724
                                         isIPv6,
 
1725
                                         maySkipICMP);
 
1726
 
 
1727
        VIR_FREE(matchState);
 
1728
        if (rc < 0)
 
1729
            return rc;
 
1730
    }
 
1731
 
 
1732
    maySkipICMP = !directionIn || inout;
 
1733
    create = true;
 
1734
 
 
1735
    if (!directionIn) {
 
1736
        if ((rule->flags & IPTABLES_STATE_FLAGS))
 
1737
            create = false;
 
1738
    }
 
1739
 
 
1740
    if (create && (rule->flags & IPTABLES_STATE_FLAGS)) {
 
1741
        if (printStateMatchFlags(rule->flags, &matchState) < 0)
 
1742
            return -1;
 
1743
    }
 
1744
 
 
1745
    chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
 
1746
    if (create) {
 
1747
        rc = _iptablesCreateRuleInstance(!directionIn,
 
1748
                                         chainPrefix,
 
1749
                                         nwfilter,
 
1750
                                         rule,
 
1751
                                         ifname,
 
1752
                                         vars,
 
1753
                                         res,
 
1754
                                         matchState, false,
 
1755
                                         "ACCEPT",
 
1756
                                         isIPv6,
 
1757
                                         maySkipICMP);
 
1758
 
 
1759
        VIR_FREE(matchState);
 
1760
 
 
1761
        if (rc < 0)
 
1762
            return rc;
 
1763
    }
 
1764
 
 
1765
    maySkipICMP = directionIn;
 
1766
 
 
1767
    create = true;
 
1768
 
 
1769
    if (directionIn && !inout) {
 
1770
        if ((rule->flags & IPTABLES_STATE_FLAGS))
 
1771
            create = false;
 
1772
    } else {
 
1773
        if ((rule->flags & IPTABLES_STATE_FLAGS)) {
 
1774
            if (printStateMatchFlags(rule->flags, &matchState) < 0)
 
1775
                return -1;
 
1776
        }
 
1777
    }
 
1778
 
 
1779
    if (create) {
 
1780
        chainPrefix[0] = 'H';
 
1781
        chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
 
1782
        rc = _iptablesCreateRuleInstance(directionIn,
 
1783
                                         chainPrefix,
 
1784
                                         nwfilter,
 
1785
                                         rule,
 
1786
                                         ifname,
 
1787
                                         vars,
 
1788
                                         res,
 
1789
                                         matchState, false,
 
1790
                                         "RETURN",
 
1791
                                         isIPv6,
 
1792
                                         maySkipICMP);
 
1793
        VIR_FREE(matchState);
 
1794
    }
 
1795
 
 
1796
    return rc;
 
1797
}
 
1798
 
 
1799
 
 
1800
static int
 
1801
iptablesCreateRuleInstance(virNWFilterDefPtr nwfilter,
 
1802
                           virNWFilterRuleDefPtr rule,
 
1803
                           const char *ifname,
 
1804
                           virNWFilterVarCombIterPtr vars,
 
1805
                           virNWFilterRuleInstPtr res,
 
1806
                           bool isIPv6)
 
1807
{
 
1808
    int rc;
 
1809
    int directionIn = 0;
 
1810
    char chainPrefix[2];
 
1811
    int needState = 1;
 
1812
    bool maySkipICMP, inout = false;
 
1813
    const char *matchState;
 
1814
 
 
1815
    if (!(rule->flags & RULE_FLAG_NO_STATEMATCH) &&
 
1816
         (rule->flags & IPTABLES_STATE_FLAGS)) {
 
1817
        return iptablesCreateRuleInstanceStateCtrl(nwfilter,
 
1818
                                                   rule,
 
1819
                                                   ifname,
 
1820
                                                   vars,
 
1821
                                                   res,
 
1822
                                                   isIPv6);
 
1823
    }
 
1824
 
 
1825
    if ((rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN) ||
 
1826
        (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT)) {
 
1827
        directionIn = 1;
 
1828
        inout = (rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
 
1829
        if (inout)
 
1830
            needState = 0;
 
1831
    }
 
1832
 
 
1833
    if ((rule->flags & RULE_FLAG_NO_STATEMATCH))
 
1834
        needState = 0;
 
1835
 
 
1836
    chainPrefix[0] = 'F';
 
1837
 
 
1838
    maySkipICMP = directionIn || inout;
 
1839
 
 
1840
    if (needState)
 
1841
        matchState = directionIn ? MATCH_STATE_IN : MATCH_STATE_OUT;
 
1842
    else
 
1843
        matchState = NULL;
 
1844
 
 
1845
    chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
 
1846
    rc = _iptablesCreateRuleInstance(directionIn,
 
1847
                                     chainPrefix,
 
1848
                                     nwfilter,
 
1849
                                     rule,
 
1850
                                     ifname,
 
1851
                                     vars,
 
1852
                                     res,
 
1853
                                     matchState, true,
 
1854
                                     "RETURN",
 
1855
                                     isIPv6,
 
1856
                                     maySkipICMP);
 
1857
    if (rc < 0)
 
1858
        return rc;
 
1859
 
 
1860
 
 
1861
    maySkipICMP = !directionIn || inout;
 
1862
    if (needState)
 
1863
        matchState = directionIn ? MATCH_STATE_OUT : MATCH_STATE_IN;
 
1864
    else
 
1865
        matchState = NULL;
 
1866
 
 
1867
    chainPrefix[1] = CHAINPREFIX_HOST_OUT_TEMP;
 
1868
    rc = _iptablesCreateRuleInstance(!directionIn,
 
1869
                                     chainPrefix,
 
1870
                                     nwfilter,
 
1871
                                     rule,
 
1872
                                     ifname,
 
1873
                                     vars,
 
1874
                                     res,
 
1875
                                     matchState, true,
 
1876
                                     "ACCEPT",
 
1877
                                     isIPv6,
 
1878
                                     maySkipICMP);
 
1879
    if (rc < 0)
 
1880
        return rc;
 
1881
 
 
1882
    maySkipICMP = directionIn;
 
1883
    if (needState)
 
1884
        matchState = directionIn ? MATCH_STATE_IN : MATCH_STATE_OUT;
 
1885
    else
 
1886
        matchState = NULL;
 
1887
 
 
1888
    chainPrefix[0] = 'H';
 
1889
    chainPrefix[1] = CHAINPREFIX_HOST_IN_TEMP;
 
1890
    rc = _iptablesCreateRuleInstance(directionIn,
 
1891
                                     chainPrefix,
 
1892
                                     nwfilter,
 
1893
                                     rule,
 
1894
                                     ifname,
 
1895
                                     vars,
 
1896
                                     res,
 
1897
                                     matchState, true,
 
1898
                                     "RETURN",
 
1899
                                     isIPv6,
 
1900
                                     maySkipICMP);
 
1901
 
 
1902
    return rc;
 
1903
}
 
1904
 
 
1905
 
 
1906
 
 
1907
 
 
1908
/*
 
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
 
1917
 *
 
1918
 * Convert a single rule into its representation for later instantiation
 
1919
 *
 
1920
 * Returns 0 in case of success with the result stored in the data structure
 
1921
 * pointed to by res, != 0 otherwise.
 
1922
 */
 
1923
static int
 
1924
ebtablesCreateRuleInstance(char chainPrefix,
 
1925
                           virNWFilterDefPtr nwfilter,
 
1926
                           virNWFilterRuleDefPtr rule,
 
1927
                           const char *ifname,
 
1928
                           virNWFilterVarCombIterPtr vars,
 
1929
                           virNWFilterRuleInstPtr res,
 
1930
                           bool reverse)
 
1931
{
 
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;
 
1940
    const char *target;
 
1941
 
 
1942
    if (!ebtables_cmd_path) {
 
1943
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
 
1944
                               _("cannot create rule since ebtables tool is "
 
1945
                                 "missing."));
 
1946
        goto err_exit;
 
1947
    }
 
1948
 
 
1949
    if (STREQ(nwfilter->chainsuffix,
 
1950
              virNWFilterChainSuffixTypeToString(
 
1951
                  VIR_NWFILTER_CHAINSUFFIX_ROOT)))
 
1952
        PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
1953
    else
 
1954
        PRINT_CHAIN(chain, chainPrefix, ifname,
 
1955
                    nwfilter->chainsuffix);
 
1956
 
 
1957
 
 
1958
    switch (rule->prtclType) {
 
1959
    case VIR_NWFILTER_RULE_PROTOCOL_MAC:
 
1960
 
 
1961
        virBufferAsprintf(&buf,
 
1962
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
1963
                          chain);
 
1964
 
 
1965
        if (ebtablesHandleEthHdr(&buf,
 
1966
                                 vars,
 
1967
                                 &rule->p.ethHdrFilter.ethHdr,
 
1968
                                 reverse) < 0)
 
1969
            goto err_exit;
 
1970
 
 
1971
        if (HAS_ENTRY_ITEM(&rule->p.ethHdrFilter.dataProtocolID)) {
 
1972
            if (printDataTypeAsHex(vars,
 
1973
                                   number, sizeof(number),
 
1974
                                   &rule->p.ethHdrFilter.dataProtocolID) < 0)
 
1975
                goto err_exit;
 
1976
            virBufferAsprintf(&buf,
 
1977
                          " -p %s %s",
 
1978
                          ENTRY_GET_NEG_SIGN(&rule->p.ethHdrFilter.dataProtocolID),
 
1979
                          number);
 
1980
        }
 
1981
    break;
 
1982
 
 
1983
    case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
 
1984
 
 
1985
        virBufferAsprintf(&buf,
 
1986
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
1987
                          chain);
 
1988
 
 
1989
 
 
1990
        if (ebtablesHandleEthHdr(&buf,
 
1991
                                 vars,
 
1992
                                 &rule->p.vlanHdrFilter.ethHdr,
 
1993
                                 reverse) < 0)
 
1994
            goto err_exit;
 
1995
 
 
1996
        virBufferAddLit(&buf,
 
1997
                        " -p 0x8100");
 
1998
 
 
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) \
 
2004
                goto err_exit; \
 
2005
            virBufferAsprintf(&buf, \
 
2006
                          " " CLI " %s %s", \
 
2007
                          ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
 
2008
                          field); \
 
2009
        }
 
2010
 
 
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) \
 
2016
                goto err_exit; \
 
2017
            virBufferAsprintf(&buf, \
 
2018
                          " " CLI " %s %s", \
 
2019
                          ENTRY_GET_NEG_SIGN(&rule->p.STRUCT.ITEM), \
 
2020
                          field); \
 
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) \
 
2025
                    goto err_exit; \
 
2026
                virBufferAsprintf(&buf, SEP "%s", field); \
 
2027
            } \
 
2028
        }
 
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, "/")
 
2033
 
 
2034
        INST_ITEM(vlanHdrFilter, dataVlanID, "--vlan-id")
 
2035
        INST_ITEM(vlanHdrFilter, dataVlanEncap, "--vlan-encap")
 
2036
    break;
 
2037
 
 
2038
    case VIR_NWFILTER_RULE_PROTOCOL_STP:
 
2039
 
 
2040
        /* cannot handle inout direction with srcmask set in reverse dir.
 
2041
           since this clashes with -d below... */
 
2042
        if (reverse &&
 
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));
 
2049
            return -1;
 
2050
        }
 
2051
 
 
2052
        virBufferAsprintf(&buf,
 
2053
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
2054
                          chain);
 
2055
 
 
2056
 
 
2057
        if (ebtablesHandleEthHdr(&buf,
 
2058
                                 vars,
 
2059
                                 &rule->p.stpHdrFilter.ethHdr,
 
2060
                                 reverse) < 0)
 
2061
            goto err_exit;
 
2062
 
 
2063
        virBufferAddLit(&buf, " -d " NWFILTER_MAC_BGA);
 
2064
 
 
2065
        INST_ITEM(stpHdrFilter, dataType, "--stp-type")
 
2066
        INST_ITEM(stpHdrFilter, dataFlags, "--stp-flags")
 
2067
        INST_ITEM_RANGE(stpHdrFilter, dataRootPri, dataRootPriHi,
 
2068
                        "--stp-root-pri");
 
2069
        INST_ITEM_MASK( stpHdrFilter, dataRootAddr, dataRootAddrMask,
 
2070
                       "--stp-root-addr");
 
2071
        INST_ITEM_RANGE(stpHdrFilter, dataRootCost, dataRootCostHi,
 
2072
                        "--stp-root-cost");
 
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,
 
2080
                        "--stp-max-age");
 
2081
        INST_ITEM_RANGE(stpHdrFilter, dataHelloTime, dataHelloTimeHi,
 
2082
                        "--stp-hello-time");
 
2083
        INST_ITEM_RANGE(stpHdrFilter, dataFwdDelay, dataFwdDelayHi,
 
2084
                        "--stp-forward-delay");
 
2085
    break;
 
2086
 
 
2087
    case VIR_NWFILTER_RULE_PROTOCOL_ARP:
 
2088
    case VIR_NWFILTER_RULE_PROTOCOL_RARP:
 
2089
 
 
2090
        virBufferAsprintf(&buf,
 
2091
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
2092
                          chain);
 
2093
 
 
2094
        if (ebtablesHandleEthHdr(&buf,
 
2095
                                 vars,
 
2096
                                 &rule->p.arpHdrFilter.ethHdr,
 
2097
                                 reverse) < 0)
 
2098
            goto err_exit;
 
2099
 
 
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);
 
2104
 
 
2105
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataHWType)) {
 
2106
             if (printDataType(vars,
 
2107
                               number, sizeof(number),
 
2108
                               &rule->p.arpHdrFilter.dataHWType) < 0)
 
2109
                goto err_exit;
 
2110
           virBufferAsprintf(&buf,
 
2111
                          " --arp-htype %s %s",
 
2112
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataHWType),
 
2113
                          number);
 
2114
        }
 
2115
 
 
2116
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataOpcode)) {
 
2117
            if (printDataType(vars,
 
2118
                              number, sizeof(number),
 
2119
                              &rule->p.arpHdrFilter.dataOpcode) < 0)
 
2120
                goto err_exit;
 
2121
            virBufferAsprintf(&buf,
 
2122
                          " --arp-opcode %s %s",
 
2123
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataOpcode),
 
2124
                          number);
 
2125
        }
 
2126
 
 
2127
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataProtocolType)) {
 
2128
            if (printDataTypeAsHex(vars,
 
2129
                                   number, sizeof(number),
 
2130
                                   &rule->p.arpHdrFilter.dataProtocolType) < 0)
 
2131
                goto err_exit;
 
2132
            virBufferAsprintf(&buf,
 
2133
                          " --arp-ptype %s %s",
 
2134
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataProtocolType),
 
2135
                          number);
 
2136
        }
 
2137
 
 
2138
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcIPAddr)) {
 
2139
            if (printDataType(vars,
 
2140
                              ipaddr, sizeof(ipaddr),
 
2141
                              &rule->p.arpHdrFilter.dataARPSrcIPAddr) < 0)
 
2142
                goto err_exit;
 
2143
 
 
2144
            virBufferAsprintf(&buf,
 
2145
                          " %s %s %s",
 
2146
                          reverse ? "--arp-ip-dst" : "--arp-ip-src",
 
2147
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcIPAddr),
 
2148
                          ipaddr);
 
2149
        }
 
2150
 
 
2151
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstIPAddr)) {
 
2152
            if (printDataType(vars,
 
2153
                              ipaddr, sizeof(ipaddr),
 
2154
                              &rule->p.arpHdrFilter.dataARPDstIPAddr) < 0)
 
2155
                goto err_exit;
 
2156
 
 
2157
            virBufferAsprintf(&buf,
 
2158
                          " %s %s %s",
 
2159
                          reverse ? "--arp-ip-src" : "--arp-ip-dst",
 
2160
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstIPAddr),
 
2161
                          ipaddr);
 
2162
        }
 
2163
 
 
2164
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPSrcMACAddr)) {
 
2165
            if (printDataType(vars,
 
2166
                              macaddr, sizeof(macaddr),
 
2167
                              &rule->p.arpHdrFilter.dataARPSrcMACAddr) < 0)
 
2168
                goto err_exit;
 
2169
 
 
2170
            virBufferAsprintf(&buf,
 
2171
                          " %s %s %s",
 
2172
                          reverse ? "--arp-mac-dst" : "--arp-mac-src",
 
2173
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPSrcMACAddr),
 
2174
                          macaddr);
 
2175
        }
 
2176
 
 
2177
        if (HAS_ENTRY_ITEM(&rule->p.arpHdrFilter.dataARPDstMACAddr)) {
 
2178
            if (printDataType(vars,
 
2179
                              macaddr, sizeof(macaddr),
 
2180
                              &rule->p.arpHdrFilter.dataARPDstMACAddr) < 0)
 
2181
                goto err_exit;
 
2182
 
 
2183
            virBufferAsprintf(&buf,
 
2184
                          " %s %s %s",
 
2185
                          reverse ? "--arp-mac-src" : "--arp-mac-dst",
 
2186
                          ENTRY_GET_NEG_SIGN(&rule->p.arpHdrFilter.dataARPDstMACAddr),
 
2187
                          macaddr);
 
2188
        }
 
2189
 
 
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));
 
2195
        }
 
2196
    break;
 
2197
 
 
2198
    case VIR_NWFILTER_RULE_PROTOCOL_IP:
 
2199
        virBufferAsprintf(&buf,
 
2200
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
2201
                          chain);
 
2202
 
 
2203
        if (ebtablesHandleEthHdr(&buf,
 
2204
                                 vars,
 
2205
                                 &rule->p.ipHdrFilter.ethHdr,
 
2206
                                 reverse) < 0)
 
2207
            goto err_exit;
 
2208
 
 
2209
        virBufferAddLit(&buf,
 
2210
                        " -p ipv4");
 
2211
 
 
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)
 
2216
                goto err_exit;
 
2217
 
 
2218
            virBufferAsprintf(&buf,
 
2219
                          " %s %s %s",
 
2220
                          reverse ? "--ip-destination" : "--ip-source",
 
2221
                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr),
 
2222
                          ipaddr);
 
2223
 
 
2224
            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)) {
 
2225
                if (printDataType(vars,
 
2226
                                  number, sizeof(number),
 
2227
                                  &rule->p.ipHdrFilter.ipHdr.dataSrcIPMask)
 
2228
                    < 0)
 
2229
                    goto err_exit;
 
2230
                virBufferAsprintf(&buf,
 
2231
                             "/%s",
 
2232
                             number);
 
2233
            }
 
2234
        }
 
2235
 
 
2236
        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr)) {
 
2237
 
 
2238
            if (printDataType(vars,
 
2239
                              ipaddr, sizeof(ipaddr),
 
2240
                              &rule->p.ipHdrFilter.ipHdr.dataDstIPAddr) < 0)
 
2241
                goto err_exit;
 
2242
 
 
2243
            virBufferAsprintf(&buf,
 
2244
                          " %s %s %s",
 
2245
                          reverse ? "--ip-source" : "--ip-destination",
 
2246
                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDstIPAddr),
 
2247
                          ipaddr);
 
2248
 
 
2249
            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.ipHdr.dataDstIPMask)) {
 
2250
                if (printDataType(vars,
 
2251
                                  number, sizeof(number),
 
2252
                                  &rule->p.ipHdrFilter.ipHdr.dataDstIPMask)
 
2253
                    < 0)
 
2254
                    goto err_exit;
 
2255
                virBufferAsprintf(&buf,
 
2256
                                  "/%s",
 
2257
                                  number);
 
2258
            }
 
2259
        }
 
2260
 
 
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)
 
2265
                goto err_exit;
 
2266
 
 
2267
            virBufferAsprintf(&buf,
 
2268
                 " --ip-protocol %s %s",
 
2269
                 ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataProtocolID),
 
2270
                 number);
 
2271
        }
 
2272
 
 
2273
        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortStart)) {
 
2274
 
 
2275
            if (printDataType(vars,
 
2276
                              number, sizeof(number),
 
2277
                              &rule->p.ipHdrFilter.portData.dataSrcPortStart)
 
2278
                < 0)
 
2279
                goto err_exit;
 
2280
 
 
2281
            virBufferAsprintf(&buf,
 
2282
                          " %s %s %s",
 
2283
                          reverse ? "--ip-destination-port" : "--ip-source-port",
 
2284
                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataSrcPortStart),
 
2285
                          number);
 
2286
 
 
2287
            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataSrcPortEnd)) {
 
2288
                if (printDataType(vars,
 
2289
                                  number, sizeof(number),
 
2290
                                  &rule->p.ipHdrFilter.portData.dataSrcPortEnd)
 
2291
                    < 0)
 
2292
                    goto err_exit;
 
2293
 
 
2294
                virBufferAsprintf(&buf,
 
2295
                                  ":%s",
 
2296
                                  number);
 
2297
            }
 
2298
        }
 
2299
 
 
2300
        if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortStart)) {
 
2301
 
 
2302
            if (printDataType(vars,
 
2303
                              number, sizeof(number),
 
2304
                              &rule->p.ipHdrFilter.portData.dataDstPortStart)
 
2305
                < 0)
 
2306
                goto err_exit;
 
2307
 
 
2308
            virBufferAsprintf(&buf,
 
2309
                          " %s %s %s",
 
2310
                          reverse ? "--ip-source-port" : "--ip-destination-port",
 
2311
                          ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.portData.dataDstPortStart),
 
2312
                          number);
 
2313
 
 
2314
            if (HAS_ENTRY_ITEM(&rule->p.ipHdrFilter.portData.dataDstPortEnd)) {
 
2315
                if (printDataType(vars,
 
2316
                                number, sizeof(number),
 
2317
                                &rule->p.ipHdrFilter.portData.dataDstPortEnd)
 
2318
                    < 0)
 
2319
                    goto err_exit;
 
2320
 
 
2321
                virBufferAsprintf(&buf,
 
2322
                                  ":%s",
 
2323
                                  number);
 
2324
            }
 
2325
        }
 
2326
 
 
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)
 
2331
                goto err_exit;
 
2332
 
 
2333
            virBufferAsprintf(&buf,
 
2334
                       " --ip-tos %s %s",
 
2335
                       ENTRY_GET_NEG_SIGN(&rule->p.ipHdrFilter.ipHdr.dataDSCP),
 
2336
                       number);
 
2337
        }
 
2338
    break;
 
2339
 
 
2340
    case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
 
2341
        virBufferAsprintf(&buf,
 
2342
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
2343
                          chain);
 
2344
 
 
2345
        if (ebtablesHandleEthHdr(&buf,
 
2346
                                 vars,
 
2347
                                 &rule->p.ipv6HdrFilter.ethHdr,
 
2348
                                 reverse) < 0)
 
2349
            goto err_exit;
 
2350
 
 
2351
        virBufferAddLit(&buf,
 
2352
                        " -p ipv6");
 
2353
 
 
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)
 
2358
                goto err_exit;
 
2359
 
 
2360
            virBufferAsprintf(&buf,
 
2361
                          " %s %s %s",
 
2362
                          reverse ? "--ip6-destination" : "--ip6-source",
 
2363
                          ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr),
 
2364
                          ipv6addr);
 
2365
 
 
2366
            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)) {
 
2367
                if (printDataType(vars,
 
2368
                                  number, sizeof(number),
 
2369
                                  &rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask)
 
2370
                    < 0)
 
2371
                    goto err_exit;
 
2372
                virBufferAsprintf(&buf,
 
2373
                             "/%s",
 
2374
                             number);
 
2375
            }
 
2376
        }
 
2377
 
 
2378
        if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr)) {
 
2379
 
 
2380
            if (printDataType(vars,
 
2381
                              ipv6addr, sizeof(ipv6addr),
 
2382
                              &rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr) < 0)
 
2383
                goto err_exit;
 
2384
 
 
2385
            virBufferAsprintf(&buf,
 
2386
                          " %s %s %s",
 
2387
                          reverse ? "--ip6-source" : "--ip6-destination",
 
2388
                          ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr),
 
2389
                          ipv6addr);
 
2390
 
 
2391
            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)) {
 
2392
                if (printDataType(vars,
 
2393
                                  number, sizeof(number),
 
2394
                                  &rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask)
 
2395
                    < 0)
 
2396
                    goto err_exit;
 
2397
                virBufferAsprintf(&buf,
 
2398
                                  "/%s",
 
2399
                                  number);
 
2400
            }
 
2401
        }
 
2402
 
 
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)
 
2407
                goto err_exit;
 
2408
 
 
2409
            virBufferAsprintf(&buf,
 
2410
                 " --ip6-protocol %s %s",
 
2411
                 ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.ipHdr.dataProtocolID),
 
2412
                 number);
 
2413
        }
 
2414
 
 
2415
        if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart)) {
 
2416
 
 
2417
            if (printDataType(vars,
 
2418
                              number, sizeof(number),
 
2419
                              &rule->p.ipv6HdrFilter.portData.dataSrcPortStart)
 
2420
                < 0)
 
2421
                goto err_exit;
 
2422
 
 
2423
            virBufferAsprintf(&buf,
 
2424
                          " %s %s %s",
 
2425
                          reverse ? "--ip6-destination-port" : "--ip6-source-port",
 
2426
                          ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataSrcPortStart),
 
2427
                          number);
 
2428
 
 
2429
            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)) {
 
2430
                if (printDataType(vars,
 
2431
                                  number, sizeof(number),
 
2432
                                  &rule->p.ipv6HdrFilter.portData.dataSrcPortEnd)
 
2433
                    < 0)
 
2434
                    goto err_exit;
 
2435
 
 
2436
                virBufferAsprintf(&buf,
 
2437
                                  ":%s",
 
2438
                                  number);
 
2439
            }
 
2440
        }
 
2441
 
 
2442
        if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortStart)) {
 
2443
 
 
2444
            if (printDataType(vars,
 
2445
                              number, sizeof(number),
 
2446
                              &rule->p.ipv6HdrFilter.portData.dataDstPortStart)
 
2447
                < 0)
 
2448
                goto err_exit;
 
2449
 
 
2450
            virBufferAsprintf(&buf,
 
2451
                          " %s %s %s",
 
2452
                          reverse ? "--ip6-source-port" : "--ip6-destination-port",
 
2453
                          ENTRY_GET_NEG_SIGN(&rule->p.ipv6HdrFilter.portData.dataDstPortStart),
 
2454
                          number);
 
2455
 
 
2456
            if (HAS_ENTRY_ITEM(&rule->p.ipv6HdrFilter.portData.dataDstPortEnd)) {
 
2457
                if (printDataType(vars,
 
2458
                                  number, sizeof(number),
 
2459
                                  &rule->p.ipv6HdrFilter.portData.dataDstPortEnd)
 
2460
                    < 0)
 
2461
                    goto err_exit;
 
2462
 
 
2463
                virBufferAsprintf(&buf,
 
2464
                                  ":%s",
 
2465
                                  number);
 
2466
            }
 
2467
        }
 
2468
    break;
 
2469
 
 
2470
    case VIR_NWFILTER_RULE_PROTOCOL_NONE:
 
2471
        virBufferAsprintf(&buf,
 
2472
                          CMD_DEF_PRE "$EBT -t nat -%%c %s %%s",
 
2473
                          chain);
 
2474
    break;
 
2475
 
 
2476
    default:
 
2477
        return -1;
 
2478
    }
 
2479
 
 
2480
    switch (rule->action) {
 
2481
    case VIR_NWFILTER_RULE_ACTION_REJECT:
 
2482
        /* REJECT not supported */
 
2483
        target = virNWFilterJumpTargetTypeToString(
 
2484
                                     VIR_NWFILTER_RULE_ACTION_DROP);
 
2485
    break;
 
2486
    default:
 
2487
        target = virNWFilterJumpTargetTypeToString(rule->action);
 
2488
    }
 
2489
 
 
2490
    virBufferAsprintf(&buf,
 
2491
                      " -j %s" CMD_DEF_POST CMD_SEPARATOR
 
2492
                      CMD_EXEC,
 
2493
                      target);
 
2494
 
 
2495
    if (virBufferError(&buf)) {
 
2496
        virBufferFreeAndReset(&buf);
 
2497
        virReportOOMError();
 
2498
        return -1;
 
2499
    }
 
2500
 
 
2501
    return ebiptablesAddRuleInst(res,
 
2502
                                 virBufferContentAndReset(&buf),
 
2503
                                 nwfilter->chainsuffix,
 
2504
                                 nwfilter->chainPriority,
 
2505
                                 chainPrefix,
 
2506
                                 rule->priority,
 
2507
                                 RT_EBTABLES);
 
2508
 
 
2509
err_exit:
 
2510
    virBufferFreeAndReset(&buf);
 
2511
 
 
2512
    return -1;
 
2513
}
 
2514
 
 
2515
 
 
2516
/*
 
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
 
2523
 *
 
2524
 * Convert a single rule into its representation for later instantiation
 
2525
 *
 
2526
 * Returns 0 in case of success with the result stored in the data structure
 
2527
 * pointed to by res, -1 otherwise
 
2528
 */
 
2529
static int
 
2530
ebiptablesCreateRuleInstance(enum virDomainNetType nettype ATTRIBUTE_UNUSED,
 
2531
                             virNWFilterDefPtr nwfilter,
 
2532
                             virNWFilterRuleDefPtr rule,
 
2533
                             const char *ifname,
 
2534
                             virNWFilterVarCombIterPtr vars,
 
2535
                             virNWFilterRuleInstPtr res)
 
2536
{
 
2537
    int rc = 0;
 
2538
    bool isIPv6;
 
2539
 
 
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:
 
2549
 
 
2550
        if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_OUT ||
 
2551
            rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
 
2552
            rc = ebtablesCreateRuleInstance(CHAINPREFIX_HOST_IN_TEMP,
 
2553
                                            nwfilter,
 
2554
                                            rule,
 
2555
                                            ifname,
 
2556
                                            vars,
 
2557
                                            res,
 
2558
                                            rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT);
 
2559
            if (rc < 0)
 
2560
                return rc;
 
2561
        }
 
2562
 
 
2563
        if (rule->tt == VIR_NWFILTER_RULE_DIRECTION_IN ||
 
2564
            rule->tt == VIR_NWFILTER_RULE_DIRECTION_INOUT) {
 
2565
            rc = ebtablesCreateRuleInstance(CHAINPREFIX_HOST_OUT_TEMP,
 
2566
                                            nwfilter,
 
2567
                                            rule,
 
2568
                                            ifname,
 
2569
                                            vars,
 
2570
                                            res,
 
2571
                                            false);
 
2572
        }
 
2573
    break;
 
2574
 
 
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:
 
2584
        isIPv6 = 0;
 
2585
        rc = iptablesCreateRuleInstance(nwfilter,
 
2586
                                        rule,
 
2587
                                        ifname,
 
2588
                                        vars,
 
2589
                                        res,
 
2590
                                        isIPv6);
 
2591
    break;
 
2592
 
 
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:
 
2601
        isIPv6 = 1;
 
2602
        rc = iptablesCreateRuleInstance(nwfilter,
 
2603
                                        rule,
 
2604
                                        ifname,
 
2605
                                        vars,
 
2606
                                        res,
 
2607
                                        isIPv6);
 
2608
    break;
 
2609
 
 
2610
    case VIR_NWFILTER_RULE_PROTOCOL_LAST:
 
2611
        virNWFilterReportError(VIR_ERR_OPERATION_FAILED,
 
2612
                               "%s", _("illegal protocol type"));
 
2613
        rc = -1;
 
2614
    break;
 
2615
    }
 
2616
 
 
2617
    return rc;
 
2618
}
 
2619
 
 
2620
static int
 
2621
ebiptablesCreateRuleInstanceIterate(
 
2622
                             enum virDomainNetType nettype ATTRIBUTE_UNUSED,
 
2623
                             virNWFilterDefPtr nwfilter,
 
2624
                             virNWFilterRuleDefPtr rule,
 
2625
                             const char *ifname,
 
2626
                             virNWFilterHashTablePtr vars,
 
2627
                             virNWFilterRuleInstPtr res)
 
2628
{
 
2629
    int rc = 0;
 
2630
    virNWFilterVarCombIterPtr vciter;
 
2631
 
 
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.
 
2635
     */
 
2636
    vciter = virNWFilterVarCombIterCreate(vars,
 
2637
                                          rule->varAccess, rule->nVarAccess);
 
2638
    if (!vciter)
 
2639
        return -1;
 
2640
 
 
2641
    do {
 
2642
        rc = ebiptablesCreateRuleInstance(nettype,
 
2643
                                          nwfilter,
 
2644
                                          rule,
 
2645
                                          ifname,
 
2646
                                          vciter,
 
2647
                                          res);
 
2648
        if (rc < 0)
 
2649
            break;
 
2650
        vciter = virNWFilterVarCombIterNext(vciter);
 
2651
    } while (vciter != NULL);
 
2652
 
 
2653
    virNWFilterVarCombIterFree(vciter);
 
2654
 
 
2655
    return rc;
 
2656
}
 
2657
 
 
2658
static int
 
2659
ebiptablesFreeRuleInstance(void *_inst)
 
2660
{
 
2661
    ebiptablesRuleInstFree((ebiptablesRuleInstPtr)_inst);
 
2662
    return 0;
 
2663
}
 
2664
 
 
2665
 
 
2666
static int
 
2667
ebiptablesDisplayRuleInstance(void *_inst)
 
2668
{
 
2669
    ebiptablesRuleInstPtr inst = (ebiptablesRuleInstPtr)_inst;
 
2670
    VIR_INFO("Command Template: '%s', Needed protocol: '%s'",
 
2671
             inst->commandTemplate,
 
2672
             inst->neededProtocolChain);
 
2673
    return 0;
 
2674
}
 
2675
 
 
2676
 
 
2677
/**
 
2678
 * ebiptablesExecCLI:
 
2679
 * @buf : pointer to virBuffer containing the string with the commands to
 
2680
 *        execute.
 
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.
 
2687
 *
 
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
 
2690
 * script.
 
2691
 *
 
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).
 
2695
 */
 
2696
static int
 
2697
ebiptablesExecCLI(virBufferPtr buf,
 
2698
                  int *status, char **outbuf)
 
2699
{
 
2700
    int rc = -1;
 
2701
    virCommandPtr cmd;
 
2702
 
 
2703
    if (status)
 
2704
         *status = 0;
 
2705
 
 
2706
    if (!virBufferError(buf) && !virBufferUse(buf))
 
2707
        return 0;
 
2708
 
 
2709
    if (outbuf)
 
2710
        VIR_FREE(*outbuf);
 
2711
 
 
2712
    cmd = virCommandNewArgList("/bin/sh", "-c", NULL);
 
2713
    virCommandAddArgBuffer(cmd, buf);
 
2714
    if (outbuf)
 
2715
        virCommandSetOutputBuffer(cmd, outbuf);
 
2716
 
 
2717
    virMutexLock(&execCLIMutex);
 
2718
 
 
2719
    rc = virCommandRun(cmd, status);
 
2720
 
 
2721
    virMutexUnlock(&execCLIMutex);
 
2722
 
 
2723
    virCommandFree(cmd);
 
2724
 
 
2725
    return rc;
 
2726
}
 
2727
 
 
2728
 
 
2729
static int
 
2730
ebtablesCreateTmpRootChain(virBufferPtr buf,
 
2731
                           int incoming, const char *ifname,
 
2732
                           int stopOnError)
 
2733
{
 
2734
    char chain[MAX_CHAINNAME_LENGTH];
 
2735
    char chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
2736
                                  : CHAINPREFIX_HOST_OUT_TEMP;
 
2737
 
 
2738
    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
2739
 
 
2740
    virBufferAsprintf(buf,
 
2741
                      CMD_DEF("$EBT -t nat -N %s") CMD_SEPARATOR
 
2742
                      CMD_EXEC
 
2743
                      "%s",
 
2744
                      chain,
 
2745
                      CMD_STOPONERR(stopOnError));
 
2746
 
 
2747
    return 0;
 
2748
}
 
2749
 
 
2750
 
 
2751
static int
 
2752
ebtablesLinkTmpRootChain(virBufferPtr buf,
 
2753
                         int incoming, const char *ifname,
 
2754
                         int stopOnError)
 
2755
{
 
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';
 
2760
 
 
2761
    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
2762
 
 
2763
    virBufferAsprintf(buf,
 
2764
                      CMD_DEF("$EBT -t nat -A %s -%c %s -j %s") CMD_SEPARATOR
 
2765
                      CMD_EXEC
 
2766
                      "%s",
 
2767
                      (incoming) ? EBTABLES_CHAIN_INCOMING
 
2768
                                 : EBTABLES_CHAIN_OUTGOING,
 
2769
                      iodev, ifname, chain,
 
2770
 
 
2771
                      CMD_STOPONERR(stopOnError));
 
2772
 
 
2773
    return 0;
 
2774
}
 
2775
 
 
2776
 
 
2777
static int
 
2778
_ebtablesRemoveRootChain(virBufferPtr buf,
 
2779
                         int incoming, const char *ifname,
 
2780
                         int isTempChain)
 
2781
{
 
2782
    char chain[MAX_CHAINNAME_LENGTH];
 
2783
    char chainPrefix;
 
2784
    if (isTempChain)
 
2785
        chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
2786
                                 : CHAINPREFIX_HOST_OUT_TEMP;
 
2787
    else
 
2788
        chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
 
2789
                                 : CHAINPREFIX_HOST_OUT;
 
2790
 
 
2791
    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
2792
 
 
2793
    virBufferAsprintf(buf,
 
2794
                      "$EBT -t nat -F %s" CMD_SEPARATOR
 
2795
                      "$EBT -t nat -X %s" CMD_SEPARATOR,
 
2796
                      chain,
 
2797
                      chain);
 
2798
 
 
2799
    return 0;
 
2800
}
 
2801
 
 
2802
 
 
2803
static int
 
2804
ebtablesRemoveRootChain(virBufferPtr buf,
 
2805
                        int incoming, const char *ifname)
 
2806
{
 
2807
    return _ebtablesRemoveRootChain(buf, incoming, ifname, 0);
 
2808
}
 
2809
 
 
2810
 
 
2811
static int
 
2812
ebtablesRemoveTmpRootChain(virBufferPtr buf,
 
2813
                           int incoming, const char *ifname)
 
2814
{
 
2815
    return _ebtablesRemoveRootChain(buf, incoming, ifname, 1);
 
2816
}
 
2817
 
 
2818
 
 
2819
static int
 
2820
_ebtablesUnlinkRootChain(virBufferPtr buf,
 
2821
                         int incoming, const char *ifname,
 
2822
                         int isTempChain)
 
2823
{
 
2824
    char chain[MAX_CHAINNAME_LENGTH];
 
2825
    char iodev = (incoming) ? 'i' : 'o';
 
2826
    char chainPrefix;
 
2827
 
 
2828
    if (isTempChain) {
 
2829
        chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN_TEMP
 
2830
                                 : CHAINPREFIX_HOST_OUT_TEMP;
 
2831
    } else {
 
2832
        chainPrefix = (incoming) ? CHAINPREFIX_HOST_IN
 
2833
                                 : CHAINPREFIX_HOST_OUT;
 
2834
    }
 
2835
 
 
2836
    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
2837
 
 
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);
 
2843
 
 
2844
    return 0;
 
2845
}
 
2846
 
 
2847
 
 
2848
static int
 
2849
ebtablesUnlinkRootChain(virBufferPtr buf,
 
2850
                        int incoming, const char *ifname)
 
2851
{
 
2852
    return _ebtablesUnlinkRootChain(buf, incoming, ifname, 0);
 
2853
}
 
2854
 
 
2855
 
 
2856
static int
 
2857
ebtablesUnlinkTmpRootChain(virBufferPtr buf,
 
2858
                           int incoming, const char *ifname)
 
2859
{
 
2860
    return _ebtablesUnlinkRootChain(buf, incoming, ifname, 1);
 
2861
}
 
2862
 
 
2863
 
 
2864
static int
 
2865
ebtablesCreateTmpSubChain(ebiptablesRuleInstPtr *inst,
 
2866
                          int *nRuleInstances,
 
2867
                          int incoming,
 
2868
                          const char *ifname,
 
2869
                          enum l3_proto_idx protoidx,
 
2870
                          const char *filtername,
 
2871
                          int stopOnError,
 
2872
                          virNWFilterChainPriority priority)
 
2873
{
 
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;
 
2881
 
 
2882
    PRINT_ROOT_CHAIN(rootchain, chainPrefix, ifname);
 
2883
    PRINT_CHAIN(chain, chainPrefix, ifname,
 
2884
                (filtername) ? filtername : l3_protocols[protoidx].val);
 
2885
 
 
2886
    switch (protoidx) {
 
2887
    case L2_PROTO_MAC_IDX:
 
2888
        protostr = strdup("");
 
2889
        break;
 
2890
    case L2_PROTO_STP_IDX:
 
2891
        ignore_value(virAsprintf(&protostr, "-d " NWFILTER_MAC_BGA " "));
 
2892
        break;
 
2893
    default:
 
2894
        ignore_value(virAsprintf(&protostr, "-p 0x%04x ",
 
2895
                     l3_protocols[protoidx].attr));
 
2896
        break;
 
2897
    }
 
2898
 
 
2899
    if (!protostr) {
 
2900
        virReportOOMError();
 
2901
        return -1;
 
2902
    }
 
2903
 
 
2904
    virBufferAsprintf(&buf,
 
2905
                      CMD_DEF("$EBT -t nat -F %s") CMD_SEPARATOR
 
2906
                      CMD_EXEC
 
2907
                      CMD_DEF("$EBT -t nat -X %s") CMD_SEPARATOR
 
2908
                      CMD_EXEC
 
2909
                      CMD_DEF("$EBT -t nat -N %s") CMD_SEPARATOR
 
2910
                      CMD_EXEC
 
2911
                      "%s"
 
2912
                      CMD_DEF("$EBT -t nat -%%c %s %%s %s-j %s")
 
2913
                          CMD_SEPARATOR
 
2914
                      CMD_EXEC
 
2915
                      "%s",
 
2916
 
 
2917
                      chain,
 
2918
                      chain,
 
2919
                      chain,
 
2920
 
 
2921
                      CMD_STOPONERR(stopOnError),
 
2922
 
 
2923
                      rootchain, protostr, chain,
 
2924
 
 
2925
                      CMD_STOPONERR(stopOnError));
 
2926
 
 
2927
    VIR_FREE(protostr);
 
2928
 
 
2929
    if (virBufferError(&buf) ||
 
2930
        VIR_EXPAND_N(tmp, count, 1) < 0) {
 
2931
        virReportOOMError();
 
2932
        virBufferFreeAndReset(&buf);
 
2933
        return -1;
 
2934
    }
 
2935
 
 
2936
    *nRuleInstances = count;
 
2937
    *inst = tmp;
 
2938
 
 
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);
 
2944
 
 
2945
    return 0;
 
2946
}
 
2947
 
 
2948
static int
 
2949
_ebtablesRemoveSubChains(virBufferPtr buf,
 
2950
                         const char *ifname,
 
2951
                         const char *chains)
 
2952
{
 
2953
    char rootchain[MAX_CHAINNAME_LENGTH];
 
2954
    unsigned i;
 
2955
 
 
2956
    NWFILTER_SET_EBTABLES_SHELLVAR(buf);
 
2957
 
 
2958
    virBufferAsprintf(buf, NWFILTER_FUNC_COLLECT_CHAINS,
 
2959
                      chains);
 
2960
    virBufferAdd(buf, NWFILTER_FUNC_RM_CHAINS, -1);
 
2961
 
 
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);
 
2967
    }
 
2968
    virBufferAddLit(buf, ")\"\n");
 
2969
 
 
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",
 
2974
                          rootchain);
 
2975
    }
 
2976
    virBufferAddLit(buf, "rm_chains $chains\n");
 
2977
 
 
2978
    return 0;
 
2979
}
 
2980
 
 
2981
static int
 
2982
ebtablesRemoveSubChains(virBufferPtr buf,
 
2983
                        const char *ifname)
 
2984
{
 
2985
    char chains[3] = {
 
2986
        CHAINPREFIX_HOST_IN,
 
2987
        CHAINPREFIX_HOST_OUT,
 
2988
        0
 
2989
    };
 
2990
 
 
2991
    return _ebtablesRemoveSubChains(buf, ifname, chains);
 
2992
}
 
2993
 
 
2994
static int
 
2995
ebtablesRemoveTmpSubChains(virBufferPtr buf,
 
2996
                           const char *ifname)
 
2997
{
 
2998
    char chains[3] = {
 
2999
        CHAINPREFIX_HOST_IN_TEMP,
 
3000
        CHAINPREFIX_HOST_OUT_TEMP,
 
3001
        0
 
3002
    };
 
3003
 
 
3004
    return _ebtablesRemoveSubChains(buf, ifname, chains);
 
3005
}
 
3006
 
 
3007
static int
 
3008
ebtablesRenameTmpSubChain(virBufferPtr buf,
 
3009
                          int incoming,
 
3010
                          const char *ifname,
 
3011
                          const char *protocol)
 
3012
{
 
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;
 
3018
 
 
3019
    if (protocol) {
 
3020
        PRINT_CHAIN(tmpchain, tmpChainPrefix, ifname, protocol);
 
3021
        PRINT_CHAIN(   chain,    chainPrefix, ifname, protocol);
 
3022
    } else {
 
3023
        PRINT_ROOT_CHAIN(tmpchain, tmpChainPrefix, ifname);
 
3024
        PRINT_ROOT_CHAIN(   chain,    chainPrefix, ifname);
 
3025
    }
 
3026
 
 
3027
    virBufferAsprintf(buf,
 
3028
                      "$EBT -t nat -E %s %s" CMD_SEPARATOR,
 
3029
                      tmpchain, chain);
 
3030
    return 0;
 
3031
}
 
3032
 
 
3033
static int
 
3034
ebtablesRenameTmpRootChain(virBufferPtr buf,
 
3035
                           int incoming,
 
3036
                           const char *ifname)
 
3037
{
 
3038
    return ebtablesRenameTmpSubChain(buf, incoming, ifname, NULL);
 
3039
}
 
3040
 
 
3041
static int
 
3042
ebtablesRenameTmpSubAndRootChains(virBufferPtr buf,
 
3043
                                  const char *ifname)
 
3044
{
 
3045
    char rootchain[MAX_CHAINNAME_LENGTH];
 
3046
    unsigned i;
 
3047
    char chains[3] = {
 
3048
        CHAINPREFIX_HOST_IN_TEMP,
 
3049
        CHAINPREFIX_HOST_OUT_TEMP,
 
3050
        0};
 
3051
 
 
3052
    NWFILTER_SET_EBTABLES_SHELLVAR(buf);
 
3053
 
 
3054
    virBufferAsprintf(buf, NWFILTER_FUNC_COLLECT_CHAINS,
 
3055
                      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);
 
3061
 
 
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);
 
3067
    }
 
3068
    virBufferAddLit(buf, ")\"\n");
 
3069
 
 
3070
    virBufferAddLit(buf, "rename_chains $chains\n");
 
3071
 
 
3072
    ebtablesRenameTmpRootChain(buf, 1, ifname);
 
3073
    ebtablesRenameTmpRootChain(buf, 0, ifname);
 
3074
 
 
3075
    return 0;
 
3076
}
 
3077
 
 
3078
static void
 
3079
ebiptablesInstCommand(virBufferPtr buf,
 
3080
                      const char *templ, char cmd, int pos,
 
3081
                      int stopOnError)
 
3082
{
 
3083
    char position[10] = { 0 };
 
3084
    if (pos >= 0)
 
3085
        snprintf(position, sizeof(position), "%d", pos);
 
3086
    virBufferAsprintf(buf, templ, cmd, position);
 
3087
    virBufferAsprintf(buf, CMD_SEPARATOR "%s",
 
3088
                      CMD_STOPONERR(stopOnError));
 
3089
}
 
3090
 
 
3091
 
 
3092
/**
 
3093
 * ebiptablesCanApplyBasicRules
 
3094
 *
 
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.
 
3098
 */
 
3099
static int
 
3100
ebiptablesCanApplyBasicRules(void) {
 
3101
    return ebtables_cmd_path != NULL;
 
3102
}
 
3103
 
 
3104
/**
 
3105
 * ebtablesApplyBasicRules
 
3106
 *
 
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
 
3109
 *    interface
 
3110
 *
 
3111
 * Returns 0 on success, -1 on failure with the rules removed
 
3112
 *
 
3113
 * Apply basic filtering rules on the given interface
 
3114
 * - filtering for MAC address spoofing
 
3115
 * - allowing IPv4 & ARP traffic
 
3116
 */
 
3117
static int
 
3118
ebtablesApplyBasicRules(const char *ifname,
 
3119
                        const unsigned char *macaddr)
 
3120
{
 
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];
 
3125
 
 
3126
    if (!ebtables_cmd_path) {
 
3127
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
 
3128
                               _("cannot create rules since ebtables tool is "
 
3129
                                 "missing."));
 
3130
        return -1;
 
3131
    }
 
3132
 
 
3133
    virMacAddrFormat(macaddr, macaddr_str);
 
3134
 
 
3135
    ebiptablesAllTeardown(ifname);
 
3136
 
 
3137
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3138
 
 
3139
    ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
 
3140
 
 
3141
    PRINT_ROOT_CHAIN(chain, chainPrefix, ifname);
 
3142
    virBufferAsprintf(&buf,
 
3143
                      CMD_DEF("$EBT -t nat -A %s -s ! %s -j DROP") CMD_SEPARATOR
 
3144
                      CMD_EXEC
 
3145
                      "%s",
 
3146
 
 
3147
                      chain, macaddr_str,
 
3148
                      CMD_STOPONERR(1));
 
3149
 
 
3150
    virBufferAsprintf(&buf,
 
3151
                      CMD_DEF("$EBT -t nat -A %s -p IPv4 -j ACCEPT") CMD_SEPARATOR
 
3152
                      CMD_EXEC
 
3153
                      "%s",
 
3154
 
 
3155
                      chain,
 
3156
                      CMD_STOPONERR(1));
 
3157
 
 
3158
    virBufferAsprintf(&buf,
 
3159
                      CMD_DEF("$EBT -t nat -A %s -p ARP -j ACCEPT") CMD_SEPARATOR
 
3160
                      CMD_EXEC
 
3161
                      "%s",
 
3162
 
 
3163
                      chain,
 
3164
                      CMD_STOPONERR(1));
 
3165
 
 
3166
    virBufferAsprintf(&buf,
 
3167
                      CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
 
3168
                      CMD_EXEC
 
3169
                      "%s",
 
3170
 
 
3171
                      chain,
 
3172
                      CMD_STOPONERR(1));
 
3173
 
 
3174
    ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
 
3175
    ebtablesRenameTmpRootChain(&buf, 1, ifname);
 
3176
 
 
3177
    if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
 
3178
        goto tear_down_tmpebchains;
 
3179
 
 
3180
    return 0;
 
3181
 
 
3182
tear_down_tmpebchains:
 
3183
    ebtablesCleanAll(ifname);
 
3184
 
 
3185
    virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
 
3186
                           "%s",
 
3187
                           _("Some rules could not be created."));
 
3188
 
 
3189
    return -1;
 
3190
}
 
3191
 
 
3192
 
 
3193
/**
 
3194
 * ebtablesApplyDHCPOnlyRules
 
3195
 *
 
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
 
3198
 *    interface
 
3199
 * @dhcpsrvrs: The DHCP server(s) from which the VM may receive traffic
 
3200
 *    from; may be NULL
 
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)
 
3204
 *
 
3205
 * Returns 0 on success, -1 on failure with the rules removed
 
3206
 *
 
3207
 * Apply filtering rules so that the VM can only send and receive
 
3208
 * DHCP traffic and nothing else.
 
3209
 */
 
3210
static int
 
3211
ebtablesApplyDHCPOnlyRules(const char *ifname,
 
3212
                           const unsigned char *macaddr,
 
3213
                           virNWFilterVarValuePtr dhcpsrvrs,
 
3214
                           bool leaveTemporary)
 
3215
{
 
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;
 
3222
 
 
3223
    if (!ebtables_cmd_path) {
 
3224
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
 
3225
                               _("cannot create rules since ebtables tool is "
 
3226
                                 "missing."));
 
3227
        return -1;
 
3228
    }
 
3229
 
 
3230
    virMacAddrFormat(macaddr, macaddr_str);
 
3231
 
 
3232
    ebiptablesAllTeardown(ifname);
 
3233
 
 
3234
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3235
 
 
3236
    ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
 
3237
    ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
 
3238
 
 
3239
    PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
 
3240
    PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
 
3241
 
 
3242
    virBufferAsprintf(&buf,
 
3243
                      CMD_DEF("$EBT -t nat -A %s"
 
3244
                              " -s %s"
 
3245
                              " -p ipv4 --ip-protocol udp"
 
3246
                              " --ip-sport 68 --ip-dport 67"
 
3247
                              " -j ACCEPT") CMD_SEPARATOR
 
3248
                      CMD_EXEC
 
3249
                      "%s",
 
3250
 
 
3251
                      chain_in,
 
3252
                      macaddr_str,
 
3253
                      CMD_STOPONERR(1));
 
3254
 
 
3255
    virBufferAsprintf(&buf,
 
3256
                      CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
 
3257
                      CMD_EXEC
 
3258
                      "%s",
 
3259
 
 
3260
                      chain_in,
 
3261
                      CMD_STOPONERR(1));
 
3262
 
 
3263
    num_dhcpsrvrs = (dhcpsrvrs != NULL)
 
3264
                    ? virNWFilterVarValueGetCardinality(dhcpsrvrs)
 
3265
                    : 0;
 
3266
 
 
3267
    while (true) {
 
3268
        char *srcIPParam = NULL;
 
3269
 
 
3270
        if (idx < num_dhcpsrvrs) {
 
3271
            const char *dhcpserver;
 
3272
 
 
3273
            dhcpserver = virNWFilterVarValueGetNthValue(dhcpsrvrs, idx);
 
3274
 
 
3275
            if (virAsprintf(&srcIPParam, "--ip-src %s", dhcpserver) < 0) {
 
3276
                virReportOOMError();
 
3277
                goto tear_down_tmpebchains;
 
3278
            }
 
3279
        }
 
3280
 
 
3281
        virBufferAsprintf(&buf,
 
3282
                          CMD_DEF("$EBT -t nat -A %s"
 
3283
                                  " -d %s"
 
3284
                                  " -p ipv4 --ip-protocol udp"
 
3285
                                  " %s"
 
3286
                                  " --ip-sport 67 --ip-dport 68"
 
3287
                                  " -j ACCEPT") CMD_SEPARATOR
 
3288
                          CMD_EXEC
 
3289
                          "%s",
 
3290
 
 
3291
                          chain_out,
 
3292
                          macaddr_str,
 
3293
                          srcIPParam != NULL ? srcIPParam : "",
 
3294
                          CMD_STOPONERR(1));
 
3295
 
 
3296
        VIR_FREE(srcIPParam);
 
3297
 
 
3298
        if (idx == num_dhcpsrvrs)
 
3299
            break;
 
3300
 
 
3301
        idx++;
 
3302
    }
 
3303
 
 
3304
    virBufferAsprintf(&buf,
 
3305
                      CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
 
3306
                      CMD_EXEC
 
3307
                      "%s",
 
3308
 
 
3309
                      chain_out,
 
3310
                      CMD_STOPONERR(1));
 
3311
 
 
3312
    ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
 
3313
    ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
 
3314
 
 
3315
    if (!leaveTemporary) {
 
3316
        ebtablesRenameTmpRootChain(&buf, 1, ifname);
 
3317
        ebtablesRenameTmpRootChain(&buf, 0, ifname);
 
3318
    }
 
3319
 
 
3320
    if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
 
3321
        goto tear_down_tmpebchains;
 
3322
 
 
3323
    return 0;
 
3324
 
 
3325
tear_down_tmpebchains:
 
3326
    ebtablesCleanAll(ifname);
 
3327
 
 
3328
    virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
 
3329
                           "%s",
 
3330
                           _("Some rules could not be created."));
 
3331
 
 
3332
    return -1;
 
3333
}
 
3334
 
 
3335
 
 
3336
/**
 
3337
 * ebtablesApplyDropAllRules
 
3338
 *
 
3339
 * @ifname: name of the backend-interface to which to apply the rules
 
3340
 *
 
3341
 * Returns 0 on success, -1 on failure with the rules removed
 
3342
 *
 
3343
 * Apply filtering rules so that the VM cannot receive or send traffic.
 
3344
 */
 
3345
static int
 
3346
ebtablesApplyDropAllRules(const char *ifname)
 
3347
{
 
3348
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
3349
    char chain_in [MAX_CHAINNAME_LENGTH],
 
3350
         chain_out[MAX_CHAINNAME_LENGTH];
 
3351
 
 
3352
    if (!ebtables_cmd_path) {
 
3353
        virNWFilterReportError(VIR_ERR_INTERNAL_ERROR, "%s",
 
3354
                               _("cannot create rules since ebtables tool is "
 
3355
                                 "missing."));
 
3356
        return -1;
 
3357
    }
 
3358
 
 
3359
    ebiptablesAllTeardown(ifname);
 
3360
 
 
3361
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3362
 
 
3363
    ebtablesCreateTmpRootChain(&buf, 1, ifname, 1);
 
3364
    ebtablesCreateTmpRootChain(&buf, 0, ifname, 1);
 
3365
 
 
3366
    PRINT_ROOT_CHAIN(chain_in , CHAINPREFIX_HOST_IN_TEMP , ifname);
 
3367
    PRINT_ROOT_CHAIN(chain_out, CHAINPREFIX_HOST_OUT_TEMP, ifname);
 
3368
 
 
3369
    virBufferAsprintf(&buf,
 
3370
                      CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
 
3371
                      CMD_EXEC
 
3372
                      "%s",
 
3373
 
 
3374
                      chain_in,
 
3375
                      CMD_STOPONERR(1));
 
3376
 
 
3377
    virBufferAsprintf(&buf,
 
3378
                      CMD_DEF("$EBT -t nat -A %s -j DROP") CMD_SEPARATOR
 
3379
                      CMD_EXEC
 
3380
                      "%s",
 
3381
 
 
3382
                      chain_out,
 
3383
                      CMD_STOPONERR(1));
 
3384
 
 
3385
    ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
 
3386
    ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
 
3387
    ebtablesRenameTmpRootChain(&buf, 1, ifname);
 
3388
    ebtablesRenameTmpRootChain(&buf, 0, ifname);
 
3389
 
 
3390
    if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
 
3391
        goto tear_down_tmpebchains;
 
3392
 
 
3393
    return 0;
 
3394
 
 
3395
tear_down_tmpebchains:
 
3396
    ebtablesCleanAll(ifname);
 
3397
 
 
3398
    virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
 
3399
                           "%s",
 
3400
                           _("Some rules could not be created."));
 
3401
 
 
3402
    return -1;
 
3403
}
 
3404
 
 
3405
 
 
3406
static int
 
3407
ebtablesRemoveBasicRules(const char *ifname)
 
3408
{
 
3409
    return ebtablesCleanAll(ifname);
 
3410
}
 
3411
 
 
3412
 
 
3413
static int ebtablesCleanAll(const char *ifname)
 
3414
{
 
3415
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
3416
    int cli_status;
 
3417
 
 
3418
    if (!ebtables_cmd_path)
 
3419
        return 0;
 
3420
 
 
3421
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3422
 
 
3423
    ebtablesUnlinkRootChain(&buf, 1, ifname);
 
3424
    ebtablesUnlinkRootChain(&buf, 0, ifname);
 
3425
    ebtablesRemoveSubChains(&buf, ifname);
 
3426
    ebtablesRemoveRootChain(&buf, 1, ifname);
 
3427
    ebtablesRemoveRootChain(&buf, 0, ifname);
 
3428
 
 
3429
    ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
 
3430
    ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
 
3431
    ebtablesRemoveTmpSubChains(&buf, ifname);
 
3432
    ebtablesRemoveTmpRootChain(&buf, 1, ifname);
 
3433
    ebtablesRemoveTmpRootChain(&buf, 0, ifname);
 
3434
 
 
3435
    ebiptablesExecCLI(&buf, &cli_status, NULL);
 
3436
    return 0;
 
3437
}
 
3438
 
 
3439
 
 
3440
static int
 
3441
ebiptablesRuleOrderSort(const void *a, const void *b)
 
3442
{
 
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);
 
3449
 
 
3450
    /* ensure root chain commands appear before all others since
 
3451
       we will need them to create the child chains */
 
3452
    if (root_a) {
 
3453
        if (root_b) {
 
3454
            goto normal;
 
3455
        }
 
3456
        return -1; /* a before b */
 
3457
    }
 
3458
    if (root_b) {
 
3459
        return 1; /* b before a */
 
3460
    }
 
3461
normal:
 
3462
    /* priorities are limited to range [-1000, 1000] */
 
3463
    return insta->priority - instb->priority;
 
3464
}
 
3465
 
 
3466
static int
 
3467
ebiptablesRuleOrderSortPtr(const void *a, const void *b)
 
3468
{
 
3469
    const ebiptablesRuleInstPtr *insta = a;
 
3470
    const ebiptablesRuleInstPtr *instb = b;
 
3471
    return ebiptablesRuleOrderSort(*insta, *instb);
 
3472
}
 
3473
 
 
3474
static int
 
3475
ebiptablesFilterOrderSort(const virHashKeyValuePairPtr a,
 
3476
                          const virHashKeyValuePairPtr b)
 
3477
{
 
3478
    /* elements' values has been limited to range [-1000, 1000] */
 
3479
    return *(virNWFilterChainPriority *)a->value -
 
3480
           *(virNWFilterChainPriority *)b->value;
 
3481
}
 
3482
 
 
3483
static void
 
3484
iptablesCheckBridgeNFCallEnabled(bool isIPv6)
 
3485
{
 
3486
    static time_t lastReport, lastReportIPv6;
 
3487
    const char *pathname = NULL;
 
3488
    char buffer[1];
 
3489
    time_t now = time(NULL);
 
3490
 
 
3491
    if (isIPv6 &&
 
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;
 
3496
    }
 
3497
 
 
3498
    if (pathname) {
 
3499
        int fd = open(pathname, O_RDONLY);
 
3500
        if (fd >= 0) {
 
3501
            if (read(fd, buffer, 1) == 1) {
 
3502
                if (buffer[0] == '0') {
 
3503
                    char msg[256];
 
3504
                    snprintf(msg, sizeof(msg),
 
3505
                             _("To enable ip%stables filtering for the VM do "
 
3506
                              "'echo 1 > %s'"),
 
3507
                             isIPv6 ? "6" : "",
 
3508
                             pathname);
 
3509
                    VIR_WARN("%s", msg);
 
3510
                    if (isIPv6)
 
3511
                        lastReportIPv6 = now;
 
3512
                    else
 
3513
                        lastReport = now;
 
3514
                }
 
3515
            }
 
3516
            VIR_FORCE_CLOSE(fd);
 
3517
        }
 
3518
    }
 
3519
}
 
3520
 
 
3521
/*
 
3522
 * Given a filtername determine the protocol it is used for evaluating
 
3523
 * We do prefix-matching to determine the protocol.
 
3524
 */
 
3525
static enum l3_proto_idx
 
3526
ebtablesGetProtoIdxByFiltername(const char *filtername)
 
3527
{
 
3528
    enum l3_proto_idx idx;
 
3529
 
 
3530
    for (idx = 0; idx < L3_PROTO_LAST_IDX; idx++) {
 
3531
        if (STRPREFIX(filtername, l3_protocols[idx].val)) {
 
3532
            return idx;
 
3533
        }
 
3534
    }
 
3535
 
 
3536
    return -1;
 
3537
}
 
3538
 
 
3539
static int
 
3540
ebtablesCreateTmpRootAndSubChains(virBufferPtr buf,
 
3541
                                  const char *ifname,
 
3542
                                  virHashTablePtr chains, int direction,
 
3543
                                  ebiptablesRuleInstPtr *inst,
 
3544
                                  int *nRuleInstances)
 
3545
{
 
3546
    int rc = 0, i;
 
3547
    virHashKeyValuePairPtr filter_names;
 
3548
    const virNWFilterChainPriority *priority;
 
3549
 
 
3550
    if (ebtablesCreateTmpRootChain(buf, direction, ifname, 1) < 0)
 
3551
        return -1;
 
3552
 
 
3553
    filter_names = virHashGetItems(chains,
 
3554
                                   ebiptablesFilterOrderSort);
 
3555
    if (filter_names == NULL)
 
3556
        return -1;
 
3557
 
 
3558
    for (i = 0; filter_names[i].key; i++) {
 
3559
        enum l3_proto_idx idx = ebtablesGetProtoIdxByFiltername(
 
3560
                                  filter_names[i].key);
 
3561
        if ((int)idx < 0)
 
3562
            continue;
 
3563
        priority = (const virNWFilterChainPriority *)filter_names[i].value;
 
3564
        rc = ebtablesCreateTmpSubChain(inst, nRuleInstances,
 
3565
                                       direction, ifname, idx,
 
3566
                                       filter_names[i].key, 1,
 
3567
                                       *priority);
 
3568
        if (rc < 0)
 
3569
            break;
 
3570
    }
 
3571
 
 
3572
    VIR_FREE(filter_names);
 
3573
    return rc;
 
3574
}
 
3575
 
 
3576
static int
 
3577
ebiptablesApplyNewRules(const char *ifname,
 
3578
                        int nruleInstances,
 
3579
                        void **_inst)
 
3580
{
 
3581
    int i, j;
 
3582
    int cli_status;
 
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;
 
3590
    int nEbtChains = 0;
 
3591
    char *errmsg = NULL;
 
3592
 
 
3593
    if (inst == NULL)
 
3594
        nruleInstances = 0;
 
3595
 
 
3596
    if (!chains_in_set || !chains_out_set) {
 
3597
        virReportOOMError();
 
3598
        goto exit_free_sets;
 
3599
    }
 
3600
 
 
3601
    if (nruleInstances > 1 && inst)
 
3602
        qsort(inst, nruleInstances, sizeof(inst[0]),
 
3603
              ebiptablesRuleOrderSortPtr);
 
3604
 
 
3605
    /* scan the rules to see which chains need to be created */
 
3606
    for (i = 0; i < nruleInstances; i++) {
 
3607
        sa_assert (inst);
 
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;
 
3615
                }
 
3616
            } else {
 
3617
                if (virHashUpdateEntry(chains_out_set, name,
 
3618
                                       &inst[i]->chainPriority) < 0) {
 
3619
                    virReportOOMError();
 
3620
                    goto exit_free_sets;
 
3621
                }
 
3622
            }
 
3623
        }
 
3624
    }
 
3625
 
 
3626
 
 
3627
    /* cleanup whatever may exist */
 
3628
    if (ebtables_cmd_path) {
 
3629
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3630
 
 
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);
 
3637
    }
 
3638
 
 
3639
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3640
 
 
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;
 
3649
    }
 
3650
 
 
3651
    if (nEbtChains > 0)
 
3652
        qsort(&ebtChains[0], nEbtChains, sizeof(ebtChains[0]),
 
3653
              ebiptablesRuleOrderSort);
 
3654
 
 
3655
    if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3656
        goto tear_down_tmpebchains;
 
3657
 
 
3658
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3659
 
 
3660
    /* process ebtables commands; interleave commands from filters with
 
3661
       commands for creating and connecting ebtables chains */
 
3662
    j = 0;
 
3663
    for (i = 0; i < nruleInstances; i++) {
 
3664
        sa_assert (inst);
 
3665
        switch (inst[i]->ruleType) {
 
3666
        case RT_EBTABLES:
 
3667
            while (j < nEbtChains &&
 
3668
                   ebtChains[j].priority <= inst[i]->priority) {
 
3669
                ebiptablesInstCommand(&buf,
 
3670
                                      ebtChains[j++].commandTemplate,
 
3671
                                      'A', -1, 1);
 
3672
            }
 
3673
            ebiptablesInstCommand(&buf,
 
3674
                                  inst[i]->commandTemplate,
 
3675
                                  'A', -1, 1);
 
3676
        break;
 
3677
        case RT_IPTABLES:
 
3678
            haveIptables = true;
 
3679
        break;
 
3680
        case RT_IP6TABLES:
 
3681
            haveIp6tables = true;
 
3682
        break;
 
3683
        }
 
3684
    }
 
3685
 
 
3686
    while (j < nEbtChains)
 
3687
        ebiptablesInstCommand(&buf,
 
3688
                              ebtChains[j++].commandTemplate,
 
3689
                              'A', -1, 1);
 
3690
 
 
3691
    if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3692
        goto tear_down_tmpebchains;
 
3693
 
 
3694
    if (haveIptables) {
 
3695
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3696
 
 
3697
        iptablesUnlinkTmpRootChains(&buf, ifname);
 
3698
        iptablesRemoveTmpRootChains(&buf, ifname);
 
3699
 
 
3700
        iptablesCreateBaseChains(&buf);
 
3701
 
 
3702
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3703
            goto tear_down_tmpebchains;
 
3704
 
 
3705
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3706
 
 
3707
        iptablesCreateTmpRootChains(&buf, ifname);
 
3708
 
 
3709
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3710
           goto tear_down_tmpiptchains;
 
3711
 
 
3712
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3713
 
 
3714
        iptablesLinkTmpRootChains(&buf, ifname);
 
3715
        iptablesSetupVirtInPost(&buf, ifname);
 
3716
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3717
           goto tear_down_tmpiptchains;
 
3718
 
 
3719
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3720
 
 
3721
        for (i = 0; i < nruleInstances; i++) {
 
3722
            sa_assert (inst);
 
3723
            if (inst[i]->ruleType == RT_IPTABLES)
 
3724
                iptablesInstCommand(&buf,
 
3725
                                    inst[i]->commandTemplate,
 
3726
                                    'A', -1, 1);
 
3727
        }
 
3728
 
 
3729
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3730
           goto tear_down_tmpiptchains;
 
3731
 
 
3732
        iptablesCheckBridgeNFCallEnabled(false);
 
3733
    }
 
3734
 
 
3735
    if (haveIp6tables) {
 
3736
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3737
 
 
3738
        iptablesUnlinkTmpRootChains(&buf, ifname);
 
3739
        iptablesRemoveTmpRootChains(&buf, ifname);
 
3740
 
 
3741
        iptablesCreateBaseChains(&buf);
 
3742
 
 
3743
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3744
            goto tear_down_tmpiptchains;
 
3745
 
 
3746
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3747
 
 
3748
        iptablesCreateTmpRootChains(&buf, ifname);
 
3749
 
 
3750
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3751
           goto tear_down_tmpip6tchains;
 
3752
 
 
3753
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3754
 
 
3755
        iptablesLinkTmpRootChains(&buf, ifname);
 
3756
        iptablesSetupVirtInPost(&buf, ifname);
 
3757
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3758
           goto tear_down_tmpip6tchains;
 
3759
 
 
3760
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3761
 
 
3762
        for (i = 0; i < nruleInstances; i++) {
 
3763
            if (inst[i]->ruleType == RT_IP6TABLES)
 
3764
                iptablesInstCommand(&buf,
 
3765
                                    inst[i]->commandTemplate,
 
3766
                                    'A', -1, 1);
 
3767
        }
 
3768
 
 
3769
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3770
           goto tear_down_tmpip6tchains;
 
3771
 
 
3772
        iptablesCheckBridgeNFCallEnabled(true);
 
3773
    }
 
3774
 
 
3775
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3776
 
 
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);
 
3781
 
 
3782
    if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
 
3783
        goto tear_down_ebsubchains_and_unlink;
 
3784
 
 
3785
    virHashFree(chains_in_set);
 
3786
    virHashFree(chains_out_set);
 
3787
 
 
3788
    for (i = 0; i < nEbtChains; i++)
 
3789
        VIR_FREE(ebtChains[i].commandTemplate);
 
3790
    VIR_FREE(ebtChains);
 
3791
 
 
3792
    VIR_FREE(errmsg);
 
3793
 
 
3794
    return 0;
 
3795
 
 
3796
tear_down_ebsubchains_and_unlink:
 
3797
    if (ebtables_cmd_path) {
 
3798
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3799
 
 
3800
        ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
 
3801
        ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
 
3802
    }
 
3803
 
 
3804
tear_down_tmpip6tchains:
 
3805
    if (haveIp6tables) {
 
3806
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3807
 
 
3808
        iptablesUnlinkTmpRootChains(&buf, ifname);
 
3809
        iptablesRemoveTmpRootChains(&buf, ifname);
 
3810
    }
 
3811
 
 
3812
tear_down_tmpiptchains:
 
3813
    if (haveIptables) {
 
3814
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3815
 
 
3816
        iptablesUnlinkTmpRootChains(&buf, ifname);
 
3817
        iptablesRemoveTmpRootChains(&buf, ifname);
 
3818
    }
 
3819
 
 
3820
tear_down_tmpebchains:
 
3821
    if (ebtables_cmd_path) {
 
3822
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3823
 
 
3824
        ebtablesRemoveTmpSubChains(&buf, ifname);
 
3825
        ebtablesRemoveTmpRootChain(&buf, 1, ifname);
 
3826
        ebtablesRemoveTmpRootChain(&buf, 0, ifname);
 
3827
    }
 
3828
 
 
3829
    ebiptablesExecCLI(&buf, &cli_status, NULL);
 
3830
 
 
3831
    virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
 
3832
                           _("Some rules could not be created for "
 
3833
                             "interface %s%s%s"),
 
3834
                           ifname,
 
3835
                           errmsg ? ": " : "",
 
3836
                           errmsg ? errmsg : "");
 
3837
 
 
3838
exit_free_sets:
 
3839
    virHashFree(chains_in_set);
 
3840
    virHashFree(chains_out_set);
 
3841
 
 
3842
    for (i = 0; i < nEbtChains; i++)
 
3843
        VIR_FREE(ebtChains[i].commandTemplate);
 
3844
    VIR_FREE(ebtChains);
 
3845
 
 
3846
    VIR_FREE(errmsg);
 
3847
 
 
3848
    return -1;
 
3849
}
 
3850
 
 
3851
 
 
3852
static int
 
3853
ebiptablesTearNewRules(const char *ifname)
 
3854
{
 
3855
    int cli_status;
 
3856
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
3857
 
 
3858
    if (iptables_cmd_path) {
 
3859
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3860
 
 
3861
        iptablesUnlinkTmpRootChains(&buf, ifname);
 
3862
        iptablesRemoveTmpRootChains(&buf, ifname);
 
3863
    }
 
3864
 
 
3865
    if (ip6tables_cmd_path) {
 
3866
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3867
 
 
3868
        iptablesUnlinkTmpRootChains(&buf, ifname);
 
3869
        iptablesRemoveTmpRootChains(&buf, ifname);
 
3870
    }
 
3871
 
 
3872
    if (ebtables_cmd_path) {
 
3873
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3874
 
 
3875
        ebtablesUnlinkTmpRootChain(&buf, 1, ifname);
 
3876
        ebtablesUnlinkTmpRootChain(&buf, 0, ifname);
 
3877
 
 
3878
        ebtablesRemoveTmpSubChains(&buf, ifname);
 
3879
        ebtablesRemoveTmpRootChain(&buf, 1, ifname);
 
3880
        ebtablesRemoveTmpRootChain(&buf, 0, ifname);
 
3881
    }
 
3882
 
 
3883
    ebiptablesExecCLI(&buf, &cli_status, NULL);
 
3884
 
 
3885
    return 0;
 
3886
}
 
3887
 
 
3888
 
 
3889
static int
 
3890
ebiptablesTearOldRules(const char *ifname)
 
3891
{
 
3892
    int cli_status;
 
3893
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
3894
 
 
3895
    /* switch to new iptables user defined chains */
 
3896
    if (iptables_cmd_path) {
 
3897
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3898
 
 
3899
        iptablesUnlinkRootChains(&buf, ifname);
 
3900
        iptablesRemoveRootChains(&buf, ifname);
 
3901
 
 
3902
        iptablesRenameTmpRootChains(&buf, ifname);
 
3903
        ebiptablesExecCLI(&buf, &cli_status, NULL);
 
3904
    }
 
3905
 
 
3906
    if (ip6tables_cmd_path) {
 
3907
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
3908
 
 
3909
        iptablesUnlinkRootChains(&buf, ifname);
 
3910
        iptablesRemoveRootChains(&buf, ifname);
 
3911
 
 
3912
        iptablesRenameTmpRootChains(&buf, ifname);
 
3913
        ebiptablesExecCLI(&buf, &cli_status, NULL);
 
3914
    }
 
3915
 
 
3916
    if (ebtables_cmd_path) {
 
3917
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3918
 
 
3919
        ebtablesUnlinkRootChain(&buf, 1, ifname);
 
3920
        ebtablesUnlinkRootChain(&buf, 0, ifname);
 
3921
 
 
3922
        ebtablesRemoveSubChains(&buf, ifname);
 
3923
 
 
3924
        ebtablesRemoveRootChain(&buf, 1, ifname);
 
3925
        ebtablesRemoveRootChain(&buf, 0, ifname);
 
3926
 
 
3927
        ebtablesRenameTmpSubAndRootChains(&buf, ifname);
 
3928
 
 
3929
        ebiptablesExecCLI(&buf, &cli_status, NULL);
 
3930
    }
 
3931
 
 
3932
    return 0;
 
3933
}
 
3934
 
 
3935
 
 
3936
/**
 
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
 
3941
 *
 
3942
 * Remove all rules one after the other
 
3943
 *
 
3944
 * Return 0 on success, -1 if execution of one or more cleanup
 
3945
 * commands failed.
 
3946
 */
 
3947
static int
 
3948
ebiptablesRemoveRules(const char *ifname ATTRIBUTE_UNUSED,
 
3949
                      int nruleInstances,
 
3950
                      void **_inst)
 
3951
{
 
3952
    int rc = 0;
 
3953
    int cli_status;
 
3954
    int i;
 
3955
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
3956
    ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
 
3957
 
 
3958
    NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
3959
 
 
3960
    for (i = 0; i < nruleInstances; i++)
 
3961
        ebiptablesInstCommand(&buf,
 
3962
                              inst[i]->commandTemplate,
 
3963
                              'D', -1,
 
3964
                              0);
 
3965
 
 
3966
    if (ebiptablesExecCLI(&buf, &cli_status, NULL) < 0)
 
3967
        goto err_exit;
 
3968
 
 
3969
    if (cli_status) {
 
3970
        virNWFilterReportError(VIR_ERR_BUILD_FIREWALL,
 
3971
                               "%s",
 
3972
                               _("error while executing CLI commands"));
 
3973
        rc = -1;
 
3974
    }
 
3975
 
 
3976
err_exit:
 
3977
    return rc;
 
3978
}
 
3979
 
 
3980
 
 
3981
/**
 
3982
 * ebiptablesAllTeardown:
 
3983
 * @ifname : the name of the interface to which the rules apply
 
3984
 *
 
3985
 * Unconditionally remove all possible user defined tables and rules
 
3986
 * that were created for the given interface (ifname).
 
3987
 *
 
3988
 * Always returns 0.
 
3989
 */
 
3990
static int
 
3991
ebiptablesAllTeardown(const char *ifname)
 
3992
{
 
3993
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
3994
    int cli_status;
 
3995
 
 
3996
    if (iptables_cmd_path) {
 
3997
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
3998
 
 
3999
        iptablesUnlinkRootChains(&buf, ifname);
 
4000
        iptablesClearVirtInPost (&buf, ifname);
 
4001
        iptablesRemoveRootChains(&buf, ifname);
 
4002
    }
 
4003
 
 
4004
    if (ip6tables_cmd_path) {
 
4005
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
4006
 
 
4007
        iptablesUnlinkRootChains(&buf, ifname);
 
4008
        iptablesClearVirtInPost (&buf, ifname);
 
4009
        iptablesRemoveRootChains(&buf, ifname);
 
4010
    }
 
4011
 
 
4012
    if (ebtables_cmd_path) {
 
4013
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
4014
 
 
4015
        ebtablesUnlinkRootChain(&buf, 1, ifname);
 
4016
        ebtablesUnlinkRootChain(&buf, 0, ifname);
 
4017
 
 
4018
        ebtablesRemoveSubChains(&buf, ifname);
 
4019
 
 
4020
        ebtablesRemoveRootChain(&buf, 1, ifname);
 
4021
        ebtablesRemoveRootChain(&buf, 0, ifname);
 
4022
    }
 
4023
    ebiptablesExecCLI(&buf, &cli_status, NULL);
 
4024
 
 
4025
    return 0;
 
4026
}
 
4027
 
 
4028
 
 
4029
virNWFilterTechDriver ebiptables_driver = {
 
4030
    .name = EBIPTABLES_DRIVER_ID,
 
4031
    .flags = 0,
 
4032
 
 
4033
    .init     = ebiptablesDriverInit,
 
4034
    .shutdown = ebiptablesDriverShutdown,
 
4035
 
 
4036
    .createRuleInstance  = ebiptablesCreateRuleInstanceIterate,
 
4037
    .applyNewRules       = ebiptablesApplyNewRules,
 
4038
    .tearNewRules        = ebiptablesTearNewRules,
 
4039
    .tearOldRules        = ebiptablesTearOldRules,
 
4040
    .allTeardown         = ebiptablesAllTeardown,
 
4041
    .removeRules         = ebiptablesRemoveRules,
 
4042
    .freeRuleInstance    = ebiptablesFreeRuleInstance,
 
4043
    .displayRuleInstance = ebiptablesDisplayRuleInstance,
 
4044
 
 
4045
    .canApplyBasicRules  = ebiptablesCanApplyBasicRules,
 
4046
    .applyBasicRules     = ebtablesApplyBasicRules,
 
4047
    .applyDHCPOnlyRules  = ebtablesApplyDHCPOnlyRules,
 
4048
    .applyDropAllRules   = ebtablesApplyDropAllRules,
 
4049
    .removeBasicRules    = ebtablesRemoveBasicRules,
 
4050
};
 
4051
 
 
4052
 
 
4053
static int
 
4054
ebiptablesDriverInit(bool privileged)
 
4055
{
 
4056
    virBuffer buf = VIR_BUFFER_INITIALIZER;
 
4057
    char *errmsg = NULL;
 
4058
 
 
4059
    if (!privileged)
 
4060
        return 0;
 
4061
 
 
4062
    if (virMutexInit(&execCLIMutex) < 0)
 
4063
        return -EINVAL;
 
4064
 
 
4065
    gawk_cmd_path = virFindFileInPath("gawk");
 
4066
    grep_cmd_path = virFindFileInPath("grep");
 
4067
 
 
4068
    ebtables_cmd_path = virFindFileInPath("ebtables");
 
4069
    if (ebtables_cmd_path) {
 
4070
        NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
 
4071
        /* basic probing */
 
4072
        virBufferAsprintf(&buf,
 
4073
                          CMD_DEF("$EBT -t nat -L") CMD_SEPARATOR
 
4074
                          CMD_EXEC
 
4075
                          "%s",
 
4076
                          CMD_STOPONERR(1));
 
4077
 
 
4078
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
 
4079
            VIR_FREE(ebtables_cmd_path);
 
4080
            VIR_ERROR(_("Testing of ebtables command failed: %s"),
 
4081
                      errmsg);
 
4082
        }
 
4083
    } else {
 
4084
        VIR_WARN("Could not find 'ebtables' executable");
 
4085
    }
 
4086
 
 
4087
    iptables_cmd_path = virFindFileInPath("iptables");
 
4088
    if (iptables_cmd_path) {
 
4089
        NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
 
4090
 
 
4091
        virBufferAsprintf(&buf,
 
4092
                          CMD_DEF("$IPT -n -L FORWARD") CMD_SEPARATOR
 
4093
                          CMD_EXEC
 
4094
                          "%s",
 
4095
                          CMD_STOPONERR(1));
 
4096
 
 
4097
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
 
4098
            VIR_FREE(iptables_cmd_path);
 
4099
            VIR_ERROR(_("Testing of iptables command failed: %s"),
 
4100
                      errmsg);
 
4101
        }
 
4102
    } else {
 
4103
        VIR_WARN("Could not find 'iptables' executable");
 
4104
    }
 
4105
 
 
4106
    ip6tables_cmd_path = virFindFileInPath("ip6tables");
 
4107
    if (ip6tables_cmd_path) {
 
4108
        NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
 
4109
 
 
4110
        virBufferAsprintf(&buf,
 
4111
                          CMD_DEF("$IPT -n -L FORWARD") CMD_SEPARATOR
 
4112
                          CMD_EXEC
 
4113
                          "%s",
 
4114
                          CMD_STOPONERR(1));
 
4115
 
 
4116
        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
 
4117
            VIR_FREE(ip6tables_cmd_path);
 
4118
            VIR_ERROR(_("Testing of ip6tables command failed: %s"),
 
4119
                      errmsg);
 
4120
        }
 
4121
    } else {
 
4122
        VIR_WARN("Could not find 'ip6tables' executable");
 
4123
    }
 
4124
 
 
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);
 
4132
    }
 
4133
 
 
4134
    VIR_FREE(errmsg);
 
4135
 
 
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();
 
4139
        return -ENOTSUP;
 
4140
    }
 
4141
 
 
4142
    ebiptables_driver.flags = TECHDRV_FLAG_INITIALIZED;
 
4143
 
 
4144
    return 0;
 
4145
}
 
4146
 
 
4147
 
 
4148
static void
 
4149
ebiptablesDriverShutdown(void)
 
4150
{
 
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;
 
4157
}