|
|
|
use proc_macro2::TokenStream;
|
|
|
|
use quote::quote;
|
|
|
|
use syn::{
|
|
|
|
parse::{Parse, ParseStream},
|
|
|
|
punctuated::{Pair, Punctuated},
|
|
|
|
token::Eq,
|
|
|
|
Error, Ident, ItemFn, ItemStatic, LitStr, Result, Token,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub struct NameValue {
|
|
|
|
name: Ident,
|
|
|
|
_eq: Eq,
|
|
|
|
value: LitStr,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Args {
|
|
|
|
args: Vec<NameValue>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parse for Args {
|
|
|
|
fn parse(input: ParseStream) -> Result<Args> {
|
|
|
|
let args = Punctuated::<NameValue, Token![,]>::parse_terminated_with(input, |input| {
|
|
|
|
Ok(NameValue {
|
|
|
|
name: input.parse()?,
|
|
|
|
_eq: input.parse()?,
|
|
|
|
value: input.parse()?,
|
|
|
|
})
|
|
|
|
})?
|
|
|
|
.into_pairs()
|
|
|
|
.map(|pair| match pair {
|
|
|
|
Pair::Punctuated(name_val, _) => name_val,
|
|
|
|
Pair::End(name_val) => name_val,
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
|
|
|
|
Ok(Args { args })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SockAddrArgs {
|
|
|
|
pub(crate) attach_type: Ident,
|
|
|
|
pub(crate) args: Args,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parse for SockAddrArgs {
|
|
|
|
fn parse(input: ParseStream) -> Result<SockAddrArgs> {
|
|
|
|
let attach_type: Ident = input.parse()?;
|
|
|
|
match attach_type.to_string().as_str() {
|
|
|
|
"connect4" | "connect6" | "bind4" | "bind6" | "getpeername4" | "getpeername6"
|
|
|
|
| "getsockname4" | "getsockname6" | "sendmsg4" | "sendmsg6" | "recvmsg4"
|
|
|
|
| "recvmsg6" => (),
|
|
|
|
_ => return Err(input.error("invalid attach type")),
|
|
|
|
}
|
|
|
|
let args = if input.parse::<Token![,]>().is_ok() {
|
|
|
|
Args::parse(input)?
|
|
|
|
} else {
|
|
|
|
Args { args: vec![] }
|
|
|
|
};
|
|
|
|
Ok(SockAddrArgs { attach_type, args })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SockoptArgs {
|
|
|
|
pub(crate) attach_type: Ident,
|
|
|
|
pub(crate) args: Args,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parse for SockoptArgs {
|
|
|
|
fn parse(input: ParseStream) -> Result<SockoptArgs> {
|
|
|
|
let attach_type: Ident = input.parse()?;
|
|
|
|
match attach_type.to_string().as_str() {
|
|
|
|
"getsockopt" | "setsockopt" => (),
|
|
|
|
_ => return Err(input.error("invalid attach type")),
|
|
|
|
}
|
|
|
|
let args = if input.parse::<Token![,]>().is_ok() {
|
|
|
|
Args::parse(input)?
|
|
|
|
} else {
|
|
|
|
Args { args: vec![] }
|
|
|
|
};
|
|
|
|
Ok(SockoptArgs { attach_type, args })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Map {
|
|
|
|
item: ItemStatic,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Map {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemStatic) -> Result<Map> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.ident.to_string());
|
|
|
|
Ok(Map { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = "maps".to_string();
|
|
|
|
let name = &self.name;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[link_section = #section_name]
|
|
|
|
#[export_name = #name]
|
|
|
|
#item
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Probe {
|
|
|
|
kind: ProbeKind,
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Probe {
|
|
|
|
pub fn from_syn(kind: ProbeKind, mut args: Args, item: ItemFn) -> Result<Probe> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(Probe { kind, item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("{}/{}", self.kind, self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::ProbeContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SockOps {
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SockOps {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SockOps> {
|
|
|
|
let name = name_arg(&mut args)?;
|
|
|
|
|
|
|
|
Ok(SockOps { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("sockops/{}", name)
|
|
|
|
} else {
|
|
|
|
"sockops".to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock_ops) -> u32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SockOpsContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SkMsg {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SkMsg {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SkMsg> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(SkMsg { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("sk_msg/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::sk_msg_md) -> u32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SkMsgContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Xdp {
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Xdp {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<Xdp> {
|
|
|
|
let name = name_arg(&mut args)?;
|
|
|
|
|
|
|
|
Ok(Xdp { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("xdp/{}", name)
|
|
|
|
} else {
|
|
|
|
"xdp".to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::xdp_md) -> u32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::XdpContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SchedClassifier {
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SchedClassifier {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SchedClassifier> {
|
|
|
|
let name = name_arg(&mut args)?;
|
|
|
|
|
|
|
|
Ok(SchedClassifier { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("classifier/{}", name)
|
|
|
|
} else {
|
|
|
|
"classifier".to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::TcContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CgroupSysctl {
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CgroupSysctl {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<CgroupSysctl> {
|
|
|
|
let name = name_arg(&mut args)?;
|
|
|
|
|
|
|
|
Ok(CgroupSysctl { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("cgroup/sysctl/{}", name)
|
|
|
|
} else {
|
|
|
|
("cgroup/sysctl").to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sysctl) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SysctlContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CgroupSockopt {
|
|
|
|
item: ItemFn,
|
|
|
|
attach_type: String,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CgroupSockopt {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn, attach_type: String) -> Result<CgroupSockopt> {
|
|
|
|
let name = pop_arg(&mut args, "name");
|
|
|
|
err_on_unknown_args(&args)?;
|
|
|
|
|
|
|
|
Ok(CgroupSockopt {
|
|
|
|
item,
|
|
|
|
attach_type,
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("cgroup/{}/{}", self.attach_type, name)
|
|
|
|
} else {
|
|
|
|
format!("cgroup/{}", self.attach_type)
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sockopt) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SockoptContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CgroupSkb {
|
|
|
|
item: ItemFn,
|
|
|
|
expected_attach_type: Option<String>,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CgroupSkb {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<CgroupSkb> {
|
|
|
|
let name = pop_arg(&mut args, "name");
|
|
|
|
let expected_attach_type = pop_arg(&mut args, "attach");
|
|
|
|
err_on_unknown_args(&args)?;
|
|
|
|
|
|
|
|
Ok(CgroupSkb {
|
|
|
|
item,
|
|
|
|
expected_attach_type,
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(attach) = &self.expected_attach_type {
|
|
|
|
if let Some(name) = &self.name {
|
|
|
|
format!("cgroup_skb/{}/{}", attach, name)
|
|
|
|
} else {
|
|
|
|
format!("cgroup_skb/{}", attach)
|
|
|
|
}
|
|
|
|
} else if let Some(name) = &self.name {
|
|
|
|
format!("cgroup/skb/{}", name)
|
|
|
|
} else {
|
|
|
|
("cgroup/skb").to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SkBuffContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CgroupSockAddr {
|
|
|
|
item: ItemFn,
|
|
|
|
attach_type: String,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CgroupSockAddr {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn, attach_type: String) -> Result<CgroupSockAddr> {
|
|
|
|
let name = pop_arg(&mut args, "name");
|
|
|
|
err_on_unknown_args(&args)?;
|
|
|
|
|
|
|
|
Ok(CgroupSockAddr {
|
|
|
|
item,
|
|
|
|
attach_type,
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("cgroup/{}/{}", self.attach_type, name)
|
|
|
|
} else {
|
|
|
|
format!("cgroup/{}", self.attach_type)
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock_addr) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SockAddrContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct CgroupSock {
|
|
|
|
item: ItemFn,
|
|
|
|
attach_type: Option<String>,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CgroupSock {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<CgroupSock> {
|
|
|
|
let name = pop_arg(&mut args, "name");
|
|
|
|
let attach_type = pop_arg(&mut args, "attach");
|
|
|
|
err_on_unknown_args(&args)?;
|
|
|
|
|
|
|
|
Ok(CgroupSock {
|
|
|
|
item,
|
|
|
|
attach_type,
|
|
|
|
name,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
if let Some(attach_type) = &self.attach_type {
|
|
|
|
format!("cgroup/{}/{}", attach_type, name)
|
|
|
|
} else {
|
|
|
|
format!("cgroup/sock/{}", name)
|
|
|
|
}
|
|
|
|
} else if let Some(attach_type) = &self.attach_type {
|
|
|
|
format!("cgroup/{}", attach_type)
|
|
|
|
} else {
|
|
|
|
"cgroup/sock".to_string()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sock) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SockContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pop_arg(args: &mut Args, name: &str) -> Option<String> {
|
|
|
|
match args.args.iter().position(|arg| arg.name == name) {
|
|
|
|
Some(index) => Some(args.args.remove(index).value.value()),
|
|
|
|
None => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn err_on_unknown_args(args: &Args) -> Result<()> {
|
|
|
|
if let Some(arg) = args.args.get(0) {
|
|
|
|
return Err(Error::new_spanned(&arg.name, "invalid argument"));
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn name_arg(args: &mut Args) -> Result<Option<String>> {
|
|
|
|
let name = pop_arg(args, "name");
|
|
|
|
err_on_unknown_args(args)?;
|
|
|
|
|
|
|
|
Ok(name)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::enum_variant_names)]
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub enum ProbeKind {
|
|
|
|
KProbe,
|
|
|
|
KRetProbe,
|
|
|
|
UProbe,
|
|
|
|
URetProbe,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for ProbeKind {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
use ProbeKind::*;
|
|
|
|
match self {
|
|
|
|
KProbe => write!(f, "kprobe"),
|
|
|
|
KRetProbe => write!(f, "kretprobe"),
|
|
|
|
UProbe => write!(f, "uprobe"),
|
|
|
|
URetProbe => write!(f, "uretprobe"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct TracePoint {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TracePoint {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<TracePoint> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(TracePoint { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("tp/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::TracePointContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct PerfEvent {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PerfEvent {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<PerfEvent> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(PerfEvent { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("perf_event/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::PerfEventContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct RawTracePoint {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl RawTracePoint {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<RawTracePoint> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(RawTracePoint { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("raw_tp/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> u32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::RawTracePointContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Lsm {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Lsm {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<Lsm> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(Lsm { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("lsm/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
// LSM probes need to return an integer corresponding to the correct
|
|
|
|
// policy decision. Therefore we do not simply default to a return value
|
|
|
|
// of 0 as in other program types.
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::LsmContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct BtfTracePoint {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BtfTracePoint {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<BtfTracePoint> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(BtfTracePoint { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("tp_btf/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::BtfTracePointContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::enum_variant_names)]
|
|
|
|
#[derive(Debug, Copy, Clone)]
|
|
|
|
pub enum SkSkbKind {
|
|
|
|
StreamVerdict,
|
|
|
|
StreamParser,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for SkSkbKind {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
use SkSkbKind::*;
|
|
|
|
match self {
|
|
|
|
StreamVerdict => write!(f, "stream_verdict"),
|
|
|
|
StreamParser => write!(f, "stream_parser"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SkSkb {
|
|
|
|
kind: SkSkbKind,
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SkSkb {
|
|
|
|
pub fn from_syn(kind: SkSkbKind, mut args: Args, item: ItemFn) -> Result<SkSkb> {
|
|
|
|
let name = pop_arg(&mut args, "name");
|
|
|
|
err_on_unknown_args(&args)?;
|
|
|
|
|
|
|
|
Ok(SkSkb { item, kind, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let kind = &self.kind;
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("sk_skb/{}/{}", kind, name)
|
|
|
|
} else {
|
|
|
|
format!("sk_skb/{}", kind)
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> u32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SkBuffContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SocketFilter {
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SocketFilter {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SocketFilter> {
|
|
|
|
let name = name_arg(&mut args)?;
|
|
|
|
err_on_unknown_args(&args)?;
|
|
|
|
|
|
|
|
Ok(SocketFilter { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("socket/{}", name)
|
|
|
|
} else {
|
|
|
|
"socket".to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::__sk_buff) -> i64 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SkBuffContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct FEntry {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FEntry {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<FEntry> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(FEntry { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("fentry/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::FEntryContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct FExit {
|
|
|
|
item: ItemFn,
|
|
|
|
name: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FExit {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<FExit> {
|
|
|
|
let name = name_arg(&mut args)?.unwrap_or_else(|| item.sig.ident.to_string());
|
|
|
|
|
|
|
|
Ok(FExit { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = format!("fexit/{}", self.name);
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::core::ffi::c_void) -> i32 {
|
|
|
|
let _ = #fn_name(::aya_bpf::programs::FExitContext::new(ctx));
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct SkLookup {
|
|
|
|
item: ItemFn,
|
|
|
|
name: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SkLookup {
|
|
|
|
pub fn from_syn(mut args: Args, item: ItemFn) -> Result<SkLookup> {
|
|
|
|
let name = name_arg(&mut args)?;
|
|
|
|
|
|
|
|
Ok(SkLookup { item, name })
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn expand(&self) -> Result<TokenStream> {
|
|
|
|
let section_name = if let Some(name) = &self.name {
|
|
|
|
format!("sk_lookup/{}", name)
|
|
|
|
} else {
|
|
|
|
"sk_lookup".to_owned()
|
|
|
|
};
|
|
|
|
let fn_name = &self.item.sig.ident;
|
|
|
|
let item = &self.item;
|
|
|
|
Ok(quote! {
|
|
|
|
#[no_mangle]
|
|
|
|
#[link_section = #section_name]
|
|
|
|
fn #fn_name(ctx: *mut ::aya_bpf::bindings::bpf_sk_lookup) -> u32 {
|
|
|
|
return #fn_name(::aya_bpf::programs::SkLookupContext::new(ctx));
|
|
|
|
|
|
|
|
#item
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use syn::parse_quote;
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cgroup_skb_with_attach_and_name() {
|
|
|
|
let prog = CgroupSkb::from_syn(
|
|
|
|
parse_quote!(name = "foo", attach = "ingress"),
|
|
|
|
parse_quote!(
|
|
|
|
fn foo(ctx: SkBuffContext) -> i32 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let stream = prog.expand().unwrap();
|
|
|
|
assert!(stream
|
|
|
|
.to_string()
|
|
|
|
.contains("[link_section = \"cgroup_skb/ingress/foo\"]"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cgroup_skb_with_name() {
|
|
|
|
let prog = CgroupSkb::from_syn(
|
|
|
|
parse_quote!(name = "foo"),
|
|
|
|
parse_quote!(
|
|
|
|
fn foo(ctx: SkBuffContext) -> i32 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let stream = prog.expand().unwrap();
|
|
|
|
assert!(stream
|
|
|
|
.to_string()
|
|
|
|
.contains("[link_section = \"cgroup/skb/foo\"]"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cgroup_skb_no_name() {
|
|
|
|
let prog = CgroupSkb::from_syn(
|
|
|
|
parse_quote!(),
|
|
|
|
parse_quote!(
|
|
|
|
fn foo(ctx: SkBuffContext) -> i32 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let stream = prog.expand().unwrap();
|
|
|
|
assert!(stream
|
|
|
|
.to_string()
|
|
|
|
.contains("[link_section = \"cgroup/skb\"]"));
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn cgroup_skb_with_attach_no_name() {
|
|
|
|
let prog = CgroupSkb::from_syn(
|
|
|
|
parse_quote!(attach = "egress"),
|
|
|
|
parse_quote!(
|
|
|
|
fn foo(ctx: SkBuffContext) -> i32 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
let stream = prog.expand().unwrap();
|
|
|
|
assert!(stream
|
|
|
|
.to_string()
|
|
|
|
.contains("[link_section = \"cgroup_skb/egress\"]"));
|
|
|
|
}
|
|
|
|
}
|