From: Otto Moerbeek Date: Fri, 29 Nov 2024 13:19:34 +0000 (+0100) Subject: Implement webserver acl X-Git-Tag: dnsdist-2.0.0-alpha1~95^2~25 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=de0d13874d30497d4c686cfd60c77e126685e215;p=thirdparty%2Fpdns.git Implement webserver acl --- diff --git a/pdns/recursordist/settings/cxxsupport.cc b/pdns/recursordist/settings/cxxsupport.cc index b6118e4634..bd5084b6ce 100644 --- a/pdns/recursordist/settings/cxxsupport.cc +++ b/pdns/recursordist/settings/cxxsupport.cc @@ -39,6 +39,8 @@ #include "base64.hh" #include "validate-recursor.hh" #include "threadname.hh" +#include "iputils.hh" +#include "bridge.hh" ::rust::Vec<::rust::String> pdns::settings::rec::getStrings(const std::string& name) { @@ -1454,3 +1456,39 @@ bool pdns::rust::settings::rec::isValidHostname(::rust::Str str) return false; } } + +namespace pdns::rust::web::rec +{ +NetmaskGroup::NetmaskGroup(const ::NetmaskGroup& arg) : + d_ptr(std::make_unique<::NetmaskGroup>(arg)) +{ +} +NetmaskGroup::~NetmaskGroup() = default; + + +ComboAddress::ComboAddress(const ::ComboAddress& arg) : + d_ptr(std::make_unique<::ComboAddress>(arg)) +{ +} +ComboAddress::~ComboAddress() = default; + +std::unique_ptr comboaddress(::rust::Str str) +{ + return std::make_unique(::ComboAddress(std::string(str))); +} + +[[nodiscard]] const ::NetmaskGroup& NetmaskGroup::get() const +{ + return *d_ptr; +} + +[[nodiscard]] const ::ComboAddress& ComboAddress::get() const +{ + return *d_ptr; +} + +bool matches(const std::unique_ptr& nmg, const std::unique_ptr& address) +{ + return nmg->get().match(address->get()); +} +} diff --git a/pdns/recursordist/settings/rust/build.rs b/pdns/recursordist/settings/rust/build.rs index e0fdf17c9c..cdf64ab167 100644 --- a/pdns/recursordist/settings/rust/build.rs +++ b/pdns/recursordist/settings/rust/build.rs @@ -4,5 +4,6 @@ fn main() { // .file("src/source.cc") Code callable from Rust is in ../cxxsupport.cc .flag_if_supported("-std=c++17") .flag("-Isrc") + .flag("-I../../..") .compile("settings"); } diff --git a/pdns/recursordist/settings/rust/src/bridge.hh b/pdns/recursordist/settings/rust/src/bridge.hh index 633035f2d6..2d9e04611c 100644 --- a/pdns/recursordist/settings/rust/src/bridge.hh +++ b/pdns/recursordist/settings/rust/src/bridge.hh @@ -22,8 +22,7 @@ #pragma once #include "rust/cxx.h" -#include "../../../credentials.hh" - +#include "credentials.hh" namespace pdns::rust::settings::rec { @@ -32,12 +31,35 @@ bool isValidHostname(::rust::Str str); void setThreadName(::rust::Str str); } +class NetmaskGroup; +union ComboAddress; + namespace pdns::rust::web::rec { using CredentialsHolder = ::CredentialsHolder; + //using NetmaskGroup = ::NetmaskGroup; struct KeyValue; struct Request; struct Response; +class NetmaskGroup +{ +public: + NetmaskGroup(const ::NetmaskGroup& arg); + ~NetmaskGroup(); + [[nodiscard]] const ::NetmaskGroup& get() const; +private: + std::unique_ptr<::NetmaskGroup> d_ptr; +}; +class ComboAddress +{ +public: + ComboAddress(const ::ComboAddress& arg); + ~ComboAddress(); + [[nodiscard]] const ::ComboAddress& get() const; +private: + std::unique_ptr<::ComboAddress> d_ptr; +}; + void apiServer(const Request& rustRequest, Response& rustResponse); void apiDiscovery(const Request& rustRequest, Response& rustResponse); void apiDiscoveryV1(const Request& rustRequest, Response& rustResponse); @@ -59,4 +81,6 @@ void apiServerSearchData(const Request& rustRequest, Response& rustResponse); void apiServerZoneDetailGET(const Request& rustRequest, Response& rustResponse); void apiServerZoneDetailPUT(const Request& rustRequest, Response& rustResponse); void apiServerZoneDetailDELETE(const Request& rustRequest, Response& rustResponse); +std::unique_ptr comboaddress(::rust::Str str); +bool matches(const std::unique_ptr& nmg, const std::unique_ptr& address); } diff --git a/pdns/recursordist/settings/rust/src/web.rs b/pdns/recursordist/settings/rust/src/web.rs index 6e0e51966f..c694d3e80d 100644 --- a/pdns/recursordist/settings/rust/src/web.rs +++ b/pdns/recursordist/settings/rust/src/web.rs @@ -166,6 +166,7 @@ struct Context { urls: Vec, password_ch: cxx::UniquePtr, api_ch: cxx::UniquePtr, + acl: cxx::UniquePtr, counter: Mutex, } @@ -382,9 +383,22 @@ async fn serveweb_async(listener: TcpListener, ctx: Arc) -> MyResult<() // We start a loop to continuously accept incoming connections loop { let ctx = Arc::clone(&ctx); - let ctx2 = Arc::clone(&ctx); let (stream, _) = listener.accept().await?; + match stream.peer_addr() { + Ok(address) => { + eprintln!("Peer: {:?}", address); + let combo = rustweb::comboaddress(&address.to_string()); + if !rustweb::matches(&ctx.acl, &combo) { + eprintln!("No acl match! {:?}", address); + continue; + } + } + Err(err) => { + eprintln!("Can't get: {:?}", err); + continue; // If we can't determine the peer address, don't + } + } // Use an adapter to access something implementing `tokio::io` traits as if they implement // `hyper::rt` IO traits. let io = TokioIo::new(stream); @@ -405,12 +419,13 @@ async fn serveweb_async(listener: TcpListener, ctx: Arc) -> MyResult<() } } -pub fn serveweb(addresses: &Vec, urls: &[String], password_ch: cxx::UniquePtr, api_ch: cxx::UniquePtr) -> Result<(), std::io::Error> { +pub fn serveweb(addresses: &Vec, urls: &[String], password_ch: cxx::UniquePtr, api_ch: cxx::UniquePtr, acl: cxx::UniquePtr) -> Result<(), std::io::Error> { // Context (R/O for now) let ctx = Arc::new(Context { urls: urls.to_vec(), password_ch, api_ch, + acl, counter: Mutex::new(0), }); @@ -460,18 +475,22 @@ pub fn serveweb(addresses: &Vec, urls: &[String], password_ch: cxx::Uniq unsafe impl Send for rustweb::CredentialsHolder {} unsafe impl Sync for rustweb::CredentialsHolder {} +unsafe impl Send for rustweb::NetmaskGroup {} +unsafe impl Sync for rustweb::NetmaskGroup {} #[cxx::bridge(namespace = "pdns::rust::web::rec")] mod rustweb { extern "C++" { - type CredentialsHolder; + type CredentialsHolder; + type NetmaskGroup; + type ComboAddress; } /* * Functions callable from C++ */ extern "Rust" { - fn serveweb(addreses: &Vec, urls: &[String], pwch: UniquePtr, apikeych: UniquePtr) -> Result<()>; + fn serveweb(addreses: &Vec, urls: &[String], pwch: UniquePtr, apikeych: UniquePtr, acl: UniquePtr) -> Result<()>; } struct KeyValue { @@ -520,5 +539,7 @@ mod rustweb { fn serveStuff(request: &Request, response: &mut Response) -> Result<()>; fn matches(self: &CredentialsHolder, str: &CxxString) -> bool; + fn comboaddress(address: &str) -> UniquePtr; + fn matches(nmg: &UniquePtr, address: &UniquePtr) -> bool; // match is a keyword } } diff --git a/pdns/recursordist/ws-recursor.cc b/pdns/recursordist/ws-recursor.cc index d4449971fc..10698e2b71 100644 --- a/pdns/recursordist/ws-recursor.cc +++ b/pdns/recursordist/ws-recursor.cc @@ -46,6 +46,7 @@ #include "tcpiohandler.hh" #include "rec-main.hh" #include "settings/cxxsettings.hh" // IWYU pragma: keep, needed by included generated file +#include "settings/rust/src/bridge.hh" #include "settings/rust/web.rs.h" using json11::Json; @@ -994,7 +995,11 @@ void serveRustWeb() if (!apikeyString.empty()) { apikey = std::make_unique(std::move(apikeyString), arg().mustDo("webserver-hash-plaintext-credentials")); } - pdns::rust::web::rec::serveweb({::rust::String(address.toStringWithPort())}, ::rust::Slice{urls.data(), urls.size()}, std::move(password), std::move(apikey)); + NetmaskGroup acl; + acl.toMasks(::arg()["webserver-allow-from"]); + auto aclPtr = std::make_unique(acl); + + pdns::rust::web::rec::serveweb({::rust::String(address.toStringWithPort())}, ::rust::Slice{urls.data(), urls.size()}, std::move(password), std::move(apikey), std::move(aclPtr)); } static void fromCxxToRust(const HttpResponse& cxxresp, pdns::rust::web::rec::Response& rustResponse)