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