Add missing libxml2-tools dependency
[archive/platform/upstream/libvirt.git] / tests / nwfilterxml2firewalltest.c
1 /*
2  * nwfilterxml2firewalltest.c: Test iptables rule generation
3  *
4  * Copyright (C) 2014 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library.  If not, see
18  * <http://www.gnu.org/licenses/>.
19  *
20  */
21
22 #include <config.h>
23
24 #if defined (__linux__)
25
26 # include "testutils.h"
27 # include "nwfilter/nwfilter_ebiptables_driver.h"
28 # include "virbuffer.h"
29
30 # define __VIR_FIREWALL_PRIV_H_ALLOW__
31 # include "virfirewallpriv.h"
32
33 # define __VIR_COMMAND_PRIV_H_ALLOW__
34 # include "vircommandpriv.h"
35
36 # define VIR_FROM_THIS VIR_FROM_NONE
37
38 static const char *abs_top_srcdir;
39
40 # ifdef __linux__
41 #  define RULESTYPE "linux"
42 # else
43 #  error "test case not ported to this platform"
44 # endif
45
46 typedef struct _virNWFilterInst virNWFilterInst;
47 typedef virNWFilterInst *virNWFilterInstPtr;
48 struct _virNWFilterInst {
49     virNWFilterDefPtr *filters;
50     size_t nfilters;
51     virNWFilterRuleInstPtr *rules;
52     size_t nrules;
53 };
54
55 /*
56  * Some sets of rules that will be common to all test files,
57  * so we don't bother including them in the test data files
58  * as that would just bloat them
59  */
60
61 static const char *commonRules[] = {
62     /* Dropping ebtables rules */
63     "ebtables -t nat -D PREROUTING -i vnet0 -j libvirt-J-vnet0\n"
64     "ebtables -t nat -D POSTROUTING -o vnet0 -j libvirt-P-vnet0\n"
65     "ebtables -t nat -L libvirt-J-vnet0\n"
66     "ebtables -t nat -L libvirt-P-vnet0\n"
67     "ebtables -t nat -F libvirt-J-vnet0\n"
68     "ebtables -t nat -X libvirt-J-vnet0\n"
69     "ebtables -t nat -F libvirt-P-vnet0\n"
70     "ebtables -t nat -X libvirt-P-vnet0\n",
71
72     /* Creating ebtables chains */
73     "ebtables -t nat -N libvirt-J-vnet0\n"
74     "ebtables -t nat -N libvirt-P-vnet0\n",
75
76     /* Dropping iptables rules */
77     "iptables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FP-vnet0\n"
78     "iptables -D libvirt-out -m physdev --physdev-out vnet0 -g FP-vnet0\n"
79     "iptables -D libvirt-in -m physdev --physdev-in vnet0 -g FJ-vnet0\n"
80     "iptables -D libvirt-host-in -m physdev --physdev-in vnet0 -g HJ-vnet0\n"
81     "iptables -F FP-vnet0\n"
82     "iptables -X FP-vnet0\n"
83     "iptables -F FJ-vnet0\n"
84     "iptables -X FJ-vnet0\n"
85     "iptables -F HJ-vnet0\n"
86     "iptables -X HJ-vnet0\n",
87
88     /* Creating iptables chains */
89     "iptables -N libvirt-in\n"
90     "iptables -N libvirt-out\n"
91     "iptables -N libvirt-in-post\n"
92     "iptables -N libvirt-host-in\n"
93     "iptables -D FORWARD -j libvirt-in\n"
94     "iptables -D FORWARD -j libvirt-out\n"
95     "iptables -D FORWARD -j libvirt-in-post\n"
96     "iptables -D INPUT -j libvirt-host-in\n"
97     "iptables -I FORWARD 1 -j libvirt-in\n"
98     "iptables -I FORWARD 2 -j libvirt-out\n"
99     "iptables -I FORWARD 3 -j libvirt-in-post\n"
100     "iptables -I INPUT 1 -j libvirt-host-in\n"
101     "iptables -N FP-vnet0\n"
102     "iptables -N FJ-vnet0\n"
103     "iptables -N HJ-vnet0\n"
104     "iptables -A libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FP-vnet0\n"
105     "iptables -A libvirt-in -m physdev --physdev-in vnet0 -g FJ-vnet0\n"
106     "iptables -A libvirt-host-in -m physdev --physdev-in vnet0 -g HJ-vnet0\n"
107     "iptables -D libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n"
108     "iptables -A libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n",
109
110     /* Dropping ip6tables rules */
111     "ip6tables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FP-vnet0\n"
112     "ip6tables -D libvirt-out -m physdev --physdev-out vnet0 -g FP-vnet0\n"
113     "ip6tables -D libvirt-in -m physdev --physdev-in vnet0 -g FJ-vnet0\n"
114     "ip6tables -D libvirt-host-in -m physdev --physdev-in vnet0 -g HJ-vnet0\n"
115     "ip6tables -F FP-vnet0\n"
116     "ip6tables -X FP-vnet0\n"
117     "ip6tables -F FJ-vnet0\n"
118     "ip6tables -X FJ-vnet0\n"
119     "ip6tables -F HJ-vnet0\n"
120     "ip6tables -X HJ-vnet0\n",
121
122     /* Creating ip6tables chains */
123     "ip6tables -N libvirt-in\n"
124     "ip6tables -N libvirt-out\n"
125     "ip6tables -N libvirt-in-post\n"
126     "ip6tables -N libvirt-host-in\n"
127     "ip6tables -D FORWARD -j libvirt-in\n"
128     "ip6tables -D FORWARD -j libvirt-out\n"
129     "ip6tables -D FORWARD -j libvirt-in-post\n"
130     "ip6tables -D INPUT -j libvirt-host-in\n"
131     "ip6tables -I FORWARD 1 -j libvirt-in\n"
132     "ip6tables -I FORWARD 2 -j libvirt-out\n"
133     "ip6tables -I FORWARD 3 -j libvirt-in-post\n"
134     "ip6tables -I INPUT 1 -j libvirt-host-in\n"
135     "ip6tables -N FP-vnet0\n"
136     "ip6tables -N FJ-vnet0\n"
137     "ip6tables -N HJ-vnet0\n"
138     "ip6tables -A libvirt-out -m physdev --physdev-is-bridged --physdev-out vnet0 -g FP-vnet0\n"
139     "ip6tables -A libvirt-in -m physdev --physdev-in vnet0 -g FJ-vnet0\n"
140     "ip6tables -A libvirt-host-in -m physdev --physdev-in vnet0 -g HJ-vnet0\n"
141     "ip6tables -D libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n"
142     "ip6tables -A libvirt-in-post -m physdev --physdev-in vnet0 -j ACCEPT\n",
143
144     /* Inserting ebtables rules */
145     "ebtables -t nat -A PREROUTING -i vnet0 -j libvirt-J-vnet0\n"
146     "ebtables -t nat -A POSTROUTING -o vnet0 -j libvirt-P-vnet0\n",
147 };
148
149
150 static virNWFilterHashTablePtr
151 virNWFilterCreateVarsFrom(virNWFilterHashTablePtr vars1,
152                           virNWFilterHashTablePtr vars2)
153 {
154     virNWFilterHashTablePtr res = virNWFilterHashTableCreate(0);
155     if (!res)
156         return NULL;
157
158     if (virNWFilterHashTablePutAll(vars1, res) < 0)
159         goto err_exit;
160
161     if (virNWFilterHashTablePutAll(vars2, res) < 0)
162         goto err_exit;
163
164     return res;
165
166  err_exit:
167     virNWFilterHashTableFree(res);
168     return NULL;
169 }
170
171
172 static void
173 virNWFilterRuleInstFree(virNWFilterRuleInstPtr inst)
174 {
175     if (!inst)
176         return;
177
178     virNWFilterHashTableFree(inst->vars);
179     VIR_FREE(inst);
180 }
181
182
183 static void
184 virNWFilterInstReset(virNWFilterInstPtr inst)
185 {
186     size_t i;
187
188     for (i = 0; i < inst->nfilters; i++)
189         virNWFilterDefFree(inst->filters[i]);
190     VIR_FREE(inst->filters);
191     inst->nfilters = 0;
192
193     for (i = 0; i < inst->nrules; i++)
194         virNWFilterRuleInstFree(inst->rules[i]);
195     VIR_FREE(inst->rules);
196     inst->nrules = 0;
197 }
198
199
200 static int
201 virNWFilterDefToInst(const char *xml,
202                      virNWFilterHashTablePtr vars,
203                      virNWFilterInstPtr inst);
204
205 static int
206 virNWFilterRuleDefToRuleInst(virNWFilterDefPtr def,
207                              virNWFilterRuleDefPtr rule,
208                              virNWFilterHashTablePtr vars,
209                              virNWFilterInstPtr inst)
210 {
211     virNWFilterRuleInstPtr ruleinst;
212     int ret = -1;
213
214     if (VIR_ALLOC(ruleinst) < 0)
215         goto cleanup;
216
217     ruleinst->chainSuffix = def->chainsuffix;
218     ruleinst->chainPriority = def->chainPriority;
219     ruleinst->def = rule;
220     ruleinst->priority = rule->priority;
221     if (!(ruleinst->vars = virNWFilterHashTableCreate(0)))
222         goto cleanup;
223     if (virNWFilterHashTablePutAll(vars, ruleinst->vars) < 0)
224         goto cleanup;
225
226     if (VIR_APPEND_ELEMENT(inst->rules,
227                            inst->nrules,
228                            ruleinst) < 0)
229         goto cleanup;
230     ruleinst = NULL;
231
232     ret = 0;
233  cleanup:
234     virNWFilterRuleInstFree(ruleinst);
235     return ret;
236 }
237
238
239 static int
240 virNWFilterIncludeDefToRuleInst(virNWFilterIncludeDefPtr inc,
241                                 virNWFilterHashTablePtr vars,
242                                 virNWFilterInstPtr inst)
243 {
244     virNWFilterHashTablePtr tmpvars = NULL;
245     int ret = -1;
246     char *xml;
247
248     if (virAsprintf(&xml, "%s/nwfilterxml2firewalldata/%s.xml",
249                     abs_srcdir, inc->filterref) < 0)
250         return -1;
251
252     /* create a temporary hashmap for depth-first tree traversal */
253     if (!(tmpvars = virNWFilterCreateVarsFrom(inc->params,
254                                               vars)))
255         goto cleanup;
256
257     if (virNWFilterDefToInst(xml,
258                              tmpvars,
259                              inst) < 0)
260         goto cleanup;
261
262     ret = 0;
263  cleanup:
264     if (ret < 0)
265         virNWFilterInstReset(inst);
266     virNWFilterHashTableFree(tmpvars);
267     VIR_FREE(xml);
268     return ret;
269 }
270
271 static int
272 virNWFilterDefToInst(const char *xml,
273                      virNWFilterHashTablePtr vars,
274                      virNWFilterInstPtr inst)
275 {
276     size_t i;
277     int ret = -1;
278     virNWFilterDefPtr def = virNWFilterDefParseFile(xml);
279
280     if (!def)
281         return -1;
282
283     if (VIR_APPEND_ELEMENT_COPY(inst->filters,
284                                 inst->nfilters,
285                                 def) < 0) {
286         virNWFilterDefFree(def);
287         goto cleanup;
288     }
289
290     for (i = 0; i < def->nentries; i++) {
291         if (def->filterEntries[i]->rule) {
292             if (virNWFilterRuleDefToRuleInst(def,
293                                              def->filterEntries[i]->rule,
294                                              vars,
295                                              inst) < 0)
296                 goto cleanup;
297         } else if (def->filterEntries[i]->include) {
298             if (virNWFilterIncludeDefToRuleInst(def->filterEntries[i]->include,
299                                                 vars,
300                                                 inst) < 0)
301                 goto cleanup;
302         }
303     }
304
305     ret = 0;
306  cleanup:
307     if (ret < 0)
308         virNWFilterInstReset(inst);
309     return ret;
310 }
311
312
313 static void testRemoveCommonRules(char *rules)
314 {
315     size_t i;
316     char *offset = rules;
317
318     for (i = 0; i < ARRAY_CARDINALITY(commonRules); i++) {
319         char *tmp = strstr(offset, commonRules[i]);
320         size_t len = strlen(commonRules[i]);
321         if (tmp) {
322             memmove(tmp, tmp + len, (strlen(tmp) + 1) - len);
323             offset = tmp;
324         }
325     }
326 }
327
328
329 static int testSetOneParameter(virNWFilterHashTablePtr vars,
330                                const char *name,
331                                const char *value)
332 {
333     int ret = -1;
334     virNWFilterVarValuePtr val;
335
336     if ((val = virHashLookup(vars->hashTable, name)) == NULL) {
337         val = virNWFilterVarValueCreateSimpleCopyValue(value);
338         if (!val)
339             goto cleanup;
340         if (virNWFilterHashTablePut(vars, name, val) < 0) {
341             virNWFilterVarValueFree(val);
342             goto cleanup;
343         }
344     } else {
345         if (virNWFilterVarValueAddValueCopy(val, value) < 0)
346             goto cleanup;
347     }
348     ret = 0;
349  cleanup:
350     return ret;
351 }
352
353 static int testSetDefaultParameters(virNWFilterHashTablePtr vars)
354 {
355     if (testSetOneParameter(vars, "IPSETNAME", "tck_test") < 0 ||
356         testSetOneParameter(vars, "A", "1.1.1.1") ||
357         testSetOneParameter(vars, "A", "2.2.2.2") ||
358         testSetOneParameter(vars, "A", "3.3.3.3") ||
359         testSetOneParameter(vars, "A", "3.3.3.3") ||
360         testSetOneParameter(vars, "B", "80") ||
361         testSetOneParameter(vars, "B", "90") ||
362         testSetOneParameter(vars, "B", "80") ||
363         testSetOneParameter(vars, "B", "80") ||
364         testSetOneParameter(vars, "C", "1080") ||
365         testSetOneParameter(vars, "C", "1090") ||
366         testSetOneParameter(vars, "C", "1100") ||
367         testSetOneParameter(vars, "C", "1110"))
368         return -1;
369     return 0;
370 }
371
372 static int testCompareXMLToArgvFiles(const char *xml,
373                                      const char *cmdline)
374 {
375     char *expectargv = NULL;
376     int len;
377     char *actualargv = NULL;
378     virBuffer buf = VIR_BUFFER_INITIALIZER;
379     virNWFilterHashTablePtr vars = virNWFilterHashTableCreate(0);
380     virNWFilterInst inst;
381     int ret = -1;
382
383     memset(&inst, 0, sizeof(inst));
384
385     virCommandSetDryRun(&buf, NULL, NULL);
386
387     if (!vars)
388         goto cleanup;
389
390     if (testSetDefaultParameters(vars) < 0)
391         goto cleanup;
392
393     if (virNWFilterDefToInst(xml,
394                              vars,
395                              &inst) < 0)
396         goto cleanup;
397
398     if (ebiptables_driver.applyNewRules("vnet0", inst.rules, inst.nrules) < 0)
399         goto cleanup;
400
401     if (virBufferError(&buf))
402         goto cleanup;
403
404     actualargv = virBufferContentAndReset(&buf);
405     virtTestClearCommandPath(actualargv);
406     virCommandSetDryRun(NULL, NULL, NULL);
407
408     testRemoveCommonRules(actualargv);
409
410     len = virtTestLoadFile(cmdline, &expectargv);
411     if (len < 0)
412         goto cleanup;
413
414     if (STRNEQ(expectargv, actualargv)) {
415         virtTestDifference(stderr, expectargv, actualargv);
416         goto cleanup;
417     }
418
419     ret = 0;
420
421  cleanup:
422     virBufferFreeAndReset(&buf);
423     VIR_FREE(expectargv);
424     VIR_FREE(actualargv);
425     virNWFilterInstReset(&inst);
426     virNWFilterHashTableFree(vars);
427     return ret;
428 }
429
430 struct testInfo {
431     const char *name;
432 };
433
434
435 static int
436 testCompareXMLToIPTablesHelper(const void *data)
437 {
438     int result = -1;
439     const struct testInfo *info = data;
440     char *xml = NULL;
441     char *args = NULL;
442
443     if (virAsprintf(&xml, "%s/nwfilterxml2firewalldata/%s.xml",
444                     abs_srcdir, info->name) < 0 ||
445         virAsprintf(&args, "%s/nwfilterxml2firewalldata/%s-%s.args",
446                     abs_srcdir, info->name, RULESTYPE) < 0)
447         goto cleanup;
448
449     result = testCompareXMLToArgvFiles(xml, args);
450
451  cleanup:
452     VIR_FREE(xml);
453     VIR_FREE(args);
454     return result;
455 }
456
457
458 static int
459 mymain(void)
460 {
461     int ret = 0;
462
463     abs_top_srcdir = getenv("abs_top_srcdir");
464     if (!abs_top_srcdir)
465         abs_top_srcdir = abs_srcdir "/..";
466
467 # define DO_TEST(name)                                                  \
468     do {                                                                \
469         static struct testInfo info = {                                 \
470             name,                                                       \
471         };                                                              \
472         if (virtTestRun("NWFilter XML-2-firewall " name,                \
473                         testCompareXMLToIPTablesHelper, &info) < 0)     \
474             ret = -1;                                                   \
475     } while (0)
476
477     if (virFirewallSetBackend(VIR_FIREWALL_BACKEND_DIRECT) < 0) {
478         ret = -1;
479         goto cleanup;
480     }
481
482     DO_TEST("ah");
483     DO_TEST("ah-ipv6");
484     DO_TEST("all");
485     DO_TEST("all-ipv6");
486     DO_TEST("arp");
487     DO_TEST("comment");
488     DO_TEST("conntrack");
489     DO_TEST("esp");
490     DO_TEST("esp-ipv6");
491     DO_TEST("example-1");
492     DO_TEST("example-2");
493     DO_TEST("hex-data");
494     DO_TEST("icmp-direction2");
495     DO_TEST("icmp-direction3");
496     DO_TEST("icmp-direction");
497     DO_TEST("icmp");
498     DO_TEST("icmpv6");
499     DO_TEST("igmp");
500     DO_TEST("ip");
501     DO_TEST("ipset");
502     DO_TEST("ipt-no-macspoof");
503     DO_TEST("ipv6");
504     DO_TEST("iter1");
505     DO_TEST("iter2");
506     DO_TEST("iter3");
507     DO_TEST("mac");
508     DO_TEST("rarp");
509     DO_TEST("sctp");
510     DO_TEST("sctp-ipv6");
511     DO_TEST("stp");
512     DO_TEST("target2");
513     DO_TEST("target");
514     DO_TEST("tcp");
515     DO_TEST("tcp-ipv6");
516     DO_TEST("udp");
517     DO_TEST("udp-ipv6");
518     DO_TEST("udplite");
519     DO_TEST("udplite-ipv6");
520     DO_TEST("vlan");
521
522  cleanup:
523     return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
524 }
525
526 VIRT_TEST_MAIN(mymain)
527
528 #else /* ! defined (__linux__) */
529
530 int main(void)
531 {
532     return EXIT_AM_SKIP;
533 }
534
535 #endif /* ! defined (__linux__) */