use crate::{MsgType, ProtoFamily};
use nftnl_sys::{self as sys, libc};
use std::{
collections::HashSet,
ffi::{CStr, CString, c_void},
os::raw::c_char,
ptr,
};
pub struct Table {
table: ptr::NonNull<sys::nftnl_table>,
family: ProtoFamily,
}
unsafe impl Send for Table {}
unsafe impl Sync for Table {}
impl Table {
pub fn new<T: AsRef<CStr>>(name: T, family: ProtoFamily) -> Table {
let table = try_alloc!(unsafe { sys::nftnl_table_alloc() });
unsafe {
let table = table.as_ptr();
sys::nftnl_table_set_u32(table, sys::NFTNL_TABLE_FAMILY as u16, family as u32);
sys::nftnl_table_set_str(table, sys::NFTNL_TABLE_NAME as u16, name.as_ref().as_ptr());
sys::nftnl_table_set_u32(table, sys::NFTNL_TABLE_FLAGS as u16, 0u32);
}
Table { table, family }
}
pub fn get_name(&self) -> &CStr {
unsafe {
let ptr = sys::nftnl_table_get_str(self.table.as_ptr(), sys::NFTNL_TABLE_NAME as u16);
CStr::from_ptr(ptr)
}
}
pub fn get_family(&self) -> ProtoFamily {
self.family
}
}
unsafe impl crate::NlMsg for Table {
unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
let raw_msg_type = match msg_type {
MsgType::Add => libc::NFT_MSG_NEWTABLE,
MsgType::Del => libc::NFT_MSG_DELTABLE,
};
let header = unsafe {
sys::nftnl_nlmsg_build_hdr(
buf.cast::<c_char>(),
raw_msg_type as u16,
self.family as u16,
libc::NLM_F_ACK as u16,
seq,
)
};
unsafe { sys::nftnl_table_nlmsg_build_payload(header, self.table.as_ptr()) };
}
}
impl Drop for Table {
fn drop(&mut self) {
unsafe { sys::nftnl_table_free(self.table.as_ptr()) };
}
}
pub fn get_tables_nlmsg(seq: u32) -> Vec<u8> {
let mut buffer = vec![0; crate::nft_nlmsg_maxsize() as usize];
let _ = unsafe {
sys::nftnl_nlmsg_build_hdr(
buffer.as_mut_ptr().cast::<c_char>(),
libc::NFT_MSG_GETTABLE as u16,
ProtoFamily::Unspec as u16,
(libc::NLM_F_ROOT | libc::NLM_F_MATCH | libc::NLM_F_ACK) as u16,
seq,
)
};
buffer
}
pub fn get_tables_cb(header: &libc::nlmsghdr, tables: &mut HashSet<CString>) -> libc::c_int {
unsafe {
let nf_table = sys::nftnl_table_alloc();
let err = sys::nftnl_table_nlmsg_parse(header, nf_table);
if err < 0 {
error!("Failed to parse nelink table message - {err}");
sys::nftnl_table_free(nf_table);
return err;
}
let table_name = CStr::from_ptr(sys::nftnl_table_get_str(
nf_table,
sys::NFTNL_TABLE_NAME as u16,
))
.to_owned();
tables.insert(table_name);
sys::nftnl_table_free(nf_table);
};
1
}