erbium_net/addr/
mod.rs

1/*   Copyright 2023 Perry Lorier
2 *
3 *  Licensed under the Apache License, Version 2.0 (the "License");
4 *  you may not use this file except in compliance with the License.
5 *  You may obtain a copy of the License at
6 *
7 *      http://www.apache.org/licenses/LICENSE-2.0
8 *
9 *  Unless required by applicable law or agreed to in writing, software
10 *  distributed under the License is distributed on an "AS IS" BASIS,
11 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 *  See the License for the specific language governing permissions and
13 *  limitations under the License.
14 *
15 *  SPDX-License-Identifier: Apache-2.0
16 *
17 *  Unfortunately, the std library address types are often woefully lacking, causing everyone to
18 *  create their own types, often missing conversions.  This leads to leaking internal details
19 *  everywhere.  Instead, we alias the types here, so we have one consistent set of types.
20 */
21
22mod link;
23
24pub use link::*;
25pub use nix::sys::socket::{
26    SockaddrIn as Inet4Addr, SockaddrIn6 as Inet6Addr, SockaddrStorage as NetAddr, UnixAddr,
27};
28pub use std::net::{Ipv4Addr, Ipv6Addr};
29pub const UNSPECIFIED6: Ipv6Addr = Ipv6Addr::UNSPECIFIED;
30pub const UNSPECIFIED4: Ipv4Addr = Ipv4Addr::UNSPECIFIED;
31pub const ALL_NODES: Ipv6Addr = Ipv6Addr::new(
32    0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001,
33);
34pub const ALL_ROUTERS: Ipv6Addr = Ipv6Addr::new(
35    0xff02, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0002,
36);
37
38/// Converts the socket address to a NetAddr.
39pub trait ToNetAddr {
40    fn to_net_addr(&self) -> NetAddr;
41}
42
43impl<X: nix::sys::socket::SockaddrLike> ToNetAddr for X {
44    fn to_net_addr(&self) -> NetAddr {
45        use nix::sys::socket::SockaddrLike;
46        unsafe {
47            NetAddr::from_raw(<Self as SockaddrLike>::as_ptr(self), Some(Self::size())).unwrap()
48        }
49    }
50}
51
52pub fn tokio_to_unixaddr(src: &tokio::net::unix::SocketAddr) -> UnixAddr {
53    if let Some(path) = src.as_pathname() {
54        UnixAddr::new(path).unwrap()
55    } else {
56        unimplemented!()
57    }
58}
59
60// convenience function for .map()
61pub fn to_net_addr<X: ToNetAddr>(x: X) -> NetAddr {
62    x.to_net_addr()
63}
64
65/// Takes an address, gives it a port, and makes a NetAddr.
66pub trait WithPort {
67    fn with_port(&self, port: u16) -> NetAddr;
68}
69
70impl WithPort for std::net::Ipv4Addr {
71    fn with_port(&self, port: u16) -> NetAddr {
72        Inet4Addr::from(std::net::SocketAddrV4::new(*self, port)).to_net_addr()
73    }
74}
75
76impl WithPort for std::net::Ipv6Addr {
77    fn with_port(&self, port: u16) -> NetAddr {
78        Inet6Addr::from(std::net::SocketAddrV6::new(*self, port, 0, 0)).to_net_addr()
79    }
80}
81
82impl WithPort for std::net::IpAddr {
83    fn with_port(&self, port: u16) -> NetAddr {
84        match self {
85            Self::V4(ip) => ip.with_port(port),
86            Self::V6(ip) => ip.with_port(port),
87        }
88    }
89}
90
91// I can't implement ToSocketAddrs on nix's types directly, but nix doesn't implement them either.
92// (https://github.com/nix-rust/nix/issues/1799)
93//
94// I'm so very much over everyone having their own socket types.  sigh.
95//
96// So this trait will be used on exactly one type - NetAddr.
97pub trait NetAddrExt {
98    fn to_std_socket_addr(&self) -> Option<std::net::SocketAddr>;
99    fn to_unix_addr(&self) -> Option<UnixAddr>;
100    fn ip(&self) -> Option<std::net::IpAddr>;
101    fn port(&self) -> Option<u16>;
102}
103
104impl NetAddrExt for NetAddr {
105    fn to_std_socket_addr(&self) -> Option<std::net::SocketAddr> {
106        if let Some(&v4) = self.as_sockaddr_in() {
107            Some(std::net::SocketAddrV4::from(v4).into())
108        } else if let Some(&v6) = self.as_sockaddr_in6() {
109            Some(std::net::SocketAddrV6::from(v6).into())
110        } else {
111            None
112        }
113    }
114    // unixaddr is difficult to create from just a sockaddr. (https://github.com/nix-rust/nix/issues/1800)
115    fn to_unix_addr(&self) -> Option<UnixAddr> {
116        use nix::sys::socket::SockaddrLike;
117        if self.family() == Some(nix::sys::socket::AddressFamily::Unix) {
118            unsafe { UnixAddr::from_raw(<Self as SockaddrLike>::as_ptr(self), Some(Self::size())) }
119        } else {
120            None
121        }
122    }
123    fn ip(&self) -> Option<std::net::IpAddr> {
124        if let Some(&v4) = self.as_sockaddr_in() {
125            Some(std::net::Ipv4Addr::from(v4.ip()).into())
126        } else if let Some(&v6) = self.as_sockaddr_in6() {
127            Some(v6.ip().into())
128        } else {
129            None
130        }
131    }
132    fn port(&self) -> Option<u16> {
133        if let Some(&v4) = self.as_sockaddr_in() {
134            Some(v4.port())
135        } else if let Some(&v6) = self.as_sockaddr_in6() {
136            Some(v6.port())
137        } else {
138            None
139        }
140    }
141}