1use std::
17{
18    ffi::{CStr, CString}, 
19    mem::MaybeUninit, 
20    net::{IpAddr, Ipv4Addr, Ipv6Addr}
21};
22
23use nix::libc;
24
25use crate::{error::*, internal_error, internal_error_map};
26
27pub struct IfInfo
34{
35    if_inf: *mut libc::ifaddrs,
37}
38
39impl Drop for IfInfo
40{
41    fn drop(&mut self) 
42    {
43        if self.if_inf.is_null() == true
44        {
45            return;
46        }
47
48        unsafe
49        {
50            libc::freeifaddrs(self.if_inf);
51        }
52    }
53}
54
55impl IfInfo
56{
57    pub unsafe
61    fn get_interfaces_info() -> CDnsResult<Self>
62    {
63        let mut addrs = MaybeUninit::<*mut libc::ifaddrs>::uninit();
64
65        let ifaddrs = unsafe { libc::getifaddrs(addrs.as_mut_ptr()) };
66
67        if ifaddrs == -1
68        {
69            internal_error!(CDnsErrorType::InternalError, "{}", std::io::Error::last_os_error());
70        }
71
72        return Ok(
73            Self { if_inf: unsafe { addrs.assume_init() } }
74        );
75    }
76
77    pub unsafe
79    fn get_ifr_ip(&self, ifr: &str, ip_addr: &IpAddr) -> CDnsResult<Option<IpAddr>>
80    {
81        if self.if_inf.is_null() == true
82        {
83            panic!("if_inf is NULL");
84        }
85
86        let c_ifr = 
87            CString::new(ifr)
88                .map_err(|e| 
89                    internal_error_map!(CDnsErrorType::InternalError, "{}", e)
90                )?;
91
92        let mut tmp = self.if_inf;
93        while tmp.is_null() == false
94        {
95            unsafe 
96            {
97                if (*tmp).ifa_name.is_null() == true
98                {
99                    tmp = (*tmp).ifa_next;
100                    continue;
101                }
102            }
103
104            let name = unsafe { CStr::from_ptr((*tmp).ifa_name) };
106
107            if name != c_ifr.as_c_str()
109            {
110                unsafe { tmp = (*tmp).ifa_next };
111                continue;
112            }
113
114            let addr = unsafe { (*tmp).ifa_addr };
115
116            if addr.is_null() == false
117            {
118                
119                let mut host = [0_u8; libc::NI_MAXHOST as usize];
120
121                let fam = unsafe { (*addr).sa_family };
122
123                if fam as i32 == libc::AF_INET && ip_addr.is_ipv4() == true
124                {
125                    let s = 
126                        unsafe {
127                            libc::getnameinfo(
128                                addr,
129                                std::mem::size_of::<libc::sockaddr_in>() as u32,
130                                host.as_mut_ptr() as *mut i8, 
131                                libc::NI_MAXHOST,
132                                std::ptr::null_mut(), 
133                                0, 
134                                libc::NI_NUMERICHOST
135                            )
136                        };
137
138                    if s != 0
139                    {
140                        internal_error!(CDnsErrorType::InternalError, "{}", std::io::Error::last_os_error());
141                    }
142
143                    let c = 
144                        unsafe {
145                            CStr::from_ptr(host.as_ptr() as *const i8)
146                                .to_str()
147                                .map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?
148                        };
149                    
150                    let ip4: Ipv4Addr = c.parse().map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?;
151                    
152                    return Ok(Some(IpAddr::from(ip4)));
153                }
154                else if fam as i32 == libc::AF_INET6 && ip_addr.is_ipv6() == true
155                {
156                    let s = 
157                        unsafe 
158                        {
159                            libc::getnameinfo(
160                                addr,
161                                std::mem::size_of::<libc::sockaddr_in6>() as u32,
162                                host.as_mut_ptr() as *mut i8, 
163                                libc::NI_MAXHOST,
164                                std::ptr::null_mut(), 
165                                0, 
166                                libc::NI_NUMERICHOST
167                            )
168                        };
169
170                    if s != 0
171                    {
172                        internal_error!(CDnsErrorType::InternalError, "{}", std::io::Error::last_os_error());
173                    }
174
175                    let c = 
176                        unsafe 
177                        {
178                            CStr::from_ptr(host.as_ptr() as *const i8)
179                                .to_str()
180                                .map_err(|e| internal_error_map!(CDnsErrorType::InternalError, "{}", e))?
181                        };
182                    
183                    let ip6: Ipv6Addr = 
184                        c
185                            .split_once("%")
186                            .map_or(c, |(ip, _)| ip)
187                            .parse()
188                            .map_err(|e| 
189                                internal_error_map!(CDnsErrorType::InternalError, "{}", e)
190                            )?;
191                   
192                    return Ok(Some(IpAddr::from(Ipv6Addr::from(ip6))));
193                }
194            }
195
196            tmp = unsafe { (*tmp).ifa_next };
198        }
199
200        return Ok(None);
201    }
202
203}