netlink/protocol_family/
sock_diag.rs1mod eventloop;
8mod request;
9
10pub(crate) use eventloop::SockDiagEventLoop;
11pub(crate) use request::NetlinkSockDiagRequestHandler;
12
13use std::num::NonZeroU32;
14
15use fidl_fuchsia_net_sockets_ext as fnet_sockets_ext;
16use netlink_packet_sock_diag::{SockDiagRequest, SockDiagResponse};
17
18use crate::client::{AsyncWorkCompletionWaiter, ExternalClient};
19use crate::messaging::{MessageWithPermission, Sender};
20use crate::multicast_groups::{
21 GroupSupport, InvalidLegacyGroupsError, InvalidModernGroupError, LegacyGroups, ModernGroup,
22 MulticastCapableNetlinkFamily,
23};
24use crate::protocol_family::{NamedNetlinkFamily, NetlinkClient, ProtocolFamily};
25
26pub(crate) struct NetlinkSockDiag;
28
29impl MulticastCapableNetlinkFamily for NetlinkSockDiag {
30 fn check_support(group: &ModernGroup) -> Result<GroupSupport, InvalidModernGroupError> {
31 if group.0 == linux_uapi::sknetlink_groups_SKNLGRP_NONE {
32 Ok(GroupSupport::Unsupported)
33 } else {
34 NetlinkSockDiagNotifiedGroup::try_from(*group).map(|_| GroupSupport::Supported)
35 }
36 }
37}
38
39#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
40pub(crate) enum NetlinkSockDiagNotifiedGroup {
41 TcpV4Destroy,
42 TcpV6Destroy,
43 UdpV4Destroy,
44 UdpV6Destroy,
45}
46
47impl TryFrom<ModernGroup> for NetlinkSockDiagNotifiedGroup {
48 type Error = InvalidModernGroupError;
49
50 fn try_from(ModernGroup(group): ModernGroup) -> Result<Self, Self::Error> {
51 match group {
52 linux_uapi::sknetlink_groups_SKNLGRP_INET_TCP_DESTROY => {
53 Ok(NetlinkSockDiagNotifiedGroup::TcpV4Destroy)
54 }
55 linux_uapi::sknetlink_groups_SKNLGRP_INET6_TCP_DESTROY => {
56 Ok(NetlinkSockDiagNotifiedGroup::TcpV6Destroy)
57 }
58 linux_uapi::sknetlink_groups_SKNLGRP_INET_UDP_DESTROY => {
59 Ok(NetlinkSockDiagNotifiedGroup::UdpV4Destroy)
60 }
61 linux_uapi::sknetlink_groups_SKNLGRP_INET6_UDP_DESTROY => {
62 Ok(NetlinkSockDiagNotifiedGroup::UdpV6Destroy)
63 }
64 _ => Err(InvalidModernGroupError),
65 }
66 }
67}
68
69impl From<NetlinkSockDiagNotifiedGroup> for ModernGroup {
70 fn from(group: NetlinkSockDiagNotifiedGroup) -> Self {
71 match group {
72 NetlinkSockDiagNotifiedGroup::TcpV4Destroy => {
73 ModernGroup(linux_uapi::sknetlink_groups_SKNLGRP_INET_TCP_DESTROY)
74 }
75 NetlinkSockDiagNotifiedGroup::TcpV6Destroy => {
76 ModernGroup(linux_uapi::sknetlink_groups_SKNLGRP_INET6_TCP_DESTROY)
77 }
78 NetlinkSockDiagNotifiedGroup::UdpV4Destroy => {
79 ModernGroup(linux_uapi::sknetlink_groups_SKNLGRP_INET_UDP_DESTROY)
80 }
81 NetlinkSockDiagNotifiedGroup::UdpV6Destroy => {
82 ModernGroup(linux_uapi::sknetlink_groups_SKNLGRP_INET6_UDP_DESTROY)
83 }
84 }
85 }
86}
87
88impl NetlinkSockDiagNotifiedGroup {
89 pub(crate) fn from_socket_state(socket: &fnet_sockets_ext::IpSocketState) -> Self {
90 match socket {
91 fnet_sockets_ext::IpSocketState::V4(s) => match &s.transport {
92 fnet_sockets_ext::IpSocketTransportState::Tcp(_) => {
93 NetlinkSockDiagNotifiedGroup::TcpV4Destroy
94 }
95 fnet_sockets_ext::IpSocketTransportState::Udp(_) => {
96 NetlinkSockDiagNotifiedGroup::UdpV4Destroy
97 }
98 },
99 fnet_sockets_ext::IpSocketState::V6(s) => match &s.transport {
100 fnet_sockets_ext::IpSocketTransportState::Tcp(_) => {
101 NetlinkSockDiagNotifiedGroup::TcpV6Destroy
102 }
103 fnet_sockets_ext::IpSocketTransportState::Udp(_) => {
104 NetlinkSockDiagNotifiedGroup::UdpV6Destroy
105 }
106 },
107 }
108 }
109}
110
111impl MessageWithPermission for SockDiagRequest {
112 fn permission(&self) -> crate::messaging::Permission {
113 match self {
114 SockDiagRequest::InetRequest(_) | SockDiagRequest::UnixRequest(_) => {
115 crate::messaging::Permission::NetlinkSockDiagRead
116 }
117 SockDiagRequest::InetSockDestroy(_) => {
118 crate::messaging::Permission::NetlinkSockDiagDestroy
119 }
120 }
121 }
122}
123
124pub struct NetlinkSockDiagClient(pub(crate) ExternalClient<NetlinkSockDiag>);
126
127impl NetlinkClient for NetlinkSockDiagClient {
128 type Request = SockDiagRequest;
129
130 fn set_pid(&self, pid: NonZeroU32) {
131 let NetlinkSockDiagClient(client) = self;
132 client.set_port_number(pid)
133 }
134
135 fn add_membership(
136 &self,
137 group: ModernGroup,
138 ) -> Result<AsyncWorkCompletionWaiter, InvalidModernGroupError> {
139 let NetlinkSockDiagClient(client) = self;
140 client.add_membership(group)
141 }
142
143 fn del_membership(&self, group: ModernGroup) -> Result<(), InvalidModernGroupError> {
144 let NetlinkSockDiagClient(client) = self;
145 client.del_membership(group)
146 }
147
148 fn set_legacy_memberships(
149 &self,
150 legacy_memberships: LegacyGroups,
151 ) -> Result<AsyncWorkCompletionWaiter, InvalidLegacyGroupsError> {
152 let NetlinkSockDiagClient(client) = self;
153 client.set_legacy_memberships(legacy_memberships)
154 }
155}
156
157impl NamedNetlinkFamily for NetlinkSockDiag {
158 const NAME: &'static str = "NETLINK_SOCK_DIAG";
159}
160
161impl ProtocolFamily for NetlinkSockDiag {
162 type Request = SockDiagRequest;
163 type Response = SockDiagResponse;
164 type RequestHandler<S: Sender<Self::Response>> = NetlinkSockDiagRequestHandler<S>;
165 type NotifiedMulticastGroup = NetlinkSockDiagNotifiedGroup;
166 type AsyncWorkItem = !;
167
168 fn should_notify_on_group_membership_change(
169 group: ModernGroup,
170 ) -> Option<Self::NotifiedMulticastGroup> {
171 NetlinkSockDiagNotifiedGroup::try_from(group).ok()
172 }
173}
174
175#[cfg(test)]
176mod testutil {
177 use net_declare::{std_ip_v4, std_ip_v6};
178 use net_types::ip::{Ip, Ipv4, Ipv4Addr, Ipv6, Ipv6Addr};
179
180 pub(crate) trait TestIpExt: Ip {
181 const SRC_ADDR: Self::Addr;
182 const DST_ADDR: Self::Addr;
183 const LINUX_FAMILY: u8;
184 }
185
186 impl TestIpExt for Ipv4 {
187 const SRC_ADDR: Ipv4Addr = Ipv4Addr::new(std_ip_v4!("192.168.0.1").octets());
188 const DST_ADDR: Ipv4Addr = Ipv4Addr::new(std_ip_v4!("192.168.0.2").octets());
189 const LINUX_FAMILY: u8 = linux_uapi::AF_INET as u8;
190 }
191
192 impl TestIpExt for Ipv6 {
193 const SRC_ADDR: Ipv6Addr = Ipv6Addr::new(std_ip_v6!("2001:db8::1").segments());
194 const DST_ADDR: Ipv6Addr = Ipv6Addr::new(std_ip_v6!("2001:db8::2").segments());
195 const LINUX_FAMILY: u8 = linux_uapi::AF_INET6 as u8;
196 }
197}