From: Francis Dupont Date: Thu, 21 Aug 2025 07:39:23 +0000 (+0200) Subject: [#3860] More vsa X-Git-Tag: Kea-3.1.2~45 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=68ee91bb01d77837a6e1e3c6842dab287ed31943;p=thirdparty%2Fkea.git [#3860] More vsa --- diff --git a/src/hooks/dhcp/radius/client_attribute.cc b/src/hooks/dhcp/radius/client_attribute.cc index 41aac45726..7840bd4b97 100644 --- a/src/hooks/dhcp/radius/client_attribute.cc +++ b/src/hooks/dhcp/radius/client_attribute.cc @@ -24,36 +24,6 @@ using namespace std; namespace isc { namespace radius { -AttributePtr -Attribute::fromText(const string& repr) { - if (repr.empty()) { - isc_throw(BadValue, "empty text attribute"); - } - string trimed = str::trim(repr); - if (trimed.empty()) { - isc_throw(BadValue, "blank text attribute '" << repr << "'"); - } - size_t equal = trimed.find('='); - if (equal == string::npos) { - isc_throw(BadValue, "can't find '=' in text attribute '" - << repr << "'"); - } - string name = str::trim(trimed.substr(0, equal)); - if (name.empty()) { - isc_throw(BadValue, "empty attribute name in '" << repr << "'"); - } - string value = str::trim(trimed.substr(equal + 1)); - if (value.empty()) { - isc_throw(BadValue, "empty attribute value in '" << repr << "'"); - } - AttrDefPtr def = AttrDefs::instance().getByName(name); - if (!def) { - isc_throw(NotFound, "can't find attribute definition for '" - << name << "'"); - } - return (Attribute::fromText(def, value)); -} - AttributePtr Attribute::fromText(const AttrDefPtr& def, const string& value) { if (!def) { @@ -81,7 +51,7 @@ Attribute::fromText(const AttrDefPtr& def, const string& value) { case PW_TYPE_IPV6PREFIX: return (AttrIpv6Prefix::fromText(def->type_, value)); case PW_TYPE_VSA: - return (AttrVSA::fromText(def->type_, value)); + return (AttrVsa::fromText(def->type_, value)); default: // Impossible case. isc_throw(OutOfRange, "unknown value type " @@ -134,7 +104,7 @@ Attribute::fromBytes(const AttrDefPtr& def, const vector& value) { case PW_TYPE_IPV6PREFIX: return (AttrIpv6Prefix::fromBytes(def->type_, value)); case PW_TYPE_VSA: - return (AttrVSA::fromBytes(def->type_, value)); + return (AttrVsa::fromBytes(def->type_, value)); default: // Impossible case. isc_throw(OutOfRange, "unknown value type " @@ -179,15 +149,27 @@ Attribute::fromIpv6Prefix(const uint8_t type, const uint8_t len, return (AttributePtr(new AttrIpv6Prefix(type, len, value))); } +AttributePtr +Attribute::fromVsa(const uint8_t type, const uint32_t vendor, + const std::string& value) { + return (AttributePtr(new AttrVsa(type, vendor, value))); +} + +AttributePtr +Attribute::fromVsa(const uint8_t type, const uint32_t vendor, + const std::vector& value) { + return (AttributePtr(new AttrVsa(type, vendor, value))); +} + string Attribute::toString() const { - isc_throw(TypeError, "the attribute value type must be string or vsa, not " + isc_throw(TypeError, "the attribute value type must be string, not " << attrValueTypeToText(getValueType())); } vector Attribute::toBinary() const { - isc_throw(TypeError, "the attribute value type must be string or vsa, not " + isc_throw(TypeError, "the attribute value type must be string, not " << attrValueTypeToText(getValueType())); } @@ -227,8 +209,8 @@ Attribute::toVendorId() const { << attrValueTypeToText(getValueType())); } -void -Attribute::setVendorId(const uint32_t vendor) { +string +Attribute::toVsaData() const { isc_throw(TypeError, "the attribute value type must be vsa, not " << attrValueTypeToText(getValueType())); } @@ -276,7 +258,17 @@ AttrString::toText(size_t indent) const { for (size_t i = 0; i < indent; i++) { output << " "; } - output << AttrDefs::instance().getName(getType()) << '=' << value_; + output << AttrDefs::instance().getName(getType()) << '='; + if (str::isPrintable(value_)) { + output << "'" << value_ << "'"; + } else { + vector binary; + binary.resize(value_.size()); + if (binary.size() > 0) { + memmove(&binary[0], value_.c_str(), binary.size()); + } + output << "0x" << encode::encodeHex(binary); + } return (output.str()); } @@ -628,7 +620,7 @@ AttrIpv6Prefix::toElement() const { return (output); } -AttrVSA::AttrVSA(const uint8_t type, const int32_t vendor, +AttrVsa::AttrVsa(const uint8_t type, const uint32_t vendor, const vector& value) : Attribute(type), vendor_(vendor), value_() { if (value.empty()) { @@ -643,12 +635,12 @@ AttrVSA::AttrVSA(const uint8_t type, const int32_t vendor, } AttributePtr -AttrVSA::fromText(const uint8_t type, const string& repr) { - isc_throw(NotImplemented, "Can't decode VSA from text"); +AttrVsa::fromText(const uint8_t type, const string& repr) { + isc_throw(NotImplemented, "Can't decode vsa from text"); } AttributePtr -AttrVSA::fromBytes(const uint8_t type, const vector& bytes) { +AttrVsa::fromBytes(const uint8_t type, const vector& bytes) { if (bytes.empty()) { isc_throw(BadValue, "empty attribute value"); } @@ -667,16 +659,28 @@ AttrVSA::fromBytes(const uint8_t type, const vector& bytes) { if (value.size() > 0) { memmove(&value[0], &bytes[4], value.size()); } - return (AttributePtr(new AttrVSA(type, vendor, value))); + return (AttributePtr(new AttrVsa(type, vendor, value))); } string -AttrVSA::toText(size_t indent) const { - isc_throw(NotImplemented, "Can't encode VSA into text"); +AttrVsa::toText(size_t indent) const { + ostringstream output; + for (size_t i = 0; i < indent; i++) { + output << " "; + } + output << AttrDefs::instance().getName(getType()) << "=[" + << vendor_ << "]"; + vector binary; + binary.resize(value_.size()); + if (binary.size() > 0) { + memmove(&binary[0], value_.c_str(), binary.size()); + } + output << "0x" << encode::encodeHex(binary); + return (output.str()); } std::vector -AttrVSA::toBytes() const { +AttrVsa::toBytes() const { vector output; output.resize(2 + getValueLen()); output[0] = getType(); @@ -691,18 +695,8 @@ AttrVSA::toBytes() const { return (output); } -std::vector -AttrVSA::toBinary() const { - vector binary; - binary.resize(getValueLen() - 4); - if (binary.size() > 0) { - memmove(&binary[0], &value_[0], binary.size()); - } - return (binary); -} - ElementPtr -AttrVSA::toElement() const { +AttrVsa::toElement() const { ElementPtr output = Element::createMap(); AttrDefPtr def = AttrDefs::instance().getByType(getType()); if (def) { diff --git a/src/hooks/dhcp/radius/client_attribute.h b/src/hooks/dhcp/radius/client_attribute.h index ac13cfbd79..d98ee9d601 100644 --- a/src/hooks/dhcp/radius/client_attribute.h +++ b/src/hooks/dhcp/radius/client_attribute.h @@ -69,13 +69,6 @@ public: /// Generic factories. - /// @brief From text. - /// - /// @param repr name=value representation. - /// @return pointer to the attribute. - /// @throw NotFound if the definition can't be found. - static AttributePtr fromText(const std::string& repr); - /// @brief From bytes (wire format). /// /// @param bytes binary attribute. @@ -164,12 +157,12 @@ public: /// @brief From Vendor ID and string data with type. /// - /// @note Requires the type to be of the Vendor Specific attribute (26). + /// @note Requires the type to be of a standard vsa attribute. /// /// @param type type of attribute. /// @param vendor vendor id. /// @param value vsa data. - static AttributePtr fromVSA(const uint8_t type, + static AttributePtr fromVsa(const uint8_t type, const uint32_t vendor, const std::string& value); @@ -180,7 +173,7 @@ public: /// @param type type of attribute. /// @param vendor vendor id. /// @param value vsa data. - static AttributePtr fromVSA(const uint8_t type, + static AttributePtr fromVsa(const uint8_t type, const uint32_t vendor, const std::vector& value); @@ -209,13 +202,13 @@ public: /// @brief To string. /// /// @return the string value. - /// @throw TypeError if the attribute is not a string or vsa one. + /// @throw TypeError if the attribute is not a string one. virtual std::string toString() const; /// @brief To binary. /// /// @return the string value as a binary. - /// @throw TypeError if the attribute is not a string or vsa one. + /// @throw TypeError if the attribute is not a string one. virtual std::vector toBinary() const; /// @brief To integer. @@ -254,13 +247,11 @@ public: /// @throw TypeError if the attribute is not a vsa one. virtual uint32_t toVendorId() const; - /// Generic set methods. - - /// @brief Set vendor id. + /// @brief To vsa data. /// - /// @param vendor vendor id. + /// @return the vsa data. /// @throw TypeError if the attribute is not a vsa one. - virtual void setVendorId(const uint32_t vendor); + virtual std::string toVsaData() const; /// @brief Type. const uint8_t type_; @@ -689,7 +680,7 @@ private: }; /// @brief RADIUS attribute holding vsa. -class AttrVSA : public Attribute { +class AttrVsa : public Attribute { protected: /// @brief Constructor. @@ -697,7 +688,8 @@ protected: /// @param type attribute type. /// @param vendor vendor id. /// @param value string vsa data. - AttrVSA(const uint8_t type, const int32_t vendor, const std::string& value) + AttrVsa(const uint8_t type, const uint32_t vendor, + const std::string& value) : Attribute(type), vendor_(vendor), value_(value) { if (value.empty()) { isc_throw(BadValue, "value is empty"); @@ -713,7 +705,7 @@ protected: /// @param type attribute type. /// @param vendor vendor id. /// @param value binary vsa data. - AttrVSA(const uint8_t type, const int32_t vendor, + AttrVsa(const uint8_t type, const uint32_t vendor, const std::vector& value); /// @brief From text. @@ -721,6 +713,7 @@ protected: /// @param type attribute type. /// @param repr value representation. /// @return pointer to the attribute or null. + /// @throw NotImplemented static AttributePtr fromText(const uint8_t type, const std::string& repr); /// @brief From bytes. @@ -761,18 +754,6 @@ public: /// @return binary representation. virtual std::vector toBytes() const override; - /// @brief To string. - /// - /// @return the string value. - virtual std::string toString() const override { - return (value_); - } - - /// @brief To binary. - /// - /// @return the string value as a binary. - virtual std::vector toBinary() const override; - /// @brief To vendor id. /// /// @return the vendor id. @@ -780,11 +761,11 @@ public: return (vendor_); } - /// @brief Set vendor id. + /// @brief To vsa data. /// - /// @param vendor vendor id. - virtual void setVendorId(const uint32_t vendor) override { - vendor_ = vendor; + /// @return the vsa data. + virtual std::string toVsaData() const override { + return (value_); } /// @brief Unparse attribute. diff --git a/src/hooks/dhcp/radius/client_dictionary.cc b/src/hooks/dhcp/radius/client_dictionary.cc index 988ab2f2ff..479db62e0d 100644 --- a/src/hooks/dhcp/radius/client_dictionary.cc +++ b/src/hooks/dhcp/radius/client_dictionary.cc @@ -291,6 +291,9 @@ AttrDefs::parseLine(const string& line, unsigned int depth) { } catch (...) { isc_throw(Unexpected, "can't parse integer value " << value_str); } + if (value == 0) { + isc_throw(Unexpected, "0 is reserved"); + } IntCstDefPtr def(new IntCstDef(PW_VENDOR_SPECIFIC, name, value)); add(def); return; diff --git a/src/hooks/dhcp/radius/data/dictionary b/src/hooks/dhcp/radius/data/dictionary index f06dde01b3..94ed4716bc 100644 --- a/src/hooks/dhcp/radius/data/dictionary +++ b/src/hooks/dhcp/radius/data/dictionary @@ -26,7 +26,7 @@ ATTRIBUTE Framed-Route 22 string ATTRIBUTE Framed-IPX-Network 23 ipaddr ATTRIBUTE State 24 string ATTRIBUTE Class 25 string -ATTRIBUTE Vendor-Specific 26 string +ATTRIBUTE Vendor-Specific 26 vsa ATTRIBUTE Session-Timeout 27 integer ATTRIBUTE Idle-Timeout 28 integer ATTRIBUTE Termination-Action 29 integer diff --git a/src/hooks/dhcp/radius/radius_parsers.cc b/src/hooks/dhcp/radius/radius_parsers.cc index 1e98f413db..20c89d1053 100644 --- a/src/hooks/dhcp/radius/radius_parsers.cc +++ b/src/hooks/dhcp/radius/radius_parsers.cc @@ -74,6 +74,7 @@ const AttrDefList RadiusConfigParser::USED_STANDARD_ATTR_DEFS = { { PW_FRAMED_IP_ADDRESS, "Framed-IP-Address", PW_TYPE_IPADDR }, { PW_REPLY_MESSAGE, "Reply-Message", PW_TYPE_STRING }, { PW_CLASS, "Class", PW_TYPE_STRING }, + { PW_VENDOR_SPECIFIC, "Vendor-Specific", PW_TYPE_VSA }, { PW_CALLING_STATION_ID, "Calling-Station-Id", PW_TYPE_STRING }, { PW_ACCT_STATUS_TYPE, "Acct-Status-Type", PW_TYPE_INTEGER }, { PW_ACCT_DELAY_TIME, "Acct-Delay-Time", PW_TYPE_INTEGER }, diff --git a/src/hooks/dhcp/radius/tests/access_unittests.cc b/src/hooks/dhcp/radius/tests/access_unittests.cc index a42da6cde8..d97fe16f14 100644 --- a/src/hooks/dhcp/radius/tests/access_unittests.cc +++ b/src/hooks/dhcp/radius/tests/access_unittests.cc @@ -1755,12 +1755,12 @@ TEST_F(AccessTest, buildHWAddr4) { EXPECT_LE(2, handler->env_.send_attrs_->size()); ConstAttributePtr user_name = handler->env_.send_attrs_->get(PW_USER_NAME); ASSERT_TRUE(user_name); - string expected = "User-Name=" + text; + string expected = "User-Name='" + text + "'"; EXPECT_EQ(expected, user_name->toText()); ConstAttributePtr calling_station_id = handler->env_.send_attrs_->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); } @@ -1783,12 +1783,12 @@ TEST_F(AccessTest, buildHWAddr6) { EXPECT_LE(2, handler->env_.send_attrs_->size()); ConstAttributePtr user_name = handler->env_.send_attrs_->get(PW_USER_NAME); ASSERT_TRUE(user_name); - string expected = "User-Name=" + text; + string expected = "User-Name='" + text + "'"; EXPECT_EQ(expected, user_name->toText()); ConstAttributePtr calling_station_id = handler->env_.send_attrs_->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=08:00:27:58:f1:e8", + EXPECT_EQ("Calling-Station-Id='08:00:27:58:f1:e8'", calling_station_id->toText()); } @@ -1809,7 +1809,7 @@ TEST_F(AccessTest, buildCanonHWAddr4) { ConstAttributePtr calling_station_id = handler->env_.send_attrs_->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20-e5-2a-b8-15-14", + EXPECT_EQ("Calling-Station-Id='20-e5-2a-b8-15-14'", calling_station_id->toText()); } @@ -1830,7 +1830,7 @@ TEST_F(AccessTest, buildCanonHWAddr6) { ConstAttributePtr calling_station_id = handler->env_.send_attrs_->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=08-00-27-58-f1-e8", + EXPECT_EQ("Calling-Station-Id='08-00-27-58-f1-e8'", calling_station_id->toText()); } diff --git a/src/hooks/dhcp/radius/tests/accounting_unittests.cc b/src/hooks/dhcp/radius/tests/accounting_unittests.cc index 2521a200de..9af3040647 100644 --- a/src/hooks/dhcp/radius/tests/accounting_unittests.cc +++ b/src/hooks/dhcp/radius/tests/accounting_unittests.cc @@ -743,10 +743,10 @@ void AccountingTest::testBuildAcctLease4() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); ConstAttributePtr framed_ip_address = attrs->get(PW_FRAMED_IP_ADDRESS); ASSERT_TRUE(framed_ip_address); @@ -782,7 +782,7 @@ void AccountingTest::testBuildAcctLease4canon() { ASSERT_LE(5, attrs->size()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20-e5-2a-b8-15-14", + EXPECT_EQ("Calling-Station-Id='20-e5-2a-b8-15-14'", calling_station_id->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -805,7 +805,7 @@ void AccountingTest::testBuildAcctLease4noDuid() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -827,7 +827,7 @@ void AccountingTest::testBuildAcctLease4noPop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -849,7 +849,7 @@ void AccountingTest::testBuildAcctLease4notPrintable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -873,7 +873,7 @@ void AccountingTest::testBuildAcctLease4Duid() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=05:06:07:08:09", user_name->toText()); + EXPECT_EQ("User-Name='05:06:07:08:09'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -898,7 +898,7 @@ void AccountingTest::testBuildAcctLease4DuidPrintable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -920,7 +920,7 @@ void AccountingTest::testBuildAcctLease4Pop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -942,7 +942,7 @@ void AccountingTest::testBuildAcctLease4Pop0Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -962,7 +962,7 @@ void AccountingTest::testBuildAcctLease4noClientId() { ASSERT_LE(4, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=20:e5:2a:b8:15:14", user_name->toText()); + EXPECT_EQ("User-Name='20:e5:2a:b8:15:14'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); EXPECT_FALSE(calling_station_id); EXPECT_EQ(0, attrs->count(PW_CLASS)); @@ -1166,7 +1166,7 @@ void AccountingTest::testBuildAcctLease4ClassClientID() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct on IPv4/HwAddr can get the Class from host cache. @@ -1200,7 +1200,7 @@ void AccountingTest::testBuildAcctLease4ClassHwAddr() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct on IPv4/DUID can get the Class from host cache. @@ -1235,7 +1235,7 @@ void AccountingTest::testBuildAcctLease4ClassDuid() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct on IPv4/Flex can get the Class from host cache. @@ -1268,7 +1268,7 @@ void AccountingTest::testBuildAcctLease4ClassFlex() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct on IPv6 lease works. @@ -1292,10 +1292,10 @@ void AccountingTest::testBuildAcctLease6() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); ConstAttributePtr framed_ip_address = attrs->get(PW_FRAMED_IPV6_ADDRESS); ASSERT_TRUE(framed_ip_address); @@ -1335,10 +1335,10 @@ void AccountingTest::testBuildAcctLease6prefix() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); ConstAttributePtr delegated_prefix = attrs->get(PW_DELEGATED_IPV6_PREFIX); ASSERT_TRUE(delegated_prefix); @@ -1376,7 +1376,7 @@ void AccountingTest::testBuildAcctLease6canon() { ASSERT_LE(5, attrs->size()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20-e5-2a-b8-15-14", + EXPECT_EQ("Calling-Station-Id='20-e5-2a-b8-15-14'", calling_station_id->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1400,7 +1400,7 @@ void AccountingTest::testBuildAcctLease6noPop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); } /// Verify that buildAcct on IPv6 lease works with not printable duid. @@ -1422,7 +1422,7 @@ void AccountingTest::testBuildAcctLease6notPrintable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1445,7 +1445,7 @@ void AccountingTest::testBuildAcctLease6Pop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1468,7 +1468,7 @@ void AccountingTest::testBuildAcctLease6Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1491,7 +1491,7 @@ void AccountingTest::testBuildAcctLease6Pop0Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1701,7 +1701,7 @@ void AccountingTest::testBuildAcctLease6ClassDUID() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct on IPv6/HwAddr can get the Class from host cache. @@ -1736,7 +1736,7 @@ void AccountingTest::testBuildAcctLease6ClassHwAddr() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct on IPv6/Flex can get the Class from host cache. @@ -1770,7 +1770,7 @@ void AccountingTest::testBuildAcctLease6ClassFlex() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct4 works. @@ -1794,10 +1794,10 @@ void AccountingTest::testBuildAcct4() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); ConstAttributePtr framed_ip_address = attrs->get(PW_FRAMED_IP_ADDRESS); ASSERT_TRUE(framed_ip_address); @@ -1872,7 +1872,7 @@ void AccountingTest::testBuildAcct4canon() { ASSERT_LE(5, attrs->size()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20-e5-2a-b8-15-14", + EXPECT_EQ("Calling-Station-Id='20-e5-2a-b8-15-14'", calling_station_id->toText()); ConstAttributePtr framed_ip_address = attrs->get(PW_FRAMED_IP_ADDRESS); EXPECT_EQ("Framed-IP-Address=192.0.2.1", framed_ip_address->toText()); @@ -1897,7 +1897,7 @@ void AccountingTest::testBuildAcct4noPop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1919,7 +1919,7 @@ void AccountingTest::testBuildAcct4notPrintable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1941,7 +1941,7 @@ void AccountingTest::testBuildAcct4Pop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1963,7 +1963,7 @@ void AccountingTest::testBuildAcct4Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -1985,7 +1985,7 @@ void AccountingTest::testBuildAcct4Pop0Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2029,7 +2029,7 @@ void AccountingTest::testBuildAcct4noClientId() { ASSERT_LE(4, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=20:e5:2a:b8:15:14", user_name->toText()); + EXPECT_EQ("User-Name='20:e5:2a:b8:15:14'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2050,7 +2050,7 @@ void AccountingTest::testBuildAcct4noClientIdcanon() { ASSERT_LE(4, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=20-e5-2a-b8-15-14", user_name->toText()); + EXPECT_EQ("User-Name='20-e5-2a-b8-15-14'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2132,7 +2132,7 @@ void AccountingTest::testBuildAcct4ClassClientID() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct4 on HwAddr can get the Class from host cache. @@ -2167,7 +2167,7 @@ void AccountingTest::testBuildAcct4ClassHwAddr() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct4 on Flex can get the Class from host cache. @@ -2202,7 +2202,7 @@ void AccountingTest::testBuildAcct4ClassFlex() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct6 works. @@ -2226,10 +2226,10 @@ void AccountingTest::testBuildAcct6() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); ConstAttributePtr framed_ip_address = attrs->get(PW_FRAMED_IPV6_ADDRESS); ASSERT_TRUE(framed_ip_address); @@ -2270,10 +2270,10 @@ void AccountingTest::testBuildAcct6prefix() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20:e5:2a:b8:15:14", + EXPECT_EQ("Calling-Station-Id='20:e5:2a:b8:15:14'", calling_station_id->toText()); ConstAttributePtr delegated_prefix = attrs->get(PW_DELEGATED_IPV6_PREFIX); ASSERT_TRUE(delegated_prefix); @@ -2464,7 +2464,7 @@ void AccountingTest::testBuildAcct6canon() { ASSERT_LE(5, attrs->size()); ConstAttributePtr calling_station_id = attrs->get(PW_CALLING_STATION_ID); ASSERT_TRUE(calling_station_id); - EXPECT_EQ("Calling-Station-Id=20-e5-2a-b8-15-14", + EXPECT_EQ("Calling-Station-Id='20-e5-2a-b8-15-14'", calling_station_id->toText()); ConstAttributePtr framed_ip_address = attrs->get(PW_FRAMED_IPV6_ADDRESS); EXPECT_EQ("Framed-IPv6-Address=2001:db8::1235", @@ -2491,7 +2491,7 @@ void AccountingTest::testBuildAcct6noPop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2514,7 +2514,7 @@ void AccountingTest::testBuildAcct6notPrintable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2537,7 +2537,7 @@ void AccountingTest::testBuildAcct6Pop0() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=01:02:03:04", user_name->toText()); + EXPECT_EQ("User-Name='01:02:03:04'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2560,7 +2560,7 @@ void AccountingTest::testBuildAcct6Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2583,7 +2583,7 @@ void AccountingTest::testBuildAcct6Pop0Printable() { ASSERT_LE(5, attrs->size()); ConstAttributePtr user_name = attrs->get(PW_USER_NAME); ASSERT_TRUE(user_name); - EXPECT_EQ("User-Name=Foobar", user_name->toText()); + EXPECT_EQ("User-Name='Foobar'", user_name->toText()); EXPECT_EQ(0, attrs->count(PW_CLASS)); } @@ -2690,7 +2690,7 @@ void AccountingTest::testBuildAcct6ClassDUID() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct6 on HwAddr can get the Class from host cache. @@ -2724,7 +2724,7 @@ void AccountingTest::testBuildAcct6ClassHwAddr() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that buildAcct6 on Flex can get the Class from host cache. @@ -2758,7 +2758,7 @@ void AccountingTest::testBuildAcct6ClassFlex() { ASSERT_LE(6, attrs->size()); ConstAttributePtr cclass = attrs->get(PW_CLASS); ASSERT_TRUE(cclass); - EXPECT_EQ("Class=foobar", cclass->toText()); + EXPECT_EQ("Class='foobar'", cclass->toText()); } /// Verify that lease4_select hook returns for fake allocations. diff --git a/src/hooks/dhcp/radius/tests/attribute_test.cc b/src/hooks/dhcp/radius/tests/attribute_test.cc index 927e391af4..dc3e0c45f4 100644 --- a/src/hooks/dhcp/radius/tests/attribute_test.cc +++ b/src/hooks/dhcp/radius/tests/attribute_test.cc @@ -35,6 +35,9 @@ AttributeTest::compare(ConstAttributePtr first, ConstAttributePtr second) { } else if (first->getValueType() == PW_TYPE_IPV6PREFIX) { return ((first->toIpv6Prefix() == second->toIpv6Prefix()) && (first->toIpv6PrefixLen() == second->toIpv6PrefixLen())); + } else if (first->getValueType() == PW_TYPE_VSA) { + return ((first->toVendorId() == second->toVendorId()) && + (first->toVsaData() == second->toVsaData())); } // Should not happen... return (false); diff --git a/src/hooks/dhcp/radius/tests/attribute_unittests.cc b/src/hooks/dhcp/radius/tests/attribute_unittests.cc index 1bc3e32c90..e7f51066dd 100644 --- a/src/hooks/dhcp/radius/tests/attribute_unittests.cc +++ b/src/hooks/dhcp/radius/tests/attribute_unittests.cc @@ -28,22 +28,6 @@ using namespace isc::test; namespace { -// Verify error cases for generic factory fromText. -TEST_F(AttributeTest, fromText) { - EXPECT_THROW_MSG(Attribute::fromText(""), BadValue, - "empty text attribute"); - EXPECT_THROW_MSG(Attribute::fromText(" "), BadValue, - "blank text attribute ' '"); - EXPECT_THROW_MSG(Attribute::fromText("foo-bar"), BadValue, - "can't find '=' in text attribute 'foo-bar'"); - EXPECT_THROW_MSG(Attribute::fromText("=bar"), BadValue, - "empty attribute name in '=bar'"); - EXPECT_THROW_MSG(Attribute::fromText("foo="), BadValue, - "empty attribute value in 'foo='"); - EXPECT_THROW_MSG(Attribute::fromText("Foo-Bar=1"), NotFound, - "can't find attribute definition for 'Foo-Bar'"); -} - // Verify error cases for factory fromText with definition. TEST_F(AttributeTest, defFromText) { AttrDefPtr def; @@ -107,18 +91,13 @@ TEST_F(AttributeTest, attrString) { string to_string; EXPECT_NO_THROW_LOG(to_string = attr->toString()); EXPECT_EQ("foobar", to_string); - EXPECT_EQ("User-Name=foobar", attr->toText()); + EXPECT_EQ("User-Name='foobar'", attr->toText()); vector binary = { 1, 8, 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72 }; EXPECT_EQ(binary, attr->toBytes()); string expected = "{ \"type\": 1, \"name\": \"User-Name\", "; expected += " \"data\": \"foobar\" }"; runToElementTest(expected, *attr); - AttributePtr from_text = Attribute::fromText("User-Name=foobar"); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - AttributePtr from_bytes = Attribute::fromBytes(binary); ASSERT_TRUE(from_bytes); EXPECT_TRUE(compare(from_bytes, attr)) @@ -177,6 +156,8 @@ TEST_F(AttributeTest, attrString) { "the attribute value type must be ipv6prefix, not string"); EXPECT_THROW_MSG(attr->toVendorId(), TypeError, "the attribute value type must be vsa, not string"); + EXPECT_THROW_MSG(attr->toVsaData(), TypeError, + "the attribute value type must be vsa, not string"); } // Verifies raw string attribute. @@ -190,18 +171,13 @@ TEST_F(AttributeTest, rawAttrString) { string to_string; EXPECT_NO_THROW_LOG(to_string = attr->toString()); EXPECT_EQ("\x01\x02\x03", to_string); - EXPECT_EQ("User-Name=\x01\x02\x03", attr->toText()); + EXPECT_EQ("User-Name=0x010203", attr->toText()); vector binary = { 1, 5, 1, 2, 3 }; EXPECT_EQ(binary, attr->toBytes()); string expected = "{ \"type\": 1, \"name\": \"User-Name\", "; expected += " \"raw\": \"010203\" }"; runToElementTest(expected, *attr); - AttributePtr from_text = Attribute::fromText("User-Name=\x01\x02\x03"); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - AttributePtr from_bytes = Attribute::fromBytes(binary); ASSERT_TRUE(from_bytes); EXPECT_TRUE(compare(from_bytes, attr)) @@ -232,19 +208,6 @@ TEST_F(AttributeTest, attrInt) { expected += " \"data\": \"15\" }"; runToElementTest(expected, *attr); - AttributePtr from_text = Attribute::fromText("NAS-Port-Type=Ethernet"); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - - AttributePtr attr2; - ASSERT_NO_THROW(attr2 = Attribute::fromInt(61, 1155)); - ASSERT_TRUE(attr2); - AttributePtr from_text2 = Attribute::fromText("NAS-Port-Type=1155"); - ASSERT_TRUE(from_text2); - EXPECT_TRUE(compare(from_text2, attr2)) - << from_text2->toText() << " != " << attr2->toText(); - AttributePtr from_bytes = Attribute::fromBytes(binary); ASSERT_TRUE(from_bytes); EXPECT_TRUE(compare(from_bytes, attr)) @@ -270,9 +233,9 @@ TEST_F(AttributeTest, attrInt) { << def_bytes->toText() << " != " << attr->toText(); EXPECT_THROW_MSG(attr->toString(), TypeError, - "the attribute value type must be string or vsa, not integer"); + "the attribute value type must be string, not integer"); EXPECT_THROW_MSG(attr->toBinary(), TypeError, - "the attribute value type must be string or vsa, not integer"); + "the attribute value type must be string, not integer"); EXPECT_THROW_MSG(attr->toIpAddr(), TypeError, "the attribute value type must be ipaddr, not integer"); EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError, @@ -284,6 +247,8 @@ TEST_F(AttributeTest, attrInt) { ); EXPECT_THROW_MSG(attr->toVendorId(), TypeError, "the attribute value type must be vsa, not integer"); + EXPECT_THROW_MSG(attr->toVsaData(), TypeError, + "the attribute value type must be vsa, not integer"); } // Verifies IP address attribute. @@ -310,11 +275,6 @@ TEST_F(AttributeTest, attrIpAddr) { expected += " \"data\": \"192.0.2.1\" }"; runToElementTest(expected, *attr); - AttributePtr from_text = Attribute::fromText("Framed-IP-Address=192.0.2.1"); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - EXPECT_THROW_MSG(Attribute::fromIpAddr(8, IOAddress("2001:db8::1235")), BadValue, "not v4 address 2001:db8::1235"); @@ -343,9 +303,9 @@ TEST_F(AttributeTest, attrIpAddr) { << def_bytes->toText() << " != " << attr->toText(); EXPECT_THROW_MSG(attr->toString(), TypeError, - "the attribute value type must be string or vsa, not ipaddr"); + "the attribute value type must be string, not ipaddr"); EXPECT_THROW_MSG(attr->toBinary(), TypeError, - "the attribute value type must be string or vsa, not ipaddr"); + "the attribute value type must be string, not ipaddr"); EXPECT_THROW_MSG(attr->toInt(), TypeError, "the attribute value type must be integer, not ipaddr"); EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError, @@ -356,6 +316,8 @@ TEST_F(AttributeTest, attrIpAddr) { "the attribute value type must be ipv6prefix, not ipaddr"); EXPECT_THROW_MSG(attr->toVendorId(), TypeError, "the attribute value type must be vsa, not ipaddr"); + EXPECT_THROW_MSG(attr->toVsaData(), TypeError, + "the attribute value type must be vsa, not ipaddr"); } // Verifies IPv6 address attribute. @@ -384,19 +346,13 @@ TEST_F(AttributeTest, attrIpv6Addr) { expected += " \"data\": \"2001:db8::1235\" }"; runToElementTest(expected, *attr); - AttributePtr from_text = - Attribute::fromText("Framed-IPv6-Address=2001:db8::1235"); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - EXPECT_THROW_MSG(Attribute::fromIpv6Addr(168, IOAddress("192.0.2.1")), BadValue, "not v6 address 192.0.2.1"); AttributePtr def_text = Attribute::fromText(def, "2001:db8::1235"); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); + ASSERT_TRUE(def_text); + EXPECT_TRUE(compare(def_text, attr)) + << def_text->toText() << " != " << attr->toText(); AttributePtr from_bytes = Attribute::fromBytes(binary); ASSERT_TRUE(from_bytes); @@ -422,9 +378,9 @@ TEST_F(AttributeTest, attrIpv6Addr) { << def_bytes->toText() << " != " << attr->toText(); EXPECT_THROW_MSG(attr->toString(), TypeError, - "the attribute value type must be string or vsa, not ipv6addr"); + "the attribute value type must be string, not ipv6addr"); EXPECT_THROW_MSG(attr->toBinary(), TypeError, - "the attribute value type must be string or vsa, not ipv6addr"); + "the attribute value type must be string, not ipv6addr"); EXPECT_THROW_MSG(attr->toInt(), TypeError, "the attribute value type must be integer, not ipv6addr"); EXPECT_THROW_MSG(attr->toIpAddr(), TypeError, @@ -435,6 +391,8 @@ TEST_F(AttributeTest, attrIpv6Addr) { "the attribute value type must be ipv6prefix, not ipv6addr"); EXPECT_THROW_MSG(attr->toVendorId(), TypeError, "the attribute value type must be vsa, not ipv6addr"); + EXPECT_THROW_MSG(attr->toVsaData(), TypeError, + "the attribute value type must be vsa, not ipv6addr"); } // Verifies IPv6 prefix attribute. @@ -466,28 +424,11 @@ TEST_F(AttributeTest, attrIpv6Prefix) { expected += " \"data\": \"2001:db8::1235/128\" }"; runToElementTest(expected, *attr); - AttributePtr from_text; - EXPECT_NO_THROW_LOG(from_text = Attribute::fromText("Delegated-IPv6-Prefix=2001:db8::1235/128")); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - - EXPECT_THROW_MSG(Attribute::fromText("Delegated-IPv6-Prefix=192.0.2.1/32"), - BadValue, "not v6 address 192.0.2.1"); - AttributePtr def_text; EXPECT_NO_THROW_LOG(def_text = Attribute::fromText(def, "2001:db8::1235/128")); - ASSERT_TRUE(from_text); - EXPECT_TRUE(compare(from_text, attr)) - << from_text->toText() << " != " << attr->toText(); - - string long_prefix = "Delegated-IPv6-Prefix=2001:db8::1235/300"; - EXPECT_THROW_MSG(Attribute::fromText(long_prefix), BadValue, - "not 8 bit prefix length 2001:db8::1235/300"); - - long_prefix = "Delegated-IPv6-Prefix=2001:db8::1235/129"; - EXPECT_THROW_MSG(Attribute::fromText(long_prefix), BadValue, - "too long prefix 129"); + ASSERT_TRUE(def_text); + EXPECT_TRUE(compare(def_text, attr)) + << def_text->toText() << " != " << attr->toText(); AttributePtr from_bytes; EXPECT_NO_THROW_LOG(from_bytes = Attribute::fromBytes(binary)); @@ -533,9 +474,9 @@ TEST_F(AttributeTest, attrIpv6Prefix) { << def_bytes->toText() << " != " << attr->toText(); EXPECT_THROW_MSG(attr->toString(), TypeError, - "the attribute value type must be string or vsa, not ipv6prefix"); + "the attribute value type must be string, not ipv6prefix"); EXPECT_THROW_MSG(attr->toBinary(), TypeError, - "the attribute value type must be string or vsa, not ipv6prefix"); + "the attribute value type must be string, not ipv6prefix"); EXPECT_THROW_MSG(attr->toInt(), TypeError, "the attribute value type must be integer, not ipv6prefix"); EXPECT_THROW_MSG(attr->toIpAddr(), TypeError, @@ -544,6 +485,109 @@ TEST_F(AttributeTest, attrIpv6Prefix) { "the attribute value type must be ipv6addr, not ipv6prefix"); EXPECT_THROW_MSG(attr->toVendorId(), TypeError, "the attribute value type must be vsa, not ipv6prefix"); + EXPECT_THROW_MSG(attr->toVsaData(), TypeError, + "the attribute value type must be vsa, not ipv6prefix"); +} + +// Verifies vsa attribute. +TEST_F(AttributeTest, attrVsa) { + // Using Vector-Specific (26) *only* vsa attribute. + AttrDefPtr def = AttrDefs::instance().getByType(PW_VENDOR_SPECIFIC); + ASSERT_TRUE(def); + EXPECT_EQ(26, def->type_); + EXPECT_EQ(PW_TYPE_VSA, def->value_type_); + + AttributePtr attr; + ASSERT_NO_THROW(attr = Attribute::fromVsa(PW_VENDOR_SPECIFIC, + 1234, "foobar")); + ASSERT_TRUE(attr); + + EXPECT_EQ(26, attr->getType()); + EXPECT_EQ(PW_TYPE_VSA, attr->getValueType()); + uint32_t vendor = 0; + ASSERT_NO_THROW(vendor = attr->toVendorId()); + EXPECT_EQ(1234, vendor); + EXPECT_EQ("Vendor-Specific=[1234]0x666F6F626172", attr->toText()); + vector binary = { 26, 12, 0, 0, 0x04, 0xd2, + 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72 }; + EXPECT_EQ(binary, attr->toBytes()); + string expected = "{ \"type\": 26, \"name\": \"Vendor-Specific\", "; + expected += " \"vendor\": \"1234\", \"vsa-raw\": \"666F6F626172\" }"; + runToElementTest(expected, *attr); + + AttributePtr from_bytes = Attribute::fromBytes(binary); + ASSERT_TRUE(from_bytes); + EXPECT_TRUE(compare(from_bytes, attr)) + << from_bytes->toText() << " != " << attr->toText(); + + vector value = { 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72 }; + AttributePtr def_value = Attribute::fromVsa(PW_VENDOR_SPECIFIC, + 1234, value); + ASSERT_TRUE(def_value); + EXPECT_TRUE(compare(def_value, attr)) + << def_value->toText() << " != " << attr->toText(); + + vector bytes = { 0, 0, 0x04, 0xd2, + 0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72 }; + AttributePtr def_bytes = Attribute::fromBytes(def, bytes); + ASSERT_TRUE(def_bytes); + EXPECT_TRUE(compare(def_bytes, attr)) + << def_bytes->toText() << " != " << attr->toText(); + + EXPECT_THROW_MSG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, 1234, ""), + BadValue, "value is empty"); + + vector empty; + EXPECT_THROW_MSG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, 1234, empty), + BadValue, "value is empty"); + + vector small = { 26, 6, 0, 0, 0x4, 0xd2 }; + EXPECT_THROW_MSG(Attribute::fromBytes(small), BadValue, + "value is too small 4 < 5"); + + vector small2 = { 0, 0, 0x4, 0xd2 }; + EXPECT_THROW_MSG(Attribute::fromBytes(def, small2), BadValue, + "value is too small 4 < 5"); + + string big_text(MAX_VSA_DATA_LEN, 'x'); + EXPECT_NO_THROW_LOG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, + 1234, big_text)); + + vector big_binary(MAX_VSA_DATA_LEN, 0x78); + EXPECT_NO_THROW_LOG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, + 1234, big_binary)); + + vector big_value(MAX_STRING_LEN, 0x87); + EXPECT_NO_THROW_LOG(Attribute::fromBytes(def, big_value)); + + string too_big_text(MAX_VSA_DATA_LEN + 1, 'x'); + EXPECT_THROW_MSG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, 1234, + too_big_text), BadValue, + "value is too large 250 > 249"); + + vector too_big_binary(MAX_VSA_DATA_LEN + 1, 0x87); + EXPECT_THROW_MSG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, 1234, + too_big_binary), BadValue, + "value is too large 250 > 249"); + + vector too_bigvalue(MAX_STRING_LEN + 1, 0x87); + EXPECT_THROW_MSG(Attribute::fromBytes(def, too_bigvalue), BadValue, + "value is too large 254 > 253"); + + EXPECT_THROW_MSG(attr->toString(), TypeError, + "the attribute value type must be string, not vsa"); + EXPECT_THROW_MSG(attr->toBinary(), TypeError, + "the attribute value type must be string, not vsa"); + EXPECT_THROW_MSG(attr->toInt(), TypeError, + "the attribute value type must be integer, not vsa"); + EXPECT_THROW_MSG(attr->toIpAddr(), TypeError, + "the attribute value type must be ipaddr, not vsa"); + EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError, + "the attribute value type must be ipv6addr, not vsa"); + EXPECT_THROW_MSG(attr->toIpv6Prefix(), TypeError, + "the attribute value type must be ipv6prefix, not vsa"); + EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError, + "the attribute value type must be ipv6prefix, not vsa"); } // Verifies basic methods for attribute collection. @@ -604,8 +648,8 @@ TEST_F(AttributeTest, attributesAddDel) { attr.reset(); // toText. - string expected = "User-Name=foobar,\nUser-Name=foo,\n"; - expected += "Service-Type=20,\nUser-Name=bar"; + string expected = "User-Name='foobar',\nUser-Name='foo',\n"; + expected += "Service-Type=20,\nUser-Name='bar'"; string got; ASSERT_NO_THROW(got = attrs.toText()); EXPECT_EQ(expected, got) << expected << "\n" << got << "\n"; diff --git a/src/hooks/dhcp/radius/tests/config_unittests.cc b/src/hooks/dhcp/radius/tests/config_unittests.cc index f1caf080d8..d060aa21bc 100644 --- a/src/hooks/dhcp/radius/tests/config_unittests.cc +++ b/src/hooks/dhcp/radius/tests/config_unittests.cc @@ -792,7 +792,7 @@ TEST_F(ConfigTest, attribute) { ASSERT_EQ(1, attrs.size()); const ConstAttributePtr& first = *attrs.cbegin(); ASSERT_TRUE(first); - EXPECT_EQ("User-Name=foobar", first->toText()); + EXPECT_EQ("User-Name='foobar'", first->toText()); // Another way to check. string expected = "[ { " @@ -801,6 +801,15 @@ TEST_F(ConfigTest, attribute) { " \"data\": \"foobar\" } ]"; runToElementTest(expected, srv->attributes_); + // Vendor-Specific (26) does not support textual data. + srv->attributes_.clear(); + attr = Element::createMap(); + attr->set("data", Element::create("foobar")); + attr->set("type", Element::create(26)); + expected = "can't create Vendor-Specific attribute from [foobar]: "; + expected += "Can't decode vsa from text"); + EXPECT_THROW_MSG(parser.parse(srv, attr), ConfigError, expected); + // One of expr, data, raw srv->attributes_.clear(); attr = Element::createMap(); @@ -845,9 +854,7 @@ TEST_F(ConfigTest, attribute) { EXPECT_EQ("", srv->attributes_.getTest(1)); const ConstAttributePtr& firstr = srv->attributes_.get(1); ASSERT_TRUE(firstr); - expected = "User-Name=f\x01\x02"; - expected += "bar"; - EXPECT_EQ(expected, firstr->toText()); + EXPECT_EQ("User-Name=0x660102626172", firstr->toText()); expected = "[ { " " \"name\": \"User-Name\", " " \"type\": 1, " diff --git a/src/hooks/dhcp/radius/tests/dictionary_unittests.cc b/src/hooks/dhcp/radius/tests/dictionary_unittests.cc index a0589478d3..9cbacbe61e 100644 --- a/src/hooks/dhcp/radius/tests/dictionary_unittests.cc +++ b/src/hooks/dhcp/radius/tests/dictionary_unittests.cc @@ -140,6 +140,8 @@ TEST_F(DictionaryTest, parseLine) { "expected 3 tokens, got 2 at line 1"); EXPECT_THROW_MSG(parseLine("VENDOR my-vendor 44 17"), BadValue, "expected 3 tokens, got 4 at line 1"); + EXPECT_THROW_MSG(parseLine("VENDOR my-vendor 0"), BadValue, + "0 is reserved at line 1"); EXPECT_THROW_MSG(parseLine("BEGIN-VENDOR my-vendor"), BadValue, "unknown dictionary entry 'BEGIN-VENDOR' at line 1"); diff --git a/src/hooks/dhcp/radius/tests/request_unittests.h b/src/hooks/dhcp/radius/tests/request_unittests.h index 05aafd88cb..981a3b6dc5 100644 --- a/src/hooks/dhcp/radius/tests/request_unittests.h +++ b/src/hooks/dhcp/radius/tests/request_unittests.h @@ -743,7 +743,7 @@ TEST_F(RequestTest, accept) { ASSERT_EQ(1, received_attributes_->count(1)); const ConstAttributePtr& attr = received_attributes_->get(1); ASSERT_TRUE(attr); - EXPECT_EQ("User-Name=user", attr->toText()); + EXPECT_EQ("User-Name='user'", attr->toText()); } /// Verify what happens with Accounting-Response response. @@ -938,7 +938,7 @@ TEST_F(RequestTest, badAccept) { ASSERT_EQ(1, received_attributes_->count(1)); const ConstAttributePtr& attr = received_attributes_->get(1); ASSERT_TRUE(attr); - EXPECT_EQ("User-Name=user", attr->toText()); + EXPECT_EQ("User-Name='user'", attr->toText()); } /// Verify what happens with bad Accounting-Response response. @@ -1326,7 +1326,7 @@ TEST_F(RequestTest, reject) { ASSERT_EQ(1, received_attributes_->count(1)); const ConstAttributePtr& attr = received_attributes_->get(1); ASSERT_TRUE(attr); - EXPECT_EQ("User-Name=user", attr->toText()); + EXPECT_EQ("User-Name='user'", attr->toText()); } /// Verify what happens with a backup authentication server. @@ -1427,7 +1427,7 @@ TEST_F(RequestTest, accept2) { ASSERT_EQ(1, received_attributes_->count(1)); const ConstAttributePtr& attr = received_attributes_->get(1); ASSERT_TRUE(attr); - EXPECT_EQ("User-Name=user", attr->toText()); + EXPECT_EQ("User-Name='user'", attr->toText()); } /// Verify what happens with a backup accounting server.