use std::{
fmt,
net::{IpAddr, SocketAddr, SocketAddrV4, SocketAddrV6},
str::FromStr,
};
use crate::error::{AresError, Result};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct HostEntry {
pub name: String,
pub aliases: Vec<String>,
pub addresses: Vec<IpAddr>,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct NameInfo {
pub node: Option<String>,
pub service: Option<String>,
}
macro_rules! dns_enum {
($(#[$meta:meta])* $name:ident { $($(#[$item:meta])* $variant:ident = $value:literal,)+ }) => {
$(#[$meta])*
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u32)]
pub enum $name { $($(#[$item])* $variant = $value,)+ }
impl $name {
pub const fn as_raw(self) -> u32 { self as u32 }
pub fn from_raw(value: u32) -> Result<Self> {
match value {
$($value => Ok(Self::$variant),)+
_ => Err(AresError::invalid_input(format!(
"unsupported {} value {value}", stringify!($name)
))),
}
}
}
impl TryFrom<u32> for $name {
type Error = AresError;
fn try_from(value: u32) -> Result<Self> { Self::from_raw(value) }
}
impl TryFrom<u16> for $name {
type Error = AresError;
fn try_from(value: u16) -> Result<Self> { Self::from_raw(u32::from(value)) }
}
impl From<$name> for u32 {
fn from(value: $name) -> Self { value.as_raw() }
}
};
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(transparent)]
pub struct DnsClass(u16);
impl DnsClass {
pub const IN: Self = Self(1);
pub const CHAOS: Self = Self(3);
pub const HESIOD: Self = Self(4);
pub const NONE: Self = Self(254);
pub const ANY: Self = Self(255);
pub const fn new(value: u16) -> Self {
Self(value)
}
pub const fn as_raw(self) -> u32 {
self.0 as u32
}
pub fn from_raw(value: u32) -> Result<Self> {
u16::try_from(value).map(Self).map_err(|_| {
AresError::invalid_input(format!("DNS class exceeds its 16-bit wire field: {value}"))
})
}
}
impl From<u16> for DnsClass {
fn from(value: u16) -> Self {
Self(value)
}
}
impl TryFrom<u32> for DnsClass {
type Error = AresError;
fn try_from(value: u32) -> Result<Self> {
Self::from_raw(value)
}
}
impl From<DnsClass> for u32 {
fn from(value: DnsClass) -> Self {
value.as_raw()
}
}
dns_enum! {
DnsRecordType {
A = 1,
NS = 2,
CNAME = 5,
SOA = 6,
PTR = 12,
HINFO = 13,
MX = 15,
TXT = 16,
SIG = 24,
AAAA = 28,
SRV = 33,
NAPTR = 35,
OPT = 41,
TLSA = 52,
SVCB = 64,
HTTPS = 65,
ANY = 255,
URI = 256,
CAA = 257,
RawRr = 65536,
}
}
dns_enum! {
DnsSection {
Answer = 1,
Authority = 2,
Additional = 3,
}
}
dns_enum! {
DnsOpcode {
Query = 0,
Iquery = 1,
Status = 2,
Notify = 4,
Update = 5,
}
}
dns_enum! {
DnsRcode {
NoError = 0,
FormErr = 1,
ServFail = 2,
NxDomain = 3,
NotImp = 4,
Refused = 5,
YxDomain = 6,
YxRrset = 7,
NxRrset = 8,
NotAuth = 9,
NotZone = 10,
DsoTypeNotImplemented = 11,
BadSig = 16,
BadKey = 17,
BadTime = 18,
BadMode = 19,
BadName = 20,
BadAlg = 21,
BadTrunc = 22,
BadCookie = 23,
}
}
impl DnsRcode {
pub const BADVERS: Self = Self::BadSig;
}
macro_rules! ffi_conversions {
($($safe:ident => $raw:ident;)+) => {$(
impl TryFrom<cares_sys::$raw> for $safe {
type Error = AresError;
fn try_from(value: cares_sys::$raw) -> Result<Self> {
Self::from_raw(value.0)
}
}
impl From<$safe> for cares_sys::$raw {
fn from(value: $safe) -> Self {
Self(value.as_raw())
}
}
)+};
}
ffi_conversions! {
DnsClass => ares_dns_class_t;
DnsRecordType => ares_dns_rec_type_t;
DnsSection => ares_dns_section_t;
DnsOpcode => ares_dns_opcode_t;
DnsRcode => ares_dns_rcode_t;
}
bitflags::bitflags! {
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct DnsFlags: u16 {
const QR = 1;
const AA = 2;
const TC = 4;
const RD = 8;
const RA = 16;
const AD = 32;
const CD = 64;
}
#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
pub struct ServerStateFlags: i32 {
const UDP = 1;
const TCP = 2;
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct SocketAddress(pub SocketAddr);
impl SocketAddress {
pub const fn new(ip: IpAddr, port: u16) -> Self {
Self(SocketAddr::new(ip, port))
}
pub const fn ip(self) -> IpAddr {
self.0.ip()
}
pub const fn port(self) -> u16 {
self.0.port()
}
pub const fn as_std(&self) -> &SocketAddr {
&self.0
}
pub const fn into_std(self) -> SocketAddr {
self.0
}
}
impl From<SocketAddr> for SocketAddress {
fn from(value: SocketAddr) -> Self {
Self(value)
}
}
impl From<SocketAddrV4> for SocketAddress {
fn from(value: SocketAddrV4) -> Self {
Self(SocketAddr::V4(value))
}
}
impl From<SocketAddrV6> for SocketAddress {
fn from(value: SocketAddrV6) -> Self {
Self(SocketAddr::V6(value))
}
}
impl From<SocketAddress> for SocketAddr {
fn from(value: SocketAddress) -> Self {
value.0
}
}
impl FromStr for SocketAddress {
type Err = AresError;
fn from_str(value: &str) -> Result<Self> {
value.parse().map(Self).map_err(|error| {
AresError::invalid_input(format!("invalid DNS server endpoint {value:?}: {error}"))
})
}
}
impl fmt::Display for SocketAddress {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(formatter)
}
}