From: Remi Gacogne Date: Mon, 9 May 2022 10:27:33 +0000 (+0200) Subject: dnsdist: Add getListOfRangesOfNetworkInterface() Lua binding X-Git-Tag: dnsdist-1.8.0-rc1~285^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6f0bf6e80c5eabee7e25d4a5beb69751840f489d;p=thirdparty%2Fpdns.git dnsdist: Add getListOfRangesOfNetworkInterface() Lua binding --- diff --git a/pdns/dnsdist-console.cc b/pdns/dnsdist-console.cc index bf802fc856..a559258b1b 100644 --- a/pdns/dnsdist-console.cc +++ b/pdns/dnsdist-console.cc @@ -522,6 +522,7 @@ const std::vector g_consoleKeywords{ { "getDOHFrontendCount", true, "", "returns the number of DoH listeners" }, { "getListOfAddressesOfNetworkInterface", true, "itf", "returns the list of addresses configured on a given network interface, as strings" }, { "getListOfNetworkInterfaces", true, "", "returns the list of network interfaces present on the system, as strings" }, + { "getListOfRangesOfNetworkInterface", true, "itf", "returns the list of network ranges configured on a given network interface, as strings" }, { "getMACAddress", true, "IP addr", "return the link-level address (MAC) corresponding to the supplied neighbour IP address, if known by the kernel" }, { "getOutgoingTLSSessionCacheSize", true, "", "returns the number of TLS sessions (for outgoing connections) currently cached" }, { "getPool", true, "name", "return the pool named `name`, or \"\" for the default pool" }, diff --git a/pdns/dnsdist-lua-bindings.cc b/pdns/dnsdist-lua-bindings.cc index e0337d3fa3..dd00c0485e 100644 --- a/pdns/dnsdist-lua-bindings.cc +++ b/pdns/dnsdist-lua-bindings.cc @@ -746,6 +746,16 @@ void setupLuaBindings(LuaContext& luaCtx, bool client) return result; }); + luaCtx.writeFunction("getListOfRangesOfNetworkInterface", [](const std::string& itf) { + LuaArray result; + auto addrs = getListOfRangesOfNetworkInterface(itf); + int counter = 1; + for (const auto& addr : addrs) { + result.push_back({counter++, addr.toString()}); + } + return result; + }); + luaCtx.writeFunction("getMACAddress", [](const std::string& ip) { return getMACAddress(ComboAddress(ip)); }); diff --git a/pdns/dnsdistdist/docs/reference/config.rst b/pdns/dnsdistdist/docs/reference/config.rst index 512a15eb56..99c4e14593 100644 --- a/pdns/dnsdistdist/docs/reference/config.rst +++ b/pdns/dnsdistdist/docs/reference/config.rst @@ -1029,6 +1029,15 @@ Status, Statistics and More Return the list of network interfaces configured on the system, as strings. This function requires support for ``getifaddrs``, which is known to be present on FreeBSD, Linux, and OpenBSD at least. +.. function:: getListOfRangesOfNetworkInterface(itf) + + .. versionadded:: 1.8.0 + + Return the list of network ranges configured on a given network interface, as strings. + This function requires support for ``getifaddrs``, which is known to be present on FreeBSD, Linux, and OpenBSD at least. + + :param str itf: The name of the network interface + .. function:: getMACAddress(ip) -> str .. versionadded:: 1.8.0 diff --git a/pdns/iputils.cc b/pdns/iputils.cc index 528ae90149..e28927d1e4 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -587,3 +587,54 @@ std::vector getListOfAddressesOfNetworkInterface(const std::string #endif return result; } + +#if HAVE_GETIFADDRS +static uint8_t convertNetmaskToBits(const struct in_addr* mask, socklen_t len) +{ + uint8_t result = 0; + // for all bytes in the address (4 for IPv4, 16 for IPv6) + for (size_t idx = 0; idx < len; idx++) { + uint8_t byte = *(reinterpret_cast(&mask->s_addr) + idx); + // count the number of bits set + while (byte > 0) { + result += (byte & 1); + byte >>= 1; + } + } + return result; +} +#endif /* HAVE_GETIFADDRS */ + +std::vector getListOfRangesOfNetworkInterface(const std::string& itf) +{ + std::vector result; +#if HAVE_GETIFADDRS + struct ifaddrs *ifaddr; + if (getifaddrs(&ifaddr) == -1) { + return result; + } + + for (struct ifaddrs *ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) { + if (ifa->ifa_name == nullptr || strcmp(ifa->ifa_name, itf.c_str()) != 0) { + continue; + } + if (ifa->ifa_addr == nullptr || (ifa->ifa_addr->sa_family != AF_INET && ifa->ifa_addr->sa_family != AF_INET6)) { + continue; + } + ComboAddress addr; + try { + addr.setSockaddr(ifa->ifa_addr, ifa->ifa_addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); + } + catch (...) { + continue; + } + + auto netmask = reinterpret_cast(ifa->ifa_netmask); + uint8_t maskBits = convertNetmaskToBits(&netmask->sin_addr, addr.getSocklen()); + result.emplace_back(addr, maskBits); + } + + freeifaddrs(ifaddr); +#endif + return result; +} diff --git a/pdns/iputils.hh b/pdns/iputils.hh index af3c2cc74a..459167e97b 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -1707,6 +1707,7 @@ ComboAddress parseIPAndPort(const std::string& input, uint16_t port); std::set getListOfNetworkInterfaces(); std::vector getListOfAddressesOfNetworkInterface(const std::string& itf); +std::vector getListOfRangesOfNetworkInterface(const std::string& itf); /* These functions throw if the value was already set to a higher value, or on error */