Kea 3.3.0 (development) released on July 29, 2026
+2524. [func] razvan
+ Added support for unlimited encapsulation levels in evaluated
+ expressions: option[code0].option[code1]...option[codeX],
+ relay4[code0].option[code1]...option[codeX],
+ relay6[nest].option[code0].option[code1]...option[codeX] and
+ vendor[ent-id].option[code0].option[code1]...option[codeX].
+ (Gitlab #4146)
+
2523. [func] fdupont
RADIUS accounting now ignores DHCPv4 lease reuses.
(Gitlab #4544)
ElementPtr code = Element::create(DHO_HOST_NAME);
option->set("code", code);
option->set("client-class", Element::create(string("foobar")));
+
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty()) << impl_->getErrMsg();
option->set("client-class", Element::create(string("foobar")));
ElementPtr dest = Element::create(string("query"));
option->set("destination", dest);
+
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty()) << impl_->getErrMsg();
option->set("code", code);
ElementPtr dest = Element::create(string("query"));
option->set("destination", dest);
+
EXPECT_NO_THROW(impl_->testConfigure(options));
EXPECT_TRUE(impl_->getErrMsg().empty()) << impl_->getErrMsg();
buffer_out.writeData(&(relay->linkaddr_.toBytes()[0]),
isc::asiolink::V6ADDRESS_LEN);
buffer_out.writeData(&relay->peeraddr_.toBytes()[0],
- isc::asiolink::V6ADDRESS_LEN);
+ isc::asiolink::V6ADDRESS_LEN);
// Store every option in this relay's scope.
for (auto const& opt : relay->options_) {
// hostname : VARCHAR(255) NULL
strncpy(hostname_, host->getHostname().c_str(), HOSTNAME_MAX_LEN - 1);
- hostname_length_ = host->getHostname().length();
+ hostname_length_ = std::min(host->getHostname().length(), HOSTNAME_MAX_LEN - 1);
bind_[6].buffer_type = MYSQL_TYPE_STRING;
bind_[6].buffer = reinterpret_cast<char*>(hostname_);
bind_[6].buffer_length = hostname_length_;
string classes4_txt = host->getClientClasses4().toText(",");
strncpy(dhcp4_client_classes_, classes4_txt.c_str(), CLIENT_CLASSES_MAX_LEN - 1);
bind_[7].buffer = dhcp4_client_classes_;
- bind_[7].buffer_length = classes4_txt.length();
+ bind_[7].buffer_length = std::min(classes4_txt.length(), CLIENT_CLASSES_MAX_LEN - 1);
// dhcp6_client_classes : VARCHAR(255) NULL
bind_[8].buffer_type = MYSQL_TYPE_STRING;
string classes6_txt = host->getClientClasses6().toText(",");
strncpy(dhcp6_client_classes_, classes6_txt.c_str(), CLIENT_CLASSES_MAX_LEN - 1);
bind_[8].buffer = dhcp6_client_classes_;
- bind_[8].buffer_length = classes6_txt.length();
+ bind_[8].buffer_length = std::min(classes6_txt.length(), CLIENT_CLASSES_MAX_LEN - 1);
// user_context : TEXT NULL
ConstElementPtr ctx = host->getContext();
string ctx_txt = ctx->str();
strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
bind_[9].buffer = user_context_;
- bind_[9].buffer_length = ctx_txt.length();
+ bind_[9].buffer_length = std::min(ctx_txt.length(), USER_CONTEXT_MAX_LEN - 1);
} else {
bind_[9].buffer_type = MYSQL_TYPE_NULL;
}
strncpy(dhcp4_server_hostname_, server_hostname.c_str(),
SERVER_HOSTNAME_MAX_LEN - 1);
bind_[11].buffer = dhcp4_server_hostname_;
- bind_[11].buffer_length = server_hostname.length();
+ bind_[11].buffer_length = std::min(server_hostname.length(),
+ SERVER_HOSTNAME_MAX_LEN - 1);
// dhcp4_boot_file_name
bind_[12].buffer_type = MYSQL_TYPE_STRING;
strncpy(dhcp4_boot_file_name_, boot_file_name.c_str(),
BOOT_FILE_NAME_MAX_LEN - 1);
bind_[12].buffer = dhcp4_boot_file_name_;
- bind_[12].buffer_length = boot_file_name.length();
+ bind_[12].buffer_length = std::min(boot_file_name.length(),
+ BOOT_FILE_NAME_MAX_LEN - 1);
// auth key
bind_[13].buffer_type = MYSQL_TYPE_STRING;
std::strncpy(auth_key_, auth_key.c_str(), TEXT_AUTH_KEY_LEN - 1);
auth_key_null_ = auth_key.empty() ? MLM_TRUE : MLM_FALSE;
bind_[13].buffer = auth_key_;
- bind_[13].buffer_length = auth_key.length();
+ bind_[13].buffer_length = std::min(auth_key.length(), TEXT_AUTH_KEY_LEN - 1);
} catch (const std::exception& ex) {
isc_throw(DbOperationError,
addr6_length_ = isc::asiolink::V6ADDRESS_LEN;
bind_[0].buffer_type = MYSQL_TYPE_BLOB;
bind_[0].buffer = reinterpret_cast<char*>(&addr6_[0]);
- bind_[0].buffer_length = isc::asiolink::V6ADDRESS_LEN;
+ bind_[0].buffer_length = addr6_length_;
bind_[0].length = &addr6_length_;
// prefix_len tinyint
bind_[6].buffer = reinterpret_cast<char*>(&cancelled_);
bind_[6].is_unsigned = MLM_TRUE;
- // user_context: TEST NULL,
+ // user_context: TEXT NULL,
ConstElementPtr ctx = opt_desc.getContext();
if (ctx) {
user_context_ = ctx->str();
unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[1].buffer_type = MYSQL_TYPE_BLOB;
inbind[1].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[1].buffer_length = isc::asiolink::V6ADDRESS_LEN;
+ inbind[1].buffer_length = addr6_length;
inbind[1].length = &addr6_length;
return (impl_->delStatement(ctx, MySqlHostDataSourceImpl::DEL_HOST_ADDR6, inbind));
// Identifier value.
std::vector<char> identifier_vec(identifier_begin,
identifier_begin + identifier_len);
- unsigned long int length = identifier_vec.size();
+ unsigned long length = identifier_vec.size();
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = &identifier_vec[0];
inbind[0].buffer_length = length;
memset(inbind, 0, sizeof(inbind));
// Hostname
- char hostname_[HOSTNAME_MAX_LEN];
- strncpy(hostname_, hostname.c_str(), HOSTNAME_MAX_LEN - 1);
- unsigned long length = hostname.length();
+ char hostname_c[HOSTNAME_MAX_LEN];
+ memset(hostname_c, 0, sizeof(hostname_c));
+ strncpy(hostname_c, hostname.c_str(), HOSTNAME_MAX_LEN - 1);
+ unsigned long length = std::min(hostname.length(), HOSTNAME_MAX_LEN - 1);
inbind[0].buffer_type = MYSQL_TYPE_STRING;
- inbind[0].buffer = reinterpret_cast<char*>(hostname_);
+ inbind[0].buffer = reinterpret_cast<char*>(hostname_c);
inbind[0].buffer_length = length;
inbind[0].length = &length;
memset(inbind, 0, sizeof(inbind));
// Hostname
- char hostname_[HOSTNAME_MAX_LEN];
- strncpy(hostname_, hostname.c_str(), HOSTNAME_MAX_LEN - 1);
- unsigned long length = hostname.length();
+ char hostname_c[HOSTNAME_MAX_LEN];
+ memset(hostname_c, 0, sizeof(hostname_c));
+ strncpy(hostname_c, hostname.c_str(), HOSTNAME_MAX_LEN - 1);
+ unsigned long length = std::min(hostname.length(), HOSTNAME_MAX_LEN - 1);
inbind[0].buffer_type = MYSQL_TYPE_STRING;
- inbind[0].buffer = reinterpret_cast<char*>(hostname_);
+ inbind[0].buffer = reinterpret_cast<char*>(hostname_c);
inbind[0].buffer_length = length;
inbind[0].length = &length;
memset(inbind, 0, sizeof(inbind));
// Hostname
- char hostname_[HOSTNAME_MAX_LEN];
- strncpy(hostname_, hostname.c_str(), HOSTNAME_MAX_LEN - 1);
- unsigned long length = hostname.length();
+ char hostname_c[HOSTNAME_MAX_LEN];
+ memset(hostname_c, 0, sizeof(hostname_c));
+ strncpy(hostname_c, hostname.c_str(), HOSTNAME_MAX_LEN - 1);
+ unsigned long length = std::min(hostname.length(), HOSTNAME_MAX_LEN - 1);
inbind[0].buffer_type = MYSQL_TYPE_STRING;
- inbind[0].buffer = reinterpret_cast<char*>(hostname_);
+ inbind[0].buffer = reinterpret_cast<char*>(hostname_c);
inbind[0].buffer_length = length;
inbind[0].length = &length;
unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[0].buffer_length = isc::asiolink::V6ADDRESS_LEN;
+ inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
uint8_t tmp = prefix_len;
unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[1].buffer_type = MYSQL_TYPE_BLOB;
inbind[1].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[1].buffer_length = isc::asiolink::V6ADDRESS_LEN;
+ inbind[1].buffer_length = addr6_length;
inbind[1].length = &addr6_length;
ConstHostCollection collection;
unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[1].buffer_type = MYSQL_TYPE_BLOB;
inbind[1].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[1].buffer_length = isc::asiolink::V6ADDRESS_LEN;
+ inbind[1].buffer_length = addr6_length;
inbind[1].length = &addr6_length;
ConstHostCollection collection;
unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[0].buffer_length = isc::asiolink::V6ADDRESS_LEN;
+ inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
ConstHostCollection collection;
std::string ctx_txt = ctx->str();
strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
bind_[10].buffer = user_context_;
- bind_[10].buffer_length = ctx_txt.length();
+ bind_[10].buffer_length = std::min(ctx_txt.length(), USER_CONTEXT_MAX_LEN - 1);
// bind_[10].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
} else {
try {
// address: binary(16)
addr6_ = lease->addr_.toBytes();
- if (addr6_.size() != 16) {
+ if (addr6_.size() != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
}
- addr6_length_ = 16;
+ addr6_length_ = isc::asiolink::V6ADDRESS_LEN;
bind_[0].buffer_type = MYSQL_TYPE_BLOB;
bind_[0].buffer = reinterpret_cast<char*>(&addr6_[0]);
- bind_[0].buffer_length = 16;
+ bind_[0].buffer_length = addr6_length_;
bind_[0].length = &addr6_length_;
// bind_[0].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
std::string ctx_txt = ctx->str();
strncpy(user_context_, ctx_txt.c_str(), USER_CONTEXT_MAX_LEN - 1);
bind_[16].buffer = user_context_;
- bind_[16].buffer_length = ctx_txt.length();
+ bind_[16].buffer_length = std::min(ctx_txt.length(), USER_CONTEXT_MAX_LEN - 1);
// bind_[16].is_null = &MLM_FALSE; // commented out for performance
// reasons, see memset() above
} else {
memset(bind_, 0, sizeof(bind_));
// address: binary(16)
- addr6_length_ = 16;
+ addr6_length_ = isc::asiolink::V6ADDRESS_LEN;
bind_[0].buffer_type = MYSQL_TYPE_BLOB;
bind_[0].buffer = reinterpret_cast<char*>(addr6_buffer_);
bind_[0].buffer_length = addr6_length_;
// If the data happens to be empty, we have to create a 1 byte dummy
// buffer and pass it to the binding.
- std::vector<uint8_t> single_byte_vec(1);
+ uint8_t single_byte_data = 0;
// As "buffer" is "char*" - even though the data is being read - we need
// to cast away the "const"ness as well as reinterpreting the data as
// local variable, but as the data is only being read, this introduces
// an unnecessary copy).
uint8_t* data = !hwaddr.hwaddr_.empty() ? const_cast<uint8_t*>(&hwaddr.hwaddr_[0])
- : &single_byte_vec[0];
+ : &single_byte_data;
inbind[0].buffer = reinterpret_cast<char*>(data);
inbind[0].buffer_length = hwaddr_length;
// address: binary(16)
std::vector<uint8_t>addr6 = addr.toBytes();
- if (addr6.size() != 16) {
+ if (addr6.size() != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
}
- unsigned long addr6_length = 16;
+ unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[0].buffer_length = 16;
+ inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
// LEASE_TYPE
// data). For that reason, "const_cast" has been used.
const vector<uint8_t>& duid_vector = duid.getDuid();
unsigned long duid_length = duid_vector.size();
-
- // Make sure that the buffer has at least length of 1, even if
- // empty client id is passed. This is required by some of the
- // MySQL connectors that the buffer is set to non-null value.
- // Otherwise, null value would be inserted into the database,
- // rather than empty string.
- uint8_t single_byte_data = 0;
- uint8_t* data = !duid_vector.empty() ? const_cast<uint8_t*>(&duid_vector[0])
- : &single_byte_data;
-
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
- inbind[0].buffer = reinterpret_cast<char*>(data);
+ inbind[0].buffer = reinterpret_cast<char*>(
+ const_cast<uint8_t*>(&duid_vector[0]));
inbind[0].buffer_length = duid_length;
inbind[0].length = &duid_length;
// Bind the lower bound address.
std::vector<uint8_t> lb_addr_data = lower_bound_address.toBytes();
unsigned long lb_addr_size = lb_addr_data.size();
- if (lb_addr_size != 16) {
+ if (lb_addr_size != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lower bound address is not 16 bytes long");
}
inbind[1].buffer_type = MYSQL_TYPE_BLOB;
const vector<uint8_t>& duid_vector = duid.getDuid();
unsigned long duid_length = duid_vector.size();
-
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(
const_cast<uint8_t*>(&duid_vector[0]));
// Bind lower bound address
std::vector<uint8_t>lb_addr = lower_bound_address.toBytes();
- if (lb_addr.size() != 16) {
+ if (lb_addr.size() != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "getLeases6() - lower bound address is not 16 bytes long");
}
- unsigned long lb_addr_length = 16;
+ unsigned long lb_addr_length = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&lb_addr[0]);
- inbind[0].buffer_length = 16;
+ inbind[0].buffer_length = lb_addr_length;
inbind[0].length = &lb_addr_length;
// Bind page size value
// Bind the where clause address parameter.
std::vector<uint8_t>addr6 = lease->addr_.toBytes();
- if (addr6.size() != 16) {
+ if (addr6.size() != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "updateLease6() - address is not 16 bytes long");
}
- unsigned long addr6_length = 16;
+ unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[0].buffer_length = 16;
+ inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
bind.push_back(inbind[0]);
// Bind the where clause address parameter.
std::vector<uint8_t>addr6 = addr.toBytes();
- if (addr6.size() != 16) {
+ if (addr6.size() != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "deleteLease6() - address is not 16 bytes long");
}
- unsigned long addr6_length = 16;
+ unsigned long addr6_length = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&addr6[0]);
- inbind[0].buffer_length = 16;
+ inbind[0].buffer_length = addr6_length;
inbind[0].length = &addr6_length;
// See the expire code of createBindForSend for the
// Bind the lease address.
std::vector<uint8_t> lease_addr_data = lease_addr.toBytes();
unsigned long lease_addr_length = lease_addr_data.size();
- if (lease_addr_length != 16) {
+ if (lease_addr_length != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
}
bind[1].buffer_type = MYSQL_TYPE_BLOB;
// Bind the lease address.
std::vector<uint8_t> lease_addr_data = lease_addr.toBytes();
unsigned long lease_addr_length = lease_addr_data.size();
- if (lease_addr_length != 16) {
+ if (lease_addr_length != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lease6 address is not 16 bytes long");
}
bind[1].buffer_type = MYSQL_TYPE_BLOB;
// Bind the lower bound address.
std::vector<uint8_t> lb_addr_data = lower_bound_address.toBytes();
unsigned long lb_addr_size = lb_addr_data.size();
- if (lb_addr_size != 16) {
+ if (lb_addr_size != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lower bound address is not 16 bytes long");
}
inbind[1].buffer_type = MYSQL_TYPE_BLOB;
// Bind the lower bound address.
std::vector<uint8_t> lb_addr_data = lower_bound_address.toBytes();
unsigned long lb_addr_size = lb_addr_data.size();
- if (lb_addr_size != 16) {
+ if (lb_addr_size != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "lower bound address is not 16 bytes long");
}
inbind[1].buffer_type = MYSQL_TYPE_BLOB;
// Bind start address.
std::vector<uint8_t>start_addr_bytes = start_addr.toBytes();
- if (start_addr_bytes.size() != 16) {
+ if (start_addr_bytes.size() != isc::asiolink::V6ADDRESS_LEN) {
isc_throw(DbOperationError, "start address is not 16 bytes long");
}
- unsigned long start_addr_size = 16;
+ unsigned long start_addr_size = isc::asiolink::V6ADDRESS_LEN;
inbind[0].buffer_type = MYSQL_TYPE_BLOB;
inbind[0].buffer = reinterpret_cast<char*>(&start_addr_bytes[0]);
- inbind[0].buffer_length = 16;
+ inbind[0].buffer_length = start_addr_size;
inbind[0].length = &start_addr_size;
// Bind page size value.
int status = 0;
if (!in_bind_vec.empty()) {
// Bind parameters to the prepared statement.
- status = mysql_stmt_bind_param(getStatement(index),
- in_bind_vec.empty() ? 0 : &in_bind_vec[0]);
+ status = mysql_stmt_bind_param(getStatement(index), &in_bind_vec[0]);
checkError(status, index, "unable to bind parameters for select");
}