1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
use libc::{setsockopt, SOL_SOCKET};
use std::{
io, mem,
os::unix::prelude::{AsRawFd, RawFd},
};
use thiserror::Error;
use crate::{
generated::{bpf_prog_type::BPF_PROG_TYPE_SOCKET_FILTER, SO_ATTACH_BPF, SO_DETACH_BPF},
programs::{load_program, Link, LinkRef, ProgramData, ProgramError},
};
#[derive(Debug, Error)]
pub enum SocketFilterError {
#[error("setsockopt SO_ATTACH_BPF failed")]
SoAttachBpfError {
#[source]
io_error: io::Error,
},
}
#[derive(Debug)]
#[doc(alias = "BPF_PROG_TYPE_SOCKET_FILTER")]
pub struct SocketFilter {
pub(crate) data: ProgramData,
}
impl SocketFilter {
pub fn load(&mut self) -> Result<(), ProgramError> {
load_program(BPF_PROG_TYPE_SOCKET_FILTER, &mut self.data)
}
pub fn attach<T: AsRawFd>(&mut self, socket: T) -> Result<LinkRef, ProgramError> {
let prog_fd = self.data.fd_or_err()?;
let socket = socket.as_raw_fd();
let ret = unsafe {
setsockopt(
socket,
SOL_SOCKET,
SO_ATTACH_BPF as i32,
&prog_fd as *const _ as *const _,
mem::size_of::<RawFd>() as u32,
)
};
if ret < 0 {
return Err(SocketFilterError::SoAttachBpfError {
io_error: io::Error::last_os_error(),
})?;
}
Ok(self.data.link(SocketFilterLink {
socket,
prog_fd: Some(prog_fd),
}))
}
}
#[derive(Debug)]
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 as i32,
&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();
}
}