1use if_addrs::{IfAddr, Interface};
4use socket2::{Domain, Protocol, SockAddr, Socket, Type};
5use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4};
6use tokio::net::UdpSocket;
7
8use super::errors::KaboodleError;
9
10pub fn best_available_interface() -> Result<Interface, KaboodleError> {
13 let non_loopbacks = non_loopback_interfaces();
16 let first_ipv6_interface = non_loopbacks
17 .iter()
18 .find(|xs| matches!(xs.addr, IfAddr::V6(_)));
19 first_ipv6_interface
20 .or_else(|| non_loopbacks.first())
21 .cloned()
22 .ok_or_else(|| KaboodleError::NoAvailableInterfaces)
23}
24
25pub fn create_broadcast_sockets(
28 interface: &Interface,
29 broadcast_port: &u16,
30) -> Result<(UdpSocket, UdpSocket, SocketAddr), KaboodleError> {
31 match interface.ip() {
32 IpAddr::V4(_) => {
33 let broadcast_inbound_addr = SocketAddr::V4(SocketAddrV4::new(
37 Ipv4Addr::new(0, 0, 0, 0),
38 *broadcast_port,
39 ));
40 let broadcast_outbound_addr = SocketAddr::V4(SocketAddrV4::new(
41 Ipv4Addr::new(255, 255, 255, 255),
42 *broadcast_port,
43 ));
44 let broadcast_raw_sock: std::net::UdpSocket = {
45 let broadcast_sock =
46 Socket::new(Domain::IPV4, Type::DGRAM, Some(Protocol::UDP)).unwrap();
47 broadcast_sock.set_broadcast(true).unwrap();
48 broadcast_sock.set_nonblocking(true).unwrap();
49 broadcast_sock.set_reuse_address(true).unwrap();
50 broadcast_sock.set_reuse_port(true).unwrap();
51 broadcast_sock
52 .bind(&SockAddr::from(broadcast_inbound_addr))
53 .expect("Failed to bind for broadcast");
54 broadcast_sock.into()
55 };
56
57 let broadcast_in_sock = UdpSocket::from_std(broadcast_raw_sock.try_clone()?)?;
60 let broadcast_out_sock = UdpSocket::from_std(broadcast_raw_sock)?;
61
62 Ok((
63 broadcast_in_sock,
64 broadcast_out_sock,
65 broadcast_outbound_addr,
66 ))
67 }
68 IpAddr::V6(_) => {
69 let Some(interface_idx) = interface.index else {
75 return Err(KaboodleError::UnableToFindInterfaceNumber);
76 };
77
78 let broadcast_ip_addr = Ipv6Addr::new(0xff02, 0, 0, 0, 0, 0, 0x1213, 0x1989);
87
88 let broadcast_socket_addr =
89 SocketAddr::new(IpAddr::V6(broadcast_ip_addr), *broadcast_port);
90 let broadcast_in_sock = {
91 let sock = Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::UDP))?;
92 sock.join_multicast_v6(&broadcast_ip_addr, interface_idx)?;
93 sock.set_nonblocking(true)?;
94 sock.set_only_v6(true)?;
95 sock.set_reuse_address(true)?;
96 sock.set_reuse_port(true)?;
97 sock.bind(&SockAddr::from(SocketAddr::new(
98 Ipv6Addr::UNSPECIFIED.into(),
99 *broadcast_port,
100 )))?;
101
102 UdpSocket::from_std(sock.into())?
103 };
104 let broadcast_out_sock = {
105 let sock = Socket::new(Domain::IPV6, Type::DGRAM, Some(Protocol::UDP))?;
106 sock.set_multicast_if_v6(interface_idx)?;
107 sock.set_nonblocking(true)?;
108 sock.set_reuse_address(true)?;
109 sock.set_reuse_port(true)?;
110 sock.bind(&SockAddr::from(SocketAddr::new(
111 Ipv6Addr::UNSPECIFIED.into(),
112 0,
113 )))?;
114
115 UdpSocket::from_std(sock.into())?
116 };
117
118 Ok((broadcast_in_sock, broadcast_out_sock, broadcast_socket_addr))
119 }
120 }
121}
122
123pub fn non_loopback_interfaces() -> Vec<Interface> {
125 if_addrs::get_if_addrs()
126 .unwrap_or_default()
127 .into_iter()
128 .filter(|addr| !addr.is_loopback())
129 .collect()
130}