From 8c5eaccb5d654eab6894dfa927a8cb148da55c82 Mon Sep 17 00:00:00 2001
From: Pat Hickey
Date: Mon, 25 Aug 2025 09:04:41 -0700
Subject: [PATCH] Net: replace crate::net::resolver with ngx::async_::resolver
ngx's resolver started as this crate's resolver, and includes bug fixes
---
Cargo.lock | 12 +--
Cargo.toml | 4 +-
src/conf.rs | 2 +-
src/net.rs | 1 -
src/net/http.rs | 6 +-
src/net/peer_conn.rs | 8 +-
src/net/resolver.rs | 203 -------------------------------------------
7 files changed, 16 insertions(+), 220 deletions(-)
delete mode 100644 src/net/resolver.rs
diff --git a/Cargo.lock b/Cargo.lock
index 08455d6..f00a319 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -28,9 +28,9 @@ dependencies = [
[[package]]
name = "allocator-api2"
-version = "0.2.21"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
+checksum = "c583acf993cf4245c4acb0a2cc2ab1f9cc097de73411bb6d3647ff6af2b1013d"
dependencies = [
"serde",
]
@@ -484,9 +484,9 @@ dependencies = [
[[package]]
name = "nginx-sys"
-version = "0.5.0-beta"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c042c2e0b0bfbc6422ef53a4a8275518438b4f5447ec9fd32eb2d31f018fc492"
+checksum = "3c85fc3a3b71cdb9269103e3934e989fe5c9f22a34d9068c1b23db1f0349ca79"
dependencies = [
"bindgen 0.72.0",
"cc",
@@ -498,9 +498,9 @@ dependencies = [
[[package]]
name = "ngx"
-version = "0.5.0-beta"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fd6e2877ca7004675715d9d2ce03fa0f83b513e6b6cb80391eedc9f10cf7f4c3"
+checksum = "3cafa4700c0836055c5c78ba9defc418cea187d92ac65478bb7053a5a1d39775"
dependencies = [
"allocator-api2",
"async-task",
diff --git a/Cargo.toml b/Cargo.toml
index 932b351..56a0a7a 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -21,8 +21,8 @@ http-body-util = "0.1.3"
http-serde = "2.1.1"
hyper = { version = "1.6.0", features = ["client", "http1"] }
libc = "0.2.174"
-nginx-sys = "0.5.0-beta"
-ngx = { version = "0.5.0-beta", features = ["async", "serde", "std"] }
+nginx-sys = "0.5.0"
+ngx = { version = "0.5.0", features = ["async", "serde", "std"] }
openssl = { version = "0.10.73", features = ["bindgen"] }
openssl-foreign-types = { package = "foreign-types", version = "0.3" }
openssl-sys = { version = "0.9.109", features = ["bindgen"] }
diff --git a/src/conf.rs b/src/conf.rs
index fce646c..f191a9f 100644
--- a/src/conf.rs
+++ b/src/conf.rs
@@ -412,7 +412,7 @@ extern "C" fn cmd_issuer_set_external_account_key(
return NGX_CONF_DUPLICATE;
}
- let mut pool = cf.pool();
+ let pool = cf.pool();
// NGX_CONF_TAKE2 ensures that args contains 3 elements
let args = cf.args();
diff --git a/src/net.rs b/src/net.rs
index c7022a9..c98b61a 100644
--- a/src/net.rs
+++ b/src/net.rs
@@ -6,4 +6,3 @@
pub mod connection;
pub mod http;
pub mod peer_conn;
-pub mod resolver;
diff --git a/src/net/http.rs b/src/net/http.rs
index 17b42e7..8a712a6 100644
--- a/src/net/http.rs
+++ b/src/net/http.rs
@@ -15,12 +15,12 @@ use http_body::Body;
use http_body_util::BodyExt;
use nginx_sys::{ngx_log_t, ngx_resolver_t, NGX_LOG_WARN};
use ngx::allocator::Box;
+use ngx::async_::resolver::Resolver;
use ngx::async_::spawn;
use ngx::ngx_log_error;
use thiserror::Error;
use super::peer_conn::PeerConnection;
-use super::resolver::Resolver;
use crate::conf::ssl::NgxSsl;
// The largest response we can reasonably expect is a certificate chain, which should not exceed
@@ -65,7 +65,7 @@ pub enum HttpClientError {
#[error("request error: {0}")]
Http(#[from] hyper::Error),
#[error("name resolution error: {0}")]
- Resolver(super::resolver::Error),
+ Resolver(ngx::async_::resolver::Error),
#[error("connection error: {0}")]
Io(io::Error),
#[error("invalid uri: {0}")]
@@ -74,7 +74,7 @@ pub enum HttpClientError {
impl From for HttpClientError {
fn from(err: io::Error) -> Self {
- match err.downcast::() {
+ match err.downcast::() {
Ok(x) => Self::Resolver(x),
Err(x) => Self::Io(x),
}
diff --git a/src/net/peer_conn.rs b/src/net/peer_conn.rs
index 73984de..8e9b427 100644
--- a/src/net/peer_conn.rs
+++ b/src/net/peer_conn.rs
@@ -17,13 +17,13 @@ use nginx_sys::{
ngx_ssl_shutdown, ngx_ssl_t, ngx_str_t, ngx_url_t, NGX_DEFAULT_POOL_SIZE, NGX_LOG_ERR,
NGX_LOG_WARN,
};
+use ngx::async_::resolver::Resolver;
use ngx::collections::Vec;
-use ngx::core::Status;
+use ngx::core::{Pool, Status};
use ngx::{ngx_log_debug, ngx_log_error};
use openssl_sys::{SSL_get_verify_result, X509_verify_cert_error_string, X509_V_OK};
use super::connection::{Connection, ConnectionLogError};
-use super::resolver::Resolver;
use crate::util::OwnedPool;
const ACME_DEFAULT_READ_TIMEOUT: ngx_msec_t = 60000;
@@ -165,7 +165,7 @@ impl PeerConnection {
url.default_port = if ssl.is_some() { 443 } else { 80 };
url.set_no_resolve(1);
- let addr_vec: Vec;
+ let addr_vec: Vec;
if Status(unsafe { nginx_sys::ngx_parse_url(self.pool.as_mut(), &mut url) })
!= Status::NGX_OK
@@ -183,7 +183,7 @@ impl PeerConnection {
self.pc.socklen = addr.socklen;
} else {
addr_vec = res
- .resolve(&url.host, self.pool.as_mut())
+ .resolve_name(&url.host, self.pool.as_mut())
.await
.map_err(io::Error::other)?;
diff --git a/src/net/resolver.rs b/src/net/resolver.rs
deleted file mode 100644
index 8407f69..0000000
--- a/src/net/resolver.rs
+++ /dev/null
@@ -1,203 +0,0 @@
-// Copyright (c) F5, Inc.
-//
-// This source code is licensed under the Apache License, Version 2.0 license found in the
-// LICENSE file in the root directory of this source tree.
-
-use core::ffi::c_void;
-use core::ptr::NonNull;
-use std::boxed::Box;
-use std::string::{String, ToString};
-
-use futures_channel::oneshot::{channel, Sender};
-use nginx_sys::{
- NGX_RESOLVE_FORMERR, NGX_RESOLVE_NOTIMP, NGX_RESOLVE_NXDOMAIN, NGX_RESOLVE_REFUSED,
- NGX_RESOLVE_SERVFAIL, NGX_RESOLVE_TIMEDOUT,
-};
-use ngx::{
- collections::Vec,
- core::Pool,
- ffi::{
- ngx_addr_t, ngx_msec_t, ngx_resolve_name, ngx_resolve_start, ngx_resolver_ctx_t,
- ngx_resolver_t, ngx_str_t,
- },
-};
-
-/// Error type for all uses of `Resolver`.
-#[derive(thiserror::Error, Debug)]
-pub enum Error {
- #[error("No resolver configured")]
- NoResolver,
- #[error("{0}: resolving `{1}`")]
- Resolver(ResolverError, String),
- #[error("Allocation failed")]
- AllocationFailed,
- #[error("Unexpected error: {0}")]
- Unexpected(String),
-}
-
-/// These cases directly reflect the NGX_RESOLVE_ error codes,
-/// plus a timeout, and a case for an unknown error where a known
-/// NGX_RESOLVE_ should be.
-#[derive(thiserror::Error, Debug)]
-pub enum ResolverError {
- #[error("Format error")]
- Format,
- #[error("Server failure")]
- Server,
- #[error("Host not found")]
- HostNotFound,
- #[error("Unimplemented")]
- Unimplemented,
- #[error("Operation refused")]
- Refused,
- #[error("Timed Out")]
- TimedOut,
- #[error("Unknown NGX_RESOLVE error {0}")]
- Unknown(isize),
-}
-/// Convert from the NGX_RESOLVE_ error codes. Fails if code was success.
-impl TryFrom for ResolverError {
- type Error = ();
- fn try_from(code: isize) -> Result {
- match code as u32 {
- 0 => Err(()),
- NGX_RESOLVE_FORMERR => Ok(ResolverError::Format),
- NGX_RESOLVE_SERVFAIL => Ok(ResolverError::Server),
- NGX_RESOLVE_NXDOMAIN => Ok(ResolverError::HostNotFound),
- NGX_RESOLVE_NOTIMP => Ok(ResolverError::Unimplemented),
- NGX_RESOLVE_REFUSED => Ok(ResolverError::Refused),
- NGX_RESOLVE_TIMEDOUT => Ok(ResolverError::TimedOut),
- _ => Ok(ResolverError::Unknown(code)),
- }
- }
-}
-
-type Res = Result, Error>;
-
-struct ResCtx<'a> {
- ctx: Option<*mut ngx_resolver_ctx_t>,
- sender: Option>,
- pool: &'a mut Pool,
-}
-
-impl Drop for ResCtx<'_> {
- fn drop(&mut self) {
- if let Some(ctx) = self.ctx.take() {
- unsafe {
- nginx_sys::ngx_resolve_name_done(ctx);
- }
- }
- }
-}
-
-fn copy_resolved_addr(
- addr: *mut nginx_sys::ngx_resolver_addr_t,
- pool: &mut Pool,
-) -> Result {
- let addr = NonNull::new(addr).ok_or(Error::Unexpected(
- "null ngx_resolver_addr_t in ngx_resolver_ctx_t.addrs".to_string(),
- ))?;
- let addr = unsafe { addr.as_ref() };
-
- let sockaddr = pool.alloc(addr.socklen as usize) as *mut nginx_sys::sockaddr;
- if sockaddr.is_null() {
- Err(Error::AllocationFailed)?;
- }
- unsafe {
- addr.sockaddr
- .cast::()
- .copy_to_nonoverlapping(sockaddr.cast(), addr.socklen as usize)
- };
-
- let name = unsafe { ngx_str_t::from_bytes(pool.as_mut(), addr.name.as_bytes()) }
- .ok_or(Error::AllocationFailed)?;
-
- Ok(ngx_addr_t {
- sockaddr,
- socklen: addr.socklen,
- name,
- })
-}
-
-pub struct Resolver {
- resolver: NonNull,
- timeout: ngx_msec_t,
-}
-
-impl Resolver {
- /// Create a new `Resolver` from existing pointer to `ngx_resolver_t` and
- /// timeout.
- pub fn from_resolver(resolver: NonNull, timeout: ngx_msec_t) -> Self {
- Self { resolver, timeout }
- }
-
- /// Resolve a name into a set of addresses.
- ///
- /// The set of addresses may not be deterministic, because the
- /// implementation of the resolver may race multiple DNS requests.
- pub async fn resolve(&self, name: &ngx_str_t, pool: &mut Pool) -> Res {
- unsafe {
- let ctx: *mut ngx_resolver_ctx_t =
- ngx_resolve_start(self.resolver.as_ptr(), core::ptr::null_mut());
- if ctx.is_null() {
- Err(Error::AllocationFailed)?
- }
- if ctx as isize == -1 {
- Err(Error::NoResolver)?
- }
-
- let (sender, receiver) = channel::();
- let rctx = Box::new(ResCtx {
- ctx: Some(ctx),
- sender: Some(sender),
- pool,
- });
-
- (*ctx).name = *name;
- (*ctx).timeout = self.timeout;
- (*ctx).set_cancelable(1);
- (*ctx).handler = Some(Self::resolve_handler);
- (*ctx).data = Box::into_raw(rctx) as *mut c_void;
-
- let ret = ngx_resolve_name(ctx);
- if ret != 0 {
- Err(Error::Resolver(
- ResolverError::try_from(ret).expect("nonzero, checked above"),
- name.to_string(),
- ))?;
- }
-
- receiver
- .await
- .map_err(|_| Error::Resolver(ResolverError::TimedOut, name.to_string()))?
- }
- }
-
- unsafe extern "C" fn resolve_handler(ctx: *mut ngx_resolver_ctx_t) {
- let mut rctx = *Box::from_raw((*ctx).data as *mut ResCtx);
- rctx.ctx.take();
- if let Some(sender) = rctx.sender.take() {
- let _ = sender.send(Self::resolve_result(ctx, rctx.pool));
- }
- nginx_sys::ngx_resolve_name_done(ctx);
- }
-
- fn resolve_result(ctx: *mut ngx_resolver_ctx_t, pool: &mut Pool) -> Res {
- let ctx = unsafe { ctx.as_ref().unwrap() };
- let s = ctx.state;
- if s != 0 {
- Err(Error::Resolver(
- ResolverError::try_from(s).expect("nonzero, checked above"),
- ctx.name.to_string(),
- ))?;
- }
- if ctx.addrs.is_null() {
- Err(Error::AllocationFailed)?;
- }
- let mut out = Vec::new();
- for i in 0..ctx.naddrs {
- out.push(copy_resolved_addr(unsafe { ctx.addrs.add(i) }, pool)?);
- }
- Ok(out)
- }
-}