use std::{env, mem, process, vec::Vec};
extern crate libc;
extern crate errno;
use errno::Errno;
extern crate rsmnl as mnl;
use mnl::{AttrTbl, CbResult, CbStatus, MsgVec, Msghdr, Socket};
extern crate rsmnl_linux as linux;
use linux::netfilter::{
nfnetlink as nfnl,
nfnetlink::Nfgenmsg,
nfnetlink_log as nful,
nfnetlink_log::{
NfulnlAttrConfig, NfulnlAttrTypeTbl, NfulnlMsgConfigCmd, NfulnlMsgConfigCmds,
NfulnlMsgConfigMode, NfulnlMsgPacketHdr, NfulnlMsgTypes,
},
};
fn log_cb(nlh: &Msghdr) -> CbResult {
let mut ph = &NfulnlMsgPacketHdr {
hw_protocol: 0,
hook: 0,
_pad: 0,
};
let mut prefix = "";
let mut mark: u32 = 0;
let tb = NfulnlAttrTypeTbl::from_nlmsg(mem::size_of::<Nfgenmsg>(), nlh)?;
tb.packet_hdr()?.map(|x| ph = x);
tb.prefix()?.map(|x| prefix = x);
tb.mark()?.map(|x| mark = *x);
println!(
"log received (prefix=\"{}\", hw=0x{:x}, hook={}, mark={})",
prefix, ph.hw_protocol, ph.hook, mark
);
Ok(CbStatus::Ok)
}
fn nflog_build_cfg_pf_request(nlv: &mut MsgVec, command: u8) -> Result<(), Errno> {
let mut nlh = nlv.put_header();
nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | NfulnlMsgTypes::Config as u16;
nlh.nlmsg_flags = libc::NLM_F_REQUEST as u16;
let nfg = nlv.put_extra_header::<Nfgenmsg>()?;
nfg.nfgen_family = libc::AF_INET as u8;
nfg.version = libc::NFNETLINK_V0 as u8;
let cmd = NfulnlMsgConfigCmd { command: command };
NfulnlAttrConfig::put_cmd(nlv, &cmd)?;
Ok(())
}
fn nflog_build_cfg_request(nlv: &mut MsgVec, command: u8, qnum: u16) -> Result<(), Errno> {
let mut nlh = nlv.put_header();
nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | NfulnlMsgTypes::Config as u16;
nlh.nlmsg_flags = libc::NLM_F_REQUEST as u16;
let nfg = nlv.put_extra_header::<Nfgenmsg>()?;
nfg.nfgen_family = libc::AF_INET as u8;
nfg.version = libc::NFNETLINK_V0 as u8;
nfg.res_id = qnum.to_be();
let cmd = nful::NfulnlMsgConfigCmd { command: command };
NfulnlAttrConfig::put_cmd(nlv, &cmd)?;
Ok(())
}
fn nflog_build_cfg_params(nlv: &mut MsgVec, mode: u8, range: u32, qnum: u16) -> Result<(), Errno> {
let mut nlh = nlv.put_header();
nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | NfulnlMsgTypes::Config as u16;
nlh.nlmsg_flags = libc::NLM_F_REQUEST as u16;
let nfg = nlv.put_extra_header::<Nfgenmsg>()?;
nfg.nfgen_family = libc::AF_UNSPEC as u8;
nfg.version = nfnl::NFNETLINK_V0;
nfg.res_id = qnum.to_be();
let params = NfulnlMsgConfigMode {
copy_range: range.to_be(),
copy_mode: mode,
_pad: 0,
};
NfulnlAttrConfig::put_mode(nlv, ¶ms)?;
Ok(())
}
fn main() -> Result<(), String> {
let args: Vec<_> = env::args().collect();
if args.len() != 2 {
println!("Usage: {} [queue_num]", args[0]);
process::exit(libc::EXIT_FAILURE);
}
let qnum: u16 = args[1].trim().parse().expect("queue number required");
let mut nl = Socket::open(libc::NETLINK_NETFILTER, 0)
.map_err(|errno| format!("mnl_socket_open: {}", errno))?;
nl.bind(0, mnl::SOCKET_AUTOPID)
.map_err(|errno| format!("mnl_socket_bind: {}", errno))?;
let portid = nl.portid();
let mut nlv = MsgVec::new();
nflog_build_cfg_pf_request(&mut nlv, NfulnlMsgConfigCmds::PfUnbind as u8)
.map_err(|errno| format!("nflog_build_cfg_pf_request: {}", errno))?;
nl.sendto(&nlv)
.map_err(|errno| format!("mnl_socket_sendto: {}", errno))?;
nlv.reset();
nflog_build_cfg_pf_request(&mut nlv, NfulnlMsgConfigCmds::PfBind as u8)
.map_err(|errno| format!("nflog_build_cfg_pf_request: {}", errno))?;
nl.sendto(&nlv)
.map_err(|errno| format!("mnl_socket_sendto: {}", errno))?;
nlv.reset();
nflog_build_cfg_request(&mut nlv, NfulnlMsgConfigCmds::Bind as u8, qnum)
.map_err(|errno| format!("nflog_build_cfg_request: {}", errno))?;
nl.sendto(&nlv)
.map_err(|errno| format!("mnl_socket_sendto: {}", errno))?;
nlv.reset();
nflog_build_cfg_params(&mut nlv, nful::NFULNL_COPY_PACKET, 0xffff, qnum)
.map_err(|errno| format!("nflog_build_cfg_params: {}", errno))?;
nl.sendto(&nlv)
.map_err(|errno| format!("mnl_socket_sendto: {}", errno))?;
let mut buf = mnl::default_buffer();
loop {
let nrecv = nl
.recvfrom(&mut buf)
.map_err(|errno| format!("mnl_socket_recvfrom: {}", errno))?;
mnl::cb_run(&buf[..nrecv], 0, portid, Some(log_cb))
.map_err(|errno| format!("mnl_cb_run: {}", errno))?;
}
}