Compare commits
2 commits
dcfce58525
...
feca3758a9
Author | SHA1 | Date | |
---|---|---|---|
chayleaf | feca3758a9 | ||
chayleaf | 4f43475c76 |
40
Cargo.toml
40
Cargo.toml
|
@ -9,20 +9,34 @@ crate-type = ["rlib", "cdylib"]
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
boxcar = "0.2.5"
|
||||
boxcar = { version = "0.2.5", optional = true }
|
||||
ctor = { version = "0.2.8", optional = true }
|
||||
filetime = "0.2.24"
|
||||
ipnet = { version = "2.9.0", features = ["serde"] }
|
||||
iptrie = "0.8.5"
|
||||
libc = "0.2.155"
|
||||
mnl = { version = "0.2.2", features = ["mnl-1-0-4"] }
|
||||
nftnl = { version = "0.6.2", features = ["nftnl-1-1-2"] }
|
||||
nix = { version = "0.29.0", features = ["poll", "user"] }
|
||||
radix_trie = "0.2.1"
|
||||
serde = { version = "1.0.205", features = ["derive"] }
|
||||
serde_json = "1.0.122"
|
||||
smallvec = "1.13.2"
|
||||
filetime = { version = "0.2.24", optional = true }
|
||||
ipnet = { version = "2.9.0", features = ["serde"], optional = true }
|
||||
iptrie = { version = "0.8.5", optional = true }
|
||||
libc = { version = "0.2.155", optional = true }
|
||||
mnl = { version = "0.2.2", features = ["mnl-1-0-4"], optional = true }
|
||||
nftnl = { version = "0.6.2", features = ["nftnl-1-1-2"], optional = true }
|
||||
nix = { version = "0.29.0", features = ["poll", "user"], optional = true }
|
||||
radix_trie = { version = "0.2.1", optional = true }
|
||||
serde = { version = "1.0.205", features = ["derive"], optional = true }
|
||||
serde_json = { version = "1.0.122", optional = true }
|
||||
smallvec = { version = "1.13.2", optional = true }
|
||||
|
||||
[features]
|
||||
example = ["ctor"]
|
||||
example = [
|
||||
"boxcar",
|
||||
"ctor",
|
||||
"filetime",
|
||||
"ipnet",
|
||||
"iptrie",
|
||||
"libc",
|
||||
"mnl",
|
||||
"nftnl",
|
||||
"nix",
|
||||
"radix_trie",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"smallvec",
|
||||
]
|
||||
default = ["example"]
|
||||
|
|
|
@ -22,15 +22,23 @@ use serde::{
|
|||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{
|
||||
domain_tree::PrefixSet,
|
||||
nftables::{nftables_thread, NftData},
|
||||
unbound::{rr_class, rr_type, ModuleEvent, ModuleExtState, ReplyInfo},
|
||||
UnboundMod,
|
||||
};
|
||||
use domain_tree::PrefixSet;
|
||||
use nftables::{nftables_thread, NftData};
|
||||
|
||||
mod domain_tree;
|
||||
mod nftables;
|
||||
|
||||
type Domain = SmallVec<[u8; 32]>;
|
||||
type DomainSeg = SmallVec<[u8; 16]>;
|
||||
|
||||
#[ctor]
|
||||
fn setup() {
|
||||
crate::set_unbound_mod::<ExampleMod>();
|
||||
}
|
||||
|
||||
struct IpNetDeser(IpNet);
|
||||
struct IpNetVisitor;
|
||||
impl<'de> Visitor<'de> for IpNetVisitor {
|
||||
|
@ -462,7 +470,9 @@ impl ExampleMod {
|
|||
let mut ip6: SmallVec<[Ipv6Addr; 4]> = SmallVec::new();
|
||||
for rrset in rep.rrsets() {
|
||||
let entry = rrset.entry();
|
||||
let d = entry.data();
|
||||
let Some(d) = entry.data() else {
|
||||
continue;
|
||||
};
|
||||
let rk = rrset.rk();
|
||||
if rk.rrset_class() != rr_class::IN {
|
||||
continue;
|
||||
|
@ -738,11 +748,6 @@ impl UnboundMod for ExampleMod {
|
|||
}
|
||||
}
|
||||
|
||||
#[ctor]
|
||||
fn setup() {
|
||||
crate::set_unbound_mod::<ExampleMod>();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{net::Ipv4Addr, os::unix::fs::MetadataExt, path::PathBuf, str::FromStr, sync::mpsc};
|
|
@ -471,7 +471,7 @@ pub(crate) fn nftables_thread(
|
|||
}
|
||||
}
|
||||
let socket = mnl::Socket::new(mnl::Bus::Netfilter).unwrap();
|
||||
let all_sets = crate::nftables::get_sets(&socket).unwrap();
|
||||
let all_sets = get_sets(&socket).unwrap();
|
||||
for set in all_sets {
|
||||
for ruleset in &mut rulesets {
|
||||
if set.table_name_str() == Some("global") && set.family() == libc::NFPROTO_INET as u32 {
|
||||
|
@ -531,9 +531,7 @@ mod test {
|
|||
use ipnet::{Ipv4Net, Ipv6Net};
|
||||
use iptrie::RTrieSet;
|
||||
|
||||
use crate::nftables::{iter_ip_trie, should_add};
|
||||
|
||||
use super::get_sets;
|
||||
use super::{get_sets, iter_ip_trie, should_add};
|
||||
|
||||
#[test]
|
||||
fn test_nftables() {
|
45
src/lib.rs
45
src/lib.rs
|
@ -15,11 +15,9 @@ use unbound::ModuleExtState;
|
|||
)]
|
||||
mod bindings;
|
||||
mod combine;
|
||||
mod domain_tree;
|
||||
#[cfg(feature = "example")]
|
||||
mod example;
|
||||
mod exports;
|
||||
mod nftables;
|
||||
mod unbound;
|
||||
|
||||
pub trait UnboundMod: Send + Sync + Sized + RefUnwindSafe + UnwindSafe {
|
||||
|
@ -92,7 +90,7 @@ unsafe impl<T: UnboundMod> SealedUnboundMod for T {
|
|||
id: ::std::os::raw::c_int,
|
||||
) {
|
||||
std::panic::catch_unwind(|| {
|
||||
self.deinit(&mut unbound::ModuleEnvMut(env, id, Default::default()));
|
||||
self.deinit(&mut unbound::ModuleEnvMut::from_raw(env, id).unwrap());
|
||||
})
|
||||
.unwrap_or(());
|
||||
}
|
||||
|
@ -105,15 +103,13 @@ unsafe impl<T: UnboundMod> SealedUnboundMod for T {
|
|||
) {
|
||||
std::panic::catch_unwind(|| {
|
||||
if let Some(ext_state) = self.operate(
|
||||
&mut unbound::ModuleQstateMut(unbound::ModuleQstate(
|
||||
qstate,
|
||||
id,
|
||||
Default::default(),
|
||||
)),
|
||||
&mut unbound::ModuleQstateMut::from_raw(qstate, id).unwrap(),
|
||||
event.into(),
|
||||
&mut unbound::OutboundEntryMut(entry, Default::default()),
|
||||
&mut unbound::OutboundEntryMut::from_raw(entry).unwrap(),
|
||||
) {
|
||||
(*qstate).ext_state[id as usize] = ext_state as bindings::module_ext_state;
|
||||
if let Some(id) = unbound::check_id(id) {
|
||||
(*qstate).ext_state[id] = ext_state as bindings::module_ext_state;
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap_or(());
|
||||
|
@ -126,16 +122,8 @@ unsafe impl<T: UnboundMod> SealedUnboundMod for T {
|
|||
) {
|
||||
std::panic::catch_unwind(|| {
|
||||
self.inform_super(
|
||||
&mut unbound::ModuleQstateMut(unbound::ModuleQstate(
|
||||
qstate,
|
||||
id,
|
||||
Default::default(),
|
||||
)),
|
||||
&mut unbound::ModuleQstateMut(unbound::ModuleQstate(
|
||||
super_qstate,
|
||||
-1,
|
||||
Default::default(),
|
||||
)),
|
||||
&mut unbound::ModuleQstateMut::from_raw(qstate, id).unwrap(),
|
||||
&mut unbound::ModuleQstateMut::from_raw(super_qstate, -1).unwrap(),
|
||||
);
|
||||
})
|
||||
.unwrap_or(());
|
||||
|
@ -146,11 +134,7 @@ unsafe impl<T: UnboundMod> SealedUnboundMod for T {
|
|||
id: ::std::os::raw::c_int,
|
||||
) {
|
||||
std::panic::catch_unwind(|| {
|
||||
self.clear(&mut unbound::ModuleQstateMut(unbound::ModuleQstate(
|
||||
qstate,
|
||||
id,
|
||||
Default::default(),
|
||||
)));
|
||||
self.clear(&mut unbound::ModuleQstateMut::from_raw(qstate, id).unwrap());
|
||||
})
|
||||
.unwrap_or(());
|
||||
}
|
||||
|
@ -160,7 +144,7 @@ unsafe impl<T: UnboundMod> SealedUnboundMod for T {
|
|||
id: ::std::os::raw::c_int,
|
||||
) -> usize {
|
||||
std::panic::catch_unwind(|| {
|
||||
self.get_mem(&mut unbound::ModuleEnvMut(env, id, Default::default()))
|
||||
self.get_mem(&mut unbound::ModuleEnvMut::from_raw(env, id).unwrap())
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
@ -183,13 +167,12 @@ pub fn set_unbound_mod<T: 'static + UnboundMod>() {
|
|||
MODULE_FACTORY
|
||||
.set(Box::new(|env, id| {
|
||||
std::panic::catch_unwind(|| {
|
||||
T::init(&mut unbound::ModuleEnvMut(env, id, Default::default())).map_or(
|
||||
0,
|
||||
|module| {
|
||||
unbound::ModuleEnvMut::from_raw(env, id)
|
||||
.and_then(|mut env| T::init(&mut env).ok())
|
||||
.map_or(0, |module| {
|
||||
MODULE.set(Box::new(module)).map_err(|_| ()).unwrap();
|
||||
1
|
||||
},
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap_or(0)
|
||||
}))
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
fn run<T: ToString>(
|
||||
family: &str,
|
||||
table: &str,
|
||||
set: &str,
|
||||
flush: bool,
|
||||
items: impl IntoIterator<T>,
|
||||
) {
|
||||
let nft = libnftables1_sys::Nftables::new();
|
||||
let mut cmd = String::new();
|
||||
if flush {
|
||||
cmd.push_str(&format!("flush set {family} {table} {set}"));
|
||||
nft.run_cmd(c)
|
||||
}
|
||||
nft.set_numeric_time
|
||||
}
|
514
src/unbound.rs
514
src/unbound.rs
|
@ -1,38 +1,68 @@
|
|||
#![allow(dead_code)]
|
||||
use crate::bindings::{
|
||||
self, config_file, dns_msg, in6_addr, in6_addr__bindgen_ty_1, in_addr, infra_cache, key_cache,
|
||||
lruhash_entry, module_env, module_ev, module_ext_state, module_qstate, outbound_entry,
|
||||
packed_rrset_data, packed_rrset_key, query_info, reply_info, rrset_cache, rrset_id_type,
|
||||
rrset_trust, sec_status, slabhash, sldns_enum_ede_code, sockaddr_in, sockaddr_in6,
|
||||
sockaddr_storage, ub_packed_rrset_key, AF_INET, AF_INET6,
|
||||
self, config_file, dns_msg, infra_cache, key_cache, lruhash_entry, module_env, module_ev,
|
||||
module_ext_state, module_qstate, outbound_entry, packed_rrset_data, packed_rrset_key,
|
||||
query_info, reply_info, rrset_cache, rrset_id_type, rrset_trust, sec_status, slabhash,
|
||||
sldns_enum_ede_code, ub_packed_rrset_key,
|
||||
};
|
||||
use std::{
|
||||
ffi::CStr, marker::PhantomData, net::SocketAddr, ops::Deref, os::raw::c_char, ptr,
|
||||
ffi::CStr,
|
||||
marker::PhantomData,
|
||||
ops::Deref,
|
||||
os::raw::{c_char, c_int},
|
||||
ptr,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
pub struct ConfigFileMut<'a>(
|
||||
pub(crate) *mut config_file,
|
||||
PhantomData<&'a mut config_file>,
|
||||
);
|
||||
pub struct SlabHashMut<'a>(pub(crate) *mut slabhash, PhantomData<&'a mut slabhash>);
|
||||
pub struct RrsetCacheMut<'a>(
|
||||
pub(crate) *mut rrset_cache,
|
||||
PhantomData<&'a mut rrset_cache>,
|
||||
);
|
||||
pub struct InfraCacheMut<'a>(
|
||||
pub(crate) *mut infra_cache,
|
||||
PhantomData<&'a mut infra_cache>,
|
||||
);
|
||||
pub struct KeyCacheMut<'a>(pub(crate) *mut key_cache, PhantomData<&'a mut key_cache>);
|
||||
pub struct ModuleEnvMut<T>(
|
||||
macro_rules! create_struct {
|
||||
($ptr:tt, $name:tt, $mut:tt) => {
|
||||
pub struct $name<'a>(pub(crate) *mut $ptr, pub(crate) PhantomData<&'a $ptr>);
|
||||
pub struct $mut<'a>(pub(crate) $name<'a>);
|
||||
impl<'a> Deref for $mut<'a> {
|
||||
type Target = $name<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
impl<'a> $name<'a> {
|
||||
pub const fn as_ptr(&self) -> *const $ptr {
|
||||
self.0.cast_const()
|
||||
}
|
||||
pub unsafe fn from_raw(raw: *const $ptr) -> Option<Self> {
|
||||
(!raw.is_null()).then_some(Self(raw.cast_mut(), PhantomData))
|
||||
}
|
||||
}
|
||||
impl<'a> $mut<'a> {
|
||||
pub fn as_mut_ptr(&mut self) -> *mut $ptr {
|
||||
self.0 .0
|
||||
}
|
||||
pub unsafe fn from_raw(raw: *mut $ptr) -> Option<Self> {
|
||||
(!raw.is_null()).then_some(Self($name(raw, PhantomData)))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
create_struct!(config_file, ConfigFile, ConfigFileMut);
|
||||
create_struct!(slabhash, SlabHash, SlabHashMut);
|
||||
create_struct!(rrset_cache, RrsetCache, RrsetCacheMut);
|
||||
create_struct!(infra_cache, InfraCache, InfraCacheMut);
|
||||
create_struct!(key_cache, KeyCache, KeyCacheMut);
|
||||
pub struct ModuleEnv<'a, T>(
|
||||
pub(crate) *mut module_env,
|
||||
pub(crate) std::ffi::c_int,
|
||||
pub(crate) PhantomData<T>,
|
||||
pub(crate) c_int,
|
||||
pub(crate) PhantomData<&'a T>,
|
||||
);
|
||||
pub struct ModuleEnvMut<'a, T>(pub(crate) ModuleEnv<'a, T>);
|
||||
impl<'a, T> Deref for ModuleEnvMut<'a, T> {
|
||||
type Target = ModuleEnv<'a, T>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
pub struct ModuleQstate<'a, T>(
|
||||
pub(crate) *mut module_qstate,
|
||||
pub(crate) std::ffi::c_int,
|
||||
pub(crate) c_int,
|
||||
pub(crate) PhantomData<&'a mut T>,
|
||||
);
|
||||
pub struct ModuleQstateMut<'a, T>(pub(crate) ModuleQstate<'a, T>);
|
||||
|
@ -42,198 +72,176 @@ impl<'a, T> Deref for ModuleQstateMut<'a, T> {
|
|||
&self.0
|
||||
}
|
||||
}
|
||||
pub struct OutboundEntryMut<'a>(
|
||||
pub(crate) *mut outbound_entry,
|
||||
pub(crate) PhantomData<&'a mut outbound_entry>,
|
||||
);
|
||||
pub struct QueryInfo<'a>(
|
||||
pub(crate) *mut query_info,
|
||||
pub(crate) PhantomData<&'a mut query_info>,
|
||||
);
|
||||
pub struct QueryInfoMut<'a>(QueryInfo<'a>);
|
||||
impl<'a> Deref for QueryInfoMut<'a> {
|
||||
type Target = QueryInfo<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
pub struct DnsMsg<'a>(
|
||||
pub(crate) *mut dns_msg,
|
||||
pub(crate) PhantomData<&'a mut dns_msg>,
|
||||
);
|
||||
pub struct DnsMsgMut<'a>(DnsMsg<'a>);
|
||||
impl<'a> Deref for DnsMsgMut<'a> {
|
||||
type Target = DnsMsg<'a>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
pub struct ReplyInfo<'a>(
|
||||
pub(crate) *mut reply_info,
|
||||
pub(crate) PhantomData<&'a mut reply_info>,
|
||||
);
|
||||
pub struct UbPackedRrsetKey<'a>(
|
||||
pub(crate) *mut ub_packed_rrset_key,
|
||||
pub(crate) PhantomData<&'a mut ub_packed_rrset_key>,
|
||||
);
|
||||
pub struct LruHashEntry<'a>(
|
||||
pub(crate) *mut lruhash_entry,
|
||||
pub(crate) PhantomData<&'a mut lruhash_entry>,
|
||||
);
|
||||
pub struct PackedRrsetKey<'a>(
|
||||
pub(crate) *mut packed_rrset_key,
|
||||
pub(crate) PhantomData<&'a mut packed_rrset_key>,
|
||||
);
|
||||
pub struct PackedRrsetData<'a>(
|
||||
pub(crate) *mut packed_rrset_data,
|
||||
pub(crate) PhantomData<&'a mut packed_rrset_data>,
|
||||
);
|
||||
create_struct!(outbound_entry, OutboundEntry, OutboundEntryMut);
|
||||
create_struct!(query_info, QueryInfo, QueryInfoMut);
|
||||
create_struct!(dns_msg, DnsMsg, DnsMsgMut);
|
||||
create_struct!(reply_info, ReplyInfo, ReplyInfoMut);
|
||||
create_struct!(ub_packed_rrset_key, UbPackedRrsetKey, UbPackedRrsetKeyMut);
|
||||
create_struct!(lruhash_entry, LruHashEntry, LruHashEntryMut);
|
||||
create_struct!(packed_rrset_key, PackedRrsetKey, PackedRrsetKeyMut);
|
||||
create_struct!(packed_rrset_data, PackedRrsetData, PackedRrsetDataMut);
|
||||
|
||||
impl<'a> QueryInfo<'a> {
|
||||
pub fn qname(&self) -> &CStr {
|
||||
unsafe { CStr::from_ptr((*self.0).qname as *const c_char) }
|
||||
unsafe { CStr::from_ptr((*self.as_ptr()).qname as *const c_char) }
|
||||
}
|
||||
pub fn qtype(&self) -> u16 {
|
||||
unsafe { (*self.0).qtype }
|
||||
unsafe { (*self.as_ptr()).qtype }
|
||||
}
|
||||
pub fn qclass(&self) -> u16 {
|
||||
unsafe { (*self.0).qclass }
|
||||
unsafe { (*self.as_ptr()).qclass }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ModuleEnvMut<T> {
|
||||
pub fn config_file_mut(&mut self) -> ConfigFileMut<'_> {
|
||||
ConfigFileMut(unsafe { (*self.0).cfg }, Default::default())
|
||||
impl<'a, T> ModuleEnv<'a, T> {
|
||||
pub unsafe fn from_raw(raw: *mut bindings::module_env, id: c_int) -> Option<Self> {
|
||||
(!raw.is_null()).then_some(Self(raw, id, PhantomData))
|
||||
}
|
||||
pub fn msg_cache_mut(&mut self) -> SlabHashMut<'_> {
|
||||
SlabHashMut(unsafe { (*self.0).msg_cache }, Default::default())
|
||||
pub const fn as_ptr(&self) -> *const module_env {
|
||||
self.0.cast_const()
|
||||
}
|
||||
pub fn rrset_cache_mut(&mut self) -> RrsetCacheMut<'_> {
|
||||
RrsetCacheMut(unsafe { (*self.0).rrset_cache }, Default::default())
|
||||
pub fn config_file(&self) -> ConfigFile<'_> {
|
||||
unsafe { ConfigFile::from_raw((*self.as_ptr()).cfg).unwrap() }
|
||||
}
|
||||
pub fn infra_cache_mut(&mut self) -> InfraCacheMut<'_> {
|
||||
InfraCacheMut(unsafe { (*self.0).infra_cache }, Default::default())
|
||||
pub fn msg_cache(&self) -> SlabHash<'_> {
|
||||
unsafe { SlabHash::from_raw((*self.as_ptr()).msg_cache) }.unwrap()
|
||||
}
|
||||
pub fn key_cache_mut(&mut self) -> KeyCacheMut<'_> {
|
||||
KeyCacheMut(unsafe { (*self.0).key_cache }, Default::default())
|
||||
pub fn rrset_cache(&self) -> RrsetCache<'_> {
|
||||
unsafe { RrsetCache::from_raw((*self.as_ptr()).rrset_cache) }.unwrap()
|
||||
}
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn send_query<Y>(
|
||||
&mut self,
|
||||
qinfo: &QueryInfoMut,
|
||||
flags: u16,
|
||||
dnssec: u32,
|
||||
want_dnssec: bool,
|
||||
nocaps: bool,
|
||||
check_ratelimit: bool,
|
||||
addr: SocketAddr,
|
||||
zone: &[u8],
|
||||
tcp_upstream: bool,
|
||||
ssl_upstream: bool,
|
||||
tls_auth_name: Option<&CStr>,
|
||||
q: &mut ModuleQstate<Y>,
|
||||
) -> (Option<OutboundEntryMut<'_>>, bool) {
|
||||
let mut was_ratelimited = 0;
|
||||
let ret = unsafe {
|
||||
let mut addr4 = sockaddr_in {
|
||||
sin_port: 0,
|
||||
sin_addr: in_addr { s_addr: 0 },
|
||||
sin_zero: [0u8; 8],
|
||||
sin_family: AF_INET as u16,
|
||||
};
|
||||
let mut addr6 = sockaddr_in6 {
|
||||
sin6_port: 0,
|
||||
sin6_addr: in6_addr {
|
||||
__in6_u: in6_addr__bindgen_ty_1 {
|
||||
__u6_addr8: [0u8; 16],
|
||||
},
|
||||
},
|
||||
sin6_family: AF_INET6 as u16,
|
||||
sin6_flowinfo: 0,
|
||||
sin6_scope_id: 0,
|
||||
};
|
||||
let (addr, addr_len) = match addr {
|
||||
SocketAddr::V4(x) => {
|
||||
addr4.sin_port = x.port();
|
||||
addr4.sin_addr.s_addr = (*x.ip()).into();
|
||||
(
|
||||
std::ptr::addr_of!(addr4).cast::<sockaddr_storage>(),
|
||||
std::mem::size_of_val(&addr4),
|
||||
)
|
||||
pub fn infra_cache(&self) -> InfraCache<'_> {
|
||||
unsafe { InfraCache::from_raw((*self.as_ptr()).infra_cache) }.unwrap()
|
||||
}
|
||||
SocketAddr::V6(x) => {
|
||||
addr6.sin6_addr.__in6_u.__u6_addr8 = x.ip().octets();
|
||||
addr6.sin6_flowinfo = x.flowinfo();
|
||||
addr6.sin6_scope_id = x.scope_id();
|
||||
(
|
||||
std::ptr::addr_of!(addr6).cast(),
|
||||
std::mem::size_of_val(&addr6),
|
||||
)
|
||||
}
|
||||
};
|
||||
((*self.0).send_query.unwrap_unchecked())(
|
||||
qinfo.0 .0,
|
||||
flags,
|
||||
dnssec as i32,
|
||||
want_dnssec.into(),
|
||||
nocaps.into(),
|
||||
check_ratelimit.into(),
|
||||
addr.cast_mut(),
|
||||
addr_len as u32,
|
||||
zone.as_ptr().cast_mut(),
|
||||
zone.len(),
|
||||
tcp_upstream.into(),
|
||||
ssl_upstream.into(),
|
||||
tls_auth_name.map_or_else(ptr::null_mut, |x| x.as_ptr().cast_mut()),
|
||||
q.0,
|
||||
std::ptr::addr_of_mut!(was_ratelimited),
|
||||
)
|
||||
};
|
||||
if ret.is_null() {
|
||||
(None, was_ratelimited != 0)
|
||||
} else {
|
||||
(
|
||||
Some(OutboundEntryMut(ret, Default::default())),
|
||||
was_ratelimited != 0,
|
||||
)
|
||||
pub fn key_cache(&self) -> KeyCache<'_> {
|
||||
unsafe { KeyCache::from_raw((*self.as_ptr()).key_cache) }.unwrap()
|
||||
}
|
||||
}
|
||||
pub fn detach_subs<Y>(&mut self, qstate: &mut ModuleQstate<Y>) {
|
||||
unsafe { (*self.0).detach_subs.unwrap_unchecked()(qstate.0) }
|
||||
impl<'a, T> ModuleEnvMut<'a, T> {
|
||||
pub unsafe fn from_raw(raw: *mut bindings::module_env, id: c_int) -> Option<Self> {
|
||||
ModuleEnv::from_raw(raw, id).map(Self)
|
||||
}
|
||||
unsafe fn attach_sub<Y>(
|
||||
&mut self,
|
||||
qstate: &mut ModuleQstate<Y>,
|
||||
qinfo: &QueryInfoMut,
|
||||
qflags: u16,
|
||||
prime: bool,
|
||||
valrec: bool,
|
||||
init_sub: impl FnOnce(*mut module_qstate) -> Result<(), ()>,
|
||||
) -> Result<Option<ModuleQstate<'_, ()>>, ()> {
|
||||
let mut newq: *mut module_qstate = ptr::null_mut();
|
||||
let res = unsafe {
|
||||
((*self.0).attach_sub.unwrap_unchecked())(
|
||||
qstate.0,
|
||||
qinfo.0 .0,
|
||||
qflags,
|
||||
prime.into(),
|
||||
valrec.into(),
|
||||
&mut newq as _,
|
||||
)
|
||||
};
|
||||
if res != 0 {
|
||||
Ok(if newq.is_null() {
|
||||
None
|
||||
} else if init_sub(newq).is_ok() {
|
||||
Some(ModuleQstate(newq, qstate.1, Default::default()))
|
||||
} else {
|
||||
unsafe { ((*self.0).kill_sub.unwrap_unchecked())(newq) }
|
||||
return Err(());
|
||||
})
|
||||
} else {
|
||||
Err(())
|
||||
pub fn as_mut_ptr(&mut self) -> *mut module_env {
|
||||
self.0 .0
|
||||
}
|
||||
// FIXME: what lifetime to use?
|
||||
// #[allow(clippy::too_many_arguments)]
|
||||
// pub fn send_query<Y>(
|
||||
// &mut self,
|
||||
// qinfo: &QueryInfoMut,
|
||||
// flags: u16,
|
||||
// dnssec: u32,
|
||||
// want_dnssec: bool,
|
||||
// nocaps: bool,
|
||||
// check_ratelimit: bool,
|
||||
// addr: SocketAddr,
|
||||
// zone: &[u8],
|
||||
// tcp_upstream: bool,
|
||||
// ssl_upstream: bool,
|
||||
// tls_auth_name: Option<&CStr>,
|
||||
// q: &mut ModuleQstate<Y>,
|
||||
// ) -> (Option<OutboundEntryMut<'_>>, bool) {
|
||||
// let mut was_ratelimited = 0;
|
||||
// let ret = unsafe {
|
||||
// let mut addr4 = sockaddr_in {
|
||||
// sin_port: 0,
|
||||
// sin_addr: in_addr { s_addr: 0 },
|
||||
// sin_zero: [0u8; 8],
|
||||
// sin_family: AF_INET as u16,
|
||||
// };
|
||||
// let mut addr6 = sockaddr_in6 {
|
||||
// sin6_port: 0,
|
||||
// sin6_addr: in6_addr {
|
||||
// __in6_u: in6_addr__bindgen_ty_1 {
|
||||
// __u6_addr8: [0u8; 16],
|
||||
// },
|
||||
// },
|
||||
// sin6_family: AF_INET6 as u16,
|
||||
// sin6_flowinfo: 0,
|
||||
// sin6_scope_id: 0,
|
||||
// };
|
||||
// let (addr, addr_len) = match addr {
|
||||
// SocketAddr::V4(x) => {
|
||||
// addr4.sin_port = x.port();
|
||||
// addr4.sin_addr.s_addr = (*x.ip()).into();
|
||||
// (
|
||||
// ptr::addr_of!(addr4).cast::<sockaddr_storage>(),
|
||||
// mem::size_of_val(&addr4),
|
||||
// )
|
||||
// }
|
||||
// SocketAddr::V6(x) => {
|
||||
// addr6.sin6_addr.__in6_u.__u6_addr8 = x.ip().octets();
|
||||
// addr6.sin6_flowinfo = x.flowinfo();
|
||||
// addr6.sin6_scope_id = x.scope_id();
|
||||
// (
|
||||
// ptr::addr_of!(addr6).cast(),
|
||||
// mem::size_of_val(&addr6),
|
||||
// )
|
||||
// }
|
||||
// };
|
||||
// ((*self.as_ptr()).send_query.unwrap_unchecked())(
|
||||
// qinfo.as_ptr(),
|
||||
// flags,
|
||||
// dnssec as i32,
|
||||
// want_dnssec.into(),
|
||||
// nocaps.into(),
|
||||
// check_ratelimit.into(),
|
||||
// addr.cast_mut(),
|
||||
// addr_len as u32,
|
||||
// zone.as_ptr().cast_mut(),
|
||||
// zone.len(),
|
||||
// tcp_upstream.into(),
|
||||
// ssl_upstream.into(),
|
||||
// tls_auth_name.map_or_else(ptr::null_mut, |x| x.as_ptr().cast_mut()),
|
||||
// q.as_ptr(),
|
||||
// ptr::addr_of_mut!(was_ratelimited),
|
||||
// )
|
||||
// };
|
||||
// if ret.is_null() {
|
||||
// (None, was_ratelimited != 0)
|
||||
// } else {
|
||||
// (
|
||||
// Some(OutboundEntryMut(OutboundEntry(ret, PhantomData))),
|
||||
// was_ratelimited != 0,
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
pub fn detach_subs<Y>(&mut self, qstate: &mut ModuleQstateMut<Y>) {
|
||||
unsafe { (*self.as_ptr()).detach_subs.unwrap()(qstate.as_mut_ptr()) }
|
||||
}
|
||||
// FIXME: what lifetime to use?
|
||||
// unsafe fn attach_sub<Y>(
|
||||
// &mut self,
|
||||
// qstate: &mut ModuleQstate<Y>,
|
||||
// qinfo: &QueryInfoMut,
|
||||
// qflags: u16,
|
||||
// prime: bool,
|
||||
// valrec: bool,
|
||||
// init_sub: impl FnOnce(*mut module_qstate) -> Result<(), ()>,
|
||||
// ) -> Result<Option<ModuleQstate<'_, ()>>, ()> {
|
||||
// let mut newq: *mut module_qstate = ptr::null_mut();
|
||||
// let res = unsafe {
|
||||
// ((*self.as_ptr()).attach_sub.unwrap_unchecked())(
|
||||
// qstate.as_ptr(),
|
||||
// qinfo.as_ptr(),
|
||||
// qflags,
|
||||
// prime.into(),
|
||||
// valrec.into(),
|
||||
// &mut newq as _,
|
||||
// )
|
||||
// };
|
||||
// if res != 0 {
|
||||
// Ok(if newq.is_null() {
|
||||
// None
|
||||
// } else if init_sub(newq).is_ok() {
|
||||
// Some(ModuleQstate(newq, qstate.1, PhantomData))
|
||||
// } else {
|
||||
// unsafe { ((*self.as_ptr()).kill_sub.unwrap_unchecked())(newq) }
|
||||
// return Err(());
|
||||
// })
|
||||
// } else {
|
||||
// Err(())
|
||||
// }
|
||||
// }
|
||||
// add_sub: TODO similar to above
|
||||
// detect_cycle: TODO
|
||||
// (note that &mut T is wrapped in dynmod stuff)
|
||||
|
@ -241,21 +249,29 @@ impl<T> ModuleEnvMut<T> {
|
|||
}
|
||||
|
||||
impl<T> ModuleQstate<'_, T> {
|
||||
pub unsafe fn from_raw(raw: *mut bindings::module_qstate, id: c_int) -> Option<Self> {
|
||||
(!raw.is_null()).then_some(Self(raw, id, PhantomData))
|
||||
}
|
||||
pub const fn as_ptr(&self) -> *const module_qstate {
|
||||
self.0.cast_const()
|
||||
}
|
||||
pub fn qinfo(&self) -> QueryInfo<'_> {
|
||||
QueryInfo(
|
||||
unsafe { std::ptr::addr_of_mut!((*self.0).qinfo) },
|
||||
Default::default(),
|
||||
)
|
||||
unsafe { QueryInfo::from_raw(ptr::addr_of!((*self.as_ptr()).qinfo).cast_mut()).unwrap() }
|
||||
}
|
||||
pub fn return_msg(&self) -> Option<DnsMsg<'_>> {
|
||||
if unsafe { (*self.0).return_msg.is_null() } {
|
||||
None
|
||||
} else {
|
||||
Some(DnsMsg(unsafe { (*self.0).return_msg }, Default::default()))
|
||||
unsafe { DnsMsg::from_raw((*self.as_ptr()).return_msg) }
|
||||
}
|
||||
}
|
||||
pub(crate) fn check_id(id: i32) -> Option<usize> {
|
||||
(id >= 0 && id < bindings::MAX_MODULE as i32).then_some(id as usize)
|
||||
}
|
||||
impl<T> ModuleQstateMut<'_, T> {
|
||||
pub unsafe fn from_raw(raw: *mut bindings::module_qstate, id: c_int) -> Option<Self> {
|
||||
ModuleQstate::from_raw(raw, id).map(Self)
|
||||
}
|
||||
pub fn as_mut_ptr(&mut self) -> *mut module_qstate {
|
||||
self.0 .0
|
||||
}
|
||||
pub fn qinfo_mut(&mut self) -> QueryInfoMut<'_> {
|
||||
QueryInfoMut(self.qinfo())
|
||||
}
|
||||
|
@ -264,158 +280,150 @@ impl<T> ModuleQstateMut<'_, T> {
|
|||
}
|
||||
pub fn set_ext_state(&mut self, state: ModuleExtState) {
|
||||
unsafe {
|
||||
(*self.0 .0).ext_state[self.1 as usize] = state as module_ext_state;
|
||||
if let Some(id) = check_id(self.1) {
|
||||
(*self.as_mut_ptr()).ext_state[id] = state as module_ext_state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DnsMsg<'_> {
|
||||
pub fn rep(&self) -> Option<ReplyInfo<'_>> {
|
||||
if unsafe { (*self.0).rep.is_null() } {
|
||||
None
|
||||
} else {
|
||||
Some(ReplyInfo(unsafe { (*self.0).rep }, Default::default()))
|
||||
}
|
||||
unsafe { ReplyInfo::from_raw((*self.as_ptr()).rep) }
|
||||
}
|
||||
}
|
||||
|
||||
impl ReplyInfo<'_> {
|
||||
pub fn flags(&self) -> u16 {
|
||||
unsafe { (*self.0).flags }
|
||||
unsafe { (*self.as_ptr()).flags }
|
||||
}
|
||||
pub fn authoritative(&self) -> bool {
|
||||
unsafe { (*self.0).authoritative != 0 }
|
||||
unsafe { (*self.as_ptr()).authoritative != 0 }
|
||||
}
|
||||
pub fn qdcount(&self) -> u8 {
|
||||
unsafe { (*self.0).qdcount }
|
||||
unsafe { (*self.as_ptr()).qdcount }
|
||||
}
|
||||
pub fn padding(&self) -> u32 {
|
||||
unsafe { (*self.0).padding }
|
||||
unsafe { (*self.as_ptr()).padding }
|
||||
}
|
||||
pub fn ttl(&self) -> Option<Duration> {
|
||||
(unsafe { (*self.0).ttl })
|
||||
(unsafe { (*self.as_ptr()).ttl })
|
||||
.try_into()
|
||||
.map(Duration::from_secs)
|
||||
.ok()
|
||||
}
|
||||
pub fn prefetch_ttl(&self) -> Option<Duration> {
|
||||
(unsafe { (*self.0).prefetch_ttl })
|
||||
(unsafe { (*self.as_ptr()).prefetch_ttl })
|
||||
.try_into()
|
||||
.map(Duration::from_secs)
|
||||
.ok()
|
||||
}
|
||||
pub fn serve_expired_ttl(&self) -> Option<Duration> {
|
||||
(unsafe { (*self.0).serve_expired_ttl })
|
||||
(unsafe { (*self.as_ptr()).serve_expired_ttl })
|
||||
.try_into()
|
||||
.map(Duration::from_secs)
|
||||
.ok()
|
||||
}
|
||||
pub fn security(&self) -> SecStatus {
|
||||
SecStatus::from(unsafe { (*self.0).security })
|
||||
SecStatus::from(unsafe { (*self.as_ptr()).security })
|
||||
}
|
||||
pub fn reason_bogus(&self) -> SldnsEdeCode {
|
||||
SldnsEdeCode::from(unsafe { (*self.0).reason_bogus })
|
||||
SldnsEdeCode::from(unsafe { (*self.as_ptr()).reason_bogus })
|
||||
}
|
||||
pub fn reason_bogus_str(&self) -> Option<&CStr> {
|
||||
if unsafe { (*self.0).reason_bogus_str.is_null() } {
|
||||
if unsafe { (*self.as_ptr()).reason_bogus_str.is_null() } {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { CStr::from_ptr((*self.0).reason_bogus_str) })
|
||||
Some(unsafe { CStr::from_ptr((*self.as_ptr()).reason_bogus_str) })
|
||||
}
|
||||
}
|
||||
pub fn an_numrrsets(&self) -> usize {
|
||||
unsafe { (*self.0).an_numrrsets }
|
||||
unsafe { (*self.as_ptr()).an_numrrsets }
|
||||
}
|
||||
pub fn ns_numrrsets(&self) -> usize {
|
||||
unsafe { (*self.0).ns_numrrsets }
|
||||
unsafe { (*self.as_ptr()).ns_numrrsets }
|
||||
}
|
||||
pub fn ar_numrrsets(&self) -> usize {
|
||||
unsafe { (*self.0).ar_numrrsets }
|
||||
unsafe { (*self.as_ptr()).ar_numrrsets }
|
||||
}
|
||||
pub fn rrset_count(&self) -> usize {
|
||||
unsafe { (*self.0).rrset_count }
|
||||
unsafe { (*self.as_ptr()).rrset_count }
|
||||
}
|
||||
pub fn rrsets(&self) -> impl '_ + Iterator<Item = UbPackedRrsetKey<'_>> {
|
||||
let total = self.rrset_count();
|
||||
let rrsets = unsafe { (*self.0).rrsets };
|
||||
(0..total).map(move |i| UbPackedRrsetKey(unsafe { *rrsets.add(i) }, Default::default()))
|
||||
let rrsets = unsafe { (*self.as_ptr()).rrsets };
|
||||
(0..total).filter_map(move |i| unsafe { UbPackedRrsetKey::from_raw(*rrsets.add(i)) })
|
||||
}
|
||||
}
|
||||
|
||||
impl UbPackedRrsetKey<'_> {
|
||||
pub fn entry(&self) -> LruHashEntry<'_> {
|
||||
LruHashEntry(
|
||||
unsafe { std::ptr::addr_of_mut!((*self.0).entry) },
|
||||
Default::default(),
|
||||
)
|
||||
unsafe { LruHashEntry::from_raw(ptr::addr_of!((*self.as_ptr()).entry).cast_mut()).unwrap() }
|
||||
}
|
||||
pub fn id(&self) -> RrsetIdType {
|
||||
unsafe { (*self.0).id }
|
||||
unsafe { (*self.as_ptr()).id }
|
||||
}
|
||||
pub fn rk(&self) -> PackedRrsetKey<'_> {
|
||||
PackedRrsetKey(
|
||||
unsafe { std::ptr::addr_of_mut!((*self.0).rk) },
|
||||
Default::default(),
|
||||
)
|
||||
unsafe { PackedRrsetKey::from_raw(ptr::addr_of!((*self.as_ptr()).rk).cast_mut()).unwrap() }
|
||||
}
|
||||
}
|
||||
|
||||
impl PackedRrsetKey<'_> {
|
||||
pub fn dname(&self) -> Option<&'_ CStr> {
|
||||
if unsafe { (*self.0).dname.is_null() } {
|
||||
if unsafe { (*self.as_ptr()).dname.is_null() } {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { CStr::from_ptr((*self.0).dname as *const c_char) })
|
||||
Some(unsafe { CStr::from_ptr((*self.as_ptr()).dname as *const c_char) })
|
||||
}
|
||||
}
|
||||
pub fn flags(&self) -> u32 {
|
||||
unsafe { (*self.0).flags }
|
||||
unsafe { (*self.as_ptr()).flags }
|
||||
}
|
||||
pub fn type_(&self) -> u16 {
|
||||
u16::from_be(unsafe { (*self.0).type_ })
|
||||
u16::from_be(unsafe { (*self.as_ptr()).type_ })
|
||||
}
|
||||
pub fn rrset_class(&self) -> u16 {
|
||||
u16::from_be(unsafe { (*self.0).rrset_class })
|
||||
u16::from_be(unsafe { (*self.as_ptr()).rrset_class })
|
||||
}
|
||||
}
|
||||
|
||||
impl LruHashEntry<'_> {
|
||||
pub fn data(&self) -> PackedRrsetData<'_> {
|
||||
pub fn data(&self) -> Option<PackedRrsetData<'_>> {
|
||||
// FIXME: shouldnt pthread lock be used here?
|
||||
unsafe { PackedRrsetData((*self.0).data.cast(), Default::default()) }
|
||||
unsafe { PackedRrsetData::from_raw((*self.as_ptr()).data.cast()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PackedRrsetData<'_> {
|
||||
pub fn ttl_add(&self) -> Option<Duration> {
|
||||
(unsafe { (*self.0).ttl_add })
|
||||
(unsafe { (*self.as_ptr()).ttl_add })
|
||||
.try_into()
|
||||
.map(Duration::from_secs)
|
||||
.ok()
|
||||
}
|
||||
pub fn ttl(&self) -> Option<Duration> {
|
||||
(unsafe { (*self.0).ttl })
|
||||
(unsafe { (*self.as_ptr()).ttl })
|
||||
.try_into()
|
||||
.map(Duration::from_secs)
|
||||
.ok()
|
||||
}
|
||||
pub fn count(&self) -> usize {
|
||||
unsafe { (*self.0).count }
|
||||
unsafe { (*self.as_ptr()).count }
|
||||
}
|
||||
pub fn rrsig_count(&self) -> usize {
|
||||
unsafe { (*self.0).rrsig_count }
|
||||
unsafe { (*self.as_ptr()).rrsig_count }
|
||||
}
|
||||
pub fn trust(&self) -> RrsetTrust {
|
||||
RrsetTrust::from(unsafe { (*self.0).trust })
|
||||
RrsetTrust::from(unsafe { (*self.as_ptr()).trust })
|
||||
}
|
||||
pub fn security(&self) -> SecStatus {
|
||||
SecStatus::from(unsafe { (*self.0).security })
|
||||
SecStatus::from(unsafe { (*self.as_ptr()).security })
|
||||
}
|
||||
pub fn rr_data(&self) -> impl '_ + Iterator<Item = (&[u8], Option<Duration>)> {
|
||||
let total = self.count();
|
||||
let ttl = unsafe { (*self.0).rr_ttl };
|
||||
let len = unsafe { (*self.0).rr_len };
|
||||
let data = unsafe { (*self.0).rr_data };
|
||||
let ttl = unsafe { (*self.as_ptr()).rr_ttl };
|
||||
let len = unsafe { (*self.as_ptr()).rr_len };
|
||||
let data = unsafe { (*self.as_ptr()).rr_data };
|
||||
(0..total).map(move |i| unsafe {
|
||||
(
|
||||
std::slice::from_raw_parts(*data.add(i), *len.add(i)),
|
||||
|
@ -426,8 +434,8 @@ impl PackedRrsetData<'_> {
|
|||
pub fn rrsig_data(&self) -> impl '_ + Iterator<Item = &[u8]> {
|
||||
let total = self.count();
|
||||
let total2 = self.rrsig_count();
|
||||
let len = unsafe { (*self.0).rr_len };
|
||||
let data = unsafe { (*self.0).rr_data };
|
||||
let len = unsafe { (*self.as_ptr()).rr_len };
|
||||
let data = unsafe { (*self.as_ptr()).rr_data };
|
||||
(total..total + total2)
|
||||
.map(move |i| unsafe { std::slice::from_raw_parts(*data.add(i), *len.add(i)) })
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue