summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Berger <stefanb@us.ibm.com>2010-04-26 13:50:40 -0400
committerStefan Berger <stefanb@us.ibm.com>2010-04-26 13:50:40 -0400
commit5c7c755f50bf82d96b5c25aa622bd9c1eec45103 (patch)
tree0ac4ce5a57b895563a78e61fdd91c19b6c1e23ff
parentStarts dnsmasq from libvirtd with --dhcp-hostsfile option (diff)
downloadlibvirt-5c7c755f50bf82d96b5c25aa622bd9c1eec45103.tar.gz
libvirt-5c7c755f50bf82d96b5c25aa622bd9c1eec45103.tar.bz2
libvirt-5c7c755f50bf82d96b5c25aa622bd9c1eec45103.zip
nwfilter: enable hex number inputs in filter XML
With this patch I want to enable hex number inputs in the filter XML. A number that was entered as hex is also printed as hex unless a string representing the meaning can be found. I am also extending the schema and adding a test case. A problem with the DSCP value is fixed on the way as well. Changes from V1 to V2: - using asHex boolean in all printf type of functions to select the output format in hex or decimal format
-rw-r--r--docs/schemas/nwfilter.rng20
-rw-r--r--src/conf/nwfilter_conf.c121
-rw-r--r--src/conf/nwfilter_conf.h20
-rw-r--r--src/nwfilter/nwfilter_ebiptables_driver.c2
-rw-r--r--tests/nwfilterxml2xmlin/hex-data-test.xml56
-rw-r--r--tests/nwfilterxml2xmlout/hex-data-test.xml21
-rw-r--r--tests/nwfilterxml2xmltest.c2
7 files changed, 185 insertions, 57 deletions
diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng
index 0497d275c..3bcdd44b8 100644
--- a/docs/schemas/nwfilter.rng
+++ b/docs/schemas/nwfilter.rng
@@ -647,6 +647,10 @@
<define name="sixbitrange">
<choice>
+ <data type="string">
+ <param name="pattern">0x([0-3][0-9a-fA-F]|[0-9a-fA-F])</param>
+ </data>
+
<!-- variable -->
<data type="string">
<param name="pattern">$[a-zA-Z0-9_]+</param>
@@ -666,6 +670,10 @@
<param name="pattern">$[a-zA-Z0-9_]+</param>
</data>
+ <data type="string">
+ <param name="pattern">0x([6-9a-fA-F][0-9a-fA-F]{2}|[0-9a-fA-F]{4})</param>
+ </data>
+
<data type="int">
<param name="minInclusive">1536</param>
<param name="maxInclusive">65535</param>
@@ -686,6 +694,10 @@
<param name="pattern">$[a-zA-Z0-9_]+</param>
</data>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,2}</param>
+ </data>
+
<data type="int">
<param name="minInclusive">0</param>
<param name="maxInclusive">255</param>
@@ -700,6 +712,10 @@
<param name="pattern">$[a-zA-Z0-9_]+</param>
</data>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,4}</param>
+ </data>
+
<data type="int">
<param name="minInclusive">0</param>
<param name="maxInclusive">65535</param>
@@ -733,6 +749,10 @@
<param name="pattern">$[a-zA-Z0-9_]+</param>
</data>
+ <data type="string">
+ <param name="pattern">0x[0-9a-fA-F]{1,2}</param>
+ </data>
+
<data type="int">
<param name="minInclusive">0</param>
<param name="maxInclusive">255</param>
diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c
index 53a952225..7f68cd629 100644
--- a/src/conf/nwfilter_conf.c
+++ b/src/conf/nwfilter_conf.c
@@ -430,7 +430,9 @@ checkMacProtocolID(enum attrDatatype datatype, void *value,
if (datatype == DATATYPE_STRING) {
if (intMapGetByString(macProtoMap, (char *)value, 1, &res) == 0)
res = -1;
- } else if (datatype == DATATYPE_UINT16) {
+ datatype = DATATYPE_UINT16;
+ } else if (datatype == DATATYPE_UINT16 ||
+ datatype == DATATYPE_UINT16_HEX) {
res = (uint32_t)*(uint16_t *)value;
if (res < 0x600)
res = -1;
@@ -438,7 +440,7 @@ checkMacProtocolID(enum attrDatatype datatype, void *value,
if (res != -1) {
nwf->p.ethHdrFilter.dataProtocolID.u.u16 = res;
- nwf->p.ethHdrFilter.dataProtocolID.datatype = DATATYPE_UINT16;
+ nwf->p.ethHdrFilter.dataProtocolID.datatype = datatype;
return 1;
}
@@ -451,13 +453,17 @@ macProtocolIDFormatter(virBufferPtr buf,
virNWFilterRuleDefPtr nwf)
{
const char *str = NULL;
+ bool asHex = true;
if (intMapGetByInt(macProtoMap,
nwf->p.ethHdrFilter.dataProtocolID.u.u16,
&str)) {
virBufferVSprintf(buf, "%s", str);
} else {
- virBufferVSprintf(buf, "%d", nwf->p.ethHdrFilter.dataProtocolID.u.u16);
+ if (nwf->p.ethHdrFilter.dataProtocolID.datatype == DATATYPE_UINT16)
+ asHex = false;
+ virBufferVSprintf(buf, asHex ? "0x%x" : "%d",
+ nwf->p.ethHdrFilter.dataProtocolID.u.u16);
}
return 1;
}
@@ -528,13 +534,15 @@ arpOpcodeValidator(enum attrDatatype datatype,
if (datatype == DATATYPE_STRING) {
if (intMapGetByString(arpOpcodeMap, (char *)value, 1, &res) == 0)
res = -1;
- } else if (datatype == DATATYPE_UINT16) {
+ datatype = DATATYPE_UINT16;
+ } else if (datatype == DATATYPE_UINT16 ||
+ datatype == DATATYPE_UINT16_HEX) {
res = (uint32_t)*(uint16_t *)value;
}
if (res != -1) {
nwf->p.arpHdrFilter.dataOpcode.u.u16 = res;
- nwf->p.arpHdrFilter.dataOpcode.datatype = DATATYPE_UINT16;
+ nwf->p.arpHdrFilter.dataOpcode.datatype = datatype;
return 1;
}
return 0;
@@ -585,13 +593,15 @@ static bool checkIPProtocolID(enum attrDatatype datatype,
if (datatype == DATATYPE_STRING) {
if (intMapGetByString(ipProtoMap, (char *)value, 1, &res) == 0)
res = -1;
- } else if (datatype == DATATYPE_UINT8) {
+ datatype = DATATYPE_UINT8_HEX;
+ } else if (datatype == DATATYPE_UINT8 ||
+ datatype == DATATYPE_UINT8_HEX) {
res = (uint32_t)*(uint16_t *)value;
}
if (res != -1) {
nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8 = res;
- nwf->p.ipHdrFilter.ipHdr.dataProtocolID.datatype = DATATYPE_UINT8;
+ nwf->p.ipHdrFilter.ipHdr.dataProtocolID.datatype = datatype;
return 1;
}
return 0;
@@ -603,13 +613,16 @@ formatIPProtocolID(virBufferPtr buf,
virNWFilterRuleDefPtr nwf)
{
const char *str = NULL;
+ bool asHex = true;
if (intMapGetByInt(ipProtoMap,
nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8,
&str)) {
virBufferVSprintf(buf, "%s", str);
} else {
- virBufferVSprintf(buf, "%d",
+ if (nwf->p.ipHdrFilter.ipHdr.dataProtocolID.datatype == DATATYPE_UINT8)
+ asHex = false;
+ virBufferVSprintf(buf, asHex ? "0x%x" : "%d",
nwf->p.ipHdrFilter.ipHdr.dataProtocolID.u.u8);
}
return 1;
@@ -617,15 +630,14 @@ formatIPProtocolID(virBufferPtr buf,
static bool
-dscpValidator(enum attrDatatype datatype ATTRIBUTE_UNUSED, void *val,
+dscpValidator(enum attrDatatype datatype, void *val,
virNWFilterRuleDefPtr nwf)
{
uint8_t dscp = *(uint16_t *)val;
if (dscp > 63)
return 0;
- nwf->p.ipHdrFilter.ipHdr.dataDSCP.u.u8 = dscp;
- nwf->p.ipHdrFilter.ipHdr.dataDSCP.datatype = DATATYPE_UINT8;
+ nwf->p.ipHdrFilter.ipHdr.dataDSCP.datatype = datatype;
return 1;
}
@@ -657,7 +669,7 @@ static const virXMLAttr2Struct macAttributes[] = {
COMMON_MAC_PROPS(ethHdrFilter),
{
.name = "protocolid",
- .datatype = DATATYPE_UINT16 | DATATYPE_STRING,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX | DATATYPE_STRING,
.dataIdx = offsetof(virNWFilterRuleDef, p.ethHdrFilter.dataProtocolID),
.validator= checkMacProtocolID,
.formatter= macProtocolIDFormatter,
@@ -671,15 +683,15 @@ static const virXMLAttr2Struct arpAttributes[] = {
COMMON_MAC_PROPS(arpHdrFilter),
{
.name = "hwtype",
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataHWType),
}, {
.name = "protocoltype",
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataProtocolType),
}, {
.name = "opcode",
- .datatype = DATATYPE_UINT16 | DATATYPE_STRING,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX | DATATYPE_STRING,
.dataIdx = offsetof(virNWFilterRuleDef, p.arpHdrFilter.dataOpcode),
.validator= arpOpcodeValidator,
.formatter= arpOpcodeFormatter,
@@ -729,34 +741,34 @@ static const virXMLAttr2Struct ipAttributes[] = {
},
{
.name = "protocol",
- .datatype = DATATYPE_STRING | DATATYPE_UINT8,
+ .datatype = DATATYPE_STRING | DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataProtocolID),
.validator= checkIPProtocolID,
.formatter= formatIPProtocolID,
},
{
.name = SRCPORTSTART,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortStart),
},
{
.name = SRCPORTEND,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataSrcPortEnd),
},
{
.name = DSTPORTSTART,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortStart),
},
{
.name = DSTPORTEND,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.portData.dataDstPortEnd),
},
{
.name = DSCP,
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipHdrFilter.ipHdr.dataDSCP),
.validator = dscpValidator,
},
@@ -790,29 +802,29 @@ static const virXMLAttr2Struct ipv6Attributes[] = {
},
{
.name = "protocol",
- .datatype = DATATYPE_STRING | DATATYPE_UINT8,
+ .datatype = DATATYPE_STRING | DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.ipHdr.dataProtocolID),
.validator= checkIPProtocolID,
.formatter= formatIPProtocolID,
},
{
.name = SRCPORTSTART,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataSrcPortStart),
},
{
.name = SRCPORTEND,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataSrcPortEnd),
},
{
.name = DSTPORTSTART,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortStart),
},
{
.name = DSTPORTEND,
- .datatype = DATATYPE_UINT16,
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.ipv6HdrFilter.portData.dataDstPortEnd),
},
{
@@ -872,9 +884,9 @@ static const virXMLAttr2Struct ipv6Attributes[] = {
},\
{\
.name = DSCP,\
- .datatype = DATATYPE_UINT8,\
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,\
.dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.ipHdr.dataDSCP),\
- /*.validator = dscpValidator,*/\
+ .validator = dscpValidator,\
},\
{\
.name = "connlimit-above",\
@@ -885,22 +897,22 @@ static const virXMLAttr2Struct ipv6Attributes[] = {
#define COMMON_PORT_PROPS(STRUCT) \
{\
.name = SRCPORTSTART,\
- .datatype = DATATYPE_UINT16,\
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
.dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortStart),\
},\
{\
.name = SRCPORTEND,\
- .datatype = DATATYPE_UINT16,\
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
.dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataSrcPortEnd),\
},\
{\
.name = DSTPORTSTART,\
- .datatype = DATATYPE_UINT16,\
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
.dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortStart),\
},\
{\
.name = DSTPORTEND,\
- .datatype = DATATYPE_UINT16,\
+ .datatype = DATATYPE_UINT16 | DATATYPE_UINT16_HEX,\
.dataIdx = offsetof(virNWFilterRuleDef, p.STRUCT.portData.dataDstPortEnd),\
}
@@ -909,7 +921,7 @@ static const virXMLAttr2Struct tcpAttributes[] = {
COMMON_PORT_PROPS(tcpHdrFilter),
{
.name = "option",
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption),
},
{
@@ -959,12 +971,12 @@ static const virXMLAttr2Struct icmpAttributes[] = {
COMMON_IP_PROPS(icmpHdrFilter, DATATYPE_IPADDR, DATATYPE_IPMASK),
{
.name = "type",
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPType),
},
{
.name = "code",
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPCode),
},
{
@@ -994,7 +1006,7 @@ static const virXMLAttr2Struct tcpipv6Attributes[] = {
COMMON_PORT_PROPS(tcpHdrFilter),
{
.name = "option",
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.tcpHdrFilter.dataTCPOption),
},
{
@@ -1048,12 +1060,12 @@ static const virXMLAttr2Struct icmpv6Attributes[] = {
COMMON_IP_PROPS(icmpHdrFilter, DATATYPE_IPV6ADDR, DATATYPE_IPV6MASK),
{
.name = "type",
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPType),
},
{
.name = "code",
- .datatype = DATATYPE_UINT8,
+ .datatype = DATATYPE_UINT8 | DATATYPE_UINT8_HEX,
.dataIdx = offsetof(virNWFilterRuleDef, p.icmpHdrFilter.dataICMPCode),
},
{
@@ -1156,6 +1168,7 @@ virNWFilterRuleDetailsParse(xmlNodePtr node,
valueValidator validator;
char *match = virXMLPropString(node, "match");
nwIPAddress ipaddr;
+ int base;
if (match && STREQ(match, "no"))
match_flag = NWFILTER_ENTRY_ITEM_FLAG_IS_NEG;
@@ -1196,14 +1209,16 @@ virNWFilterRuleDetailsParse(xmlNodePtr node,
validator = att[idx].validator;
- switch (datatype) {
+ base = 10;
+ switch (datatype) {
+ case DATATYPE_UINT8_HEX:
+ base = 16;
case DATATYPE_UINT8:
storage_ptr = &item->u.u8;
- if (virStrToLong_ui(prop, NULL, 10, &uint_val) >= 0) {
+ if (virStrToLong_ui(prop, NULL, base, &uint_val) >= 0) {
if (uint_val <= 0xff) {
- if (!validator)
- *(uint8_t *)storage_ptr = uint_val;
+ *(uint8_t *)storage_ptr = uint_val;
found = 1;
data_ptr = &uint_val;
} else
@@ -1212,12 +1227,13 @@ virNWFilterRuleDetailsParse(xmlNodePtr node,
rc = -1;
break;
+ case DATATYPE_UINT16_HEX:
+ base = 16;
case DATATYPE_UINT16:
storage_ptr = &item->u.u16;
- if (virStrToLong_ui(prop, NULL, 10, &uint_val) >= 0) {
+ if (virStrToLong_ui(prop, NULL, base, &uint_val) >= 0) {
if (uint_val <= 0xffff) {
- if (!validator)
- *(uint16_t *)storage_ptr = uint_val;
+ *(uint16_t *)storage_ptr = uint_val;
found = 1;
data_ptr = &uint_val;
} else
@@ -2393,6 +2409,7 @@ virNWFilterRuleDefDetailsFormat(virBufferPtr buf,
int i = 0, j;
bool typeShown = 0;
bool neverShown = 1;
+ bool asHex;
enum match {
MATCH_NONE = 0,
MATCH_YES,
@@ -2444,19 +2461,27 @@ virNWFilterRuleDefDetailsFormat(virBufferPtr buf,
} else if ((flags & NWFILTER_ENTRY_ITEM_FLAG_HAS_VAR)) {
virBufferVSprintf(buf, "$%s", item->var);
} else {
- switch (att[i].datatype) {
+ asHex = false;
+
+ switch (item->datatype) {
+ case DATATYPE_UINT8_HEX:
+ asHex = true;
case DATATYPE_IPMASK:
case DATATYPE_IPV6MASK:
// display all masks in CIDR format
case DATATYPE_UINT8:
storage_ptr = &item->u.u8;
- virBufferVSprintf(buf, "%d", *(uint8_t *)storage_ptr);
+ virBufferVSprintf(buf, asHex ? "0x%x" : "%d",
+ *(uint8_t *)storage_ptr);
break;
+ case DATATYPE_UINT16_HEX:
+ asHex = true;
case DATATYPE_UINT16:
storage_ptr = &item->u.u16;
- virBufferVSprintf(buf, "%d", *(uint16_t *)storage_ptr);
+ virBufferVSprintf(buf, asHex ? "0x%x" : "%d",
+ *(uint16_t *)storage_ptr);
break;
case DATATYPE_IPADDR:
diff --git a/src/conf/nwfilter_conf.h b/src/conf/nwfilter_conf.h
index d4310130e..97b2e6fca 100644
--- a/src/conf/nwfilter_conf.h
+++ b/src/conf/nwfilter_conf.h
@@ -65,15 +65,17 @@ enum virNWFilterEntryItemFlags {
enum attrDatatype {
DATATYPE_UINT16 = (1 << 0),
DATATYPE_UINT8 = (1 << 1),
- DATATYPE_MACADDR = (1 << 2),
- DATATYPE_MACMASK = (1 << 3),
- DATATYPE_IPADDR = (1 << 4),
- DATATYPE_IPMASK = (1 << 5),
- DATATYPE_STRING = (1 << 6),
- DATATYPE_IPV6ADDR = (1 << 7),
- DATATYPE_IPV6MASK = (1 << 8),
-
- DATATYPE_LAST = (1 << 9),
+ DATATYPE_UINT16_HEX = (1 << 2),
+ DATATYPE_UINT8_HEX = (1 << 3),
+ DATATYPE_MACADDR = (1 << 4),
+ DATATYPE_MACMASK = (1 << 5),
+ DATATYPE_IPADDR = (1 << 6),
+ DATATYPE_IPMASK = (1 << 7),
+ DATATYPE_STRING = (1 << 8),
+ DATATYPE_IPV6ADDR = (1 << 9),
+ DATATYPE_IPV6MASK = (1 << 10),
+
+ DATATYPE_LAST = (1 << 11),
};
diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
index b9b5350c2..c2d2269fd 100644
--- a/src/nwfilter/nwfilter_ebiptables_driver.c
+++ b/src/nwfilter/nwfilter_ebiptables_driver.c
@@ -215,6 +215,7 @@ _printDataType(virNWFilterHashTablePtr vars,
break;
case DATATYPE_UINT16:
+ case DATATYPE_UINT16_HEX:
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
item->u.u16) >= bufsize) {
virNWFilterReportError(VIR_ERR_INVALID_NWFILTER, "%s",
@@ -224,6 +225,7 @@ _printDataType(virNWFilterHashTablePtr vars,
break;
case DATATYPE_UINT8:
+ case DATATYPE_UINT8_HEX:
if (snprintf(buf, bufsize, asHex ? "0x%x" : "%d",
item->u.u8) >= bufsize) {
virNWFilterReportError(VIR_ERR_INVALID_NWFILTER, "%s",
diff --git a/tests/nwfilterxml2xmlin/hex-data-test.xml b/tests/nwfilterxml2xmlin/hex-data-test.xml
new file mode 100644
index 000000000..af26a92ae
--- /dev/null
+++ b/tests/nwfilterxml2xmlin/hex-data-test.xml
@@ -0,0 +1,56 @@
+<filter name='testcase'>
+ <uuid>01a992d2-f8c8-7c27-f69b-ab0a9d377379</uuid>
+
+ <rule action='accept' direction='in'>
+ <mac protocolid='0x1234'/>
+ </rule>
+
+ <rule action='accept' direction='out'>
+ <ip srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff'
+ dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:ff'
+ srcipaddr='10.1.2.3' srcipmask='255.255.255.255'
+ dstipaddr='10.1.2.3' dstipmask='255.255.255.255'
+ protocol='udp'
+ srcportstart='0x123' srcportend='0x234'
+ dstportstart='0x3456' dstportend='0x4567'
+ dscp='0x32'/>
+ </rule>
+
+ <rule action='accept' direction='out'>
+ <ipv6 srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:fe'
+ dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:80'
+ srcipaddr='::10.1.2.3' srcipmask='22'
+ dstipaddr='::10.1.2.3'
+ dstipmask='ffff:ffff:ffff:ffff:ffff:ffff:ffff:8000'
+ protocol='tcp'
+ srcportstart='0x111' srcportend='400'
+ dstportstart='0x3333' dstportend='65535'/>
+ </rule>
+
+ <rule action='accept' direction='out'>
+ <arp srcmacaddr='1:2:3:4:5:6' srcmacmask='ff:ff:ff:ff:ff:ff'
+ dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:ff'
+ hwtype='0x12'
+ protocoltype='0x56'
+ opcode='Request'
+ arpsrcmacaddr='1:2:3:4:5:6'
+ arpdstmacaddr='a:b:c:d:e:f'/>
+ </rule>
+
+ <rule action='accept' direction='out'>
+ <udp srcmacaddr='1:2:3:4:5:6'
+ dstipaddr='10.1.2.3' dstipmask='255.255.255.255'
+ dscp='0x22'
+ srcportstart='0x123' srcportend='400'
+ dstportstart='0x234' dstportend='0x444'/>
+ </rule>
+
+ <rule action='accept' direction='in'>
+ <tcp-ipv6 srcmacaddr='1:2:3:4:5:6'
+ srcipaddr='a:b:c::' srcipmask='128'
+ dscp='0x40'
+ srcportstart='0x20' srcportend='0x21'
+ dstportstart='0x100' dstportend='0x1111'/>
+ </rule>
+
+</filter>
diff --git a/tests/nwfilterxml2xmlout/hex-data-test.xml b/tests/nwfilterxml2xmlout/hex-data-test.xml
new file mode 100644
index 000000000..35a125b60
--- /dev/null
+++ b/tests/nwfilterxml2xmlout/hex-data-test.xml
@@ -0,0 +1,21 @@
+<filter name='testcase' chain='root'>
+ <uuid>01a992d2-f8c8-7c27-f69b-ab0a9d377379</uuid>
+ <rule action='accept' direction='in' priority='500'>
+ <mac protocolid='0x1234'/>
+ </rule>
+ <rule action='accept' direction='out' priority='500'>
+ <ip srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff' dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:ff' srcipaddr='10.1.2.3' srcipmask='32' dstipaddr='10.1.2.3' dstipmask='32' protocol='udp' srcportstart='0x123' srcportend='0x234' dstportstart='0x3456' dstportend='0x4567' dscp='0x32'/>
+ </rule>
+ <rule action='accept' direction='out' priority='500'>
+ <ipv6 srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:fe' dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:80' srcipaddr='::10.1.2.3' srcipmask='22' dstipaddr='::10.1.2.3' dstipmask='113' protocol='tcp' srcportstart='0x111' srcportend='400' dstportstart='0x3333' dstportend='65535'/>
+ </rule>
+ <rule action='accept' direction='out' priority='500'>
+ <arp srcmacaddr='01:02:03:04:05:06' srcmacmask='ff:ff:ff:ff:ff:ff' dstmacaddr='aa:bb:cc:dd:ee:ff' dstmacmask='ff:ff:ff:ff:ff:ff' hwtype='0x12' protocoltype='0x56' opcode='Request' arpsrcmacaddr='01:02:03:04:05:06' arpdstmacaddr='0a:0b:0c:0d:0e:0f'/>
+ </rule>
+ <rule action='accept' direction='out' priority='500'>
+ <udp srcmacaddr='01:02:03:04:05:06' dstipaddr='10.1.2.3' dstipmask='32' dscp='0x22' srcportstart='0x123' srcportend='400' dstportstart='0x234' dstportend='0x444'/>
+ </rule>
+ <rule action='accept' direction='in' priority='500'>
+ <tcp-ipv6 srcmacaddr='01:02:03:04:05:06' srcipaddr='a:b:c::' srcipmask='128' srcportstart='0x20' srcportend='0x21' dstportstart='0x100' dstportend='0x1111'/>
+ </rule>
+</filter>
diff --git a/tests/nwfilterxml2xmltest.c b/tests/nwfilterxml2xmltest.c
index d653a9a71..1ce3e29b3 100644
--- a/tests/nwfilterxml2xmltest.c
+++ b/tests/nwfilterxml2xmltest.c
@@ -121,6 +121,8 @@ mymain(int argc, char **argv)
DO_TEST("conntrack-test");
+ DO_TEST("hex-data-test");
+
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
}