From 5c7c755f50bf82d96b5c25aa622bd9c1eec45103 Mon Sep 17 00:00:00 2001 From: Stefan Berger Date: Mon, 26 Apr 2010 13:50:40 -0400 Subject: [PATCH] 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 --- docs/schemas/nwfilter.rng | 20 ++++ src/conf/nwfilter_conf.c | 121 +++++++++++++-------- src/conf/nwfilter_conf.h | 18 +-- src/nwfilter/nwfilter_ebiptables_driver.c | 2 + tests/nwfilterxml2xmlin/hex-data-test.xml | 56 ++++++++++ tests/nwfilterxml2xmlout/hex-data-test.xml | 21 ++++ tests/nwfilterxml2xmltest.c | 2 + 7 files changed, 184 insertions(+), 56 deletions(-) create mode 100644 tests/nwfilterxml2xmlin/hex-data-test.xml create mode 100644 tests/nwfilterxml2xmlout/hex-data-test.xml diff --git a/docs/schemas/nwfilter.rng b/docs/schemas/nwfilter.rng index 0497d275ce..3bcdd44b83 100644 --- a/docs/schemas/nwfilter.rng +++ b/docs/schemas/nwfilter.rng @@ -647,6 +647,10 @@ + + 0x([0-3][0-9a-fA-F]|[0-9a-fA-F]) + + $[a-zA-Z0-9_]+ @@ -666,6 +670,10 @@ $[a-zA-Z0-9_]+ + + 0x([6-9a-fA-F][0-9a-fA-F]{2}|[0-9a-fA-F]{4}) + + 1536 65535 @@ -686,6 +694,10 @@ $[a-zA-Z0-9_]+ + + 0x[0-9a-fA-F]{1,2} + + 0 255 @@ -700,6 +712,10 @@ $[a-zA-Z0-9_]+ + + 0x[0-9a-fA-F]{1,4} + + 0 65535 @@ -733,6 +749,10 @@ $[a-zA-Z0-9_]+ + + 0x[0-9a-fA-F]{1,2} + + 0 255 diff --git a/src/conf/nwfilter_conf.c b/src/conf/nwfilter_conf.c index 53a9522252..7f68cd6291 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 d4310130ef..97b2e6fcad 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_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 << 9), + DATATYPE_LAST = (1 << 11), }; diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c index b9b5350c20..c2d2269fd0 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 0000000000..af26a92ae4 --- /dev/null +++ b/tests/nwfilterxml2xmlin/hex-data-test.xml @@ -0,0 +1,56 @@ + + 01a992d2-f8c8-7c27-f69b-ab0a9d377379 + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/nwfilterxml2xmlout/hex-data-test.xml b/tests/nwfilterxml2xmlout/hex-data-test.xml new file mode 100644 index 0000000000..35a125b600 --- /dev/null +++ b/tests/nwfilterxml2xmlout/hex-data-test.xml @@ -0,0 +1,21 @@ + + 01a992d2-f8c8-7c27-f69b-ab0a9d377379 + + + + + + + + + + + + + + + + + + + diff --git a/tests/nwfilterxml2xmltest.c b/tests/nwfilterxml2xmltest.c index d653a9a71f..1ce3e29b3a 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); }