1 /*
2 * nwfilter_conf.c: network filter XML processing
3 * (derived from storage_conf.c)
4 *
5 * Copyright (C) 2006-2018 Red Hat, Inc.
6 * Copyright (C) 2006-2008 Daniel P. Berrange
7 *
8 * Copyright (C) 2010-2011 IBM Corporation
9 * Copyright (C) 2010-2011 Stefan Berger
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with this library. If not, see
23 * <http://www.gnu.org/licenses/>.
24 */
25
26 #include <config.h>
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #if WITH_NET_ETHERNET_H
32 # include <net/ethernet.h>
33 #endif
34 #include <unistd.h>
35
36 #include "internal.h"
37
38 #include "viruuid.h"
39 #include "viralloc.h"
40 #include "virerror.h"
41 #include "datatypes.h"
42 #include "nwfilter_params.h"
43 #include "nwfilter_conf.h"
44 #include "domain_conf.h"
45 #include "virfile.h"
46 #include "virstring.h"
47
48 #define VIR_FROM_THIS VIR_FROM_NWFILTER
49
50
51 VIR_ENUM_IMPL(virNWFilterRuleAction,
52 VIR_NWFILTER_RULE_ACTION_LAST,
53 "drop",
54 "accept",
55 "reject",
56 "return",
57 "continue",
58 );
59
60 VIR_ENUM_IMPL(virNWFilterJumpTarget,
61 VIR_NWFILTER_RULE_ACTION_LAST,
62 "DROP",
63 "ACCEPT",
64 "REJECT",
65 "RETURN",
66 "CONTINUE",
67 );
68
69 VIR_ENUM_IMPL(virNWFilterRuleDirection,
70 VIR_NWFILTER_RULE_DIRECTION_LAST,
71 "in",
72 "out",
73 "inout",
74 );
75
76 VIR_ENUM_IMPL(virNWFilterChainPolicy,
77 VIR_NWFILTER_CHAIN_POLICY_LAST,
78 "ACCEPT",
79 "DROP",
80 );
81
82 VIR_ENUM_IMPL(virNWFilterEbtablesTable,
83 VIR_NWFILTER_EBTABLES_TABLE_LAST,
84 "filter",
85 "nat",
86 "broute",
87 );
88
89 VIR_ENUM_IMPL(virNWFilterChainSuffix,
90 VIR_NWFILTER_CHAINSUFFIX_LAST,
91 "root",
92 "mac",
93 "vlan",
94 "stp",
95 "arp",
96 "rarp",
97 "ipv4",
98 "ipv6",
99 );
100
101 VIR_ENUM_IMPL(virNWFilterRuleProtocol,
102 VIR_NWFILTER_RULE_PROTOCOL_LAST,
103 "none",
104 "mac",
105 "vlan",
106 "stp",
107 "arp",
108 "rarp",
109 "ip",
110 "ipv6",
111 "tcp",
112 "icmp",
113 "igmp",
114 "udp",
115 "udplite",
116 "esp",
117 "ah",
118 "sctp",
119 "all",
120 "tcp-ipv6",
121 "icmpv6",
122 "udp-ipv6",
123 "udplite-ipv6",
124 "esp-ipv6",
125 "ah-ipv6",
126 "sctp-ipv6",
127 "all-ipv6",
128 );
129
130
131 /*
132 * a map entry for a simple static int-to-string map
133 */
134 struct int_map {
135 int32_t attr;
136 const char *val;
137 };
138
139 #define INTMAP_ENTRY(ATT, VAL) { .attr = ATT, .val = VAL }
140 #define INTMAP_ENTRY_LAST { .val = NULL }
141
142 static const struct int_map chain_priorities[] = {
143 INTMAP_ENTRY(NWFILTER_ROOT_FILTER_PRI, "root"),
144 INTMAP_ENTRY(NWFILTER_MAC_FILTER_PRI, "mac"),
145 INTMAP_ENTRY(NWFILTER_VLAN_FILTER_PRI, "vlan"),
146 INTMAP_ENTRY(NWFILTER_IPV4_FILTER_PRI, "ipv4"),
147 INTMAP_ENTRY(NWFILTER_IPV6_FILTER_PRI, "ipv6"),
148 INTMAP_ENTRY(NWFILTER_ARP_FILTER_PRI, "arp"),
149 INTMAP_ENTRY(NWFILTER_RARP_FILTER_PRI, "rarp"),
150 INTMAP_ENTRY_LAST,
151 };
152
153
154 /*
155 * only one filter update allowed
156 */
157 static virRWLock updateLock;
158 static bool initialized;
159
160 void
virNWFilterReadLockFilterUpdates(void)161 virNWFilterReadLockFilterUpdates(void)
162 {
163 virRWLockRead(&updateLock);
164 }
165
166
167 void
virNWFilterWriteLockFilterUpdates(void)168 virNWFilterWriteLockFilterUpdates(void)
169 {
170 virRWLockWrite(&updateLock);
171 }
172
173
174 void
virNWFilterUnlockFilterUpdates(void)175 virNWFilterUnlockFilterUpdates(void)
176 {
177 virRWLockUnlock(&updateLock);
178 }
179
180
181 /*
182 * attribute names for the rules XML
183 */
184 static const char srcmacaddr_str[] = "srcmacaddr";
185 static const char srcmacmask_str[] = "srcmacmask";
186 static const char dstmacaddr_str[] = "dstmacaddr";
187 static const char dstmacmask_str[] = "dstmacmask";
188 static const char arpsrcmacaddr_str[] = "arpsrcmacaddr";
189 static const char arpdstmacaddr_str[] = "arpdstmacaddr";
190 static const char arpsrcipaddr_str[] = "arpsrcipaddr";
191 static const char arpsrcipmask_str[] = "arpsrcipmask";
192 static const char arpdstipaddr_str[] = "arpdstipaddr";
193 static const char arpdstipmask_str[] = "arpdstipmask";
194 static const char srcipaddr_str[] = "srcipaddr";
195 static const char srcipmask_str[] = "srcipmask";
196 static const char dstipaddr_str[] = "dstipaddr";
197 static const char dstipmask_str[] = "dstipmask";
198 static const char srcipfrom_str[] = "srcipfrom";
199 static const char srcipto_str[] = "srcipto";
200 static const char dstipfrom_str[] = "dstipfrom";
201 static const char dstipto_str[] = "dstipto";
202 static const char srcportstart_str[] = "srcportstart";
203 static const char srcportend_str[] = "srcportend";
204 static const char dstportstart_str[] = "dstportstart";
205 static const char dstportend_str[] = "dstportend";
206 static const char dscp_str[] = "dscp";
207 static const char state_str[] = "state";
208 static const char ipset_str[] = "ipset";
209 static const char ipsetflags_str[] = "ipsetflags";
210
211 #define SRCMACADDR srcmacaddr_str
212 #define SRCMACMASK srcmacmask_str
213 #define DSTMACADDR dstmacaddr_str
214 #define DSTMACMASK dstmacmask_str
215 #define ARPSRCMACADDR arpsrcmacaddr_str
216 #define ARPDSTMACADDR arpdstmacaddr_str
217 #define ARPSRCIPADDR arpsrcipaddr_str
218 #define ARPSRCIPMASK arpsrcipmask_str
219 #define ARPDSTIPADDR arpdstipaddr_str
220 #define ARPDSTIPMASK arpdstipmask_str
221 #define SRCIPADDR srcipaddr_str
222 #define SRCIPMASK srcipmask_str
223 #define DSTIPADDR dstipaddr_str
224 #define DSTIPMASK dstipmask_str
225 #define SRCIPFROM srcipfrom_str
226 #define SRCIPTO srcipto_str
227 #define DSTIPFROM dstipfrom_str
228 #define DSTIPTO dstipto_str
229 #define SRCPORTSTART srcportstart_str
230 #define SRCPORTEND srcportend_str
231 #define DSTPORTSTART dstportstart_str
232 #define DSTPORTEND dstportend_str
233 #define DSCP dscp_str
234 #define STATE state_str
235 #define IPSET ipset_str
236 #define IPSETFLAGS ipsetflags_str
237
238
239 /**
240 * intMapGetByInt:
241 * @intmap: Pointer to int-to-string map
242 * @attr: The attribute to look up
243 * @res: Pointer to string pointer for result
244 *
245 * Returns 0 if value was found with result returned, -1 otherwise.
246 *
247 * lookup a map entry given the integer.
248 */
249 static int
intMapGetByInt(const struct int_map * intmap,int32_t attr,const char ** res)250 intMapGetByInt(const struct int_map *intmap,
251 int32_t attr,
252 const char **res)
253 {
254 size_t i = 0;
255 bool found = false;
256
257 while (intmap[i].val && !found) {
258 if (intmap[i].attr == attr) {
259 *res = intmap[i].val;
260 found = true;
261 }
262 i++;
263 }
264 return (found) ? 0 : -1;
265 }
266
267
268 /**
269 * intMapGetByString:
270 * @intmap: Pointer to int-to-string map
271 * @str: Pointer to string for which to find the entry
272 * @casecmp : Whether to ignore case when doing string matching
273 * @result: Pointer to int for result
274 *
275 * Returns 0 if entry was found, -1 otherwise.
276 *
277 * Do a lookup in the map trying to find an integer key using the string
278 * value. Returns 0 if entry was found with result returned, -1 otherwise.
279 */
280 static int
intMapGetByString(const struct int_map * intmap,const char * str,int casecmp,int32_t * result)281 intMapGetByString(const struct int_map *intmap,
282 const char *str,
283 int casecmp,
284 int32_t *result)
285 {
286 size_t i = 0;
287 bool found = false;
288
289 while (intmap[i].val && !found) {
290 if ((casecmp && STRCASEEQ(intmap[i].val, str)) ||
291 STREQ(intmap[i].val, str)) {
292 *result = intmap[i].attr;
293 found = true;
294 }
295 i++;
296 }
297 return (found) ? 0 : -1;
298 }
299
300
301 void
virNWFilterRuleDefFree(virNWFilterRuleDef * def)302 virNWFilterRuleDefFree(virNWFilterRuleDef *def)
303 {
304 size_t i;
305 if (!def)
306 return;
307
308 for (i = 0; i < def->nVarAccess; i++)
309 virNWFilterVarAccessFree(def->varAccess[i]);
310
311 for (i = 0; i < def->nstrings; i++)
312 g_free(def->strings[i]);
313
314 g_free(def->varAccess);
315 g_free(def->strings);
316
317 g_free(def);
318 }
319
320
321 static void
virNWFilterIncludeDefFree(virNWFilterIncludeDef * inc)322 virNWFilterIncludeDefFree(virNWFilterIncludeDef *inc)
323 {
324 if (!inc)
325 return;
326 virHashFree(inc->params);
327 g_free(inc->filterref);
328 g_free(inc);
329 }
330
331
332 static void
virNWFilterEntryFree(virNWFilterEntry * entry)333 virNWFilterEntryFree(virNWFilterEntry *entry)
334 {
335 if (!entry)
336 return;
337
338 virNWFilterRuleDefFree(entry->rule);
339 virNWFilterIncludeDefFree(entry->include);
340 g_free(entry);
341 }
342
343
344 void
virNWFilterDefFree(virNWFilterDef * def)345 virNWFilterDefFree(virNWFilterDef *def)
346 {
347 size_t i;
348 if (!def)
349 return;
350
351 g_free(def->name);
352
353 for (i = 0; i < def->nentries; i++)
354 virNWFilterEntryFree(def->filterEntries[i]);
355
356 g_free(def->filterEntries);
357 g_free(def->chainsuffix);
358
359 g_free(def);
360 }
361
362
363 static int
virNWFilterRuleDefAddVar(virNWFilterRuleDef * nwf,nwItemDesc * item,const char * var)364 virNWFilterRuleDefAddVar(virNWFilterRuleDef *nwf,
365 nwItemDesc *item,
366 const char *var)
367 {
368 size_t i = 0;
369 virNWFilterVarAccess *varAccess;
370
371 varAccess = virNWFilterVarAccessParse(var);
372 if (varAccess == NULL)
373 return -1;
374
375 if (nwf->varAccess) {
376 for (i = 0; i < nwf->nVarAccess; i++)
377 if (virNWFilterVarAccessEqual(nwf->varAccess[i], varAccess)) {
378 virNWFilterVarAccessFree(varAccess);
379 item->varAccess = nwf->varAccess[i];
380 return 0;
381 }
382 }
383
384 VIR_EXPAND_N(nwf->varAccess, nwf->nVarAccess, 1);
385 nwf->varAccess[nwf->nVarAccess - 1] = varAccess;
386 item->varAccess = varAccess;
387
388 return 0;
389 }
390
391
392 static char *
virNWFilterRuleDefAddString(virNWFilterRuleDef * nwf,const char * string,size_t maxstrlen)393 virNWFilterRuleDefAddString(virNWFilterRuleDef *nwf,
394 const char *string,
395 size_t maxstrlen)
396 {
397 char *tmp = g_strndup(string, maxstrlen);
398
399 VIR_APPEND_ELEMENT_COPY(nwf->strings, nwf->nstrings, tmp);
400
401 return tmp;
402 }
403
404
405 union data {
406 void *v;
407 char *c;
408 unsigned char *uc;
409 unsigned int ui;
410 };
411
412 typedef bool (*valueValidator)(enum attrDatatype datatype, union data *valptr,
413 virNWFilterRuleDef *nwf,
414 nwItemDesc *item);
415 typedef bool (*valueFormatter)(virBuffer *buf,
416 virNWFilterRuleDef *nwf,
417 nwItemDesc *item);
418
419 typedef struct _virXMLAttr2Struct virXMLAttr2Struct;
420 struct _virXMLAttr2Struct
421 {
422 const char *name; /* attribute name */
423 enum attrDatatype datatype;
424 int dataIdx; /* offset of the hasXYZ boolean */
425 valueValidator validator; /* beyond-standard checkers */
426 valueFormatter formatter; /* beyond-standard formatter */
427 size_t maxstrlen;
428 };
429
430
431 static const struct int_map macProtoMap[] = {
432 INTMAP_ENTRY(ETHERTYPE_ARP, "arp"),
433 INTMAP_ENTRY(ETHERTYPE_REVARP, "rarp"),
434 INTMAP_ENTRY(ETHERTYPE_IP, "ipv4"),
435 INTMAP_ENTRY(ETHERTYPE_IPV6, "ipv6"),
436 INTMAP_ENTRY(ETHERTYPE_VLAN, "vlan"),
437 INTMAP_ENTRY_LAST
438 };
439
440
441 static bool
checkMacProtocolID(enum attrDatatype datatype,union data * value,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item G_GNUC_UNUSED)442 checkMacProtocolID(enum attrDatatype datatype,
443 union data *value,
444 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
445 nwItemDesc *item G_GNUC_UNUSED)
446 {
447 int32_t res = -1;
448
449 if (datatype == DATATYPE_STRING) {
450 if (intMapGetByString(macProtoMap, value->c, 1, &res) < 0)
451 res = -1;
452 datatype = DATATYPE_UINT16;
453 } else if (datatype == DATATYPE_UINT16 ||
454 datatype == DATATYPE_UINT16_HEX) {
455 res = value->ui;
456 if (res < 0x600)
457 res = -1;
458 }
459
460 if (res != -1) {
461 nwf->p.ethHdrFilter.dataProtocolID.u.u16 = res;
462 nwf->p.ethHdrFilter.dataProtocolID.datatype = datatype;
463 return true;
464 }
465
466 return false;
467 }
468
469
470 static bool
macProtocolIDFormatter(virBuffer * buf,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)471 macProtocolIDFormatter(virBuffer *buf,
472 virNWFilterRuleDef *nwf,
473 nwItemDesc *item G_GNUC_UNUSED)
474 {
475 const char *str = NULL;
476 bool asHex = true;
477
478 if (intMapGetByInt(macProtoMap,
479 nwf->p.ethHdrFilter.dataProtocolID.u.u16,
480 &str) == 0) {
481 virBufferAdd(buf, str, -1);
482 } else {
483 if (nwf->p.ethHdrFilter.dataProtocolID.datatype == DATATYPE_UINT16)
484 asHex = false;
485 virBufferAsprintf(buf, asHex ? "0x%x" : "%d",
486 nwf->p.ethHdrFilter.dataProtocolID.u.u16);
487 }
488 return true;
489 }
490
491
492 static bool
checkVlanVlanID(enum attrDatatype datatype,union data * value,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)493 checkVlanVlanID(enum attrDatatype datatype,
494 union data *value,
495 virNWFilterRuleDef *nwf,
496 nwItemDesc *item G_GNUC_UNUSED)
497 {
498 int32_t res;
499
500 res = value->ui;
501 if (res < 0 || res > 4095)
502 res = -1;
503
504 if (res != -1) {
505 nwf->p.vlanHdrFilter.dataVlanID.u.u16 = res;
506 nwf->p.vlanHdrFilter.dataVlanID.datatype = datatype;
507 return true;
508 }
509
510 return false;
511 }
512
513
514 static bool
checkVlanProtocolID(enum attrDatatype datatype,union data * value,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)515 checkVlanProtocolID(enum attrDatatype datatype,
516 union data *value,
517 virNWFilterRuleDef *nwf,
518 nwItemDesc *item G_GNUC_UNUSED)
519 {
520 int32_t res = -1;
521
522 if (datatype == DATATYPE_STRING) {
523 if (intMapGetByString(macProtoMap, value->c, 1, &res) < 0)
524 res = -1;
525 datatype = DATATYPE_UINT16;
526 } else if (datatype == DATATYPE_UINT16 ||
527 datatype == DATATYPE_UINT16_HEX) {
528 res = value->ui;
529 if (res < 0x3c)
530 res = -1;
531 }
532
533 if (res != -1) {
534 nwf->p.vlanHdrFilter.dataVlanEncap.u.u16 = res;
535 nwf->p.vlanHdrFilter.dataVlanEncap.datatype = datatype;
536 return true;
537 }
538
539 return false;
540 }
541
542
543 static bool
vlanProtocolIDFormatter(virBuffer * buf,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)544 vlanProtocolIDFormatter(virBuffer *buf,
545 virNWFilterRuleDef *nwf,
546 nwItemDesc *item G_GNUC_UNUSED)
547 {
548 const char *str = NULL;
549 bool asHex = true;
550
551 if (intMapGetByInt(macProtoMap,
552 nwf->p.vlanHdrFilter.dataVlanEncap.u.u16,
553 &str) == 0) {
554 virBufferAdd(buf, str, -1);
555 } else {
556 if (nwf->p.vlanHdrFilter.dataVlanEncap.datatype == DATATYPE_UINT16)
557 asHex = false;
558 virBufferAsprintf(buf, asHex ? "0x%x" : "%d",
559 nwf->p.vlanHdrFilter.dataVlanEncap.u.u16);
560 }
561 return true;
562 }
563
564
565 /* generic function to check for a valid (ipv4,ipv6, mac) mask
566 * A mask is valid of there is a sequence of 1's followed by a sequence
567 * of 0s or only 1s or only 0s
568 */
569 static bool
checkValidMask(unsigned char * data,int len)570 checkValidMask(unsigned char *data,
571 int len)
572 {
573 uint32_t idx = 0;
574 uint8_t mask = 0x80;
575 bool checkones = true;
576
577 while ((idx >> 3) < len) {
578 if (checkones) {
579 if (!(data[idx>>3] & mask))
580 checkones = false;
581 } else {
582 if ((data[idx>>3] & mask))
583 return false;
584 }
585
586 idx++;
587 mask >>= 1;
588 if (!mask)
589 mask = 0x80;
590 }
591 return true;
592 }
593
594
595 static bool
checkMACMask(enum attrDatatype datatype G_GNUC_UNUSED,union data * macMask,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item G_GNUC_UNUSED)596 checkMACMask(enum attrDatatype datatype G_GNUC_UNUSED,
597 union data *macMask,
598 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
599 nwItemDesc *item G_GNUC_UNUSED)
600 {
601 return checkValidMask(macMask->uc, 6);
602 }
603
604
605 /*
606 * supported arp opcode -- see 'ebtables -h arp' for the naming
607 */
608 static const struct int_map arpOpcodeMap[] = {
609 INTMAP_ENTRY(1, "Request"),
610 INTMAP_ENTRY(2, "Reply"),
611 INTMAP_ENTRY(3, "Request_Reverse"),
612 INTMAP_ENTRY(4, "Reply_Reverse"),
613 INTMAP_ENTRY(5, "DRARP_Request"),
614 INTMAP_ENTRY(6, "DRARP_Reply"),
615 INTMAP_ENTRY(7, "DRARP_Error"),
616 INTMAP_ENTRY(8, "InARP_Request"),
617 INTMAP_ENTRY(9, "ARP_NAK"),
618 INTMAP_ENTRY_LAST
619 };
620
621
622 static bool
arpOpcodeValidator(enum attrDatatype datatype,union data * value,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)623 arpOpcodeValidator(enum attrDatatype datatype,
624 union data *value,
625 virNWFilterRuleDef *nwf,
626 nwItemDesc *item G_GNUC_UNUSED)
627 {
628 int32_t res = -1;
629
630 if (datatype == DATATYPE_STRING) {
631 if (intMapGetByString(arpOpcodeMap, value->c, 1, &res) < 0)
632 res = -1;
633 datatype = DATATYPE_UINT16;
634 } else if (datatype == DATATYPE_UINT16 ||
635 datatype == DATATYPE_UINT16_HEX) {
636 res = (uint32_t)value->ui;
637 }
638
639 if (res != -1) {
640 nwf->p.arpHdrFilter.dataOpcode.u.u16 = res;
641 nwf->p.arpHdrFilter.dataOpcode.datatype = datatype;
642 return true;
643 }
644 return false;
645 }
646
647
648 static bool
arpOpcodeFormatter(virBuffer * buf,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)649 arpOpcodeFormatter(virBuffer *buf,
650 virNWFilterRuleDef *nwf,
651 nwItemDesc *item G_GNUC_UNUSED)
652 {
653 const char *str = NULL;
654
655 if (intMapGetByInt(arpOpcodeMap,
656 nwf->p.arpHdrFilter.dataOpcode.u.u16,
657 &str) == 0) {
658 virBufferAdd(buf, str, -1);
659 } else {
660 virBufferAsprintf(buf, "%d", nwf->p.arpHdrFilter.dataOpcode.u.u16);
661 }
662 return true;
663 }
664
665
666 static const struct int_map ipProtoMap[] = {
667 INTMAP_ENTRY(IPPROTO_TCP, "tcp"),
668 INTMAP_ENTRY(IPPROTO_UDP, "udp"),
669 #ifdef IPPROTO_UDPLITE
670 INTMAP_ENTRY(IPPROTO_UDPLITE, "udplite"),
671 #endif
672 INTMAP_ENTRY(IPPROTO_ESP, "esp"),
673 INTMAP_ENTRY(IPPROTO_AH, "ah"),
674 INTMAP_ENTRY(IPPROTO_ICMP, "icmp"),
675 INTMAP_ENTRY(IPPROTO_IGMP, "igmp"),
676 #ifdef IPPROTO_SCTP
677 INTMAP_ENTRY(IPPROTO_SCTP, "sctp"),
678 #endif
679 INTMAP_ENTRY(IPPROTO_ICMPV6, "icmpv6"),
680 INTMAP_ENTRY_LAST
681 };
682
683
684 static bool
checkIPProtocolID(enum attrDatatype datatype,union data * value,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)685 checkIPProtocolID(enum attrDatatype datatype,
686 union data *value,
687 virNWFilterRuleDef *nwf,
688 nwItemDesc *item G_GNUC_UNUSED)
689 {
690 int32_t res = -1;
691
692 if (datatype == DATATYPE_STRING) {
693 if (intMapGetByString(ipProtoMap, value->c, 1, &res) < 0)
694 res = -1;
695 datatype = DATATYPE_UINT8_HEX;
696 } else if (datatype == DATATYPE_UINT8 ||
697 datatype == DATATYPE_UINT8_HEX) {
698 res = (uint32_t)value->ui;
699 }
700
701 if (res != -1) {
702 nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8 = res;
703 nwf->p.ipHdrFilter.ipHdr.dataProtocolID.datatype = datatype;
704 return true;
705 }
706 return false;
707 }
708
709
710 static bool
formatIPProtocolID(virBuffer * buf,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)711 formatIPProtocolID(virBuffer *buf,
712 virNWFilterRuleDef *nwf,
713 nwItemDesc *item G_GNUC_UNUSED)
714 {
715 const char *str = NULL;
716 bool asHex = true;
717
718 if (intMapGetByInt(ipProtoMap,
719 nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8,
720 &str) == 0) {
721 virBufferAdd(buf, str, -1);
722 } else {
723 if (nwf->p.ipHdrFilter.ipHdr.dataProtocolID.datatype == DATATYPE_UINT8)
724 asHex = false;
725 virBufferAsprintf(buf, asHex ? "0x%x" : "%d",
726 nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8);
727 }
728 return true;
729 }
730
731
732 static bool
dscpValidator(enum attrDatatype datatype,union data * val,virNWFilterRuleDef * nwf,nwItemDesc * item G_GNUC_UNUSED)733 dscpValidator(enum attrDatatype datatype,
734 union data *val,
735 virNWFilterRuleDef *nwf,
736 nwItemDesc *item G_GNUC_UNUSED)
737 {
738 uint8_t dscp = val->ui;
739 if (dscp > 63)
740 return false;
741
742 nwf->p.ipHdrFilter.ipHdr.dataDSCP.datatype = datatype;
743
744 return true;
745 }
746
747
748 static const struct int_map stateMatchMap[] = {
749 INTMAP_ENTRY(RULE_FLAG_STATE_NEW, "NEW"),
750 INTMAP_ENTRY(RULE_FLAG_STATE_ESTABLISHED, "ESTABLISHED"),
751 INTMAP_ENTRY(RULE_FLAG_STATE_RELATED, "RELATED"),
752 INTMAP_ENTRY(RULE_FLAG_STATE_INVALID, "INVALID"),
753 INTMAP_ENTRY(RULE_FLAG_STATE_NONE, "NONE"),
754 INTMAP_ENTRY_LAST,
755 };
756
757
758 static int
parseStringItems(const struct int_map * int_map,const char * input,int32_t * flags,char sep)759 parseStringItems(const struct int_map *int_map,
760 const char *input,
761 int32_t *flags,
762 char sep)
763 {
764 int rc = 0;
765 size_t i, j;
766 bool found;
767
768 i = 0;
769 while (input[i]) {
770 found = false;
771 while (g_ascii_isspace(input[i]) || input[i] == sep)
772 i++;
773 if (!input[i])
774 break;
775 for (j = 0; int_map[j].val; j++) {
776 if (STRCASEEQLEN(&input[i], int_map[j].val,
777 strlen(int_map[j].val))) {
778 *flags |= int_map[j].attr;
779 i += strlen(int_map[j].val);
780 found = true;
781 break;
782 }
783 }
784 if (!found) {
785 rc = -1;
786 break;
787 }
788 }
789 return rc;
790 }
791
792
793 static int
printStringItems(virBuffer * buf,const struct int_map * int_map,int32_t flags,const char * sep)794 printStringItems(virBuffer *buf,
795 const struct int_map *int_map,
796 int32_t flags,
797 const char *sep)
798 {
799 size_t i;
800 unsigned int c = 0;
801 int32_t mask = 0x1;
802
803 while (mask) {
804 if ((mask & flags)) {
805 for (i = 0; int_map[i].val; i++) {
806 if (mask == int_map[i].attr) {
807 if (c >= 1)
808 virBufferAdd(buf, sep, -1);
809 virBufferAdd(buf, int_map[i].val, -1);
810 c++;
811 }
812 }
813 flags ^= mask;
814 }
815 if (!flags)
816 break;
817 mask <<= 1;
818 }
819
820 return 0;
821 }
822
823
824 static int
parseStateMatch(const char * statematch,int32_t * flags)825 parseStateMatch(const char *statematch,
826 int32_t *flags)
827 {
828 int rc = parseStringItems(stateMatchMap, statematch, flags, ',');
829
830 if ((*flags & RULE_FLAG_STATE_NONE))
831 *flags = RULE_FLAG_STATE_NONE;
832
833 return rc;
834 }
835
836
837 void
virNWFilterPrintStateMatchFlags(virBuffer * buf,const char * prefix,int32_t flags,bool disp_none)838 virNWFilterPrintStateMatchFlags(virBuffer *buf,
839 const char *prefix,
840 int32_t flags,
841 bool disp_none)
842 {
843 if (!disp_none && (flags & RULE_FLAG_STATE_NONE))
844 return;
845
846 virBufferAdd(buf, prefix, -1);
847
848 printStringItems(buf, stateMatchMap, flags, ",");
849 }
850
851
852 static bool
stateValidator(enum attrDatatype datatype G_GNUC_UNUSED,union data * val,virNWFilterRuleDef * nwf,nwItemDesc * item)853 stateValidator(enum attrDatatype datatype G_GNUC_UNUSED,
854 union data *val,
855 virNWFilterRuleDef *nwf,
856 nwItemDesc *item)
857 {
858 char *input = val->c;
859 int32_t flags = 0;
860
861 if (parseStateMatch(input, &flags) < 0)
862 return false;
863
864 item->u.u16 = flags;
865 nwf->flags |= flags;
866
867 item->datatype = DATATYPE_UINT16;
868
869 return true;
870 }
871
872
873 static bool
stateFormatter(virBuffer * buf,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)874 stateFormatter(virBuffer *buf,
875 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
876 nwItemDesc *item)
877 {
878 virNWFilterPrintStateMatchFlags(buf, "", item->u.u16, true);
879
880 return true;
881 }
882
883
884 static const struct int_map tcpFlags[] = {
885 INTMAP_ENTRY(0x1, "FIN"),
886 INTMAP_ENTRY(0x2, "SYN"),
887 INTMAP_ENTRY(0x4, "RST"),
888 INTMAP_ENTRY(0x8, "PSH"),
889 INTMAP_ENTRY(0x10, "ACK"),
890 INTMAP_ENTRY(0x20, "URG"),
891 INTMAP_ENTRY(0x3F, "ALL"),
892 INTMAP_ENTRY(0x0, "NONE"),
893 INTMAP_ENTRY_LAST
894 };
895
896
897 static bool
tcpFlagsValidator(enum attrDatatype datatype G_GNUC_UNUSED,union data * val,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)898 tcpFlagsValidator(enum attrDatatype datatype G_GNUC_UNUSED,
899 union data *val,
900 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
901 nwItemDesc *item)
902 {
903 bool rc = false;
904 char *s_mask = val->c;
905 char *sep = strchr(val->c, '/');
906 char *s_flags;
907 int32_t mask = 0, flags = 0;
908
909 if (!sep)
910 return false;
911
912 s_flags = sep + 1;
913
914 *sep = '\0';
915
916 if (parseStringItems(tcpFlags, s_mask, &mask, ',') == 0 &&
917 parseStringItems(tcpFlags, s_flags, &flags, ',') == 0) {
918 item->u.tcpFlags.mask = mask & 0x3f;
919 item->u.tcpFlags.flags = flags & 0x3f;
920 rc = true;
921 }
922
923 *sep = '/';
924
925 return rc;
926 }
927
928
929 static void
printTCPFlags(virBuffer * buf,uint8_t flags)930 printTCPFlags(virBuffer *buf,
931 uint8_t flags)
932 {
933 if (flags == 0)
934 virBufferAddLit(buf, "NONE");
935 else if (flags == 0x3f)
936 virBufferAddLit(buf, "ALL");
937 else
938 printStringItems(buf, tcpFlags, flags, ",");
939 }
940
941
942 char *
virNWFilterPrintTCPFlags(uint8_t flags)943 virNWFilterPrintTCPFlags(uint8_t flags)
944 {
945 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
946 printTCPFlags(&buf, flags);
947 return virBufferContentAndReset(&buf);
948 }
949
950
951 static bool
tcpFlagsFormatter(virBuffer * buf,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)952 tcpFlagsFormatter(virBuffer *buf,
953 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
954 nwItemDesc *item)
955 {
956 printTCPFlags(buf, item->u.tcpFlags.mask);
957 virBufferAddLit(buf, "/");
958 printTCPFlags(buf, item->u.tcpFlags.flags);
959
960 return true;
961 }
962
963
964 static bool
ipsetValidator(enum attrDatatype datatype G_GNUC_UNUSED,union data * val,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)965 ipsetValidator(enum attrDatatype datatype G_GNUC_UNUSED,
966 union data *val,
967 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
968 nwItemDesc *item)
969 {
970 const char *errmsg = NULL;
971
972 if (virStrcpyStatic(item->u.ipset.setname, val->c) < 0) {
973 errmsg = _("ipset name is too long");
974 goto arg_err_exit;
975 }
976
977 if (item->u.ipset.setname[strspn(item->u.ipset.setname,
978 VALID_IPSETNAME)] != 0) {
979 errmsg = _("ipset name contains invalid characters");
980 goto arg_err_exit;
981 }
982
983 return true;
984
985 arg_err_exit:
986 virReportError(VIR_ERR_INVALID_ARG,
987 "%s", errmsg);
988 return false;
989 }
990
991
992 static bool
ipsetFormatter(virBuffer * buf,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)993 ipsetFormatter(virBuffer *buf,
994 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
995 nwItemDesc *item)
996 {
997 virBufferAdd(buf, item->u.ipset.setname, -1);
998
999 return true;
1000 }
1001
1002
1003 static bool
ipsetFlagsValidator(enum attrDatatype datatype G_GNUC_UNUSED,union data * val,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)1004 ipsetFlagsValidator(enum attrDatatype datatype G_GNUC_UNUSED,
1005 union data *val,
1006 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
1007 nwItemDesc *item)
1008 {
1009 const char *errmsg = NULL;
1010 size_t idx = 0;
1011
1012 item->u.ipset.numFlags = 0;
1013 item->u.ipset.flags = 0;
1014
1015 errmsg = _("malformed ipset flags");
1016
1017 while (item->u.ipset.numFlags < 6) {
1018 if (STRCASEEQLEN(&val->c[idx], "src", 3)) {
1019 item->u.ipset.flags |= (1 << item->u.ipset.numFlags);
1020 } else if (!STRCASEEQLEN(&val->c[idx], "dst", 3)) {
1021 goto arg_err_exit;
1022 }
1023 item->u.ipset.numFlags++;
1024 idx += 3;
1025 if (val->c[idx] != ',')
1026 break;
1027 idx++;
1028 }
1029
1030 if (val->c[idx] != '\0')
1031 goto arg_err_exit;
1032
1033 return true;
1034
1035 arg_err_exit:
1036 virReportError(VIR_ERR_INVALID_ARG,
1037 "%s", errmsg);
1038 return false;
1039 }
1040
1041
1042 static bool
ipsetFlagsFormatter(virBuffer * buf,virNWFilterRuleDef * nwf G_GNUC_UNUSED,nwItemDesc * item)1043 ipsetFlagsFormatter(virBuffer *buf,
1044 virNWFilterRuleDef *nwf G_GNUC_UNUSED,
1045 nwItemDesc *item)
1046 {
1047 uint8_t ctr;
1048
1049 for (ctr = 0; ctr < item->u.ipset.numFlags; ctr++) {
1050 if (ctr != 0)
1051 virBufferAddLit(buf, ",");
1052 if ((item->u.ipset.flags & (1 << ctr)))
1053 virBufferAddLit(buf, "src");
1054 else
1055 virBufferAddLit(buf, "dst");
1056 }
1057
1058 return true;
1059 }
1060
1061
1062 #define COMMON_MAC_PROPS(STRUCT) \
1063 {\
1064 .name = SRCMACADDR,\
1065 .datatype = DATATYPE_MACADDR,\
1066 .dataIdx = offsetof(virNWFilterRuleDef,\
1067 p.STRUCT.ethHdr.dataSrcMACAddr),\
1068 },\
1069 {\
1070 .name = SRCMACMASK,\
1071 .datatype = DATATYPE_MACMASK,\
1072 .dataIdx = offsetof(virNWFilterRuleDef,\
1073 p.STRUCT.ethHdr.dataSrcMACMask),\
1074 },\
1075 {\
1076 .name = DSTMACADDR,\
1077 .datatype = DATATYPE_MACADDR,\
1078 .dataIdx = offsetof(virNWFilterRuleDef,\
1079 p.STRUCT.ethHdr.dataDstMACAddr),\
1080 },\
1081 {\
1082 .name = DSTMACMASK,\
1083 .datatype = DATATYPE_MACMASK,\
1084 .dataIdx = offsetof(virNWFilterRuleDef,\
1085 p.STRUCT.ethHdr.dataDstMACMask),\
1086 }
1087
1088
1089 #define COMMENT_PROP(STRUCT) \
1090 {\
1091 .name = "comment",\
1092 .datatype = DATATYPE_STRINGCOPY,\
1093 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.dataComment),\
1094 .maxstrlen = MAX_COMMENT_LENGTH,\
1095 }
1096
1097 #define COMMENT_PROP_IPHDR(STRUCT) \
1098 COMMENT_PROP(STRUCT.ipHdr)
1099
1100
1101 static const virXMLAttr2Struct macAttributes[] = {
1102 COMMON_MAC_PROPS(ethHdrFilter),
1103 {
1104 .name = "protocolid",
1105 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX | DATATYPE_STRING,
1106 .dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataProtocolID),
1107 .validator = checkMacProtocolID,
1108 .formatter = macProtocolIDFormatter,
1109 },
1110 COMMENT_PROP(ethHdrFilter),
1111 {
1112 .name = NULL,
1113 }
1114 };
1115
1116 static const virXMLAttr2Struct vlanAttributes[] = {
1117 COMMON_MAC_PROPS(ethHdrFilter),
1118 {
1119 .name = "vlanid",
1120 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1121 .dataIdx = offsetof(virNWFilterRuleDef, p.vlanHdrFilter.dataVlanID),
1122 .validator = checkVlanVlanID,
1123 },
1124 {
1125 .name = "encap-protocol",
1126 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX | DATATYPE_STRING,
1127 .dataIdx = offsetof(virNWFilterRuleDef, p.vlanHdrFilter.dataVlanEncap),
1128 .validator = checkVlanProtocolID,
1129 .formatter = vlanProtocolIDFormatter,
1130 },
1131 COMMENT_PROP(vlanHdrFilter),
1132 {
1133 .name = NULL,
1134 }
1135 };
1136
1137 /* STP is documented by IEEE 802.1D; for a synopsis,
1138 * see http://www.javvin.com/protocolSTP.html */
1139 static const virXMLAttr2Struct stpAttributes[] = {
1140 /* spanning tree uses a special destination MAC address */
1141 {
1142 .name = SRCMACADDR,
1143 .datatype = DATATYPE_MACADDR,
1144 .dataIdx = offsetof(virNWFilterRuleDef,
1145 p.stpHdrFilter.ethHdr.dataSrcMACAddr),
1146 },
1147 {
1148 .name = SRCMACMASK,
1149 .datatype = DATATYPE_MACMASK,
1150 .dataIdx = offsetof(virNWFilterRuleDef,
1151 p.stpHdrFilter.ethHdr.dataSrcMACMask),
1152 },
1153 {
1154 .name = "type",
1155 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1156 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataType),
1157 },
1158 {
1159 .name = "flags",
1160 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1161 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataFlags),
1162 },
1163 {
1164 .name = "root-priority",
1165 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1166 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootPri),
1167 },
1168 {
1169 .name = "root-priority-hi",
1170 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1171 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootPriHi),
1172 },
1173 {
1174 .name = "root-address",
1175 .datatype = DATATYPE_MACADDR,
1176 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootAddr),
1177 },
1178 {
1179 .name = "root-address-mask",
1180 .datatype = DATATYPE_MACMASK,
1181 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootAddrMask),
1182 },
1183 {
1184 .name = "root-cost",
1185 .datatype = DATATYPE_UINT32 | DATATYPE_UINT32_HEX,
1186 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootCost),
1187 },
1188 {
1189 .name = "root-cost-hi",
1190 .datatype = DATATYPE_UINT32 | DATATYPE_UINT32_HEX,
1191 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataRootCostHi),
1192 },
1193 {
1194 .name = "sender-priority",
1195 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1196 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrPrio),
1197 },
1198 {
1199 .name = "sender-priority-hi",
1200 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1201 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrPrioHi),
1202 },
1203 {
1204 .name = "sender-address",
1205 .datatype = DATATYPE_MACADDR,
1206 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrAddr),
1207 },
1208 {
1209 .name = "sender-address-mask",
1210 .datatype = DATATYPE_MACMASK,
1211 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataSndrAddrMask),
1212 },
1213 {
1214 .name = "port",
1215 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1216 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataPort),
1217 },
1218 {
1219 .name = "port-hi",
1220 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1221 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataPortHi),
1222 },
1223 {
1224 .name = "age",
1225 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1226 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataAge),
1227 },
1228 {
1229 .name = "age-hi",
1230 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1231 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataAgeHi),
1232 },
1233 {
1234 .name = "max-age",
1235 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1236 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataMaxAge),
1237 },
1238 {
1239 .name = "max-age-hi",
1240 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1241 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataMaxAgeHi),
1242 },
1243 {
1244 .name = "hello-time",
1245 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1246 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataHelloTime),
1247 },
1248 {
1249 .name = "hello-time-hi",
1250 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1251 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataHelloTimeHi),
1252 },
1253 {
1254 .name = "forward-delay",
1255 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1256 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataFwdDelay),
1257 },
1258 {
1259 .name = "forward-delay-hi",
1260 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1261 .dataIdx = offsetof(virNWFilterRuleDef, p.stpHdrFilter.dataFwdDelayHi),
1262 },
1263 COMMENT_PROP(stpHdrFilter),
1264 {
1265 .name = NULL,
1266 }
1267 };
1268
1269 static const virXMLAttr2Struct arpAttributes[] = {
1270 COMMON_MAC_PROPS(arpHdrFilter),
1271 {
1272 .name = "hwtype",
1273 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1274 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataHWType),
1275 }, {
1276 .name = "protocoltype",
1277 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1278 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataProtocolType),
1279 }, {
1280 .name = "opcode",
1281 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX | DATATYPE_STRING,
1282 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataOpcode),
1283 .validator = arpOpcodeValidator,
1284 .formatter = arpOpcodeFormatter,
1285 }, {
1286 .name = ARPSRCMACADDR,
1287 .datatype = DATATYPE_MACADDR,
1288 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPSrcMACAddr),
1289 }, {
1290 .name = ARPDSTMACADDR,
1291 .datatype = DATATYPE_MACADDR,
1292 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPDstMACAddr),
1293 }, {
1294 .name = ARPSRCIPADDR,
1295 .datatype = DATATYPE_IPADDR,
1296 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPSrcIPAddr),
1297 }, {
1298 .name = ARPSRCIPMASK,
1299 .datatype = DATATYPE_IPMASK,
1300 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPSrcIPMask),
1301 }, {
1302 .name = ARPDSTIPADDR,
1303 .datatype = DATATYPE_IPADDR,
1304 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPDstIPAddr),
1305 }, {
1306 .name = ARPDSTIPMASK,
1307 .datatype = DATATYPE_IPMASK,
1308 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataARPDstIPMask),
1309 }, {
1310 .name = "gratuitous",
1311 .datatype = DATATYPE_BOOLEAN,
1312 .dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataGratuitousARP),
1313 },
1314 COMMENT_PROP(arpHdrFilter),
1315 {
1316 .name = NULL,
1317 }
1318 };
1319
1320 static const virXMLAttr2Struct ipAttributes[] = {
1321 COMMON_MAC_PROPS(ipHdrFilter),
1322 {
1323 .name = SRCIPADDR,
1324 .datatype = DATATYPE_IPADDR,
1325 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataSrcIPAddr),
1326 },
1327 {
1328 .name = SRCIPMASK,
1329 .datatype = DATATYPE_IPMASK,
1330 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataSrcIPMask),
1331 },
1332 {
1333 .name = DSTIPADDR,
1334 .datatype = DATATYPE_IPADDR,
1335 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDstIPAddr),
1336 },
1337 {
1338 .name = DSTIPMASK,
1339 .datatype = DATATYPE_IPMASK,
1340 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDstIPMask),
1341 },
1342 {
1343 .name = "protocol",
1344 .datatype = DATATYPE_STRING | DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1345 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataProtocolID),
1346 .validator = checkIPProtocolID,
1347 .formatter = formatIPProtocolID,
1348 },
1349 {
1350 .name = SRCPORTSTART,
1351 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1352 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortStart),
1353 },
1354 {
1355 .name = SRCPORTEND,
1356 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1357 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortEnd),
1358 },
1359 {
1360 .name = DSTPORTSTART,
1361 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1362 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortStart),
1363 },
1364 {
1365 .name = DSTPORTEND,
1366 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1367 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortEnd),
1368 },
1369 {
1370 .name = DSCP,
1371 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1372 .dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDSCP),
1373 .validator = dscpValidator,
1374 },
1375 COMMENT_PROP_IPHDR(ipHdrFilter),
1376 {
1377 .name = NULL,
1378 }
1379 };
1380
1381
1382 static const virXMLAttr2Struct ipv6Attributes[] = {
1383 COMMON_MAC_PROPS(ipv6HdrFilter),
1384 {
1385 .name = SRCIPADDR,
1386 .datatype = DATATYPE_IPV6ADDR,
1387 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataSrcIPAddr),
1388 },
1389 {
1390 .name = SRCIPMASK,
1391 .datatype = DATATYPE_IPV6MASK,
1392 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataSrcIPMask),
1393 },
1394 {
1395 .name = DSTIPADDR,
1396 .datatype = DATATYPE_IPV6ADDR,
1397 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataDstIPAddr),
1398 },
1399 {
1400 .name = DSTIPMASK,
1401 .datatype = DATATYPE_IPV6MASK,
1402 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataDstIPMask),
1403 },
1404 {
1405 .name = "protocol",
1406 .datatype = DATATYPE_STRING | DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1407 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataProtocolID),
1408 .validator = checkIPProtocolID,
1409 .formatter = formatIPProtocolID,
1410 },
1411 {
1412 .name = SRCPORTSTART,
1413 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1414 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataSrcPortStart),
1415 },
1416 {
1417 .name = SRCPORTEND,
1418 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1419 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataSrcPortEnd),
1420 },
1421 {
1422 .name = DSTPORTSTART,
1423 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1424 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortStart),
1425 },
1426 {
1427 .name = DSTPORTEND,
1428 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
1429 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortEnd),
1430 },
1431 {
1432 .name = "type",
1433 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1434 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPTypeStart),
1435 },
1436 {
1437 .name = "typeend",
1438 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1439 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPTypeEnd),
1440 },
1441 {
1442 .name = "code",
1443 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1444 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPCodeStart),
1445 },
1446 {
1447 .name = "codeend",
1448 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1449 .dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.dataICMPCodeEnd),
1450 },
1451 COMMENT_PROP_IPHDR(ipv6HdrFilter),
1452 {
1453 .name = NULL,
1454 }
1455 };
1456
1457
1458 #define COMMON_L3_MAC_PROPS(STRUCT) \
1459 {\
1460 .name = SRCMACADDR,\
1461 .datatype = DATATYPE_MACADDR,\
1462 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.dataSrcMACAddr),\
1463 }
1464
1465 #define COMMON_IP_PROPS(STRUCT, ADDRTYPE, MASKTYPE) \
1466 COMMON_L3_MAC_PROPS(STRUCT),\
1467 {\
1468 .name = SRCIPADDR,\
1469 .datatype = ADDRTYPE,\
1470 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPAddr),\
1471 },\
1472 {\
1473 .name = SRCIPMASK,\
1474 .datatype = MASKTYPE,\
1475 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPMask),\
1476 },\
1477 {\
1478 .name = DSTIPADDR,\
1479 .datatype = ADDRTYPE,\
1480 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPAddr),\
1481 },\
1482 {\
1483 .name = DSTIPMASK,\
1484 .datatype = MASKTYPE,\
1485 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPMask),\
1486 },\
1487 {\
1488 .name = SRCIPFROM,\
1489 .datatype = ADDRTYPE,\
1490 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPFrom),\
1491 },\
1492 {\
1493 .name = SRCIPTO,\
1494 .datatype = ADDRTYPE,\
1495 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataSrcIPTo),\
1496 },\
1497 {\
1498 .name = DSTIPFROM,\
1499 .datatype = ADDRTYPE,\
1500 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPFrom),\
1501 },\
1502 {\
1503 .name = DSTIPTO,\
1504 .datatype = DATATYPE_IPADDR,\
1505 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDstIPTo),\
1506 },\
1507 {\
1508 .name = DSCP,\
1509 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,\
1510 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDSCP),\
1511 .validator = dscpValidator,\
1512 },\
1513 {\
1514 .name = "connlimit-above",\
1515 .datatype = DATATYPE_UINT16,\
1516 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataConnlimitAbove),\
1517 },\
1518 {\
1519 .name = STATE,\
1520 .datatype = DATATYPE_STRING,\
1521 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataState),\
1522 .validator = stateValidator,\
1523 .formatter = stateFormatter,\
1524 },\
1525 {\
1526 .name = IPSET,\
1527 .datatype = DATATYPE_IPSETNAME,\
1528 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataIPSet),\
1529 .validator = ipsetValidator,\
1530 .formatter = ipsetFormatter,\
1531 },\
1532 {\
1533 .name = IPSETFLAGS,\
1534 .datatype = DATATYPE_IPSETFLAGS,\
1535 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataIPSetFlags),\
1536 .validator = ipsetFlagsValidator,\
1537 .formatter = ipsetFlagsFormatter,\
1538 }
1539
1540 #define COMMON_PORT_PROPS(STRUCT) \
1541 {\
1542 .name = SRCPORTSTART,\
1543 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
1544 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortStart),\
1545 },\
1546 {\
1547 .name = SRCPORTEND,\
1548 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
1549 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortEnd),\
1550 },\
1551 {\
1552 .name = DSTPORTSTART,\
1553 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
1554 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortStart),\
1555 },\
1556 {\
1557 .name = DSTPORTEND,\
1558 .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
1559 .dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortEnd),\
1560 }
1561
1562 static const virXMLAttr2Struct tcpAttributes[] = {
1563 COMMON_IP_PROPS(tcpHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1564 COMMON_PORT_PROPS(tcpHdrFilter),
1565 {
1566 .name = "option",
1567 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1568 .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption),
1569 },
1570 {
1571 .name = "flags",
1572 .datatype = DATATYPE_STRING,
1573 .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPFlags),
1574 .validator = tcpFlagsValidator,
1575 .formatter = tcpFlagsFormatter,
1576 },
1577 COMMENT_PROP_IPHDR(tcpHdrFilter),
1578 {
1579 .name = NULL,
1580 }
1581 };
1582
1583 static const virXMLAttr2Struct udpAttributes[] = {
1584 COMMON_IP_PROPS(udpHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1585 COMMON_PORT_PROPS(udpHdrFilter),
1586 COMMENT_PROP_IPHDR(udpHdrFilter),
1587 {
1588 .name = NULL,
1589 }
1590 };
1591
1592 static const virXMLAttr2Struct udpliteAttributes[] = {
1593 COMMON_IP_PROPS(udpliteHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1594 COMMENT_PROP_IPHDR(udpliteHdrFilter),
1595 {
1596 .name = NULL,
1597 }
1598 };
1599
1600 static const virXMLAttr2Struct espAttributes[] = {
1601 COMMON_IP_PROPS(espHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1602 COMMENT_PROP_IPHDR(espHdrFilter),
1603 {
1604 .name = NULL,
1605 }
1606 };
1607
1608 static const virXMLAttr2Struct ahAttributes[] = {
1609 COMMON_IP_PROPS(ahHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1610 COMMENT_PROP_IPHDR(ahHdrFilter),
1611 {
1612 .name = NULL,
1613 }
1614 };
1615
1616 static const virXMLAttr2Struct sctpAttributes[] = {
1617 COMMON_IP_PROPS(sctpHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1618 COMMON_PORT_PROPS(sctpHdrFilter),
1619 COMMENT_PROP_IPHDR(sctpHdrFilter),
1620 {
1621 .name = NULL,
1622 }
1623 };
1624
1625
1626 static const virXMLAttr2Struct icmpAttributes[] = {
1627 COMMON_IP_PROPS(icmpHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1628 {
1629 .name = "type",
1630 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1631 .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPType),
1632 },
1633 {
1634 .name = "code",
1635 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1636 .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPCode),
1637 },
1638 COMMENT_PROP_IPHDR(icmpHdrFilter),
1639 {
1640 .name = NULL,
1641 }
1642 };
1643
1644
1645 static const virXMLAttr2Struct allAttributes[] = {
1646 COMMON_IP_PROPS(allHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1647 COMMENT_PROP_IPHDR(allHdrFilter),
1648 {
1649 .name = NULL,
1650 }
1651 };
1652
1653
1654 static const virXMLAttr2Struct igmpAttributes[] = {
1655 COMMON_IP_PROPS(igmpHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
1656 COMMENT_PROP_IPHDR(igmpHdrFilter),
1657 {
1658 .name = NULL,
1659 }
1660 };
1661
1662
1663 static const virXMLAttr2Struct tcpipv6Attributes[] = {
1664 COMMON_IP_PROPS(tcpHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1665 COMMON_PORT_PROPS(tcpHdrFilter),
1666 {
1667 .name = "option",
1668 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1669 .dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption),
1670 },
1671 COMMENT_PROP_IPHDR(tcpHdrFilter),
1672 {
1673 .name = NULL,
1674 }
1675 };
1676
1677 static const virXMLAttr2Struct udpipv6Attributes[] = {
1678 COMMON_IP_PROPS(udpHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1679 COMMON_PORT_PROPS(udpHdrFilter),
1680 COMMENT_PROP_IPHDR(udpHdrFilter),
1681 {
1682 .name = NULL,
1683 }
1684 };
1685
1686
1687 static const virXMLAttr2Struct udpliteipv6Attributes[] = {
1688 COMMON_IP_PROPS(udpliteHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1689 COMMENT_PROP_IPHDR(udpliteHdrFilter),
1690 {
1691 .name = NULL,
1692 }
1693 };
1694
1695
1696 static const virXMLAttr2Struct espipv6Attributes[] = {
1697 COMMON_IP_PROPS(espHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1698 COMMENT_PROP_IPHDR(espHdrFilter),
1699 {
1700 .name = NULL,
1701 }
1702 };
1703
1704
1705 static const virXMLAttr2Struct ahipv6Attributes[] = {
1706 COMMON_IP_PROPS(ahHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1707 COMMENT_PROP_IPHDR(ahHdrFilter),
1708 {
1709 .name = NULL,
1710 }
1711 };
1712
1713
1714 static const virXMLAttr2Struct sctpipv6Attributes[] = {
1715 COMMON_IP_PROPS(sctpHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1716 COMMON_PORT_PROPS(sctpHdrFilter),
1717 COMMENT_PROP_IPHDR(sctpHdrFilter),
1718 {
1719 .name = NULL,
1720 }
1721 };
1722
1723
1724 static const virXMLAttr2Struct icmpv6Attributes[] = {
1725 COMMON_IP_PROPS(icmpHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1726 {
1727 .name = "type",
1728 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1729 .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPType),
1730 },
1731 {
1732 .name = "code",
1733 .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
1734 .dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPCode),
1735 },
1736 COMMENT_PROP_IPHDR(icmpHdrFilter),
1737 {
1738 .name = NULL,
1739 }
1740 };
1741
1742
1743 static const virXMLAttr2Struct allipv6Attributes[] = {
1744 COMMON_IP_PROPS(allHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
1745 COMMENT_PROP_IPHDR(allHdrFilter),
1746 {
1747 .name = NULL,
1748 }
1749 };
1750
1751
1752 typedef struct _virAttributes virAttributes;
1753 struct _virAttributes {
1754 const char *id;
1755 const virXMLAttr2Struct *att;
1756 virNWFilterRuleProtocolType prtclType;
1757 };
1758
1759 #define PROTOCOL_ENTRY(ID, ATT, PRTCLTYPE) \
1760 { .id = ID, .att = ATT, .prtclType = PRTCLTYPE }
1761 #define PROTOCOL_ENTRY_LAST { .id = NULL }
1762
1763
1764 static const virAttributes virAttr[] = {
1765 PROTOCOL_ENTRY("arp", arpAttributes, VIR_NWFILTER_RULE_PROTOCOL_ARP),
1766 PROTOCOL_ENTRY("rarp", arpAttributes, VIR_NWFILTER_RULE_PROTOCOL_RARP),
1767 PROTOCOL_ENTRY("mac", macAttributes, VIR_NWFILTER_RULE_PROTOCOL_MAC),
1768 PROTOCOL_ENTRY("vlan", vlanAttributes, VIR_NWFILTER_RULE_PROTOCOL_VLAN),
1769 PROTOCOL_ENTRY("stp", stpAttributes, VIR_NWFILTER_RULE_PROTOCOL_STP),
1770 PROTOCOL_ENTRY("ip", ipAttributes, VIR_NWFILTER_RULE_PROTOCOL_IP),
1771 PROTOCOL_ENTRY("ipv6", ipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_IPV6),
1772 PROTOCOL_ENTRY("tcp", tcpAttributes, VIR_NWFILTER_RULE_PROTOCOL_TCP),
1773 PROTOCOL_ENTRY("udp", udpAttributes, VIR_NWFILTER_RULE_PROTOCOL_UDP),
1774 PROTOCOL_ENTRY("udplite", udpliteAttributes, VIR_NWFILTER_RULE_PROTOCOL_UDPLITE),
1775 PROTOCOL_ENTRY("esp", espAttributes, VIR_NWFILTER_RULE_PROTOCOL_ESP),
1776 PROTOCOL_ENTRY("ah", ahAttributes, VIR_NWFILTER_RULE_PROTOCOL_AH),
1777 PROTOCOL_ENTRY("sctp", sctpAttributes, VIR_NWFILTER_RULE_PROTOCOL_SCTP),
1778 PROTOCOL_ENTRY("icmp", icmpAttributes, VIR_NWFILTER_RULE_PROTOCOL_ICMP),
1779 PROTOCOL_ENTRY("all", allAttributes, VIR_NWFILTER_RULE_PROTOCOL_ALL),
1780 PROTOCOL_ENTRY("igmp", igmpAttributes, VIR_NWFILTER_RULE_PROTOCOL_IGMP),
1781 PROTOCOL_ENTRY("tcp-ipv6", tcpipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6),
1782 PROTOCOL_ENTRY("udp-ipv6", udpipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6),
1783 PROTOCOL_ENTRY("udplite-ipv6", udpliteipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6),
1784 PROTOCOL_ENTRY("esp-ipv6", espipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6),
1785 PROTOCOL_ENTRY("ah-ipv6", ahipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6),
1786 PROTOCOL_ENTRY("sctp-ipv6", sctpipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6),
1787 PROTOCOL_ENTRY("icmpv6", icmpv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_ICMPV6),
1788 PROTOCOL_ENTRY("all-ipv6", allipv6Attributes, VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6),
1789 PROTOCOL_ENTRY_LAST
1790 };
1791
1792
1793 static int
virNWFilterRuleDetailsParse(xmlNodePtr node,virNWFilterRuleDef * nwf,const virXMLAttr2Struct * att)1794 virNWFilterRuleDetailsParse(xmlNodePtr node,
1795 virNWFilterRuleDef *nwf,
1796 const virXMLAttr2Struct *att)
1797 {
1798 int rc = 0, g_rc = 0;
1799 int idx = 0;
1800 char *prop;
1801 bool found = false;
1802 enum attrDatatype datatype, att_datatypes;
1803 virNWFilterEntryItemFlags *flags, match_flag = 0, flags_set = 0;
1804 nwItemDesc *item;
1805 int int_val;
1806 unsigned int uint_val;
1807 union data data;
1808 valueValidator validator;
1809 char *match = virXMLPropString(node, "match");
1810 virSocketAddr ipaddr;
1811 int base;
1812
1813 if (match && STREQ(match, "no"))
1814 match_flag = NWFILTER_ENTRY_ITEM_FLAG_IS_NEG;
1815 VIR_FREE(match);
1816 match = NULL;
1817
1818 while (att[idx].name != NULL) {
1819 prop = virXMLPropString(node, att[idx].name);
1820
1821 VIR_WARNINGS_NO_CAST_ALIGN
1822 item = (nwItemDesc *)((char *)nwf + att[idx].dataIdx);
1823 VIR_WARNINGS_RESET
1824 flags = &item->flags;
1825 flags_set = match_flag;
1826
1827 if (prop) {
1828 found = false;
1829
1830 validator = NULL;
1831
1832 if (STRPREFIX(prop, "$")) {
1833 flags_set |= NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR;
1834 if (virNWFilterRuleDefAddVar(nwf,
1835 item,
1836 &prop[1]) < 0)
1837 rc = -1;
1838 found = true;
1839 }
1840
1841 datatype = 1;
1842
1843 att_datatypes = att[idx].datatype;
1844
1845 while (datatype <= DATATYPE_LAST && !found && rc == 0) {
1846 if ((att_datatypes & datatype)) {
1847
1848 att_datatypes ^= datatype;
1849
1850 validator = att[idx].validator;
1851
1852 base = 10;
1853
1854 switch (datatype) {
1855 case DATATYPE_UINT8_HEX:
1856 base = 16;
1857 G_GNUC_FALLTHROUGH;
1858 case DATATYPE_UINT8:
1859 if (virStrToLong_ui(prop, NULL, base, &uint_val) >= 0) {
1860 if (uint_val <= 0xff) {
1861 item->u.u8 = uint_val;
1862 found = true;
1863 data.ui = uint_val;
1864 } else {
1865 rc = -1;
1866 }
1867 } else {
1868 rc = -1;
1869 }
1870 break;
1871
1872 case DATATYPE_UINT16_HEX:
1873 base = 16;
1874 G_GNUC_FALLTHROUGH;
1875 case DATATYPE_UINT16:
1876 if (virStrToLong_ui(prop, NULL, base, &uint_val) >= 0) {
1877 if (uint_val <= 0xffff) {
1878 item->u.u16 = uint_val;
1879 found = true;
1880 data.ui = uint_val;
1881 } else {
1882 rc = -1;
1883 }
1884 } else {
1885 rc = -1;
1886 }
1887 break;
1888
1889 case DATATYPE_UINT32_HEX:
1890 base = 16;
1891 G_GNUC_FALLTHROUGH;
1892 case DATATYPE_UINT32:
1893 if (virStrToLong_ui(prop, NULL, base, &uint_val) >= 0) {
1894 item->u.u32 = uint_val;
1895 found = true;
1896 data.ui = uint_val;
1897 } else {
1898 rc = -1;
1899 }
1900 break;
1901
1902 case DATATYPE_IPADDR:
1903 if (virSocketAddrParseIPv4(&item->u.ipaddr, prop) < 0)
1904 rc = -1;
1905 found = true;
1906 break;
1907
1908 case DATATYPE_IPMASK:
1909 if (virStrToLong_ui(prop, NULL, 10, &uint_val) == 0) {
1910 if (uint_val <= 32) {
1911 if (!validator)
1912 item->u.u8 = (uint8_t)uint_val;
1913 found = true;
1914 data.ui = uint_val;
1915 } else {
1916 rc = -1;
1917 }
1918 } else {
1919 if (virSocketAddrParseIPv4(&ipaddr, prop) < 0) {
1920 rc = -1;
1921 } else {
1922 int_val = virSocketAddrGetNumNetmaskBits(&ipaddr);
1923 if (int_val >= 0)
1924 item->u.u8 = int_val;
1925 else
1926 rc = -1;
1927 found = true;
1928 }
1929 }
1930 break;
1931
1932 case DATATYPE_MACADDR:
1933 if (virMacAddrParse(prop,
1934 &item->u.macaddr) < 0) {
1935 rc = -1;
1936 }
1937 found = true;
1938 break;
1939
1940 case DATATYPE_MACMASK:
1941 validator = checkMACMask;
1942 if (virMacAddrParse(prop,
1943 &item->u.macaddr) < 0) {
1944 rc = -1;
1945 }
1946 data.v = &item->u.macaddr;
1947 found = true;
1948 break;
1949
1950 case DATATYPE_IPV6ADDR:
1951 if (virSocketAddrParseIPv6(&item->u.ipaddr, prop) < 0)
1952 rc = -1;
1953 found = true;
1954 break;
1955
1956 case DATATYPE_IPV6MASK:
1957 if (virStrToLong_ui(prop, NULL, 10, &uint_val) == 0) {
1958 if (uint_val <= 128) {
1959 if (!validator)
1960 item->u.u8 = (uint8_t)uint_val;
1961 found = true;
1962 data.ui = uint_val;
1963 } else {
1964 rc = -1;
1965 }
1966 } else {
1967 if (virSocketAddrParseIPv6(&ipaddr, prop) < 0) {
1968 rc = -1;
1969 } else {
1970 int_val = virSocketAddrGetNumNetmaskBits(&ipaddr);
1971 if (int_val >= 0)
1972 item->u.u8 = int_val;
1973 else
1974 rc = -1;
1975 found = true;
1976 }
1977 }
1978 break;
1979
1980 case DATATYPE_STRING:
1981 case DATATYPE_IPSETFLAGS:
1982 case DATATYPE_IPSETNAME:
1983 if (!validator) {
1984 /* not supported */
1985 rc = -1;
1986 break;
1987 }
1988 data.c = prop;
1989 found = true;
1990 break;
1991
1992 case DATATYPE_STRINGCOPY:
1993 if (!(item->u.string =
1994 virNWFilterRuleDefAddString(nwf, prop,
1995 att[idx].maxstrlen))) {
1996 rc = -1;
1997 break;
1998 }
1999 data.c = item->u.string;
2000 found = true;
2001 break;
2002
2003 case DATATYPE_BOOLEAN:
2004 if (STREQ(prop, "true") ||
2005 STREQ(prop, "1") ||
2006 STREQ(prop, "yes"))
2007 item->u.boolean = true;
2008 else
2009 item->u.boolean = false;
2010
2011 data.ui = item->u.boolean;
2012 found = true;
2013 break;
2014
2015 case DATATYPE_LAST:
2016 default:
2017 break;
2018 }
2019 }
2020
2021 if (rc != 0 && att_datatypes != 0) {
2022 rc = 0;
2023 found = false;
2024 }
2025
2026 datatype <<= 1;
2027 } /* while */
2028
2029 if (found && rc == 0) {
2030 *flags = NWFILTER_ENTRY_ITEM_FLAG_EXISTS | flags_set;
2031 item->datatype = datatype >> 1;
2032 if (validator) {
2033 if (!validator(datatype >> 1, &data, nwf, item)) {
2034 rc = -1;
2035 *flags = 0;
2036 }
2037 }
2038 }
2039
2040 if (!found || rc) {
2041 virReportError(VIR_ERR_INTERNAL_ERROR,
2042 _("%s has illegal value %s"),
2043 att[idx].name, prop);
2044 rc = -1;
2045 }
2046 VIR_FREE(prop);
2047 }
2048
2049 if (rc) {
2050 g_rc = rc;
2051 rc = 0;
2052 }
2053
2054 idx++;
2055 }
2056
2057 return g_rc;
2058 }
2059
2060
2061 static virNWFilterIncludeDef *
virNWFilterIncludeParse(xmlNodePtr cur)2062 virNWFilterIncludeParse(xmlNodePtr cur)
2063 {
2064 virNWFilterIncludeDef *ret;
2065
2066 ret = g_new0(virNWFilterIncludeDef, 1);
2067
2068 ret->filterref = virXMLPropString(cur, "filter");
2069 if (!ret->filterref) {
2070 virReportError(VIR_ERR_INTERNAL_ERROR,
2071 "%s",
2072 _("rule node requires action attribute"));
2073 goto err_exit;
2074 }
2075
2076 ret->params = virNWFilterParseParamAttributes(cur);
2077 if (!ret->params)
2078 goto err_exit;
2079
2080 return ret;
2081
2082 err_exit:
2083 virNWFilterIncludeDefFree(ret);
2084 return NULL;
2085 }
2086
2087
2088 static void
virNWFilterRuleDefFixupIPSet(ipHdrDataDef * ipHdr)2089 virNWFilterRuleDefFixupIPSet(ipHdrDataDef *ipHdr)
2090 {
2091 if (HAS_ENTRY_ITEM(&ipHdr->dataIPSet) &&
2092 !HAS_ENTRY_ITEM(&ipHdr->dataIPSetFlags)) {
2093 ipHdr->dataIPSetFlags.flags = NWFILTER_ENTRY_ITEM_FLAG_EXISTS;
2094 ipHdr->dataIPSetFlags.u.ipset.numFlags = 1;
2095 ipHdr->dataIPSetFlags.u.ipset.flags = 1;
2096 } else {
2097 ipHdr->dataIPSet.flags = 0;
2098 ipHdr->dataIPSetFlags.flags = 0;
2099 }
2100 }
2101
2102
2103 /*
2104 * virNWFilterRuleValidate
2105 *
2106 * Perform some basic rule validation to prevent rules from being
2107 * defined that cannot be instantiated.
2108 */
2109 static int
virNWFilterRuleValidate(virNWFilterRuleDef * rule)2110 virNWFilterRuleValidate(virNWFilterRuleDef *rule)
2111 {
2112 int ret = 0;
2113 portDataDef *portData = NULL;
2114 nwItemDesc *dataProtocolID = NULL;
2115 const char *protocol = NULL;
2116
2117 switch (rule->prtclType) {
2118 case VIR_NWFILTER_RULE_PROTOCOL_IP:
2119 portData = &rule->p.ipHdrFilter.portData;
2120 protocol = "IP";
2121 dataProtocolID = &rule->p.ipHdrFilter.ipHdr.dataProtocolID;
2122 G_GNUC_FALLTHROUGH;
2123 case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
2124 if (portData == NULL) {
2125 portData = &rule->p.ipv6HdrFilter.portData;
2126 protocol = "IPv6";
2127 dataProtocolID = &rule->p.ipv6HdrFilter.ipHdr.dataProtocolID;
2128 }
2129 if (HAS_ENTRY_ITEM(&portData->dataSrcPortStart) ||
2130 HAS_ENTRY_ITEM(&portData->dataDstPortStart) ||
2131 HAS_ENTRY_ITEM(&portData->dataSrcPortEnd) ||
2132 HAS_ENTRY_ITEM(&portData->dataDstPortEnd)) {
2133 if (HAS_ENTRY_ITEM(dataProtocolID)) {
2134 switch (dataProtocolID->u.u8) {
2135 case 6: /* tcp */
2136 case 17: /* udp */
2137 case 33: /* dccp */
2138 case 132: /* sctp */
2139 break;
2140 default:
2141 ret = -1;
2142 }
2143 } else {
2144 ret = -1;
2145 }
2146 if (ret < 0) {
2147 virReportError(VIR_ERR_INTERNAL_ERROR,
2148 _("%s rule with port specification requires "
2149 "protocol specification with protocol to be "
2150 "either one of tcp(6), udp(17), dccp(33), or "
2151 "sctp(132)"), protocol);
2152 }
2153 }
2154 break;
2155 case VIR_NWFILTER_RULE_PROTOCOL_NONE:
2156 case VIR_NWFILTER_RULE_PROTOCOL_MAC:
2157 case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
2158 case VIR_NWFILTER_RULE_PROTOCOL_STP:
2159 case VIR_NWFILTER_RULE_PROTOCOL_ARP:
2160 case VIR_NWFILTER_RULE_PROTOCOL_RARP:
2161 case VIR_NWFILTER_RULE_PROTOCOL_TCP:
2162 case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
2163 case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
2164 case VIR_NWFILTER_RULE_PROTOCOL_UDP:
2165 case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
2166 case VIR_NWFILTER_RULE_PROTOCOL_ESP:
2167 case VIR_NWFILTER_RULE_PROTOCOL_AH:
2168 case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
2169 case VIR_NWFILTER_RULE_PROTOCOL_ALL:
2170 case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
2171 case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
2172 case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
2173 case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
2174 case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
2175 case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
2176 case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
2177 case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
2178 break;
2179 case VIR_NWFILTER_RULE_PROTOCOL_LAST:
2180 default:
2181 virReportEnumRangeError(virNWFilterRuleProtocolType, rule->prtclType);
2182 return -1;
2183 }
2184
2185 return ret;
2186 }
2187
2188
2189 static void
virNWFilterRuleDefFixup(virNWFilterRuleDef * rule)2190 virNWFilterRuleDefFixup(virNWFilterRuleDef *rule)
2191 {
2192 #define COPY_NEG_SIGN(A, B) \
2193 (A).flags = ((A).flags & ~NWFILTER_ENTRY_ITEM_FLAG_IS_NEG) | \
2194 ((B).flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG);
2195
2196 switch (rule->prtclType) {
2197 case VIR_NWFILTER_RULE_PROTOCOL_MAC:
2198 COPY_NEG_SIGN(rule->p.ethHdrFilter.ethHdr.dataSrcMACMask,
2199 rule->p.ethHdrFilter.ethHdr.dataSrcMACAddr);
2200 COPY_NEG_SIGN(rule->p.ethHdrFilter.ethHdr.dataDstMACMask,
2201 rule->p.ethHdrFilter.ethHdr.dataDstMACAddr);
2202 break;
2203
2204 case VIR_NWFILTER_RULE_PROTOCOL_VLAN:
2205 COPY_NEG_SIGN(rule->p.vlanHdrFilter.ethHdr.dataSrcMACMask,
2206 rule->p.vlanHdrFilter.ethHdr.dataSrcMACAddr);
2207 COPY_NEG_SIGN(rule->p.vlanHdrFilter.ethHdr.dataDstMACMask,
2208 rule->p.vlanHdrFilter.ethHdr.dataDstMACAddr);
2209 break;
2210
2211 case VIR_NWFILTER_RULE_PROTOCOL_STP:
2212 COPY_NEG_SIGN(rule->p.stpHdrFilter.ethHdr.dataSrcMACMask,
2213 rule->p.stpHdrFilter.ethHdr.dataSrcMACAddr);
2214 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataRootPriHi,
2215 rule->p.stpHdrFilter.dataRootPri);
2216 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataRootAddrMask,
2217 rule->p.stpHdrFilter.dataRootAddr);
2218 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataRootCostHi,
2219 rule->p.stpHdrFilter.dataRootCost);
2220 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataSndrPrioHi,
2221 rule->p.stpHdrFilter.dataSndrPrio);
2222 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataSndrAddrMask,
2223 rule->p.stpHdrFilter.dataSndrAddr);
2224 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataPortHi,
2225 rule->p.stpHdrFilter.dataPort);
2226 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataAgeHi,
2227 rule->p.stpHdrFilter.dataAge);
2228 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataMaxAgeHi,
2229 rule->p.stpHdrFilter.dataMaxAge);
2230 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataHelloTimeHi,
2231 rule->p.stpHdrFilter.dataHelloTime);
2232 COPY_NEG_SIGN(rule->p.stpHdrFilter.dataFwdDelayHi,
2233 rule->p.stpHdrFilter.dataFwdDelay);
2234 break;
2235
2236 case VIR_NWFILTER_RULE_PROTOCOL_IP:
2237 COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataSrcIPMask,
2238 rule->p.ipHdrFilter.ipHdr.dataSrcIPAddr);
2239 COPY_NEG_SIGN(rule->p.ipHdrFilter.ipHdr.dataDstIPMask,
2240 rule->p.ipHdrFilter.ipHdr.dataDstIPAddr);
2241 virNWFilterRuleDefFixupIPSet(&rule->p.ipHdrFilter.ipHdr);
2242 break;
2243
2244 case VIR_NWFILTER_RULE_PROTOCOL_IPV6:
2245 COPY_NEG_SIGN(rule->p.ipv6HdrFilter.ipHdr.dataSrcIPMask,
2246 rule->p.ipv6HdrFilter.ipHdr.dataSrcIPAddr);
2247 COPY_NEG_SIGN(rule->p.ipv6HdrFilter.ipHdr.dataDstIPMask,
2248 rule->p.ipv6HdrFilter.ipHdr.dataDstIPAddr);
2249 COPY_NEG_SIGN(rule->p.ipv6HdrFilter.dataICMPTypeEnd,
2250 rule->p.ipv6HdrFilter.dataICMPTypeStart);
2251 COPY_NEG_SIGN(rule->p.ipv6HdrFilter.dataICMPCodeStart,
2252 rule->p.ipv6HdrFilter.dataICMPTypeStart);
2253 COPY_NEG_SIGN(rule->p.ipv6HdrFilter.dataICMPCodeEnd,
2254 rule->p.ipv6HdrFilter.dataICMPTypeStart);
2255 virNWFilterRuleDefFixupIPSet(&rule->p.ipv6HdrFilter.ipHdr);
2256 break;
2257
2258 case VIR_NWFILTER_RULE_PROTOCOL_ARP:
2259 case VIR_NWFILTER_RULE_PROTOCOL_RARP:
2260 case VIR_NWFILTER_RULE_PROTOCOL_NONE:
2261 break;
2262
2263 case VIR_NWFILTER_RULE_PROTOCOL_TCP:
2264 case VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6:
2265 COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataSrcIPMask,
2266 rule->p.tcpHdrFilter.ipHdr.dataSrcIPAddr);
2267 COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataDstIPMask,
2268 rule->p.tcpHdrFilter.ipHdr.dataDstIPAddr);
2269 COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataSrcIPTo,
2270 rule->p.tcpHdrFilter.ipHdr.dataSrcIPFrom);
2271 COPY_NEG_SIGN(rule->p.tcpHdrFilter.ipHdr.dataDstIPTo,
2272 rule->p.tcpHdrFilter.ipHdr.dataDstIPFrom);
2273 COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataSrcPortEnd,
2274 rule->p.tcpHdrFilter.portData.dataSrcPortStart);
2275 COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataDstPortStart,
2276 rule->p.tcpHdrFilter.portData.dataSrcPortStart);
2277 COPY_NEG_SIGN(rule->p.tcpHdrFilter.portData.dataDstPortEnd,
2278 rule->p.tcpHdrFilter.portData.dataSrcPortStart);
2279 virNWFilterRuleDefFixupIPSet(&rule->p.tcpHdrFilter.ipHdr);
2280 break;
2281
2282 case VIR_NWFILTER_RULE_PROTOCOL_UDP:
2283 case VIR_NWFILTER_RULE_PROTOCOL_UDPoIPV6:
2284 COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataSrcIPMask,
2285 rule->p.udpHdrFilter.ipHdr.dataSrcIPAddr);
2286 COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataDstIPMask,
2287 rule->p.udpHdrFilter.ipHdr.dataDstIPAddr);
2288 COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataSrcIPTo,
2289 rule->p.udpHdrFilter.ipHdr.dataSrcIPFrom);
2290 COPY_NEG_SIGN(rule->p.udpHdrFilter.ipHdr.dataDstIPTo,
2291 rule->p.udpHdrFilter.ipHdr.dataDstIPFrom);
2292 COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataSrcPortEnd,
2293 rule->p.udpHdrFilter.portData.dataSrcPortStart);
2294 COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataDstPortStart,
2295 rule->p.udpHdrFilter.portData.dataSrcPortStart);
2296 COPY_NEG_SIGN(rule->p.udpHdrFilter.portData.dataDstPortEnd,
2297 rule->p.udpHdrFilter.portData.dataSrcPortStart);
2298 virNWFilterRuleDefFixupIPSet(&rule->p.udpHdrFilter.ipHdr);
2299 break;
2300
2301 case VIR_NWFILTER_RULE_PROTOCOL_UDPLITE:
2302 case VIR_NWFILTER_RULE_PROTOCOL_UDPLITEoIPV6:
2303 COPY_NEG_SIGN(rule->p.udpliteHdrFilter.ipHdr.dataSrcIPMask,
2304 rule->p.udpliteHdrFilter.ipHdr.dataSrcIPAddr);
2305 COPY_NEG_SIGN(rule->p.udpliteHdrFilter.ipHdr.dataDstIPMask,
2306 rule->p.udpliteHdrFilter.ipHdr.dataDstIPAddr);
2307 COPY_NEG_SIGN(rule->p.udpliteHdrFilter.ipHdr.dataSrcIPTo,
2308 rule->p.udpliteHdrFilter.ipHdr.dataSrcIPFrom);
2309 COPY_NEG_SIGN(rule->p.udpliteHdrFilter.ipHdr.dataDstIPTo,
2310 rule->p.udpliteHdrFilter.ipHdr.dataDstIPFrom);
2311 virNWFilterRuleDefFixupIPSet(&rule->p.udpliteHdrFilter.ipHdr);
2312 break;
2313
2314 case VIR_NWFILTER_RULE_PROTOCOL_ESP:
2315 case VIR_NWFILTER_RULE_PROTOCOL_ESPoIPV6:
2316 COPY_NEG_SIGN(rule->p.espHdrFilter.ipHdr.dataSrcIPMask,
2317 rule->p.espHdrFilter.ipHdr.dataSrcIPAddr);
2318 COPY_NEG_SIGN(rule->p.espHdrFilter.ipHdr.dataDstIPMask,
2319 rule->p.espHdrFilter.ipHdr.dataDstIPAddr);
2320 COPY_NEG_SIGN(rule->p.espHdrFilter.ipHdr.dataSrcIPTo,
2321 rule->p.espHdrFilter.ipHdr.dataSrcIPFrom);
2322 COPY_NEG_SIGN(rule->p.espHdrFilter.ipHdr.dataDstIPTo,
2323 rule->p.espHdrFilter.ipHdr.dataDstIPFrom);
2324 virNWFilterRuleDefFixupIPSet(&rule->p.espHdrFilter.ipHdr);
2325 break;
2326
2327 case VIR_NWFILTER_RULE_PROTOCOL_AH:
2328 case VIR_NWFILTER_RULE_PROTOCOL_AHoIPV6:
2329 COPY_NEG_SIGN(rule->p.ahHdrFilter.ipHdr.dataSrcIPMask,
2330 rule->p.ahHdrFilter.ipHdr.dataSrcIPAddr);
2331 COPY_NEG_SIGN(rule->p.ahHdrFilter.ipHdr.dataDstIPMask,
2332 rule->p.ahHdrFilter.ipHdr.dataDstIPAddr);
2333 COPY_NEG_SIGN(rule->p.ahHdrFilter.ipHdr.dataSrcIPTo,
2334 rule->p.ahHdrFilter.ipHdr.dataSrcIPFrom);
2335 COPY_NEG_SIGN(rule->p.ahHdrFilter.ipHdr.dataDstIPTo,
2336 rule->p.ahHdrFilter.ipHdr.dataDstIPFrom);
2337 virNWFilterRuleDefFixupIPSet(&rule->p.ahHdrFilter.ipHdr);
2338 break;
2339
2340 case VIR_NWFILTER_RULE_PROTOCOL_SCTP:
2341 case VIR_NWFILTER_RULE_PROTOCOL_SCTPoIPV6:
2342 COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataSrcIPMask,
2343 rule->p.sctpHdrFilter.ipHdr.dataSrcIPAddr);
2344 COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataDstIPMask,
2345 rule->p.sctpHdrFilter.ipHdr.dataDstIPAddr);
2346 COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataSrcIPTo,
2347 rule->p.sctpHdrFilter.ipHdr.dataSrcIPFrom);
2348 COPY_NEG_SIGN(rule->p.sctpHdrFilter.ipHdr.dataDstIPTo,
2349 rule->p.sctpHdrFilter.ipHdr.dataDstIPFrom);
2350 COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataSrcPortEnd,
2351 rule->p.sctpHdrFilter.portData.dataSrcPortStart);
2352 COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataDstPortStart,
2353 rule->p.sctpHdrFilter.portData.dataSrcPortStart);
2354 COPY_NEG_SIGN(rule->p.sctpHdrFilter.portData.dataDstPortEnd,
2355 rule->p.sctpHdrFilter.portData.dataSrcPortStart);
2356 virNWFilterRuleDefFixupIPSet(&rule->p.sctpHdrFilter.ipHdr);
2357 break;
2358
2359 case VIR_NWFILTER_RULE_PROTOCOL_ICMP:
2360 case VIR_NWFILTER_RULE_PROTOCOL_ICMPV6:
2361 COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataSrcIPMask,
2362 rule->p.icmpHdrFilter.ipHdr.dataSrcIPAddr);
2363 COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataDstIPMask,
2364 rule->p.icmpHdrFilter.ipHdr.dataDstIPAddr);
2365 COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataSrcIPTo,
2366 rule->p.icmpHdrFilter.ipHdr.dataSrcIPFrom);
2367 COPY_NEG_SIGN(rule->p.icmpHdrFilter.ipHdr.dataDstIPTo,
2368 rule->p.icmpHdrFilter.ipHdr.dataDstIPFrom);
2369 COPY_NEG_SIGN(rule->p.icmpHdrFilter.dataICMPCode,
2370 rule->p.icmpHdrFilter.dataICMPType);
2371 virNWFilterRuleDefFixupIPSet(&rule->p.icmpHdrFilter.ipHdr);
2372 break;
2373
2374 case VIR_NWFILTER_RULE_PROTOCOL_ALL:
2375 case VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6:
2376 COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataSrcIPMask,
2377 rule->p.allHdrFilter.ipHdr.dataSrcIPAddr);
2378 COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataDstIPMask,
2379 rule->p.allHdrFilter.ipHdr.dataDstIPAddr);
2380 COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataSrcIPTo,
2381 rule->p.allHdrFilter.ipHdr.dataSrcIPFrom);
2382 COPY_NEG_SIGN(rule->p.allHdrFilter.ipHdr.dataDstIPTo,
2383 rule->p.allHdrFilter.ipHdr.dataDstIPFrom);
2384 break;
2385
2386 case VIR_NWFILTER_RULE_PROTOCOL_IGMP:
2387 COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataSrcIPMask,
2388 rule->p.igmpHdrFilter.ipHdr.dataSrcIPAddr);
2389 COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataDstIPMask,
2390 rule->p.igmpHdrFilter.ipHdr.dataDstIPAddr);
2391 COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataSrcIPTo,
2392 rule->p.igmpHdrFilter.ipHdr.dataSrcIPFrom);
2393 COPY_NEG_SIGN(rule->p.igmpHdrFilter.ipHdr.dataDstIPTo,
2394 rule->p.igmpHdrFilter.ipHdr.dataDstIPFrom);
2395 virNWFilterRuleDefFixupIPSet(&rule->p.igmpHdrFilter.ipHdr);
2396 break;
2397
2398 case VIR_NWFILTER_RULE_PROTOCOL_LAST:
2399 break;
2400 }
2401 #undef COPY_NEG_SIGN
2402 }
2403
2404
2405 static virNWFilterRuleDef *
virNWFilterRuleParse(xmlNodePtr node)2406 virNWFilterRuleParse(xmlNodePtr node)
2407 {
2408 char *action;
2409 char *direction;
2410 char *prio;
2411 char *statematch;
2412 bool found;
2413 int found_i = 0;
2414 int priority;
2415
2416 xmlNodePtr cur;
2417 virNWFilterRuleDef *ret;
2418
2419 ret = g_new0(virNWFilterRuleDef, 1);
2420
2421 action = virXMLPropString(node, "action");
2422 direction = virXMLPropString(node, "direction");
2423 prio = virXMLPropString(node, "priority");
2424 statematch = virXMLPropString(node, "statematch");
2425
2426 if (!action) {
2427 virReportError(VIR_ERR_INTERNAL_ERROR,
2428 "%s",
2429 _("rule node requires action attribute"));
2430 goto err_exit;
2431 }
2432
2433 if ((ret->action = virNWFilterRuleActionTypeFromString(action)) < 0) {
2434 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2435 "%s",
2436 _("unknown rule action attribute value"));
2437 goto err_exit;
2438 }
2439
2440 if (!direction) {
2441 virReportError(VIR_ERR_INTERNAL_ERROR,
2442 "%s",
2443 _("rule node requires direction attribute"));
2444 goto err_exit;
2445 }
2446
2447 if ((ret->tt = virNWFilterRuleDirectionTypeFromString(direction)) < 0) {
2448 virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
2449 "%s",
2450 _("unknown rule direction attribute value"));
2451 goto err_exit;
2452 }
2453
2454 ret->priority = MAX_RULE_PRIORITY / 2;
2455
2456 if (prio) {
2457 if (virStrToLong_i(prio, NULL, 10, &priority) >= 0) {
2458 if (priority <= MAX_RULE_PRIORITY &&
2459 priority >= MIN_RULE_PRIORITY)
2460 ret->priority = priority;
2461 }
2462 }
2463
2464 if (statematch &&
2465 (STREQ(statematch, "0") || STRCASEEQ(statematch, "false")))
2466 ret->flags |= RULE_FLAG_NO_STATEMATCH;
2467
2468 cur = node->children;
2469
2470 found = false;
2471
2472 while (cur != NULL) {
2473 if (cur->type == XML_ELEMENT_NODE) {
2474 size_t i = 0;
2475 while (1) {
2476 if (found)
2477 i = found_i;
2478
2479 if (virXMLNodeNameEqual(cur, virAttr[i].id)) {
2480
2481 found_i = i;
2482 found = true;
2483 ret->prtclType = virAttr[i].prtclType;
2484
2485 if (virNWFilterRuleDetailsParse(cur,
2486 ret,
2487 virAttr[i].att) < 0) {
2488 goto err_exit;
2489 }
2490 if (virNWFilterRuleValidate(ret) < 0)
2491 goto err_exit;
2492 break;
2493 }
2494 if (!found) {
2495 i++;
2496 if (!virAttr[i].id)
2497 break;
2498 } else {
2499 break;
2500 }
2501 }
2502 }
2503
2504 cur = cur->next;
2505 }
2506
2507 virNWFilterRuleDefFixup(ret);
2508
2509 cleanup:
2510 VIR_FREE(prio);
2511 VIR_FREE(action);
2512 VIR_FREE(direction);
2513 VIR_FREE(statematch);
2514
2515 return ret;
2516
2517 err_exit:
2518 virNWFilterRuleDefFree(ret);
2519 ret = NULL;
2520 goto cleanup;
2521 }
2522
2523
2524 static bool
virNWFilterIsValidChainName(const char * chainname)2525 virNWFilterIsValidChainName(const char *chainname)
2526 {
2527 if (strlen(chainname) > MAX_CHAIN_SUFFIX_SIZE) {
2528 virReportError(VIR_ERR_INVALID_ARG,
2529 _("Name of chain is longer than "
2530 "%u characters"),
2531 MAX_CHAIN_SUFFIX_SIZE);
2532 return false;
2533 }
2534
2535 if (chainname[strspn(chainname, VALID_CHAINNAME)] != 0) {
2536 virReportError(VIR_ERR_INVALID_ARG, "%s",
2537 _("Chain name contains invalid characters"));
2538 return false;
2539 }
2540
2541 return true;
2542 }
2543
2544
2545 /*
2546 * Test whether the name of the chain is supported.
2547 * It current has to have a prefix of either one of the strings found in
2548 * virNWFilterChainSuffixTypeToString().
2549 */
2550 static const char *
virNWFilterIsAllowedChain(const char * chainname)2551 virNWFilterIsAllowedChain(const char *chainname)
2552 {
2553 virNWFilterChainSuffixType i;
2554 const char *name;
2555 char *msg;
2556 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
2557 bool printed = false;
2558
2559 if (!virNWFilterIsValidChainName(chainname))
2560 return NULL;
2561
2562 for (i = 0; i < VIR_NWFILTER_CHAINSUFFIX_LAST; i++) {
2563 name = virNWFilterChainSuffixTypeToString(i);
2564 if (i == VIR_NWFILTER_CHAINSUFFIX_ROOT) {
2565 /* allow 'root' as a complete name but not as a prefix */
2566 if (STREQ(chainname, name))
2567 return name;
2568 if (STRPREFIX(chainname, name))
2569 return NULL;
2570 }
2571 if (STRPREFIX(chainname, name))
2572 return name;
2573 }
2574
2575 virBufferAsprintf(&buf,
2576 _("Invalid chain name '%s'. Please use a chain name "
2577 "called '%s' or any of the following prefixes: "),
2578 chainname,
2579 virNWFilterChainSuffixTypeToString(
2580 VIR_NWFILTER_CHAINSUFFIX_ROOT));
2581 for (i = 0; i < VIR_NWFILTER_CHAINSUFFIX_LAST; i++) {
2582 if (i == VIR_NWFILTER_CHAINSUFFIX_ROOT)
2583 continue;
2584 if (printed)
2585 virBufferAddLit(&buf, ", ");
2586 virBufferAdd(&buf, virNWFilterChainSuffixTypeToString(i), -1);
2587 printed = true;
2588 }
2589
2590 msg = virBufferContentAndReset(&buf);
2591
2592 virReportError(VIR_ERR_INVALID_ARG, "%s", msg);
2593 VIR_FREE(msg);
2594
2595 return NULL;
2596 }
2597
2598
2599 static virNWFilterDef *
virNWFilterDefParseXML(xmlXPathContextPtr ctxt)2600 virNWFilterDefParseXML(xmlXPathContextPtr ctxt)
2601 {
2602 virNWFilterDef *ret;
2603 xmlNodePtr curr = ctxt->node;
2604 char *uuid = NULL;
2605 char *chain = NULL;
2606 char *chain_pri_s = NULL;
2607 virNWFilterEntry *entry;
2608 int chain_priority;
2609 const char *name_prefix;
2610
2611 ret = g_new0(virNWFilterDef, 1);
2612
2613 ret->name = virXPathString("string(./@name)", ctxt);
2614 if (!ret->name) {
2615 virReportError(VIR_ERR_INTERNAL_ERROR,
2616 "%s", _("filter has no name"));
2617 goto cleanup;
2618 }
2619
2620 chain_pri_s = virXPathString("string(./@priority)", ctxt);
2621 if (chain_pri_s) {
2622 if (virStrToLong_i(chain_pri_s, NULL, 10, &chain_priority) < 0) {
2623 virReportError(VIR_ERR_INVALID_ARG,
2624 _("Could not parse chain priority '%s'"),
2625 chain_pri_s);
2626 goto cleanup;
2627 }
2628 if (chain_priority < NWFILTER_MIN_FILTER_PRIORITY ||
2629 chain_priority > NWFILTER_MAX_FILTER_PRIORITY) {
2630 virReportError(VIR_ERR_INVALID_ARG,
2631 _("Priority '%d' is outside valid "
2632 "range of [%d,%d]"),
2633 chain_priority,
2634 NWFILTER_MIN_FILTER_PRIORITY,
2635 NWFILTER_MAX_FILTER_PRIORITY);
2636 goto cleanup;
2637 }
2638 }
2639
2640 chain = virXPathString("string(./@chain)", ctxt);
2641 if (chain) {
2642 name_prefix = virNWFilterIsAllowedChain(chain);
2643 if (name_prefix == NULL)
2644 goto cleanup;
2645 ret->chainsuffix = g_steal_pointer(&chain);
2646
2647 if (chain_pri_s) {
2648 ret->chainPriority = chain_priority;
2649 } else {
2650 /* assign default priority if none can be found via lookup */
2651 if (intMapGetByString(chain_priorities, name_prefix,
2652 0, &ret->chainPriority) < 0) {
2653 ret->chainPriority = (NWFILTER_MAX_FILTER_PRIORITY +
2654 NWFILTER_MIN_FILTER_PRIORITY) / 2;
2655 }
2656 }
2657 } else {
2658 ret->chainsuffix = g_strdup(virNWFilterChainSuffixTypeToString(VIR_NWFILTER_CHAINSUFFIX_ROOT));
2659 }
2660
2661 uuid = virXPathString("string(./uuid)", ctxt);
2662 ret->uuid_specified = (uuid != NULL);
2663 if (uuid == NULL) {
2664 if (virUUIDGenerate(ret->uuid) < 0) {
2665 virReportError(VIR_ERR_INTERNAL_ERROR,
2666 "%s", _("unable to generate uuid"));
2667 goto cleanup;
2668 }
2669 } else {
2670 if (virUUIDParse(uuid, ret->uuid) < 0) {
2671 virReportError(VIR_ERR_XML_ERROR,
2672 "%s", _("malformed uuid element"));
2673 goto cleanup;
2674 }
2675 VIR_FREE(uuid);
2676 }
2677
2678 curr = curr->children;
2679
2680 while (curr != NULL) {
2681 if (curr->type == XML_ELEMENT_NODE) {
2682 entry = g_new0(virNWFilterEntry, 1);
2683
2684 if (virXMLNodeNameEqual(curr, "rule")) {
2685 if (!(entry->rule = virNWFilterRuleParse(curr))) {
2686 virNWFilterEntryFree(entry);
2687 goto cleanup;
2688 }
2689 } else if (virXMLNodeNameEqual(curr, "filterref")) {
2690 if (!(entry->include = virNWFilterIncludeParse(curr))) {
2691 virNWFilterEntryFree(entry);
2692 goto cleanup;
2693 }
2694 }
2695
2696 if (entry->rule || entry->include) {
2697 VIR_APPEND_ELEMENT_COPY(ret->filterEntries, ret->nentries, entry);
2698 } else {
2699 virNWFilterEntryFree(entry);
2700 }
2701 }
2702 curr = curr->next;
2703 }
2704
2705 VIR_FREE(chain);
2706 VIR_FREE(chain_pri_s);
2707
2708 return ret;
2709
2710 cleanup:
2711 virNWFilterDefFree(ret);
2712 VIR_FREE(chain);
2713 VIR_FREE(uuid);
2714 VIR_FREE(chain_pri_s);
2715 return NULL;
2716 }
2717
2718
2719 virNWFilterDef *
virNWFilterDefParseNode(xmlDocPtr xml,xmlNodePtr root)2720 virNWFilterDefParseNode(xmlDocPtr xml,
2721 xmlNodePtr root)
2722 {
2723 g_autoptr(xmlXPathContext) ctxt = NULL;
2724
2725 if (STRNEQ((const char *)root->name, "filter")) {
2726 virReportError(VIR_ERR_XML_ERROR,
2727 "%s",
2728 _("unknown root element for nw filter"));
2729 return NULL;
2730 }
2731
2732 if (!(ctxt = virXMLXPathContextNew(xml)))
2733 return NULL;
2734
2735 ctxt->node = root;
2736 return virNWFilterDefParseXML(ctxt);
2737 }
2738
2739
2740 static virNWFilterDef *
virNWFilterDefParse(const char * xmlStr,const char * filename,unsigned int flags)2741 virNWFilterDefParse(const char *xmlStr,
2742 const char *filename,
2743 unsigned int flags)
2744 {
2745 virNWFilterDef *def = NULL;
2746 g_autoptr(xmlDoc) xml = NULL;
2747
2748 if ((xml = virXMLParse(filename, xmlStr, _("(nwfilter_definition)"), "nwfilter.rng",
2749 flags & VIR_NWFILTER_DEFINE_VALIDATE))) {
2750 def = virNWFilterDefParseNode(xml, xmlDocGetRootElement(xml));
2751 }
2752
2753 return def;
2754 }
2755
2756
2757 virNWFilterDef *
virNWFilterDefParseString(const char * xmlStr,unsigned int flags)2758 virNWFilterDefParseString(const char *xmlStr,
2759 unsigned int flags)
2760 {
2761 return virNWFilterDefParse(xmlStr, NULL, flags);
2762 }
2763
2764
2765 virNWFilterDef *
virNWFilterDefParseFile(const char * filename)2766 virNWFilterDefParseFile(const char *filename)
2767 {
2768 return virNWFilterDefParse(NULL, filename, 0);
2769 }
2770
2771
2772 int
virNWFilterSaveConfig(const char * configDir,virNWFilterDef * def)2773 virNWFilterSaveConfig(const char *configDir,
2774 virNWFilterDef *def)
2775 {
2776 int ret = -1;
2777 char *xml;
2778 char uuidstr[VIR_UUID_STRING_BUFLEN];
2779 char *configFile = NULL;
2780
2781 if (!(xml = virNWFilterDefFormat(def)))
2782 goto cleanup;
2783
2784 if (!(configFile = virFileBuildPath(configDir, def->name, ".xml")))
2785 goto cleanup;
2786
2787 virUUIDFormat(def->uuid, uuidstr);
2788 ret = virXMLSaveFile(configFile,
2789 virXMLPickShellSafeComment(def->name, uuidstr),
2790 "nwfilter-edit", xml);
2791
2792 cleanup:
2793 VIR_FREE(configFile);
2794 VIR_FREE(xml);
2795 return ret;
2796 }
2797
2798
2799 int
virNWFilterDeleteDef(const char * configDir,virNWFilterDef * def)2800 virNWFilterDeleteDef(const char *configDir,
2801 virNWFilterDef *def)
2802 {
2803 int ret = -1;
2804 char *configFile = NULL;
2805
2806 if (!(configFile = virFileBuildPath(configDir, def->name, ".xml")))
2807 goto error;
2808
2809 if (unlink(configFile) < 0) {
2810 virReportError(VIR_ERR_INTERNAL_ERROR,
2811 _("cannot remove config for %s"),
2812 def->name);
2813 goto error;
2814 }
2815
2816 ret = 0;
2817 error:
2818 VIR_FREE(configFile);
2819 return ret;
2820 }
2821
2822
2823 static void
virNWIPAddressFormat(virBuffer * buf,virSocketAddr * ipaddr)2824 virNWIPAddressFormat(virBuffer *buf,
2825 virSocketAddr *ipaddr)
2826 {
2827 char *output = virSocketAddrFormat(ipaddr);
2828
2829 if (output) {
2830 virBufferAdd(buf, output, -1);
2831 VIR_FREE(output);
2832 }
2833 }
2834
2835
2836 static void
virNWFilterRuleDefDetailsFormat(virBuffer * buf,const char * type,const virXMLAttr2Struct * att,virNWFilterRuleDef * def)2837 virNWFilterRuleDefDetailsFormat(virBuffer *buf,
2838 const char *type,
2839 const virXMLAttr2Struct *att,
2840 virNWFilterRuleDef *def)
2841 {
2842 size_t i = 0, j;
2843 bool typeShown = false;
2844 bool neverShown = true;
2845 bool asHex;
2846 enum match {
2847 MATCH_NONE = 0,
2848 MATCH_YES,
2849 MATCH_NO
2850 } matchShown = MATCH_NONE;
2851 nwItemDesc *item;
2852
2853 while (att[i].name) {
2854 virNWFilterEntryItemFlags flags;
2855
2856 VIR_WARNINGS_NO_CAST_ALIGN
2857 item = (nwItemDesc *)((char *)def + att[i].dataIdx);
2858 VIR_WARNINGS_RESET
2859
2860 flags = item->flags;
2861 if ((flags & NWFILTER_ENTRY_ITEM_FLAG_EXISTS)) {
2862 if (!typeShown) {
2863 virBufferAsprintf(buf, "<%s", type);
2864 typeShown = true;
2865 neverShown = false;
2866 }
2867
2868 if ((flags & NWFILTER_ENTRY_ITEM_FLAG_IS_NEG)) {
2869 if (matchShown == MATCH_NONE) {
2870 virBufferAddLit(buf, " match='no'");
2871 matchShown = MATCH_NO;
2872 } else if (matchShown == MATCH_YES) {
2873 virBufferAddLit(buf, "/>\n");
2874 typeShown = false;
2875 matchShown = MATCH_NONE;
2876 continue;
2877 }
2878 } else {
2879 if (matchShown == MATCH_NO) {
2880 virBufferAddLit(buf, "/>\n");
2881 typeShown = false;
2882 matchShown = MATCH_NONE;
2883 continue;
2884 }
2885 matchShown = MATCH_YES;
2886 }
2887
2888 virBufferAsprintf(buf, " %s='",
2889 att[i].name);
2890 if (att[i].formatter && !(flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
2891 if (!att[i].formatter(buf, def, item)) {
2892 virReportError(VIR_ERR_INTERNAL_ERROR,
2893 _("formatter for %s %s reported error"),
2894 type,
2895 att[i].name);
2896 return;
2897 }
2898 } else if ((flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
2899 virBufferAddChar(buf, '$');
2900 virNWFilterVarAccessPrint(item->varAccess, buf);
2901 } else {
2902 asHex = false;
2903
2904 switch (item->datatype) {
2905
2906 case DATATYPE_UINT8_HEX:
2907 asHex = true;
2908 G_GNUC_FALLTHROUGH;
2909 case DATATYPE_IPMASK:
2910 case DATATYPE_IPV6MASK:
2911 /* display all masks in CIDR format */
2912 case DATATYPE_UINT8:
2913 virBufferAsprintf(buf, asHex ? "0x%x" : "%d",
2914 item->u.u8);
2915 break;
2916
2917 case DATATYPE_UINT16_HEX:
2918 asHex = true;
2919 G_GNUC_FALLTHROUGH;
2920 case DATATYPE_UINT16:
2921 virBufferAsprintf(buf, asHex ? "0x%x" : "%d",
2922 item->u.u16);
2923 break;
2924
2925 case DATATYPE_UINT32_HEX:
2926 asHex = true;
2927 G_GNUC_FALLTHROUGH;
2928 case DATATYPE_UINT32:
2929 virBufferAsprintf(buf, asHex ? "0x%x" : "%u",
2930 item->u.u32);
2931 break;
2932
2933 case DATATYPE_IPADDR:
2934 case DATATYPE_IPV6ADDR:
2935 virNWIPAddressFormat(buf,
2936 &item->u.ipaddr);
2937 break;
2938
2939 case DATATYPE_MACMASK:
2940 case DATATYPE_MACADDR:
2941 for (j = 0; j < 6; j++)
2942 virBufferAsprintf(buf, "%02x%s",
2943 item->u.macaddr.addr[j],
2944 (j < 5) ? ":" : "");
2945 break;
2946
2947 case DATATYPE_STRINGCOPY:
2948 virBufferEscapeString(buf, "%s", item->u.string);
2949 break;
2950
2951 case DATATYPE_BOOLEAN:
2952 if (item->u.boolean)
2953 virBufferAddLit(buf, "true");
2954 else
2955 virBufferAddLit(buf, "false");
2956 break;
2957
2958 case DATATYPE_IPSETNAME:
2959 case DATATYPE_IPSETFLAGS:
2960 case DATATYPE_STRING:
2961 case DATATYPE_LAST:
2962 default:
2963 virBufferAsprintf(buf,
2964 "UNSUPPORTED DATATYPE 0x%02x\n",
2965 att[i].datatype);
2966 }
2967 }
2968 virBufferAddLit(buf, "'");
2969 }
2970 i++;
2971 }
2972 if (typeShown)
2973 virBufferAddLit(buf, "/>\n");
2974
2975 if (neverShown)
2976 virBufferAsprintf(buf,
2977 "<%s/>\n", type);
2978
2979 return;
2980 }
2981
2982
2983 static int
virNWFilterRuleDefFormat(virBuffer * buf,virNWFilterRuleDef * def)2984 virNWFilterRuleDefFormat(virBuffer *buf,
2985 virNWFilterRuleDef *def)
2986 {
2987 size_t i;
2988 bool subelement = false;
2989
2990 virBufferAsprintf(buf, "<rule action='%s' direction='%s' priority='%d'",
2991 virNWFilterRuleActionTypeToString(def->action),
2992 virNWFilterRuleDirectionTypeToString(def->tt),
2993 def->priority);
2994
2995 if ((def->flags & RULE_FLAG_NO_STATEMATCH))
2996 virBufferAddLit(buf, " statematch='false'");
2997
2998 virBufferAdjustIndent(buf, 2);
2999 i = 0;
3000 while (virAttr[i].id) {
3001 if (virAttr[i].prtclType == def->prtclType) {
3002 if (!subelement)
3003 virBufferAddLit(buf, ">\n");
3004 virNWFilterRuleDefDetailsFormat(buf,
3005 virAttr[i].id,
3006 virAttr[i].att,
3007 def);
3008 subelement = true;
3009 break;
3010 }
3011 i++;
3012 }
3013
3014 virBufferAdjustIndent(buf, -2);
3015 if (subelement)
3016 virBufferAddLit(buf, "</rule>\n");
3017 else
3018 virBufferAddLit(buf, "/>\n");
3019 return 0;
3020 }
3021
3022
3023 static int
virNWFilterEntryFormat(virBuffer * buf,virNWFilterEntry * entry)3024 virNWFilterEntryFormat(virBuffer *buf,
3025 virNWFilterEntry *entry)
3026 {
3027 if (entry->rule)
3028 return virNWFilterRuleDefFormat(buf, entry->rule);
3029 return virNWFilterFormatParamAttributes(buf, entry->include->params,
3030 entry->include->filterref);
3031 }
3032
3033
3034 char *
virNWFilterDefFormat(const virNWFilterDef * def)3035 virNWFilterDefFormat(const virNWFilterDef *def)
3036 {
3037 g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER;
3038 char uuid[VIR_UUID_STRING_BUFLEN];
3039 size_t i;
3040
3041 virBufferAsprintf(&buf, "<filter name='%s' chain='%s'",
3042 def->name,
3043 def->chainsuffix);
3044 if (def->chainPriority != 0)
3045 virBufferAsprintf(&buf, " priority='%d'",
3046 def->chainPriority);
3047 virBufferAddLit(&buf, ">\n");
3048 virBufferAdjustIndent(&buf, 2);
3049
3050 virUUIDFormat(def->uuid, uuid);
3051 virBufferAsprintf(&buf, "<uuid>%s</uuid>\n", uuid);
3052
3053 for (i = 0; i < def->nentries; i++) {
3054 if (virNWFilterEntryFormat(&buf, def->filterEntries[i]) < 0)
3055 return NULL;
3056 }
3057
3058 virBufferAdjustIndent(&buf, -2);
3059 virBufferAddLit(&buf, "</filter>\n");
3060
3061 return virBufferContentAndReset(&buf);
3062 }
3063
3064 static virNWFilterTriggerRebuildCallback rebuildCallback;
3065 static void *rebuildOpaque;
3066
3067 int
virNWFilterConfLayerInit(virNWFilterTriggerRebuildCallback cb,void * opaque)3068 virNWFilterConfLayerInit(virNWFilterTriggerRebuildCallback cb,
3069 void *opaque)
3070 {
3071 if (initialized)
3072 return -1;
3073
3074 rebuildCallback = cb;
3075 rebuildOpaque = opaque;
3076
3077 initialized = true;
3078
3079 if (virRWLockInit(&updateLock) < 0)
3080 return -1;
3081
3082 return 0;
3083 }
3084
3085
3086 void
virNWFilterConfLayerShutdown(void)3087 virNWFilterConfLayerShutdown(void)
3088 {
3089 if (!initialized)
3090 return;
3091
3092 virRWLockDestroy(&updateLock);
3093
3094 initialized = false;
3095 rebuildCallback = NULL;
3096 rebuildOpaque = NULL;
3097 }
3098
3099
3100 int
virNWFilterTriggerRebuild(void)3101 virNWFilterTriggerRebuild(void)
3102 {
3103 if (rebuildCallback)
3104 return rebuildCallback(rebuildOpaque);
3105 return 0;
3106 }
3107
3108
3109 bool
virNWFilterRuleIsProtocolIPv4(virNWFilterRuleDef * rule)3110 virNWFilterRuleIsProtocolIPv4(virNWFilterRuleDef *rule)
3111 {
3112 if (rule->prtclType >= VIR_NWFILTER_RULE_PROTOCOL_TCP &&
3113 rule->prtclType <= VIR_NWFILTER_RULE_PROTOCOL_ALL)
3114 return true;
3115 return false;
3116 }
3117
3118
3119 bool
virNWFilterRuleIsProtocolIPv6(virNWFilterRuleDef * rule)3120 virNWFilterRuleIsProtocolIPv6(virNWFilterRuleDef *rule)
3121 {
3122 if (rule->prtclType >= VIR_NWFILTER_RULE_PROTOCOL_TCPoIPV6 &&
3123 rule->prtclType <= VIR_NWFILTER_RULE_PROTOCOL_ALLoIPV6)
3124 return true;
3125 return false;
3126 }
3127
3128
3129 bool
virNWFilterRuleIsProtocolEthernet(virNWFilterRuleDef * rule)3130 virNWFilterRuleIsProtocolEthernet(virNWFilterRuleDef *rule)
3131 {
3132 if (rule->prtclType <= VIR_NWFILTER_RULE_PROTOCOL_IPV6)
3133 return true;
3134 return false;
3135 }
3136