4
0

sk_buff.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432
  1. use core::{
  2. ffi::c_void,
  3. mem::{self, MaybeUninit},
  4. };
  5. use aya_bpf_bindings::helpers::{
  6. bpf_clone_redirect, bpf_get_socket_uid, bpf_l3_csum_replace, bpf_l4_csum_replace,
  7. bpf_skb_adjust_room, bpf_skb_change_proto, bpf_skb_change_type, bpf_skb_load_bytes,
  8. bpf_skb_pull_data, bpf_skb_store_bytes,
  9. };
  10. use aya_bpf_cty::c_long;
  11. use crate::{bindings::__sk_buff, BpfContext};
  12. pub struct SkBuff {
  13. pub skb: *mut __sk_buff,
  14. }
  15. impl SkBuff {
  16. pub fn new(skb: *mut __sk_buff) -> SkBuff {
  17. SkBuff { skb }
  18. }
  19. #[allow(clippy::len_without_is_empty)]
  20. #[inline]
  21. pub fn len(&self) -> u32 {
  22. unsafe { (*self.skb).len }
  23. }
  24. #[inline]
  25. pub(crate) fn data(&self) -> usize {
  26. unsafe { (*self.skb).data as usize }
  27. }
  28. #[inline]
  29. pub(crate) fn data_end(&self) -> usize {
  30. unsafe { (*self.skb).data_end as usize }
  31. }
  32. #[inline]
  33. pub fn set_mark(&mut self, mark: u32) {
  34. unsafe { (*self.skb).mark = mark }
  35. }
  36. #[inline]
  37. pub fn cb(&self) -> &[u32] {
  38. unsafe { &(*self.skb).cb }
  39. }
  40. #[inline]
  41. pub fn cb_mut(&mut self) -> &mut [u32] {
  42. unsafe { &mut (*self.skb).cb }
  43. }
  44. /// Returns the owner UID of the socket associated to the SKB context.
  45. #[inline]
  46. pub fn get_socket_uid(&self) -> u32 {
  47. unsafe { bpf_get_socket_uid(self.skb) }
  48. }
  49. #[inline]
  50. pub fn load<T>(&self, offset: usize) -> Result<T, c_long> {
  51. unsafe {
  52. let mut data = MaybeUninit::<T>::uninit();
  53. let ret = bpf_skb_load_bytes(
  54. self.skb as *const _,
  55. offset as u32,
  56. &mut data as *mut _ as *mut _,
  57. mem::size_of::<T>() as u32,
  58. );
  59. if ret == 0 {
  60. Ok(data.assume_init())
  61. } else {
  62. Err(ret)
  63. }
  64. }
  65. }
  66. /// Reads some bytes from the packet into the specified buffer, returning
  67. /// how many bytes were read.
  68. ///
  69. /// Starts reading at `offset` and reads at most `dst.len()` or
  70. /// `self.len() - offset` bytes, depending on which one is smaller.
  71. ///
  72. /// # Examples
  73. ///
  74. /// Read into a `PerCpuArray`.
  75. #[inline(always)]
  76. pub fn load_bytes(&self, offset: usize, dst: &mut [u8]) -> Result<usize, c_long> {
  77. let len = usize::try_from(self.len()).map_err(|core::num::TryFromIntError { .. }| -1)?;
  78. let len = len.checked_sub(offset).ok_or(-1)?;
  79. let len = len.min(dst.len());
  80. let len_u32 = u32::try_from(len).map_err(|core::num::TryFromIntError { .. }| -1)?;
  81. let ret = unsafe {
  82. bpf_skb_load_bytes(
  83. self.skb as *const _,
  84. offset as u32,
  85. dst.as_mut_ptr() as *mut _,
  86. len_u32,
  87. )
  88. };
  89. if ret == 0 {
  90. Ok(len)
  91. } else {
  92. Err(ret)
  93. }
  94. }
  95. #[inline]
  96. pub fn store<T>(&mut self, offset: usize, v: &T, flags: u64) -> Result<(), c_long> {
  97. unsafe {
  98. let ret = bpf_skb_store_bytes(
  99. self.skb as *mut _,
  100. offset as u32,
  101. v as *const _ as *const _,
  102. mem::size_of::<T>() as u32,
  103. flags,
  104. );
  105. if ret == 0 {
  106. Ok(())
  107. } else {
  108. Err(ret)
  109. }
  110. }
  111. }
  112. #[inline]
  113. pub fn l3_csum_replace(
  114. &self,
  115. offset: usize,
  116. from: u64,
  117. to: u64,
  118. size: u64,
  119. ) -> Result<(), c_long> {
  120. unsafe {
  121. let ret = bpf_l3_csum_replace(self.skb as *mut _, offset as u32, from, to, size);
  122. if ret == 0 {
  123. Ok(())
  124. } else {
  125. Err(ret)
  126. }
  127. }
  128. }
  129. #[inline]
  130. pub fn l4_csum_replace(
  131. &self,
  132. offset: usize,
  133. from: u64,
  134. to: u64,
  135. flags: u64,
  136. ) -> Result<(), c_long> {
  137. unsafe {
  138. let ret = bpf_l4_csum_replace(self.skb as *mut _, offset as u32, from, to, flags);
  139. if ret == 0 {
  140. Ok(())
  141. } else {
  142. Err(ret)
  143. }
  144. }
  145. }
  146. #[inline]
  147. pub fn adjust_room(&self, len_diff: i32, mode: u32, flags: u64) -> Result<(), c_long> {
  148. let ret = unsafe { bpf_skb_adjust_room(self.as_ptr() as *mut _, len_diff, mode, flags) };
  149. if ret == 0 {
  150. Ok(())
  151. } else {
  152. Err(ret)
  153. }
  154. }
  155. #[inline]
  156. pub fn clone_redirect(&self, if_index: u32, flags: u64) -> Result<(), c_long> {
  157. let ret = unsafe { bpf_clone_redirect(self.as_ptr() as *mut _, if_index, flags) };
  158. if ret == 0 {
  159. Ok(())
  160. } else {
  161. Err(ret)
  162. }
  163. }
  164. #[inline]
  165. pub fn change_proto(&self, proto: u16, flags: u64) -> Result<(), c_long> {
  166. let ret = unsafe { bpf_skb_change_proto(self.as_ptr() as *mut _, proto, flags) };
  167. if ret == 0 {
  168. Ok(())
  169. } else {
  170. Err(ret)
  171. }
  172. }
  173. #[inline]
  174. pub fn change_type(&self, ty: u32) -> Result<(), c_long> {
  175. let ret = unsafe { bpf_skb_change_type(self.as_ptr() as *mut _, ty) };
  176. if ret == 0 {
  177. Ok(())
  178. } else {
  179. Err(ret)
  180. }
  181. }
  182. /// Pulls in non-linear data in case the skb is non-linear.
  183. ///
  184. /// Make len bytes from skb readable and writable. If a zero value is passed for
  185. /// `len`, then the whole length of the skb is pulled. This helper is only needed
  186. /// for reading and writing with direct packet access.
  187. #[inline(always)]
  188. pub fn pull_data(&self, len: u32) -> Result<(), c_long> {
  189. let ret = unsafe { bpf_skb_pull_data(self.as_ptr() as *mut _, len) };
  190. if ret == 0 {
  191. Ok(())
  192. } else {
  193. Err(ret)
  194. }
  195. }
  196. pub(crate) fn as_ptr(&self) -> *mut c_void {
  197. self.skb as *mut _
  198. }
  199. #[inline]
  200. pub fn protocol(&self) -> u32 {
  201. unsafe { (*self.skb).protocol }
  202. }
  203. #[inline]
  204. pub fn family(&self) -> u32 {
  205. unsafe { (*self.skb).family }
  206. }
  207. #[inline]
  208. pub fn local_ipv4(&self) -> u32 {
  209. unsafe { (*self.skb).local_ip4 }
  210. }
  211. #[inline]
  212. pub fn local_ipv6(&self) -> &[u32; 4] {
  213. unsafe { &(*self.skb).local_ip6 }
  214. }
  215. #[inline]
  216. pub fn remote_ipv4(&self) -> u32 {
  217. unsafe { (*self.skb).remote_ip4 }
  218. }
  219. #[inline]
  220. pub fn remote_ipv6(&self) -> &[u32; 4] {
  221. unsafe { &(*self.skb).remote_ip6 }
  222. }
  223. #[inline]
  224. pub fn local_port(&self) -> u32 {
  225. unsafe { (*self.skb).local_port }
  226. }
  227. #[inline]
  228. pub fn remote_port(&self) -> u32 {
  229. unsafe { (*self.skb).remote_port }
  230. }
  231. }
  232. pub struct SkBuffContext {
  233. pub skb: SkBuff,
  234. }
  235. impl SkBuffContext {
  236. pub fn new(skb: *mut __sk_buff) -> SkBuffContext {
  237. let skb = SkBuff { skb };
  238. SkBuffContext { skb }
  239. }
  240. #[allow(clippy::len_without_is_empty)]
  241. #[inline]
  242. pub fn len(&self) -> u32 {
  243. self.skb.len()
  244. }
  245. #[inline]
  246. pub fn set_mark(&mut self, mark: u32) {
  247. self.skb.set_mark(mark)
  248. }
  249. #[inline]
  250. pub fn cb(&self) -> &[u32] {
  251. self.skb.cb()
  252. }
  253. #[inline]
  254. pub fn cb_mut(&mut self) -> &mut [u32] {
  255. self.skb.cb_mut()
  256. }
  257. /// Returns the owner UID of the socket associated to the SKB context.
  258. #[inline]
  259. pub fn get_socket_uid(&self) -> u32 {
  260. self.skb.get_socket_uid()
  261. }
  262. #[inline]
  263. pub fn load<T>(&self, offset: usize) -> Result<T, c_long> {
  264. self.skb.load(offset)
  265. }
  266. /// Reads some bytes from the packet into the specified buffer, returning
  267. /// how many bytes were read.
  268. ///
  269. /// Starts reading at `offset` and reads at most `dst.len()` or
  270. /// `self.len() - offset` bytes, depending on which one is smaller.
  271. ///
  272. /// # Examples
  273. ///
  274. /// Read into a `PerCpuArray`.
  275. ///
  276. /// ```no_run
  277. /// use core::mem;
  278. ///
  279. /// use aya_bpf::{bindings::TC_ACT_PIPE, macros::map, maps::PerCpuArray, programs::SkBuffContext};
  280. /// # #[allow(non_camel_case_types)]
  281. /// # struct ethhdr {};
  282. /// # #[allow(non_camel_case_types)]
  283. /// # struct iphdr {};
  284. /// # #[allow(non_camel_case_types)]
  285. /// # struct tcphdr {};
  286. ///
  287. /// const ETH_HDR_LEN: usize = mem::size_of::<ethhdr>();
  288. /// const IP_HDR_LEN: usize = mem::size_of::<iphdr>();
  289. /// const TCP_HDR_LEN: usize = mem::size_of::<tcphdr>();
  290. ///
  291. /// #[repr(C)]
  292. /// pub struct Buf {
  293. /// pub buf: [u8; 1500],
  294. /// }
  295. ///
  296. /// #[map]
  297. /// pub static mut BUF: PerCpuArray<Buf> = PerCpuArray::with_max_entries(1, 0);
  298. ///
  299. /// fn try_cgroup_skb(ctx: SkBuffContext) -> Result<i32, i32> {
  300. /// let buf = unsafe {
  301. /// let ptr = BUF.get_ptr_mut(0).ok_or(TC_ACT_PIPE)?;
  302. /// &mut *ptr
  303. /// };
  304. /// let offset = ETH_HDR_LEN + IP_HDR_LEN + TCP_HDR_LEN;
  305. /// ctx.load_bytes(offset, &mut buf.buf).map_err(|_| TC_ACT_PIPE)?;
  306. ///
  307. /// // do something with `buf`
  308. ///
  309. /// Ok(TC_ACT_PIPE)
  310. /// }
  311. /// ```
  312. #[inline(always)]
  313. pub fn load_bytes(&self, offset: usize, dst: &mut [u8]) -> Result<usize, c_long> {
  314. self.skb.load_bytes(offset, dst)
  315. }
  316. #[inline]
  317. pub fn store<T>(&mut self, offset: usize, v: &T, flags: u64) -> Result<(), c_long> {
  318. self.skb.store(offset, v, flags)
  319. }
  320. #[inline]
  321. pub fn l3_csum_replace(
  322. &self,
  323. offset: usize,
  324. from: u64,
  325. to: u64,
  326. size: u64,
  327. ) -> Result<(), c_long> {
  328. self.skb.l3_csum_replace(offset, from, to, size)
  329. }
  330. #[inline]
  331. pub fn l4_csum_replace(
  332. &self,
  333. offset: usize,
  334. from: u64,
  335. to: u64,
  336. flags: u64,
  337. ) -> Result<(), c_long> {
  338. self.skb.l4_csum_replace(offset, from, to, flags)
  339. }
  340. #[inline]
  341. pub fn adjust_room(&self, len_diff: i32, mode: u32, flags: u64) -> Result<(), c_long> {
  342. self.skb.adjust_room(len_diff, mode, flags)
  343. }
  344. #[inline]
  345. pub fn clone_redirect(&self, if_index: u32, flags: u64) -> Result<(), c_long> {
  346. self.skb.clone_redirect(if_index, flags)
  347. }
  348. #[inline]
  349. pub fn change_type(&self, ty: u32) -> Result<(), c_long> {
  350. self.skb.change_type(ty)
  351. }
  352. /// Pulls in non-linear data in case the skb is non-linear.
  353. ///
  354. /// Make len bytes from skb readable and writable. If a zero value is passed for
  355. /// `len`, then the whole length of the skb is pulled. This helper is only needed
  356. /// for reading and writing with direct packet access.
  357. ///
  358. /// # Examples
  359. ///
  360. /// ```no_run
  361. /// mod bindings;
  362. /// use bindings::{ethhdr, iphdr, udphdr};
  363. ///
  364. /// const ETH_HLEN: usize = core::mem::size_of::<ethhdr>();
  365. /// const IP_HLEN: usize = core::mem::size_of::<iphdr>();
  366. /// const UDP_HLEN: usize = core::mem::size_of::<udphdr>();
  367. ///
  368. /// fn try_cgroup_skb(ctx: SkBuffContext) -> Result<i32, i32> {
  369. /// let len = ETH_HLEN + IP_HLEN + UDP_HLEN;
  370. /// match ctx.pull_data(len as u32) {
  371. /// Ok(_) => return Ok(0),
  372. /// Err(ret) => return Err(ret as i32),
  373. /// }
  374. /// }
  375. /// ```
  376. #[inline(always)]
  377. pub fn pull_data(&self, len: u32) -> Result<(), c_long> {
  378. self.skb.pull_data(len)
  379. }
  380. }
  381. impl BpfContext for SkBuffContext {
  382. fn as_ptr(&self) -> *mut c_void {
  383. self.skb.as_ptr()
  384. }
  385. }