Skip to main content

aya_friday/programs/
sk_msg.rs

1//! Skmsg programs.
2
3use std::os::fd::AsFd as _;
4
5use aya_obj::generated::{
6    bpf_attach_type::BPF_SK_MSG_VERDICT, bpf_prog_type::BPF_PROG_TYPE_SK_MSG,
7};
8
9use crate::{
10    maps::sock::SockMapFd,
11    programs::{
12        CgroupAttachMode, ProgAttachLink, ProgAttachLinkId, ProgramData, ProgramError, ProgramType,
13        define_link_wrapper, load_program_with_attach_type,
14    },
15};
16
17/// A program used to intercept messages sent with `sendmsg()`/`sendfile()`.
18///
19/// [`SkMsg`] programs are attached to [socket maps], and can be used inspect,
20/// filter and redirect messages sent on sockets. See also [`SockMap`] and
21/// [`SockHash`].
22///
23/// # Minimum kernel version
24///
25/// The minimum kernel version required to use this feature is 4.17.
26///
27/// # Examples
28///
29/// ```no_run
30/// # #[derive(Debug, thiserror::Error)]
31/// # enum Error {
32/// #     #[error(transparent)]
33/// #     IO(#[from] std::io::Error),
34/// #     #[error(transparent)]
35/// #     Map(#[from] aya::maps::MapError),
36/// #     #[error(transparent)]
37/// #     Program(#[from] aya::programs::ProgramError),
38/// #     #[error(transparent)]
39/// #     Ebpf(#[from] aya::EbpfError)
40/// # }
41/// # let mut bpf = aya::Ebpf::load(&[])?;
42/// use std::io::Write;
43/// use std::net::TcpStream;
44/// use std::os::fd::AsRawFd;
45/// use aya::maps::SockHash;
46/// use aya::programs::SkMsg;
47///
48/// let intercept_egress: SockHash<_, u32> = bpf.map("INTERCEPT_EGRESS").unwrap().try_into()?;
49/// let map_fd = intercept_egress.fd().try_clone()?;
50///
51/// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
52/// prog.load()?;
53/// prog.attach(&map_fd)?;
54///
55/// let mut client = TcpStream::connect("127.0.0.1:1234")?;
56/// let mut intercept_egress: SockHash<_, u32> = bpf.map_mut("INTERCEPT_EGRESS").unwrap().try_into()?;
57///
58/// intercept_egress.insert(1234, client.as_raw_fd(), 0)?;
59///
60/// // the write will be intercepted
61/// client.write_all(b"foo")?;
62/// # Ok::<(), Error>(())
63/// ```
64///
65/// [socket maps]: crate::maps::sock
66/// [`SockMap`]: crate::maps::SockMap
67/// [`SockHash`]: crate::maps::SockHash
68#[derive(Debug)]
69#[doc(alias = "BPF_PROG_TYPE_SK_MSG")]
70pub struct SkMsg {
71    pub(crate) data: ProgramData<SkMsgLink>,
72}
73
74impl SkMsg {
75    /// The type of the program according to the kernel.
76    pub const PROGRAM_TYPE: ProgramType = ProgramType::SkMsg;
77
78    /// Loads the program inside the kernel.
79    pub fn load(&mut self) -> Result<(), ProgramError> {
80        let Self { data } = self;
81        load_program_with_attach_type(BPF_PROG_TYPE_SK_MSG, BPF_SK_MSG_VERDICT, data)
82    }
83
84    /// Attaches the program to the given sockmap.
85    ///
86    /// The returned value can be used to detach, see [`SkMsg::detach`].
87    pub fn attach(&mut self, map: &SockMapFd) -> Result<SkMsgLinkId, ProgramError> {
88        let prog_fd = self.fd()?;
89        let prog_fd = prog_fd.as_fd();
90        let link = ProgAttachLink::attach(
91            prog_fd,
92            map.as_fd(),
93            BPF_SK_MSG_VERDICT,
94            CgroupAttachMode::Single,
95        )?;
96
97        self.data.links.insert(SkMsgLink::new(link))
98    }
99}
100
101define_link_wrapper!(
102    SkMsgLink,
103    SkMsgLinkId,
104    ProgAttachLink,
105    ProgAttachLinkId,
106    SkMsg,
107);