mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-22 01:49:48 +00:00
Compare commits
8 Commits
49acb1b426
...
65c54cb880
Author | SHA1 | Date | |
---|---|---|---|
|
65c54cb880 | ||
|
88dbb7c529 | ||
|
2c6fb35352 | ||
|
b52f4b9549 | ||
|
bd819aa229 | ||
|
d7847c4bde | ||
|
662e780069 | ||
|
1d3472a2d1 |
@ -0,0 +1,4 @@
|
||||
[bug] fdupont
|
||||
When reusing an expired lease, kea-dhcp6 now correctly saves
|
||||
the client hardware address in the lease.
|
||||
(Gitlab #4058)
|
@ -550,7 +550,7 @@ RADIUS dictionary. There are differences:
|
||||
|
||||
- Yes
|
||||
|
||||
- No
|
||||
- since Kea 3.1.1
|
||||
|
||||
* - Support for Vendor Attributes
|
||||
|
||||
|
@ -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) {
|
||||
@ -80,6 +50,8 @@ Attribute::fromText(const AttrDefPtr& def, const string& value) {
|
||||
return (AttrIpv6Addr::fromText(def->type_, value));
|
||||
case PW_TYPE_IPV6PREFIX:
|
||||
return (AttrIpv6Prefix::fromText(def->type_, value));
|
||||
case PW_TYPE_VSA:
|
||||
return (AttrVsa::fromText(def->type_, value));
|
||||
default:
|
||||
// Impossible case.
|
||||
isc_throw(OutOfRange, "unknown value type "
|
||||
@ -131,6 +103,8 @@ Attribute::fromBytes(const AttrDefPtr& def, const vector<uint8_t>& value) {
|
||||
return (AttrIpv6Addr::fromBytes(def->type_, value));
|
||||
case PW_TYPE_IPV6PREFIX:
|
||||
return (AttrIpv6Prefix::fromBytes(def->type_, value));
|
||||
case PW_TYPE_VSA:
|
||||
return (AttrVsa::fromBytes(def->type_, value));
|
||||
default:
|
||||
// Impossible case.
|
||||
isc_throw(OutOfRange, "unknown value type "
|
||||
@ -175,6 +149,18 @@ 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<uint8_t>& value) {
|
||||
return (AttributePtr(new AttrVsa(type, vendor, value)));
|
||||
}
|
||||
|
||||
string
|
||||
Attribute::toString() const {
|
||||
isc_throw(TypeError, "the attribute value type must be string, not "
|
||||
@ -217,6 +203,18 @@ Attribute::toIpv6PrefixLen() const {
|
||||
<< attrValueTypeToText(getValueType()));
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Attribute::toVendorId() const {
|
||||
isc_throw(TypeError, "the attribute value type must be vsa, not "
|
||||
<< attrValueTypeToText(getValueType()));
|
||||
}
|
||||
|
||||
string
|
||||
Attribute::toVsaData() const {
|
||||
isc_throw(TypeError, "the attribute value type must be vsa, not "
|
||||
<< attrValueTypeToText(getValueType()));
|
||||
}
|
||||
|
||||
AttrString::AttrString(const uint8_t type, const vector<uint8_t>& value)
|
||||
: Attribute(type), value_() {
|
||||
if (value.empty()) {
|
||||
@ -260,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<uint8_t> 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());
|
||||
}
|
||||
|
||||
@ -612,6 +620,102 @@ AttrIpv6Prefix::toElement() const {
|
||||
return (output);
|
||||
}
|
||||
|
||||
AttrVsa::AttrVsa(const uint8_t type, const uint32_t vendor,
|
||||
const vector<uint8_t>& value)
|
||||
: Attribute(type), vendor_(vendor), value_() {
|
||||
if (value.empty()) {
|
||||
isc_throw(BadValue, "value is empty");
|
||||
}
|
||||
if (value.size() > MAX_VSA_DATA_LEN) {
|
||||
isc_throw(BadValue, "value is too large " << value.size()
|
||||
<< " > " << MAX_VSA_DATA_LEN);
|
||||
}
|
||||
value_.resize(value.size());
|
||||
memmove(&value_[0], &value[0], value_.size());
|
||||
}
|
||||
|
||||
AttributePtr
|
||||
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<uint8_t>& bytes) {
|
||||
if (bytes.empty()) {
|
||||
isc_throw(BadValue, "empty attribute value");
|
||||
}
|
||||
if (bytes.size() < 5) {
|
||||
isc_throw(BadValue, "value is too small " << bytes.size() << " < 5");
|
||||
} else if (bytes.size() > MAX_STRING_LEN) {
|
||||
isc_throw(BadValue, "value is too large " << bytes.size()
|
||||
<< " > " << MAX_STRING_LEN);
|
||||
}
|
||||
uint32_t vendor = bytes[0] << 24;
|
||||
vendor |= bytes[1] << 16;
|
||||
vendor |= bytes[2] << 8;
|
||||
vendor |= bytes[3];
|
||||
vector<uint8_t> value;
|
||||
value.resize(bytes.size() - 4);
|
||||
if (value.size() > 0) {
|
||||
memmove(&value[0], &bytes[4], value.size());
|
||||
}
|
||||
return (AttributePtr(new AttrVsa(type, vendor, value)));
|
||||
}
|
||||
|
||||
string
|
||||
AttrVsa::toText(size_t indent) const {
|
||||
ostringstream output;
|
||||
for (size_t i = 0; i < indent; i++) {
|
||||
output << " ";
|
||||
}
|
||||
output << AttrDefs::instance().getName(getType()) << "=["
|
||||
<< vendor_ << "]";
|
||||
vector<uint8_t> 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<uint8_t>
|
||||
AttrVsa::toBytes() const {
|
||||
vector<uint8_t> output;
|
||||
output.resize(2 + getValueLen());
|
||||
output[0] = getType();
|
||||
output[1] = 2 + getValueLen();
|
||||
output[2] = (vendor_ & 0xff000000U) >> 24;
|
||||
output[3] = (vendor_ & 0xff0000U) >> 16;
|
||||
output[4] = (vendor_ & 0xff00U) >> 8;
|
||||
output[5] = vendor_ & 0xffU;
|
||||
if (output.size() > 6) {
|
||||
memmove(&output[6], &value_[0], output.size() - 6);
|
||||
}
|
||||
return (output);
|
||||
}
|
||||
|
||||
ElementPtr
|
||||
AttrVsa::toElement() const {
|
||||
ElementPtr output = Element::createMap();
|
||||
AttrDefPtr def = AttrDefs::instance().getByType(getType());
|
||||
if (def) {
|
||||
output->set("name", Element::create(def->name_));
|
||||
}
|
||||
output->set("type", Element::create(static_cast<int>(getType())));
|
||||
ostringstream vendor;
|
||||
vendor << vendor_;
|
||||
output->set("vendor", Element::create(vendor.str()));
|
||||
vector<uint8_t> binary;
|
||||
binary.resize(value_.size());
|
||||
if (binary.size() > 0) {
|
||||
memmove(&binary[0], value_.c_str(), binary.size());
|
||||
}
|
||||
string raw = encode::encodeHex(binary);
|
||||
output->set("vsa-raw", Element::create(raw));
|
||||
return (output);
|
||||
}
|
||||
|
||||
void
|
||||
Attributes::add(const ConstAttributePtr& attr) {
|
||||
if (!attr) {
|
||||
|
@ -28,6 +28,9 @@ namespace radius {
|
||||
/// @brief Maximum string size.
|
||||
static constexpr size_t MAX_STRING_LEN = 253;
|
||||
|
||||
/// @brief Maximum vsa data size.
|
||||
static constexpr size_t MAX_VSA_DATA_LEN = MAX_STRING_LEN - 4;
|
||||
|
||||
/// @brief Type error.
|
||||
using isc::data::TypeError;
|
||||
|
||||
@ -66,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.
|
||||
@ -159,6 +155,28 @@ public:
|
||||
const uint8_t len,
|
||||
const asiolink::IOAddress& value);
|
||||
|
||||
/// @brief From Vendor ID and string data with type.
|
||||
///
|
||||
/// @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,
|
||||
const uint32_t vendor,
|
||||
const std::string& value);
|
||||
|
||||
/// @brief From Vendor ID and binary data with type.
|
||||
///
|
||||
/// @note Requires the type to be of the Vendor Specific attribute (26).
|
||||
///
|
||||
/// @param type type of attribute.
|
||||
/// @param vendor vendor id.
|
||||
/// @param value vsa data.
|
||||
static AttributePtr fromVsa(const uint8_t type,
|
||||
const uint32_t vendor,
|
||||
const std::vector<uint8_t>& value);
|
||||
|
||||
/// Generic get methods.
|
||||
|
||||
/// @brief Value length.
|
||||
@ -223,6 +241,18 @@ public:
|
||||
/// @throw TypeError if the attribute is not an ipv6prefix one.
|
||||
virtual uint8_t toIpv6PrefixLen() const;
|
||||
|
||||
/// @brief To vendor id.
|
||||
///
|
||||
/// @return the vendor id.
|
||||
/// @throw TypeError if the attribute is not a vsa one.
|
||||
virtual uint32_t toVendorId() const;
|
||||
|
||||
/// @brief To vsa data.
|
||||
///
|
||||
/// @return the vsa data.
|
||||
/// @throw TypeError if the attribute is not a vsa one.
|
||||
virtual std::string toVsaData() const;
|
||||
|
||||
/// @brief Type.
|
||||
const uint8_t type_;
|
||||
};
|
||||
@ -233,6 +263,7 @@ public:
|
||||
/// @brief RADIUS attribute holding strings.
|
||||
class AttrString : public Attribute {
|
||||
protected:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param type attribute type.
|
||||
@ -648,6 +679,109 @@ private:
|
||||
asiolink::IOAddress value_;
|
||||
};
|
||||
|
||||
/// @brief RADIUS attribute holding vsa.
|
||||
class AttrVsa : public Attribute {
|
||||
protected:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param type attribute type.
|
||||
/// @param vendor vendor id.
|
||||
/// @param value string vsa data.
|
||||
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");
|
||||
}
|
||||
if (value.size() > MAX_VSA_DATA_LEN) {
|
||||
isc_throw(BadValue, "value is too large " << value.size()
|
||||
<< " > " << MAX_VSA_DATA_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param type attribute type.
|
||||
/// @param vendor vendor id.
|
||||
/// @param value binary vsa data.
|
||||
AttrVsa(const uint8_t type, const uint32_t vendor,
|
||||
const std::vector<uint8_t>& value);
|
||||
|
||||
/// @brief From text.
|
||||
///
|
||||
/// @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.
|
||||
///
|
||||
/// @param type attribute type.
|
||||
/// @param bytes binary value.
|
||||
/// @return pointer to the attribute or null.
|
||||
static AttributePtr fromBytes(const uint8_t type,
|
||||
const std::vector<uint8_t>& bytes);
|
||||
|
||||
/// Make Attribute a friend class.
|
||||
friend class Attribute;
|
||||
|
||||
public:
|
||||
|
||||
/// @brief Get value type.
|
||||
///
|
||||
/// @return the value type.
|
||||
virtual AttrValueType getValueType() const override {
|
||||
return (PW_TYPE_VSA);
|
||||
}
|
||||
|
||||
/// @brief Value length.
|
||||
///
|
||||
/// @return Value length.
|
||||
virtual size_t getValueLen() const override {
|
||||
return (4 + value_.size());
|
||||
}
|
||||
|
||||
/// @brief Returns text representation of the attribute.
|
||||
///
|
||||
/// @param indent number of spaces before printing text.
|
||||
/// @return string with text representation.
|
||||
virtual std::string toText(size_t indent = 0) const override;
|
||||
|
||||
/// @brief To bytes.
|
||||
///
|
||||
/// @return binary representation.
|
||||
virtual std::vector<uint8_t> toBytes() const override;
|
||||
|
||||
/// @brief To vendor id.
|
||||
///
|
||||
/// @return the vendor id.
|
||||
virtual uint32_t toVendorId() const override {
|
||||
return (vendor_);
|
||||
}
|
||||
|
||||
/// @brief To vsa data.
|
||||
///
|
||||
/// @return the vsa data.
|
||||
virtual std::string toVsaData() const override {
|
||||
return (value_);
|
||||
}
|
||||
|
||||
/// @brief Unparse attribute.
|
||||
///
|
||||
/// @return a pointer to unparsed attribute.
|
||||
virtual data::ElementPtr toElement() const override;
|
||||
|
||||
private:
|
||||
/// @brief Vendor id.
|
||||
uint32_t vendor_;
|
||||
|
||||
/// @brief Value.
|
||||
std::string value_;
|
||||
};
|
||||
|
||||
|
||||
/// @brief Collection of attributes.
|
||||
class Attributes : public data::CfgToElement {
|
||||
public:
|
||||
|
@ -34,6 +34,8 @@ attrValueTypeToText(const AttrValueType value) {
|
||||
return ("ipv6addr");
|
||||
case PW_TYPE_IPV6PREFIX:
|
||||
return ("ipv6prefix");
|
||||
case PW_TYPE_VSA:
|
||||
return ("vsa");
|
||||
default:
|
||||
// Impossible case.
|
||||
return ("unknown?");
|
||||
@ -52,6 +54,8 @@ textToAttrValueType(const string& name) {
|
||||
return (PW_TYPE_IPV6ADDR);
|
||||
} else if (name == "ipv6prefix") {
|
||||
return (PW_TYPE_IPV6PREFIX);
|
||||
} else if (name == "vsa") {
|
||||
return (PW_TYPE_VSA);
|
||||
} else {
|
||||
isc_throw(OutOfRange, "unknown AttrValueType name " << name);
|
||||
}
|
||||
@ -64,9 +68,9 @@ AttrDefs::instance() {
|
||||
}
|
||||
|
||||
AttrDefPtr
|
||||
AttrDefs::getByType(const uint8_t type) const {
|
||||
AttrDefs::getByType(const uint8_t type, const uint32_t vendor) const {
|
||||
auto const& idx = container_.get<0>();
|
||||
auto it = idx.find(type);
|
||||
auto it = idx.find(boost::make_tuple(vendor, type));
|
||||
if (it != idx.end()) {
|
||||
return (*it);
|
||||
}
|
||||
@ -74,15 +78,15 @@ AttrDefs::getByType(const uint8_t type) const {
|
||||
}
|
||||
|
||||
AttrDefPtr
|
||||
AttrDefs::getByName(const string& name) const {
|
||||
AttrDefs::getByName(const string& name, const uint32_t vendor) const {
|
||||
auto const& idx = container_.get<1>();
|
||||
auto it = idx.find(name);
|
||||
auto it = idx.find(boost::make_tuple(vendor, name));
|
||||
if (it != idx.end()) {
|
||||
return (*it);
|
||||
}
|
||||
auto alias = aliases_.find(name);
|
||||
auto alias = aliases_.find(boost::make_tuple(vendor, name));
|
||||
if (alias != aliases_.end()) {
|
||||
auto ita = idx.find(alias->second);
|
||||
auto ita = idx.find(boost::make_tuple(vendor, alias->name_));
|
||||
if (ita != idx.end()) {
|
||||
return (*ita);
|
||||
}
|
||||
@ -96,42 +100,51 @@ AttrDefs::add(AttrDefPtr def) {
|
||||
return;
|
||||
}
|
||||
auto& idx1 = container_.get<1>();
|
||||
auto it1 = idx1.find(def->name_);
|
||||
auto it1 = idx1.find(boost::make_tuple(def->vendor_, def->name_));
|
||||
if (it1 != idx1.end()) {
|
||||
if ((def->type_ == (*it1)->type_) &&
|
||||
(def->value_type_ == (*it1)->value_type_)) {
|
||||
// Duplicate: ignore.
|
||||
return;
|
||||
}
|
||||
isc_throw(BadValue, "Illegal attribute redefinition of '" << def->name_
|
||||
<< "' type " << static_cast<unsigned>((*it1)->type_)
|
||||
<< " value type " << attrValueTypeToText((*it1)->value_type_)
|
||||
<< " by " << static_cast<unsigned>(def->type_)
|
||||
<< " " << attrValueTypeToText(def->value_type_));
|
||||
ostringstream msg;
|
||||
msg << "Illegal attribute redefinition of '" << def->name_ << "'";
|
||||
if (def->vendor_ != 0) {
|
||||
msg << " vendor " << def->vendor_;
|
||||
}
|
||||
msg << " type " << static_cast<unsigned>((*it1)->type_)
|
||||
<< " value type " << attrValueTypeToText((*it1)->value_type_)
|
||||
<< " by " << static_cast<unsigned>(def->type_)
|
||||
<< " " << attrValueTypeToText(def->value_type_);
|
||||
isc_throw(BadValue, msg.str());
|
||||
}
|
||||
auto& idx0 = container_.get<0>();
|
||||
auto it0 = idx0.find(def->type_);
|
||||
auto it0 = idx0.find(boost::make_tuple(def->vendor_, def->type_));
|
||||
if (it0 != idx0.end()) {
|
||||
if (def->value_type_ == (*it0)->value_type_) {
|
||||
// Alias.
|
||||
auto p = pair<string, string>(def->name_, (*it0)->name_);
|
||||
static_cast<void>(aliases_.insert(p));
|
||||
AttrDefAlias alias(def->name_, (*it0)->name_, def->vendor_);
|
||||
static_cast<void>(aliases_.insert(alias));
|
||||
return;
|
||||
}
|
||||
isc_throw(BadValue, "Illegal attribute redefinition of '"
|
||||
<< (*it0)->name_ << "' type "
|
||||
<< static_cast<unsigned>((*it0)->type_) << " value type "
|
||||
<< attrValueTypeToText((*it0)->value_type_)
|
||||
<< " by '" << def->name_ << "' "
|
||||
<< static_cast<unsigned>(def->type_) << " "
|
||||
<< attrValueTypeToText(def->value_type_));
|
||||
ostringstream msg;
|
||||
msg << "Illegal attribute redefinition of '" << (*it0)->name_ << "'";
|
||||
if (def->vendor_ != 0) {
|
||||
msg << " vendor " << def->vendor_;
|
||||
}
|
||||
msg << " type " << static_cast<unsigned>((*it0)->type_)
|
||||
<< " value type " << attrValueTypeToText((*it0)->value_type_)
|
||||
<< " by '" << def->name_ << "' "
|
||||
<< static_cast<unsigned>(def->type_) << " "
|
||||
<< attrValueTypeToText(def->value_type_);
|
||||
isc_throw(BadValue, msg.str());
|
||||
}
|
||||
static_cast<void>(container_.insert(def));
|
||||
}
|
||||
|
||||
string
|
||||
AttrDefs::getName(const uint8_t type) const {
|
||||
AttrDefPtr def = getByType(type);
|
||||
AttrDefs::getName(const uint8_t type, const uint32_t vendor) const {
|
||||
AttrDefPtr def = getByType(type, vendor);
|
||||
if (def) {
|
||||
return (def->name_);
|
||||
}
|
||||
@ -172,6 +185,12 @@ AttrDefs::add(IntCstDefPtr def) {
|
||||
// Duplicate: ignore.
|
||||
return;
|
||||
}
|
||||
if (def->type_ == PW_VENDOR_SPECIFIC) {
|
||||
// Vendor id special case.
|
||||
isc_throw(BadValue, "Illegal vendor id redefinition of '"
|
||||
<< def->name_ << "' value " << (*it)->value_
|
||||
<< " by " << def->value_);
|
||||
}
|
||||
isc_throw(BadValue, "Illegal integer constant redefinition of '"
|
||||
<< def->name_ << "' for attribute '" << getName(def->type_)
|
||||
<< "' value " << (*it)->value_ << " by " << def->value_);
|
||||
@ -180,7 +199,7 @@ AttrDefs::add(IntCstDefPtr def) {
|
||||
}
|
||||
|
||||
void
|
||||
AttrDefs::parseLine(const string& line) {
|
||||
AttrDefs::parseLine(const string& line, unsigned int depth) {
|
||||
// Ignore empty lines.
|
||||
if (line.empty()) {
|
||||
return;
|
||||
@ -196,6 +215,14 @@ AttrDefs::parseLine(const string& line) {
|
||||
if (tokens.empty()) {
|
||||
return;
|
||||
}
|
||||
// $INCLUDE include.
|
||||
if (tokens[0] == "$INCLUDE") {
|
||||
if (tokens.size() != 2) {
|
||||
isc_throw(Unexpected, "expected 2 tokens, got " << tokens.size());
|
||||
}
|
||||
readDictionary(tokens[1], depth + 1);
|
||||
return;
|
||||
}
|
||||
// Attribute definition.
|
||||
if (tokens[0] == "ATTRIBUTE") {
|
||||
if (tokens.size() != 4) {
|
||||
@ -216,6 +243,10 @@ AttrDefs::parseLine(const string& line) {
|
||||
isc_throw(Unexpected, "can't parse attribute type " << type_str);
|
||||
}
|
||||
AttrValueType value_type = textToAttrValueType(tokens[3]);
|
||||
if ((value_type == PW_TYPE_VSA) && (type != PW_VENDOR_SPECIFIC)) {
|
||||
isc_throw(BadValue, "only Vendor-Specific (26) attribute can "
|
||||
<< "have the vsa data type");
|
||||
}
|
||||
AttrDefPtr def(new AttrDef(type, name, value_type));
|
||||
add(def);
|
||||
return;
|
||||
@ -251,11 +282,39 @@ AttrDefs::parseLine(const string& line) {
|
||||
add(def);
|
||||
return;
|
||||
}
|
||||
// Vendor id definition.
|
||||
if (tokens[0] == "VENDOR") {
|
||||
if (tokens.size() != 3) {
|
||||
isc_throw(Unexpected, "expected 3 tokens, got " << tokens.size());
|
||||
}
|
||||
const string& name = tokens[1];
|
||||
const string& value_str = tokens[2];
|
||||
uint32_t value = 0;
|
||||
try {
|
||||
int64_t val = boost::lexical_cast<int64_t>(value_str);
|
||||
if ((val < numeric_limits<int32_t>::min()) ||
|
||||
(val > numeric_limits<uint32_t>::max())) {
|
||||
isc_throw(Unexpected, "not 32 bit " << value_str);
|
||||
}
|
||||
value = static_cast<uint32_t>(val);
|
||||
} 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;
|
||||
}
|
||||
isc_throw(Unexpected, "unknown dictionary entry '" << tokens[0] << "'");
|
||||
}
|
||||
|
||||
void
|
||||
AttrDefs::readDictionary(const string& path) {
|
||||
AttrDefs::readDictionary(const string& path, unsigned depth) {
|
||||
if (depth >= 5) {
|
||||
isc_throw(BadValue, "Too many nested $INCLUDE");
|
||||
}
|
||||
ifstream ifs(path);
|
||||
if (!ifs.is_open()) {
|
||||
isc_throw(BadValue, "can't open dictionary '" << path << "': "
|
||||
@ -265,23 +324,24 @@ AttrDefs::readDictionary(const string& path) {
|
||||
isc_throw(BadValue, "bad dictionary '" << path << "'");
|
||||
}
|
||||
try {
|
||||
readDictionary(ifs);
|
||||
readDictionary(ifs, depth);
|
||||
ifs.close();
|
||||
} catch (const exception& ex) {
|
||||
ifs.close();
|
||||
isc_throw(BadValue, ex.what() << " in dictionary '" << path << "'");
|
||||
isc_throw(BadValue, ex.what() << " in dictionary '" << path << "'"
|
||||
<< (depth > 0 ? "," : ""));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
AttrDefs::readDictionary(istream& is) {
|
||||
AttrDefs::readDictionary(istream& is, unsigned int depth) {
|
||||
size_t lines = 0;
|
||||
string line;
|
||||
try {
|
||||
while (is.good()) {
|
||||
++lines;
|
||||
getline(is, line);
|
||||
parseLine(line);
|
||||
parseLine(line, depth);
|
||||
}
|
||||
if (!is.eof()) {
|
||||
isc_throw(BadValue, "I/O error: " << strerror(errno));
|
||||
|
@ -31,7 +31,8 @@ enum AttrValueType {
|
||||
PW_TYPE_INTEGER,
|
||||
PW_TYPE_IPADDR,
|
||||
PW_TYPE_IPV6ADDR,
|
||||
PW_TYPE_IPV6PREFIX
|
||||
PW_TYPE_IPV6PREFIX,
|
||||
PW_TYPE_VSA
|
||||
};
|
||||
|
||||
/// @brief AttrValueType value -> name function.
|
||||
@ -57,9 +58,10 @@ public:
|
||||
/// @param type attribute type.
|
||||
/// @param name attribute name.
|
||||
/// @param value_type attribute value type.
|
||||
/// @param vendor vendor id (default 0).
|
||||
AttrDef(const uint8_t type, const std::string& name,
|
||||
const AttrValueType value_type)
|
||||
: type_(type), name_(name), value_type_(value_type) {
|
||||
const AttrValueType value_type, const uint32_t vendor = 0)
|
||||
: type_(type), name_(name), value_type_(value_type), vendor_(vendor) {
|
||||
}
|
||||
|
||||
/// @brief type.
|
||||
@ -70,6 +72,9 @@ public:
|
||||
|
||||
/// @brief value_type.
|
||||
const AttrValueType value_type_;
|
||||
|
||||
/// @brief vendor id (default 0).
|
||||
const uint32_t vendor_;
|
||||
};
|
||||
|
||||
/// @brief Shared pointers to Attribute definition.
|
||||
@ -78,7 +83,33 @@ typedef boost::shared_ptr<AttrDef> AttrDefPtr;
|
||||
/// @brief List of Attribute definitions.
|
||||
typedef std::list<AttrDef> AttrDefList;
|
||||
|
||||
/// @brief RADIUS attribute aliases.
|
||||
class AttrDefAlias {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// @param alias attribute alias name.
|
||||
/// @param name attribute name.
|
||||
/// @param vendor vendor id (default 0).
|
||||
AttrDefAlias(const std::string& alias, const std::string& name,
|
||||
const uint32_t vendor = 0)
|
||||
: alias_(alias), name_(name), vendor_(vendor) {
|
||||
}
|
||||
|
||||
/// @brief alias.
|
||||
const std::string alias_;
|
||||
|
||||
/// @brief name.
|
||||
const std::string name_;
|
||||
|
||||
/// @brief vendor id (default 0).
|
||||
const uint32_t vendor_;
|
||||
};
|
||||
|
||||
/// @brief RADIUS integer constant definitions.
|
||||
///
|
||||
/// Include vendor ids with Vendor-Specific attribute.
|
||||
class IntCstDef {
|
||||
public:
|
||||
|
||||
@ -115,23 +146,53 @@ public:
|
||||
AttrDefPtr,
|
||||
// Start specification of indexes here.
|
||||
boost::multi_index::indexed_by<
|
||||
// Hash index for by type.
|
||||
// Hash index for by vendor and type.
|
||||
boost::multi_index::hashed_unique<
|
||||
boost::multi_index::member<
|
||||
AttrDef, const uint8_t, &AttrDef::type_
|
||||
boost::multi_index::composite_key<
|
||||
AttrDef,
|
||||
boost::multi_index::member<
|
||||
AttrDef, const uint32_t, &AttrDef::vendor_
|
||||
>,
|
||||
boost::multi_index::member<
|
||||
AttrDef, const uint8_t, &AttrDef::type_
|
||||
>
|
||||
>
|
||||
>,
|
||||
// Hash index for by name.
|
||||
// Hash index for by vendor and name.
|
||||
boost::multi_index::hashed_unique<
|
||||
boost::multi_index::member<
|
||||
AttrDef, const std::string, &AttrDef::name_
|
||||
boost::multi_index::composite_key<
|
||||
AttrDef,
|
||||
boost::multi_index::member<
|
||||
AttrDef, const uint32_t, &AttrDef::vendor_
|
||||
>,
|
||||
boost::multi_index::member<
|
||||
AttrDef, const std::string, &AttrDef::name_
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
> AttrDefContainer;
|
||||
|
||||
/// @brief Type of the alias table (alias -> standard name map).
|
||||
typedef std::unordered_map<std::string, std::string> AttrDefAliases;
|
||||
typedef boost::multi_index_container<
|
||||
// This container stores aliases.
|
||||
AttrDefAlias,
|
||||
// Start specification of indexes here.
|
||||
boost::multi_index::indexed_by<
|
||||
// Hash index for by vendor and alias.
|
||||
boost::multi_index::hashed_unique<
|
||||
boost::multi_index::composite_key<
|
||||
AttrDefAlias,
|
||||
boost::multi_index::member<
|
||||
AttrDefAlias, const uint32_t, &AttrDefAlias::vendor_
|
||||
>,
|
||||
boost::multi_index::member<
|
||||
AttrDefAlias, const std::string, &AttrDefAlias::alias_
|
||||
>
|
||||
>
|
||||
>
|
||||
>
|
||||
> AttrDefAliases;
|
||||
|
||||
/// @brief Type of the integer constant definition container.
|
||||
typedef boost::multi_index_container<
|
||||
@ -173,17 +234,20 @@ public:
|
||||
/// @return the single instance.
|
||||
static AttrDefs& instance();
|
||||
|
||||
/// @brief Get attribute definition by type.
|
||||
/// @brief Get attribute definition by type and vendor.
|
||||
///
|
||||
/// @param type type to look for.
|
||||
/// @param vendor vendor id to look for (default 0).
|
||||
/// @return pointer to the attribute definition or null.
|
||||
AttrDefPtr getByType(const uint8_t type) const;
|
||||
AttrDefPtr getByType(const uint8_t type, const uint32_t vendor = 0) const;
|
||||
|
||||
/// @brief Get attribute definition by name.
|
||||
/// @brief Get attribute definition by name and vendor.
|
||||
///
|
||||
/// @param name name to look for.
|
||||
/// @param vendor vendor id to look for (default 0).
|
||||
/// @return pointer to the attribute definition or null.
|
||||
AttrDefPtr getByName(const std::string& name) const;
|
||||
AttrDefPtr getByName(const std::string& name,
|
||||
const uint32_t vendor = 0) const;
|
||||
|
||||
/// @brief Add (or replace) an attribute definition.
|
||||
///
|
||||
@ -200,7 +264,8 @@ public:
|
||||
/// @brief Get attribute name.
|
||||
///
|
||||
/// @param type type to look for.
|
||||
std::string getName(const uint8_t type) const;
|
||||
/// @param vendor vendor id to look for (default 0).
|
||||
std::string getName(const uint8_t type, const uint32_t vendor = 0) const;
|
||||
|
||||
/// @brief Get integer constant definition by attribute type and name.
|
||||
///
|
||||
@ -223,18 +288,22 @@ public:
|
||||
/// @brief Read a dictionary from a file.
|
||||
///
|
||||
/// Fills attribute and integer constant definition tables from
|
||||
/// a dictionary file.
|
||||
/// a dictionary file. Recursion depth is initialized to 0,
|
||||
/// incremented by includes and limited to 5.
|
||||
///
|
||||
/// @param path dictionary file path.
|
||||
void readDictionary(const std::string& path);
|
||||
/// @param depth recursion depth.
|
||||
void readDictionary(const std::string& path, unsigned int depth = 0);
|
||||
|
||||
/// @brief Read a dictionary from an input stream.
|
||||
///
|
||||
/// Fills attribute and integer constant definition tables from
|
||||
/// a dictionary input stream.
|
||||
/// a dictionary input stream. Recursion depth is initialized to 0,
|
||||
/// incremented by includes and limited to 5.
|
||||
///
|
||||
/// @param is input stream.
|
||||
void readDictionary(std::istream& is);
|
||||
/// @param depth recursion depth.
|
||||
void readDictionary(std::istream& is, unsigned int depth = 0);
|
||||
|
||||
/// @brief Check if a list of standard attribute definitions
|
||||
/// are available and correct.
|
||||
@ -255,7 +324,8 @@ protected:
|
||||
/// @brief Parse a dictionary line.
|
||||
///
|
||||
/// @param line line to parse.
|
||||
void parseLine(const std::string& line);
|
||||
/// @param depth recursion depth.
|
||||
void parseLine(const std::string& line, unsigned int depth);
|
||||
|
||||
/// @brief Attribute definition container.
|
||||
AttrDefContainer container_;
|
||||
|
@ -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
|
||||
@ -252,3 +252,8 @@ VALUE Acct-Terminate-Cause Service-Unavailable 15
|
||||
VALUE Acct-Terminate-Cause Callback 16
|
||||
VALUE Acct-Terminate-Cause User-Error 17
|
||||
VALUE Acct-Terminate-Cause Host-Request 18
|
||||
|
||||
# Examples
|
||||
|
||||
#$INCLUDE foobar
|
||||
#VENDOR DSL-Forum 3561
|
||||
|
@ -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 },
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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<uint8_t> 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<Attribute>(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))
|
||||
@ -175,6 +154,10 @@ TEST_F(AttributeTest, attrString) {
|
||||
"the attribute value type must be ipv6prefix, not string");
|
||||
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
|
||||
"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.
|
||||
@ -188,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<uint8_t> binary = { 1, 5, 1, 2, 3 };
|
||||
EXPECT_EQ(binary, attr->toBytes());
|
||||
string expected = "{ \"type\": 1, \"name\": \"User-Name\", ";
|
||||
expected += " \"raw\": \"010203\" }";
|
||||
runToElementTest<Attribute>(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))
|
||||
@ -230,19 +208,6 @@ TEST_F(AttributeTest, attrInt) {
|
||||
expected += " \"data\": \"15\" }";
|
||||
runToElementTest<Attribute>(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))
|
||||
@ -278,7 +243,12 @@ TEST_F(AttributeTest, attrInt) {
|
||||
EXPECT_THROW_MSG(attr->toIpv6Prefix(), TypeError,
|
||||
"the attribute value type must be ipv6prefix, not integer");
|
||||
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
|
||||
"the attribute value type must be ipv6prefix, not integer");
|
||||
"the attribute value type must be ipv6prefix, not integer"
|
||||
);
|
||||
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.
|
||||
@ -305,11 +275,6 @@ TEST_F(AttributeTest, attrIpAddr) {
|
||||
expected += " \"data\": \"192.0.2.1\" }";
|
||||
runToElementTest<Attribute>(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");
|
||||
|
||||
@ -349,6 +314,10 @@ TEST_F(AttributeTest, attrIpAddr) {
|
||||
"the attribute value type must be ipv6prefix, not ipaddr");
|
||||
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
|
||||
"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.
|
||||
@ -377,19 +346,13 @@ TEST_F(AttributeTest, attrIpv6Addr) {
|
||||
expected += " \"data\": \"2001:db8::1235\" }";
|
||||
runToElementTest<Attribute>(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);
|
||||
@ -426,6 +389,10 @@ TEST_F(AttributeTest, attrIpv6Addr) {
|
||||
"the attribute value type must be ipv6prefix, not ipv6addr");
|
||||
EXPECT_THROW_MSG(attr->toIpv6PrefixLen(), TypeError,
|
||||
"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.
|
||||
@ -457,28 +424,11 @@ TEST_F(AttributeTest, attrIpv6Prefix) {
|
||||
expected += " \"data\": \"2001:db8::1235/128\" }";
|
||||
runToElementTest<Attribute>(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,6 +483,111 @@ TEST_F(AttributeTest, attrIpv6Prefix) {
|
||||
"the attribute value type must be ipaddr, not ipv6prefix");
|
||||
EXPECT_THROW_MSG(attr->toIpv6Addr(), TypeError,
|
||||
"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<uint8_t> 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<Attribute>(expected, *attr);
|
||||
|
||||
AttributePtr from_bytes = Attribute::fromBytes(binary);
|
||||
ASSERT_TRUE(from_bytes);
|
||||
EXPECT_TRUE(compare(from_bytes, attr))
|
||||
<< from_bytes->toText() << " != " << attr->toText();
|
||||
|
||||
vector<uint8_t> 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<uint8_t> 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<uint8_t> empty;
|
||||
EXPECT_THROW_MSG(Attribute::fromVsa(PW_VENDOR_SPECIFIC, 1234, empty),
|
||||
BadValue, "value is empty");
|
||||
|
||||
vector<uint8_t> small = { 26, 6, 0, 0, 0x4, 0xd2 };
|
||||
EXPECT_THROW_MSG(Attribute::fromBytes(small), BadValue,
|
||||
"value is too small 4 < 5");
|
||||
|
||||
vector<uint8_t> 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<uint8_t> big_binary(MAX_VSA_DATA_LEN, 0x78);
|
||||
EXPECT_NO_THROW_LOG(Attribute::fromVsa(PW_VENDOR_SPECIFIC,
|
||||
1234, big_binary));
|
||||
|
||||
vector<uint8_t> 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<uint8_t> 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<uint8_t> 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.
|
||||
@ -593,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";
|
||||
|
@ -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<CfgAttributes>(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, "
|
||||
|
@ -47,29 +47,49 @@ public:
|
||||
/// @brief Destructor.
|
||||
virtual ~DictionaryTest() {
|
||||
AttrDefs::instance().clear();
|
||||
static_cast<void>(remove(TEST_DICT));
|
||||
}
|
||||
|
||||
/// @brief Parse a line.
|
||||
///
|
||||
/// @param line line to parse.
|
||||
void parseLine(const string& line) {
|
||||
/// @param depth recursion depth.
|
||||
void parseLine(const string& line, unsigned int depth = 0) {
|
||||
istringstream is(line + "\n");
|
||||
AttrDefs::instance().readDictionary(is);
|
||||
AttrDefs::instance().readDictionary(is, depth);
|
||||
}
|
||||
|
||||
/// @brief Parse a list of lines.
|
||||
///
|
||||
/// @param lines list of lines.
|
||||
void parseLines(const list<string>& lines) {
|
||||
/// @param depth recursion depth.
|
||||
void parseLines(const list<string>& lines, unsigned int depth = 0) {
|
||||
string content;
|
||||
for (auto const& line : lines) {
|
||||
content += line + "\n";
|
||||
}
|
||||
istringstream is(content);
|
||||
AttrDefs::instance().readDictionary(is);
|
||||
AttrDefs::instance().readDictionary(is, depth);
|
||||
}
|
||||
|
||||
/// @brief writes specified content to a file.
|
||||
///
|
||||
/// @param file_name name of file to be written.
|
||||
/// @param content content to be written to file.
|
||||
void writeFile(const std::string& file_name, const std::string& content) {
|
||||
static_cast<void>(remove(file_name.c_str()));
|
||||
ofstream out(file_name.c_str(), ios::trunc);
|
||||
EXPECT_TRUE(out.is_open());
|
||||
out << content;
|
||||
out.close();
|
||||
}
|
||||
|
||||
/// Name of a dictionary file used during tests.
|
||||
static const char* TEST_DICT;
|
||||
};
|
||||
|
||||
const char* DictionaryTest::TEST_DICT = "test-dict";
|
||||
|
||||
// Verifies standards definitions can be read from the dictionary.
|
||||
TEST_F(DictionaryTest, standard) {
|
||||
ASSERT_NO_THROW_LOG(AttrDefs::instance().readDictionary(TEST_DICTIONARY));
|
||||
@ -111,8 +131,22 @@ TEST_F(DictionaryTest, parseLine) {
|
||||
"expected 4 tokens, got 3 at line 1");
|
||||
EXPECT_THROW_MSG(parseLine("VALUE My-Attribute My-Value 1"), BadValue,
|
||||
"unknown attribute 'My-Attribute' at line 1");
|
||||
EXPECT_THROW_MSG(parseLine("VENDOR my-vendor 4417"), BadValue,
|
||||
"unknown dictionary entry 'VENDOR' at line 1");
|
||||
|
||||
EXPECT_THROW_MSG(parseLine("$INCLUDE"), BadValue,
|
||||
"expected 2 tokens, got 1 at line 1");
|
||||
EXPECT_THROW_MSG(parseLine("$INCLUDE foo bar"), BadValue,
|
||||
"expected 2 tokens, got 3 at line 1");
|
||||
EXPECT_THROW_MSG(parseLine("VENDOR my-vendor"), BadValue,
|
||||
"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");
|
||||
EXPECT_THROW_MSG(parseLine("END-VENDOR my-vendor"), BadValue,
|
||||
"unknown dictionary entry 'END-VENDOR' at line 1");
|
||||
}
|
||||
|
||||
// Verifies sequences attribute of (re)definitions.
|
||||
@ -148,6 +182,19 @@ TEST_F(DictionaryTest, parseLines) {
|
||||
expected = "Illegal attribute redefinition of 'Service-Type' ";
|
||||
expected += "type 6 value type integer by 6 string at line 2";
|
||||
EXPECT_THROW_MSG(parseLines(new_value_type), BadValue, expected);
|
||||
|
||||
// Only the attribute 26 (Vendor-Specific) can have the vsa data type.
|
||||
list<string> bad_vsa = {
|
||||
"ATTRIBUTE Attr126 126 vsa"
|
||||
};
|
||||
expected = "only Vendor-Specific (26) attribute can have ";
|
||||
expected += "the vsa data type at line 1";
|
||||
EXPECT_THROW_MSG(parseLines(bad_vsa), BadValue, expected);
|
||||
|
||||
list<string> vsa = {
|
||||
"ATTRIBUTE Attr26 26 vsa"
|
||||
};
|
||||
EXPECT_NO_THROW_LOG(parseLines(vsa));
|
||||
}
|
||||
|
||||
// Verifies integer constant definitions.
|
||||
@ -196,12 +243,49 @@ TEST_F(DictionaryTest, integerConstant) {
|
||||
EXPECT_THROW_MSG(parseLines(new_value), BadValue, expected);
|
||||
}
|
||||
|
||||
// Verifies vendor id definitions.
|
||||
TEST_F(DictionaryTest, vendorId) {
|
||||
// Value must be an integer.
|
||||
list<string> not_integer_val = {
|
||||
"VENDOR My-Value Non-Integer"
|
||||
};
|
||||
EXPECT_THROW_MSG(parseLines(not_integer_val), BadValue,
|
||||
"can't parse integer value Non-Integer at line 1");
|
||||
|
||||
// Positive case.
|
||||
list<string> positive = {
|
||||
"VENDOR ISC 2495"
|
||||
};
|
||||
EXPECT_NO_THROW_LOG(parseLines(positive));
|
||||
|
||||
// Redefine the same vendor id.
|
||||
list<string> same = {
|
||||
"VENDOR ISC 2495",
|
||||
"VENDOR ISC 2495"
|
||||
};
|
||||
EXPECT_NO_THROW_LOG(parseLines(same));
|
||||
|
||||
// Redefine with a different value is not allowed.
|
||||
list<string> new_value = {
|
||||
"VENDOR ISC 2495",
|
||||
"VENDOR ISC 24950",
|
||||
};
|
||||
string expected = "Illegal vendor id redefinition of ";
|
||||
expected += "'ISC' value 2495 by 24950 at line 2";
|
||||
EXPECT_THROW_MSG(parseLines(new_value), BadValue, expected);
|
||||
}
|
||||
|
||||
// Verifies errors from bad dictionary files.
|
||||
TEST_F(DictionaryTest, badFile) {
|
||||
string expected = "can't open dictionary '/does-not-exist': ";
|
||||
expected += "No such file or directory";
|
||||
EXPECT_THROW_MSG(AttrDefs::instance().readDictionary("/does-not-exist"),
|
||||
BadValue, expected);
|
||||
list<string> bad_include = {
|
||||
"$INCLUDE /does-not-exist"
|
||||
};
|
||||
expected += " at line 1";
|
||||
EXPECT_THROW_MSG(parseLines(bad_include), BadValue, expected);
|
||||
}
|
||||
|
||||
// Definitions of Standard attributes used by the hook.
|
||||
@ -213,6 +297,39 @@ TEST_F(DictionaryTest, hookAttributes) {
|
||||
checkStandardDefs(RadiusConfigParser::USED_STANDARD_ATTR_DEFS));
|
||||
}
|
||||
|
||||
// Verifies the $INCLUDE entry.
|
||||
TEST_F(DictionaryTest, include) {
|
||||
list<string> include;
|
||||
include.push_back("# Including the dictonary");
|
||||
include.push_back(string("$INCLUDE ") + string(TEST_DICTIONARY));
|
||||
include.push_back("# Dictionary included");
|
||||
include.push_back("VENDOR ISC 2495");
|
||||
EXPECT_NO_THROW_LOG(parseLines(include));
|
||||
EXPECT_NO_THROW_LOG(AttrDefs::instance().
|
||||
checkStandardDefs(RadiusConfigParser::USED_STANDARD_ATTR_DEFS));
|
||||
auto isc = AttrDefs::instance().getByName(PW_VENDOR_SPECIFIC, "ISC");
|
||||
ASSERT_TRUE(isc);
|
||||
EXPECT_EQ(2495, isc->value_);
|
||||
|
||||
// max depth is 5.
|
||||
EXPECT_THROW_MSG(parseLines(include, 4), BadValue,
|
||||
"Too many nested $INCLUDE at line 2");
|
||||
}
|
||||
|
||||
// Verifies the $INCLUDE entry can't eat the stack.
|
||||
TEST_F(DictionaryTest, includeLimit) {
|
||||
string include = "$INCLUDE " + string(TEST_DICT) + "\n";
|
||||
writeFile(TEST_DICT, include);
|
||||
string expected = "Too many nested $INCLUDE ";
|
||||
expected += "at line 1 in dictionary 'test-dict', ";
|
||||
expected += "at line 1 in dictionary 'test-dict', ";
|
||||
expected += "at line 1 in dictionary 'test-dict', ";
|
||||
expected += "at line 1 in dictionary 'test-dict', ";
|
||||
expected += "at line 1";
|
||||
EXPECT_THROW_MSG(parseLine(string("$INCLUDE ") + string(TEST_DICT)),
|
||||
BadValue, expected);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// RAII device freeing the glob buffer when going out of scope.
|
||||
|
@ -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.
|
||||
|
Loading…
x
Reference in New Issue
Block a user