Browse Source

Implement detaching from socket filters

Alessandro Decina 4 years ago
parent
commit
9614132724
1 changed files with 40 additions and 5 deletions
  1. 40 5
      src/programs/socket_filter.rs

+ 40 - 5
src/programs/socket_filter.rs

@@ -1,9 +1,9 @@
-use libc::{setsockopt, SOL_SOCKET, SO_ATTACH_BPF};
-use std::{io, mem, os::unix::prelude::RawFd};
+use libc::{setsockopt, SOL_SOCKET, SO_ATTACH_BPF, SO_DETACH_BPF};
+use std::{cell::RefCell, io, mem, os::unix::prelude::RawFd, rc::Rc};
 
 use crate::{
     generated::bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER,
-    programs::{load_program, ProgramData, ProgramError},
+    programs::{load_program, Link, LinkRef, ProgramData, ProgramError},
 };
 
 #[derive(Debug)]
@@ -16,7 +16,7 @@ impl SocketFilter {
         load_program(BPF_PROG_TYPE_SOCKET_FILTER, &mut self.data)
     }
 
-    pub fn attach(&self, socket: RawFd) -> Result<(), ProgramError> {
+    pub fn attach(&self, socket: RawFd) -> Result<impl Link, ProgramError> {
         let prog_fd = self.data.fd_or_err()?;
 
         let ret = unsafe {
@@ -33,7 +33,42 @@ impl SocketFilter {
                 io_error: io::Error::last_os_error(),
             });
         }
+        let link = Rc::new(RefCell::new(SocketFilterLink {
+            socket,
+            prog_fd: Some(prog_fd),
+        }));
 
-        Ok(())
+        Ok(LinkRef::new(&link))
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct SocketFilterLink {
+    socket: RawFd,
+    prog_fd: Option<RawFd>,
+}
+
+impl Link for SocketFilterLink {
+    fn detach(&mut self) -> Result<(), ProgramError> {
+        if let Some(fd) = self.prog_fd.take() {
+            unsafe {
+                setsockopt(
+                    self.socket,
+                    SOL_SOCKET,
+                    SO_DETACH_BPF,
+                    &fd as *const _ as *const _,
+                    mem::size_of::<RawFd>() as u32,
+                );
+            }
+            Ok(())
+        } else {
+            Err(ProgramError::AlreadyDetached)
+        }
+    }
+}
+
+impl Drop for SocketFilterLink {
+    fn drop(&mut self) {
+        let _ = self.detach();
     }
 }