netlink/protocol_family/
sock_diag.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! A module for handling the `NETLINK_SOCK_DIAG` API.
6
7mod 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 linux_uapi::{
17    sknetlink_groups_SKNLGRP_INET_TCP_DESTROY, sknetlink_groups_SKNLGRP_INET_UDP_DESTROY,
18    sknetlink_groups_SKNLGRP_INET6_TCP_DESTROY, sknetlink_groups_SKNLGRP_INET6_UDP_DESTROY,
19    sknetlink_groups_SKNLGRP_NONE,
20};
21use netlink_packet_sock_diag::{SockDiagRequest, SockDiagResponse};
22
23use crate::client::{AsyncWorkCompletionWaiter, ExternalClient};
24use crate::messaging::{MessageWithPermission, Sender};
25use crate::multicast_groups::{
26    InvalidLegacyGroupsError, InvalidModernGroupError, LegacyGroups, ModernGroup,
27    MulticastCapableNetlinkFamily,
28};
29use crate::protocol_family::{NetlinkClient, ProtocolFamily};
30
31/// An implementation of the `NETLINK_SOCK_DIAG` protocol family.
32pub(crate) struct NetlinkSockDiag;
33
34impl MulticastCapableNetlinkFamily for NetlinkSockDiag {
35    #[allow(non_upper_case_globals)]
36    fn is_valid_group(ModernGroup(group): &ModernGroup) -> bool {
37        match *group {
38            sknetlink_groups_SKNLGRP_INET_TCP_DESTROY
39            | sknetlink_groups_SKNLGRP_INET_UDP_DESTROY
40            | sknetlink_groups_SKNLGRP_INET6_TCP_DESTROY
41            | sknetlink_groups_SKNLGRP_INET6_UDP_DESTROY
42            | sknetlink_groups_SKNLGRP_NONE => true,
43            _ => false,
44        }
45    }
46}
47
48#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
49// TODO(https://fxbug.dev/470079735): Support multicast socket closure
50// notifications.
51#[allow(dead_code)]
52pub(crate) enum NetlinkSockDiagNotifiedGroup {
53    TcpV4Destroy,
54    TcpV6Destroy,
55    UdpV4Destroy,
56    UdpV6Destroy,
57}
58
59impl MessageWithPermission for SockDiagRequest {
60    fn permission(&self) -> crate::messaging::Permission {
61        // TODO(323590076): Implement SOCK_DIAG requests.
62        todo!()
63    }
64}
65
66/// A connection to the `NETLINK_SOCK_DIAG` protocol family.
67pub struct NetlinkSockDiagClient(pub(crate) ExternalClient<NetlinkSockDiag>);
68
69impl NetlinkSockDiagClient {
70    /// Sets the PID assigned to the client.
71    pub fn set_pid(&self, pid: NonZeroU32) {
72        let NetlinkSockDiagClient(client) = self;
73        client.set_port_number(pid)
74    }
75
76    /// Adds the given multicast group membership.
77    pub fn add_membership(
78        &self,
79        group: ModernGroup,
80    ) -> Result<AsyncWorkCompletionWaiter, InvalidModernGroupError> {
81        let NetlinkSockDiagClient(client) = self;
82        client.add_membership(group)
83    }
84
85    /// Deletes the given multicast group membership.
86    pub fn del_membership(&self, group: ModernGroup) -> Result<(), InvalidModernGroupError> {
87        let NetlinkSockDiagClient(client) = self;
88        client.del_membership(group)
89    }
90
91    /// Sets the legacy multicast group memberships.
92    pub fn set_legacy_memberships(
93        &self,
94        legacy_memberships: LegacyGroups,
95    ) -> Result<AsyncWorkCompletionWaiter, InvalidLegacyGroupsError> {
96        let NetlinkSockDiagClient(client) = self;
97        client.set_legacy_memberships(legacy_memberships)
98    }
99}
100
101impl NetlinkClient for NetlinkSockDiagClient {
102    fn set_pid(&self, pid: NonZeroU32) {
103        self.set_pid(pid)
104    }
105
106    fn set_legacy_memberships(
107        &self,
108        legacy_memberships: LegacyGroups,
109    ) -> Result<AsyncWorkCompletionWaiter, InvalidLegacyGroupsError> {
110        self.set_legacy_memberships(legacy_memberships)
111    }
112}
113
114impl ProtocolFamily for NetlinkSockDiag {
115    type Request = SockDiagRequest;
116    type Response = SockDiagResponse;
117    type RequestHandler<S: Sender<Self::Response>> = NetlinkSockDiagRequestHandler<S>;
118    const NAME: &'static str = "NETLINK_SOCK_DIAG";
119    type NotifiedMulticastGroup = NetlinkSockDiagNotifiedGroup;
120    type AsyncWorkItem = Never;
121
122    fn should_notify_on_group_membership_change(
123        _group: ModernGroup,
124    ) -> Option<Self::NotifiedMulticastGroup> {
125        // TODO(https://fxbug.dev/470079735): All membership changes need to
126        // be notified so the system can avoid generating socket destruction
127        // messages when nobody is listening.
128        None
129    }
130}