sock_hash.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. use std::{
  2. borrow::{Borrow, BorrowMut},
  3. marker::PhantomData,
  4. os::fd::{AsRawFd, RawFd},
  5. };
  6. use crate::{
  7. maps::{
  8. check_kv_size, hash_map, sock::SockMapFd, IterableMap, MapData, MapError, MapIter, MapKeys,
  9. },
  10. sys::{bpf_map_lookup_elem, SyscallError},
  11. Pod,
  12. };
  13. /// A hash map of TCP or UDP sockets.
  14. ///
  15. /// A `SockHash` is used to store TCP or UDP sockets. eBPF programs can then be
  16. /// attached to the map to inspect, filter or redirect network buffers on those
  17. /// sockets.
  18. ///
  19. /// A `SockHash` can also be used to redirect packets to sockets contained by the
  20. /// map using `bpf_redirect_map()`, `bpf_sk_redirect_hash()` etc.
  21. ///
  22. /// # Minimum kernel version
  23. ///
  24. /// The minimum kernel version required to use this feature is 4.18.
  25. ///
  26. /// # Examples
  27. ///
  28. /// ```no_run
  29. /// # #[derive(Debug, thiserror::Error)]
  30. /// # enum Error {
  31. /// # #[error(transparent)]
  32. /// # IO(#[from] std::io::Error),
  33. /// # #[error(transparent)]
  34. /// # Map(#[from] aya::maps::MapError),
  35. /// # #[error(transparent)]
  36. /// # Program(#[from] aya::programs::ProgramError),
  37. /// # #[error(transparent)]
  38. /// # Bpf(#[from] aya::BpfError)
  39. /// # }
  40. /// # let mut bpf = aya::Bpf::load(&[])?;
  41. /// use std::io::Write;
  42. /// use std::net::TcpStream;
  43. /// use std::os::fd::AsRawFd;
  44. /// use aya::maps::SockHash;
  45. /// use aya::programs::SkMsg;
  46. ///
  47. /// let mut intercept_egress = SockHash::<_, u32>::try_from(bpf.map("INTERCEPT_EGRESS").unwrap())?;
  48. /// let map_fd = intercept_egress.fd()?;
  49. ///
  50. /// let prog: &mut SkMsg = bpf.program_mut("intercept_egress_packet").unwrap().try_into()?;
  51. /// prog.load()?;
  52. /// prog.attach(map_fd)?;
  53. ///
  54. /// let mut client = TcpStream::connect("127.0.0.1:1234")?;
  55. /// let mut intercept_egress = SockHash::try_from(bpf.map_mut("INTERCEPT_EGRESS").unwrap())?;
  56. ///
  57. /// intercept_egress.insert(1234, client.as_raw_fd(), 0)?;
  58. ///
  59. /// // the write will be intercepted
  60. /// client.write_all(b"foo")?;
  61. /// # Ok::<(), Error>(())
  62. /// ```
  63. #[doc(alias = "BPF_MAP_TYPE_SOCKHASH")]
  64. pub struct SockHash<T, K> {
  65. inner: T,
  66. _k: PhantomData<K>,
  67. }
  68. impl<T: Borrow<MapData>, K: Pod> SockHash<T, K> {
  69. pub(crate) fn new(map: T) -> Result<SockHash<T, K>, MapError> {
  70. let data = map.borrow();
  71. check_kv_size::<K, u32>(data)?;
  72. let _ = data.fd_or_err()?;
  73. Ok(SockHash {
  74. inner: map,
  75. _k: PhantomData,
  76. })
  77. }
  78. /// Returns the fd of the socket stored at the given key.
  79. pub fn get(&self, key: &K, flags: u64) -> Result<RawFd, MapError> {
  80. let fd = self.inner.borrow().fd_or_err()?;
  81. let value = bpf_map_lookup_elem(fd, key, flags).map_err(|(_, io_error)| SyscallError {
  82. call: "bpf_map_lookup_elem",
  83. io_error,
  84. })?;
  85. value.ok_or(MapError::KeyNotFound)
  86. }
  87. /// An iterator visiting all key-value pairs in arbitrary order. The
  88. /// iterator item type is `Result<(K, V), MapError>`.
  89. pub fn iter(&self) -> MapIter<'_, K, RawFd, Self> {
  90. MapIter::new(self)
  91. }
  92. /// An iterator visiting all keys in arbitrary order. The iterator element
  93. /// type is `Result<K, MapError>`.
  94. pub fn keys(&self) -> MapKeys<'_, K> {
  95. MapKeys::new(self.inner.borrow())
  96. }
  97. /// Returns the map's file descriptor.
  98. ///
  99. /// The returned file descriptor can be used to attach programs that work with
  100. /// socket maps, like [`SkMsg`](crate::programs::SkMsg) and [`SkSkb`](crate::programs::SkSkb).
  101. pub fn fd(&self) -> Result<SockMapFd, MapError> {
  102. Ok(SockMapFd(self.inner.borrow().fd_or_err()?))
  103. }
  104. }
  105. impl<T: BorrowMut<MapData>, K: Pod> SockHash<T, K> {
  106. /// Inserts a socket under the given key.
  107. pub fn insert<I: AsRawFd>(
  108. &mut self,
  109. key: impl Borrow<K>,
  110. value: I,
  111. flags: u64,
  112. ) -> Result<(), MapError> {
  113. hash_map::insert(
  114. self.inner.borrow_mut(),
  115. key.borrow(),
  116. &value.as_raw_fd(),
  117. flags,
  118. )
  119. }
  120. /// Removes a socket from the map.
  121. pub fn remove(&mut self, key: &K) -> Result<(), MapError> {
  122. hash_map::remove(self.inner.borrow_mut(), key)
  123. }
  124. }
  125. impl<T: Borrow<MapData>, K: Pod> IterableMap<K, RawFd> for SockHash<T, K> {
  126. fn map(&self) -> &MapData {
  127. self.inner.borrow()
  128. }
  129. fn get(&self, key: &K) -> Result<RawFd, MapError> {
  130. SockHash::get(self, key, 0)
  131. }
  132. }