diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a9e05bfc25bd5ac02a29b3c02991d78e81fc995..a7d3fd6167a5761740dcf3af45acd04b249c77a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.16) project( kea-hook - VERSION 3.0 + VERSION 3.0.0 DESCRIPTION "Hook library for isc kea(https://kea.isc.org/), the library controls IP assignment." LANGUAGES CXX) diff --git a/src/callouts.cc b/src/callouts.cc index 41beafdbf41d9fc19c8020e992d3a7944aac9f42..5e841675394457629919e5a453e7c2eb774716ac 100644 --- a/src/callouts.cc +++ b/src/callouts.cc @@ -36,14 +36,13 @@ static std::tuple<int, std::string, std::string, std::string> parseOption82( return std::make_tuple(1, nullptr, nullptr, nullptr); } - std::string port_id{std::to_string(circuit_id[4]) + "/" + + const auto& port_id{std::to_string(circuit_id[4]) + "/" + std::to_string(circuit_id[5])}; std::string switch_name{remote_id.begin() + 2, remote_id.end()}; try { const auto& switch_id{g_switch_data.at(switch_name)}; - return std::make_tuple(0, std::move(switch_name), std::move(port_id), - switch_id); + return std::make_tuple(0, std::move(switch_name), port_id, switch_id); } catch (const std::out_of_range& e) { LOG_FATAL(kea_hook_logger, KEA_HOOK_DHCP_OPTION_82_ERROR); return std::make_tuple(1, nullptr, nullptr, nullptr); @@ -145,82 +144,96 @@ int lease4_select(isc::hooks::CalloutHandle& handle) { // Critical part begin, it's not safe to lease IP yet handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_SKIP); + try { + isc::db::PgSqlTransaction transaction(*g_pg_sql_connection); - auto [result, switch_name, port_id, switch_id] = parseOption82(query4_ptr); - if (result != 0) { - return 1; - } + auto [result, switch_name, port_id, switch_id] = parseOption82(query4_ptr); + if (result != 0) { + return 1; + } - // Check for IP override - const char* values[3] = {mac_address.c_str()}; - isc::db::PgSqlResult r(PQexecPrepared(*g_pg_sql_connection, "ip_override", 1, - values, nullptr, nullptr, 0)); + // Check for IP override + const char* values[3] = {mac_address.c_str()}; + isc::db::PgSqlResult r(PQexecPrepared(*g_pg_sql_connection, "ip_override", + 1, values, nullptr, nullptr, 0)); - std::string ip_address; - if (r.getRows() > 0) { - // IP is overridden - ip_address = PQgetvalue(r, 0, 0); - LOG_INFO(kea_hook_logger, KEA_HOOK_IP_OVERRIDDEN) - .arg(mac_address) - .arg(ip_address); - } else { - values[0] = port_id.c_str(); - values[1] = switch_id.c_str(); - isc::db::PgSqlResult r2(PQexecPrepared(*g_pg_sql_connection, "ip_address", - 2, values, nullptr, nullptr, 0)); - - // Handle incorrect room - if (r2.getRows() <= 0) { - LOG_ERROR(kea_hook_logger, KEA_HOOK_UNKNOWN_ROOM) + std::string ip_address; + if (r.getRows() > 0) { + // IP is overridden + ip_address = PQgetvalue(r, 0, 0); + LOG_INFO(kea_hook_logger, KEA_HOOK_IP_OVERRIDDEN) .arg(mac_address) - .arg(switch_name) - .arg(port_id); - - return 1; + .arg(ip_address); + } else { + values[0] = port_id.c_str(); + values[1] = switch_id.c_str(); + isc::db::PgSqlResult r2(PQexecPrepared(*g_pg_sql_connection, "ip_address", + 2, values, nullptr, nullptr, 0)); + + // Handle incorrect room + if (r2.getRows() <= 0) { + LOG_ERROR(kea_hook_logger, KEA_HOOK_UNKNOWN_ROOM) + .arg(mac_address) + .arg(switch_name) + .arg(port_id); + + return 1; + } + + ip_address = PQgetvalue(r2, 0, 0); } - ip_address = PQgetvalue(r2, 0, 0); - } + // Modify kea's IP lease + lease4_ptr->addr_ = isc::asiolink::IOAddress(ip_address); + handle.setArgument("lease4", lease4_ptr); - // Modify kea's IP lease - lease4_ptr->addr_ = isc::asiolink::IOAddress(ip_address); - handle.setArgument("lease4", lease4_ptr); + // Basic DHCP functionality ends here + // Critical part end, it's safe to lease IP now + handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_CONTINUE); - // Basic DHCP functionality ends here - // Critical part end, it's safe to lease IP now - handle.setStatus(isc::hooks::CalloutHandle::NEXT_STEP_CONTINUE); + LOG_DEBUG(kea_hook_logger, 0, KEA_HOOK_QUERIED_IP).arg(ip_address); + LOG_DEBUG(kea_hook_logger, 0, KEA_HOOK_DHCP_STATE) + .arg((fake_allocation) ? "---<DISCOVER>---" : "---<REQUEST>---"); - LOG_DEBUG(kea_hook_logger, 0, KEA_HOOK_QUERIED_IP).arg(ip_address); - LOG_DEBUG(kea_hook_logger, 0, KEA_HOOK_DHCP_STATE) - .arg((fake_allocation) ? "---<DISCOVER>---" : "---<REQUEST>---"); - - // Save to DB when the DHCP state is DHCPREQUEST - if (!fake_allocation) { - // Clear switch-port - values[0] = port_id.c_str(); - values[1] = switch_id.c_str(); - isc::db::PgSqlResult r3(PQexecPrepared(*g_pg_sql_connection, "clear_port", - 2, values, nullptr, nullptr, 0)); - - // Insert MUEB or update switch-port - values[0] = mac_address.c_str(); - values[1] = port_id.c_str(); - values[2] = switch_id.c_str(); - isc::db::PgSqlResult r4(PQexecPrepared(*g_pg_sql_connection, - "insert_or_mueb", 3, values, nullptr, - nullptr, 0)); - } else { - /* Handle device swap - * Remove the current IP from the lease DB before DHCPREQUEST - * This step is required to make the device swap work otherwise the server - * sends DHCPNAK - */ - if (isc::dhcp::LeaseMgrFactory::haveInstance()) { - isc::dhcp::LeaseMgrFactory::instance().deleteLease(lease4_ptr); + // Save to DB when the DHCP state is DHCPREQUEST + if (!fake_allocation) { + // Clear switch-port + isc::db::PgSqlResult r3(PQexecPrepared(*g_pg_sql_connection, "clear_port", + 2, values, nullptr, nullptr, 0)); + + // Insert MUEB or update switch-port + values[0] = mac_address.c_str(); + values[1] = port_id.c_str(); + values[2] = switch_id.c_str(); + isc::db::PgSqlResult r4(PQexecPrepared(*g_pg_sql_connection, + "insert_or_update_mueb", 3, values, + nullptr, nullptr, 0)); + } else { + /* Handle device swap + * Remove the current IP from the lease DB before DHCPREQUEST + * This step is required to make the device swap work otherwise the server + * sends DHCPNAK + */ + if (isc::dhcp::LeaseMgrFactory::haveInstance()) { + isc::dhcp::LeaseMgrFactory::instance().deleteLease(lease4_ptr); + } else { + /* Should not happen this needs manual fix + * Proceed as normal + */ + LOG_ERROR(kea_hook_logger, KEA_HOOK_FAILED) + .arg( + "No lease manager available, MUEB device swap will not work! " + "This should not happen, check lease database configuration!"); + } } - } - return 0; + transaction.commit(); + return 0; + } catch (const std::exception& e) { + LOG_FATAL(kea_hook_logger, KEA_HOOK_FAILED).arg(e.what()); + + return 1; + } } /* Handle lease after one allocation diff --git a/src/framework_functions.cc b/src/framework_functions.cc index 0146100859bbea04f90a288ea9b1ac2653ce86d8..2e74f6b04a277284cd1817233d77b28e1a30cd7d 100644 --- a/src/framework_functions.cc +++ b/src/framework_functions.cc @@ -39,11 +39,7 @@ int load(isc::hooks::LibraryHandle& handle) { // Store prepared statements std::array<isc::db::PgSqlTaggedStatement, 8> statements{ - {{1, - {829}, - "ip_conflict", - "select ip_conflict::int from mueb where mac_address = $1"}, - {2, + {{2, {isc::db::OID_TEXT, 869}, "mueb_in_room", "select room_id from port p join room r using(room_id) where " @@ -54,6 +50,10 @@ int load(isc::hooks::LibraryHandle& handle) { "mueb_count_in_room", "select count(*) from port p join mueb m using(port_id, switch_id) " "where m.mac_address != $1 and p.room_id = $2"}, + {1, + {829}, + "ip_conflict", + "select ip_conflict::int from mueb where mac_address = $1"}, {1, {829}, "ip_override", diff --git a/src/messages.cc b/src/messages.cc index a40b881d452d4a8e8177beb548562d62a29e0fa5..77322365ed87aaf3bd5479200355bc44a0289fbf 100644 --- a/src/messages.cc +++ b/src/messages.cc @@ -1,4 +1,4 @@ -// File created from messages.mes on Fri Sep 03 2021 19:53 +// File created from messages.mes on Sat Sep 04 2021 16:53 #include <cstddef> #include <log/message_types.h> @@ -7,6 +7,7 @@ extern const isc::log::MessageID KEA_HOOK_DATABASE_FAILED = "KEA_HOOK_DATABASE_FAILED"; extern const isc::log::MessageID KEA_HOOK_DHCP_OPTION_82_ERROR = "KEA_HOOK_DHCP_OPTION_82_ERROR"; extern const isc::log::MessageID KEA_HOOK_DHCP_STATE = "KEA_HOOK_DHCP_STATE"; +extern const isc::log::MessageID KEA_HOOK_FAILED = "KEA_HOOK_FAILED"; extern const isc::log::MessageID KEA_HOOK_IP_CONFLICT = "KEA_HOOK_IP_CONFLICT"; extern const isc::log::MessageID KEA_HOOK_IP_OVERRIDDEN = "KEA_HOOK_IP_OVERRIDDEN"; extern const isc::log::MessageID KEA_HOOK_MISSING_PARAMETERS = "KEA_HOOK_MISSING_PARAMETERS"; @@ -22,6 +23,7 @@ const char* values[] = { "KEA_HOOK_DATABASE_FAILED", "%1", "KEA_HOOK_DHCP_OPTION_82_ERROR", "Invalid DHCP option 82", "KEA_HOOK_DHCP_STATE", "%1", + "KEA_HOOK_FAILED", "%1", "KEA_HOOK_IP_CONFLICT", "Could not lease IP: %1 to MUEB: %2 because of IP conflict", "KEA_HOOK_IP_OVERRIDDEN", "MUEB: %1 IP's overridden to: %2", "KEA_HOOK_MISSING_PARAMETERS", "Not all parameters are provided", diff --git a/src/messages.h b/src/messages.h index 2b417c513eb25f65c590e90b113d8d6006a06995..71609e4d1d70e5962b5b2df6ae5d818a2d9a27a0 100644 --- a/src/messages.h +++ b/src/messages.h @@ -1,4 +1,4 @@ -// File created from messages.mes on Fri Sep 03 2021 19:53 +// File created from messages.mes on Sat Sep 04 2021 16:53 #ifndef MESSAGES_H #define MESSAGES_H @@ -8,6 +8,7 @@ extern const isc::log::MessageID KEA_HOOK_DATABASE_FAILED; extern const isc::log::MessageID KEA_HOOK_DHCP_OPTION_82_ERROR; extern const isc::log::MessageID KEA_HOOK_DHCP_STATE; +extern const isc::log::MessageID KEA_HOOK_FAILED; extern const isc::log::MessageID KEA_HOOK_IP_CONFLICT; extern const isc::log::MessageID KEA_HOOK_IP_OVERRIDDEN; extern const isc::log::MessageID KEA_HOOK_MISSING_PARAMETERS; diff --git a/src/messages.mes b/src/messages.mes index b5b30127e919152a7f12c7da28dd89781d0399ab..934344cf1ee2239491e88c64b26b7da0a3fd9ce3 100644 --- a/src/messages.mes +++ b/src/messages.mes @@ -2,6 +2,8 @@ % KEA_HOOK_OPEN_DATABASE Opened database successfully +% KEA_HOOK_FAILED %1 + % KEA_HOOK_DATABASE_FAILED %1 % KEA_HOOK_QUERIED_IP Queried IP is: %1