1use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
2use std::os::raw::c_char;
3use std::{fmt, ptr, slice};
4
5use itertools::Itertools;
6
7use crate::types::AddressFamily;
8use crate::utils::{address_family, hostname_as_str};
9
10fn hostname(hostent: &c_types::hostent) -> &str {
11 unsafe { hostname_as_str(hostent.h_name.cast()) }
12}
13
14fn addresses(hostent: &c_types::hostent) -> HostAddressResultsIter<'_> {
15 let addrtype = hostent.h_addrtype as c_types::ADDRESS_FAMILY;
16 HostAddressResultsIter {
17 family: address_family(addrtype),
18 next: unsafe { &*(hostent.h_addr_list.cast()) },
19 }
20}
21
22fn aliases(hostent: &c_types::hostent) -> HostAliasResultsIter<'_> {
23 HostAliasResultsIter {
24 next: unsafe { &*(hostent.h_aliases.cast()) },
25 }
26}
27
28fn display(hostent: &c_types::hostent, fmt: &mut fmt::Formatter) -> fmt::Result {
29 write!(fmt, "Hostname: {}, ", hostname(hostent))?;
30 let addresses = addresses(hostent).format(", ");
31 write!(fmt, "Addresses: [{addresses}], ")?;
32 let aliases = aliases(hostent).format(", ");
33 write!(fmt, "Aliases: [{aliases}]")
34}
35
36pub trait HasHostent<'a>: Sized {
37 fn hostent(self) -> &'a c_types::hostent;
38
39 fn hostname(self) -> &'a str {
40 let hostent = self.hostent();
41 hostname(hostent)
42 }
43
44 fn addresses(self) -> HostAddressResultsIter<'a> {
45 let hostent = self.hostent();
46 addresses(hostent)
47 }
48
49 fn aliases(self) -> HostAliasResultsIter<'a> {
50 let hostent = self.hostent();
51 aliases(hostent)
52 }
53}
54
55#[derive(Debug)]
56pub struct HostentOwned {
57 inner: *mut c_types::hostent,
58}
59
60impl HostentOwned {
61 pub fn new(hostent: *mut c_types::hostent) -> Self {
62 HostentOwned { inner: hostent }
63 }
64}
65
66impl<'a> HasHostent<'a> for &'a HostentOwned {
67 fn hostent(self) -> &'a c_types::hostent {
68 unsafe { &*self.inner }
69 }
70}
71
72impl fmt::Display for HostentOwned {
73 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
74 let hostent = self.hostent();
75 display(hostent, fmt)
76 }
77}
78
79impl Drop for HostentOwned {
80 fn drop(&mut self) {
81 unsafe {
82 c_ares_sys::ares_free_hostent(self.inner);
83 }
84 }
85}
86
87unsafe impl Send for HostentOwned {}
88unsafe impl Sync for HostentOwned {}
89
90#[derive(Clone, Copy)]
91pub struct HostentBorrowed<'a> {
92 inner: &'a c_types::hostent,
93}
94
95impl<'a> HostentBorrowed<'a> {
96 pub fn new(hostent: &'a c_types::hostent) -> Self {
97 HostentBorrowed { inner: hostent }
98 }
99}
100
101impl<'a> HasHostent<'a> for HostentBorrowed<'a> {
102 fn hostent(self) -> &'a c_types::hostent {
103 self.inner
104 }
105}
106
107impl fmt::Display for HostentBorrowed<'_> {
108 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
109 let hostent = self.hostent();
110 display(hostent, fmt)
111 }
112}
113
114unsafe impl Send for HostentBorrowed<'_> {}
115unsafe impl Sync for HostentBorrowed<'_> {}
116
117unsafe fn ip_address_from_bytes(family: AddressFamily, h_addr: *const u8) -> Option<IpAddr> {
119 match family {
120 AddressFamily::INET => {
121 let source = unsafe { slice::from_raw_parts(h_addr, 4) };
122 let bytes: [u8; 4] = source.try_into().unwrap();
123 let ipv4 = Ipv4Addr::from(bytes);
124 Some(IpAddr::V4(ipv4))
125 }
126 AddressFamily::INET6 => {
127 let source = unsafe { slice::from_raw_parts(h_addr, 16) };
128 let bytes: [u8; 16] = source.try_into().unwrap();
129 let ipv6 = Ipv6Addr::from(bytes);
130 Some(IpAddr::V6(ipv6))
131 }
132 _ => None,
133 }
134}
135
136#[derive(Clone, Copy, Debug)]
138pub struct HostAddressResultsIter<'a> {
139 family: Option<AddressFamily>,
140 next: &'a *const c_char,
141}
142
143impl Iterator for HostAddressResultsIter<'_> {
144 type Item = IpAddr;
145 fn next(&mut self) -> Option<Self::Item> {
146 let h_addr = *self.next;
147 if h_addr.is_null() {
148 None
149 } else {
150 unsafe {
151 self.next = &*ptr::from_ref(self.next).offset(1);
152 self.family
153 .and_then(|family| ip_address_from_bytes(family, h_addr.cast()))
154 }
155 }
156 }
157}
158
159unsafe impl Send for HostAddressResultsIter<'_> {}
160unsafe impl Sync for HostAddressResultsIter<'_> {}
161
162#[derive(Clone, Copy, Debug)]
164pub struct HostAliasResultsIter<'a> {
165 next: &'a *const c_char,
166}
167
168impl<'a> Iterator for HostAliasResultsIter<'a> {
169 type Item = &'a str;
170 fn next(&mut self) -> Option<Self::Item> {
171 let h_alias = *self.next;
172 if h_alias.is_null() {
173 None
174 } else {
175 self.next = unsafe { &*ptr::from_ref(self.next).offset(1) };
176 let string = unsafe { hostname_as_str(h_alias) };
177 Some(string)
178 }
179 }
180}
181
182unsafe impl Send for HostAliasResultsIter<'_> {}
183unsafe impl Sync for HostAliasResultsIter<'_> {}