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