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);