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

« back to all changes in this revision

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