diff --git a/README.md b/README.md index c446f79..194092f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ crslmnl ======= -Rust wrapper of libmnl, less safe. +A Rust wrapper for libmnl. sample @@ -13,7 +13,12 @@ see examples requires -------- - * libmnl +* libmnl - C libmnl library +* Rust gcc +* for examples: + - Rust time + - Rust mio + - Rust pnet links @@ -34,7 +39,7 @@ thanks to [Shepmaster](http://stackoverflow.com/users/155423/shepmaster) comparison ---------- -| original | cgolmnl | remarks | +| original | crslmnl | remarks | | ------------------------------------- | ----------------------------- | ----------------------------- | | mnl_attr_get_type | Attr.atype | | | mnl_attr_get_len | Attr.len | | @@ -47,38 +52,44 @@ comparison | mnl_attr_validate | Attr.validate | | | mnl_attr_validate2 | Attr.validate2 | | | mnl_attr_parse | Attr.parse | | +| (add) | Attr.cl_parse | | | mnl_attr_parse_nested | Attr.parse_nested | | -| mnl_attr_parse_payload | parse_payload | | +| (add) | Attr.cl_parse_nested | | +| mnl_attr_parse_payload | parse_attrs | | +| (add) | cl_parse_attrs | | | mnl_attr_get_u8 | Attr.u8 | | | mnl_attr_get_u16 | Attr.u16 | | | mnl_attr_get_u32 | Attr.u32 | | | mnl_attr_get_u64 | Attr.u64 | | | mnl_attr_get_str | Attr.str | | | (add) | Attr.string | | -| mnl_attr_put | Nlmsg.put | | -| mnl_attr_put_u8 | Nlmsg.put_u8 | | -| mnl_attr_put_u16 | Nlmsg.put_u16 | | -| mnl_attr_put_u32 | Nlmsg.put_u32 | | -| mnl_attr_put_u64 | Nlmsg.put_u64 | | -| mnl_attr_put_str | Nlmsg.put_str | | -| mnl_attr_put_strz | Nlmsg.put_strz | | -| mnl_attr_put_check | Nlmsg.put_check | | -| mnl_attr_put_u8_check | Nlmsg.put_u8_check | | -| mnl_attr_put_u16_check | Nlmsg.put_u16_check | | -| mnl_attr_put_u32_check | Nlmsg.put_u32_check | | -| mnl_attr_put_u64_check | Nlmsg.put_u64_check | | -| mnl_attr_put_str_check | Nlmsg.put_str_check | | -| mnl_attr_put_strz_check | Nlmsg.put_strz_check | | -| mnl_attr_nest_start | Nlmsg.nest_start | | -| mnl_attr_nest_start_check | Nlmsg.nest_start_check | | +| mnl_attr_put | Nlmsg.put_raw | | +| mnl_attr_put_u8 | Nlmsg.put_u8_raw | | +| mnl_attr_put_u16 | Nlmsg.put_u16_raw | | +| mnl_attr_put_u32 | Nlmsg.put_u32_raw | | +| mnl_attr_put_u64 | Nlmsg.put_u64_raw | | +| mnl_attr_put_str | Nlmsg.put_str_raw | | +| mnl_attr_put_strz | Nlmsg.put_strz_raw | | +| mnl_attr_put_check | Nlmsg.put | | +| mnl_attr_put_u8_check | Nlmsg.put_u8 | | +| mnl_attr_put_u16_check | Nlmsg.put_u16 | | +| mnl_attr_put_u32_check | Nlmsg.put_u32 | | +| mnl_attr_put_u64_check | Nlmsg.put_u64 | | +| mnl_attr_put_str_check | Nlmsg.put_str | | +| mnl_attr_put_strz_check | Nlmsg.put_strz | | +| mnl_attr_nest_start | Nlmsg.nest_start_raw | | +| mnl_attr_nest_start_check | Nlmsg.nest_start | | | mnl_attr_nest_end | Nlmsg.nest_end | | | mnl_attr_nest_cancel | Nlmsg.nest_cancel | | | ------------------------------------- | ----------------------------- | ----------------------------- | | mnl_nlmsg_size | Nlmsg::size | | | mnl_nlmsg_get_payload_len | Nlmsg.payload_len | | | mnl_nlmsg_put_header | Nlmsg::new | | -| mnl_nlmsg_put_header | Nlmsg.put_header | | -| mnl_nlmsg_put_extra_header | Nlmsg.put_extra_header | | +| mnl_nlmsg_put_header | Nlmsg.put_header_raw | | +| (add) | Nlmsg.put_header_check | | +| mnl_nlmsg_put_extra_header | Nlmsg.put_extra_header_raw | | +| (add) | Nlmsg.put_sized_header | | +| (add) | Nlmsg.put_sized_header_raw | | | (add) | Nlmsg.put_sized_header | | | mnl_nlmsg_get_paylod | Nlmsg.payload | | | mnl_nlmsg_get_paylod | Nlmsg.payload_mut | | @@ -102,7 +113,9 @@ comparison | mnl_nlmsg_batch_is_empty | NlmsgBatch.is_empty | | | ------------------------------------- | ----------------------------- | ----------------------------- | | mnl_cb_run | cb_run | | -| mnl_cb_run2 | cb_run2 | changed signature | +| mnl_cb_run2 | cb_run2 | | +| (add) | cl_run | closure instead of callback | +| (add) | cl_run2 | closure instead of callback | | ------------------------------------- | ----------------------------- | ----------------------------- | | mnl_socket_get_fd | Socket.as_raw_fd | | | mnl_socket_get_portid | Socket.portid | | @@ -120,3 +133,6 @@ comparison | ------------------------------------- | ----------------------------- | ----------------------------- | | mnl_attr_for_each | Nlmsg.attrs | | | mnl_attr_for_each_nested | Attr.nesteds | | +| ------------------------------------- | ----------------------------- | ----------------------------- | +| (add) | NlmsgIterator | | +| (add) | Iterator for NlmsgBatch | | diff --git a/examples/genl-family-get2.rs b/examples/genl-family-get2.rs new file mode 120000 index 0000000..074a4c4 --- /dev/null +++ b/examples/genl-family-get2.rs @@ -0,0 +1 @@ +genl/genl-family-get2.rs \ No newline at end of file diff --git a/examples/genl/genl-family-get.rs b/examples/genl/genl-family-get.rs index 159b3ad..d379d69 100644 --- a/examples/genl/genl-family-get.rs +++ b/examples/genl/genl-family-get.rs @@ -185,18 +185,18 @@ fn main() { let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = genl::GENL_ID_CTRL; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_ACK; *nlh.nlmsg_seq = seq; - let genl = nlh.put_sized_header::(); + let genl = nlh.put_sized_header::().unwrap(); genl.cmd = genl::CtrlCmd::GETFAMILY as u8; genl.version = 1; - nlh.put_u16(genl::CtrlAttr::FAMILY_ID as u16, genl::GENL_ID_CTRL); + nlh.put_u16(genl::CtrlAttr::FAMILY_ID as u16, genl::GENL_ID_CTRL).unwrap(); if args.len() >= 2 { - nlh.put_strz(genl::CtrlAttr::FAMILY_NAME as u16, &args[1]); + nlh.put_strz(genl::CtrlAttr::FAMILY_NAME as u16, &args[1]).unwrap(); } else { *nlh.nlmsg_flags |= netlink::NLM_F_DUMP; } diff --git a/examples/genl/genl-family-get2.rs b/examples/genl/genl-family-get2.rs new file mode 100644 index 0000000..579753e --- /dev/null +++ b/examples/genl/genl-family-get2.rs @@ -0,0 +1,226 @@ +use std::env; +use std::io::Write; +use std::mem::size_of; + +extern crate libc; +extern crate time; +extern crate crslmnl as mnl; + +use mnl::linux::netlink as netlink; +use mnl::linux::genetlink as genl; + + +macro_rules! println_stderr( + ($($arg:tt)*) => { { + let r = writeln!(&mut ::std::io::stderr(), $($arg)*); + r.expect("failed printing to stderr"); + } } +); + +fn parse_mc_grps_cb<'a, 'b>(tb: &'b mut [Option<&'a mnl::Attr>]) -> Box mnl::CbRet + 'b> { + Box::new(move |attr: &'a mnl::Attr| { + // skip unsupported attribute in user-space + if let Err(_) = attr.type_valid(genl::CTRL_ATTR_MCAST_GRP_MAX as u16) { + return mnl::CbRet::OK; + } + + let atype = attr.atype(); + match atype { + n if n == genl::CtrlAttrMcastGrp::ID as u16 => { + if let Err(errno) = attr.validate(mnl::AttrDataType::U32) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if n == genl::CtrlAttrMcastGrp::NAME as u16 => { + if let Err(errno) = attr.validate(mnl::AttrDataType::STRING) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + _ => {}, + } + tb[atype as usize] = Some(attr); + mnl::CbRet::OK + }) +} + +fn parse_genl_mc_grps(nested: &mnl::Attr) { + for pos in nested.nesteds() { + let mut tb: [Option<&mnl::Attr>; genl::CTRL_ATTR_MCAST_GRP_MAX as usize + 1] + = [None; genl::CTRL_ATTR_MCAST_GRP_MAX as usize + 1]; + + let _ = pos.cl_parse_nested(parse_mc_grps_cb(&mut tb)); + + tb[genl::CtrlAttrMcastGrp::ID as usize] + .map(|attr| print!("id-0x{:x} ", attr.u32())); + tb[genl::CtrlAttrMcastGrp::NAME as usize] + .map(|attr| print!("name: {} ", attr.str())); + println!(""); + } +} + +fn parse_genl_family_ops<'a>(nested: &mnl::Attr) { + for pos in nested.nesteds() { + let mut tb: [Option<&'a mnl::Attr>; genl::CTRL_ATTR_OP_MAX as usize + 1] + = [None; genl::CTRL_ATTR_OP_MAX as usize + 1]; + + let _ = pos.cl_parse_nested(Box::new(|attr: &'a mnl::Attr| { + if let Err(_) = attr.type_valid(genl::CTRL_ATTR_OP_MAX) { + return mnl::CbRet::OK; + } + + let atype = attr.atype(); + match atype { + n if (n == genl::CtrlAttrOp::ID as u16 || + n == genl::CtrlAttrOp::FLAGS as u16) => { + if let Err(errno) = attr.validate(mnl::AttrDataType::U32) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if n == genl::CTRL_ATTR_OP_MAX => {}, + _ => { + return mnl::CbRet::OK; + }, + } + + tb[atype as usize] = Some(attr); + return mnl::CbRet::OK; + })); + + tb[genl::CtrlAttrOp::ID as usize] + .map(|attr| print!("id-0x{:x} ", attr.u32())); + tb[genl::CtrlAttrOp::FLAGS as usize] + .map(|attr| print!("flags 0x{:08x}", attr.u32())); + println!(""); + } +} + +fn data_attr_cb<'a, 'b>(tb: &'b mut [Option<&'a mnl::Attr>]) + -> Box mnl::CbRet + 'b> +{ + Box::new(move |attr: &'a mnl::Attr| { + if let Err(_) = attr.type_valid(genl::CTRL_ATTR_MAX) { + return mnl::CbRet::OK; + } + + let atype = attr.atype(); + match atype { + n if n == genl::CtrlAttr::FAMILY_NAME as u16 => { + if let Err(errno) = attr.validate(mnl::AttrDataType::STRING) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if n == genl::CtrlAttr::FAMILY_ID as u16 => { + if let Err(errno) = attr.validate(mnl::AttrDataType::U16) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if (n == genl::CtrlAttr::VERSION as u16 || + n == genl::CtrlAttr::HDRSIZE as u16 || + n == genl::CtrlAttr::MAXATTR as u16) => { + if let Err(errno) = attr.validate(mnl::AttrDataType::U32) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if (n == genl::CtrlAttr::OPS as u16 || + n == genl::CtrlAttr::MCAST_GROUPS as u16) => { + if let Err(errno) = attr.validate(mnl::AttrDataType::NESTED) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + _ => {}, + } + + tb[atype as usize] = Some(attr); + return mnl::CbRet::OK; + }) +} + +fn data_cb() -> Box mnl::CbRet> { + Box::new(|nlh: mnl::Nlmsg| { + let mut tb: [Option<&mnl::Attr>; genl::CTRL_ATTR_MAX as usize + 1] + = [None; genl::CTRL_ATTR_MAX as usize + 1]; + + let _ = nlh.cl_parse(size_of::(), data_attr_cb(&mut tb)); + + tb[genl::CtrlAttr::FAMILY_NAME as usize] + .map(|attr| print!("name={}\t", attr.str())); + tb[genl::CtrlAttr::FAMILY_ID as usize] + .map(|attr| print!("id={}\t", attr.u16())); + tb[genl::CtrlAttr::VERSION as usize] + .map(|attr| print!("version={}\t", attr.u32())); + tb[genl::CtrlAttr::HDRSIZE as usize] + .map(|attr| print!("hdrsize={}\t", attr.u32())); + tb[genl::CtrlAttr::MAXATTR as usize] + .map(|attr| print!("maxattr={}\t", attr.u32())); + println!(""); + + tb[genl::CtrlAttr::OPS as usize] + .map(|attr| { + println!("ops:"); + parse_genl_family_ops(attr); + }); + tb[genl::CtrlAttr::MCAST_GROUPS as usize] + .map(|attr| { + println!("grps:"); + parse_genl_mc_grps(attr); + }); + println!(""); + + return mnl::CbRet::OK; + }) +} + +fn main() { + let args: Vec<_> = env::args().collect(); + if args.len() > 2 { + panic!("{} [family name]", args[0]); + } + + let nl = mnl::Socket::open(netlink::Family::GENERIC) + .unwrap_or_else(|errno| panic!("mnl_socket_open: {}", errno)); + nl.bind(0, mnl::SOCKET_AUTOPID) + .unwrap_or_else(|errno| panic!("mnl_socket_bind: {}", errno)); + let portid = nl.portid(); + + let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; + let seq = time::now().to_timespec().sec as u32; + { + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + *nlh.nlmsg_type = genl::GENL_ID_CTRL; + *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_ACK; + *nlh.nlmsg_seq = seq; + + let genl = nlh.put_sized_header::().unwrap(); + genl.cmd = genl::CtrlCmd::GETFAMILY as u8; + genl.version = 1; + + nlh.put_u16(genl::CtrlAttr::FAMILY_ID as u16, genl::GENL_ID_CTRL).unwrap(); + if args.len() >= 2 { + nlh.put_strz(genl::CtrlAttr::FAMILY_NAME as u16, &args[1]).unwrap(); + } else { + *nlh.nlmsg_flags |= netlink::NLM_F_DUMP; + } + + nl.send_nlmsg(&nlh) + .unwrap_or_else(|errno| panic!("mnl_socket_sendto: {}", errno)); + } + + loop { + let nrecv = nl.recvfrom(&mut buf) + .unwrap_or_else(|errno| panic!("mnl_socket_recvfrom: {}", errno)); + + if mnl::cl_run(&buf[0..nrecv], seq, portid, Some(data_cb())) + .unwrap_or_else(|errno| panic!("mnl_cb_run: {}", errno)) + == mnl::CbRet::STOP { + break; + } + } + let _ = nl.close(); +} diff --git a/examples/netfilter/nf-log-pnet.rs b/examples/netfilter/nf-log-pnet.rs index a679770..f8d7b3e 100644 --- a/examples/netfilter/nf-log-pnet.rs +++ b/examples/netfilter/nf-log-pnet.rs @@ -123,40 +123,40 @@ fn log_cb(nlh: mnl::Nlmsg, _: &mut Option) -> mnl::CbRet { } fn nflog_build_cfg_pf_request<'a>(buf: &'a mut [u8], command: u8) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = libc::AF_INET as u8; nfg.version = nfnl::NFNETLINK_V0; let cmd = nful::MsgConfigCmd{command: command}; - nlh.put(nful::AttrConfig::CMD as u16, &cmd); + nlh.put(nful::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nflog_build_cfg_request<'a>(buf: &'a mut [u8], command: u8, qnum: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = libc::AF_INET as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = qnum.to_be(); let cmd = nful::MsgConfigCmd{command: command}; - nlh.put(nful::AttrConfig::CMD as u16, &cmd); + nlh.put(nful::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nflog_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, qnum: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = qnum.to_be(); @@ -166,7 +166,7 @@ fn nflog_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, qnum: u16 copy_mode: mode, _pad: 0, }; - nlh.put(nful::AttrConfig::MODE as u16, ¶ms); + nlh.put(nful::AttrConfig::MODE as u16, ¶ms).unwrap(); nlh } diff --git a/examples/netfilter/nf-log.rs b/examples/netfilter/nf-log.rs index ac27113..6577f88 100644 --- a/examples/netfilter/nf-log.rs +++ b/examples/netfilter/nf-log.rs @@ -87,40 +87,40 @@ fn log_cb(nlh: mnl::Nlmsg, _: &mut Option) -> mnl::CbRet { } fn nflog_build_cfg_pf_request<'a>(buf: &'a mut [u8], command: u8) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = libc::AF_INET as u8; nfg.version = nfnl::NFNETLINK_V0; let cmd = nful::MsgConfigCmd{command: command}; - nlh.put(nful::AttrConfig::CMD as u16, &cmd); + nlh.put(nful::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nflog_build_cfg_request<'a>(buf: &'a mut [u8], command: u8, qnum: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = libc::AF_INET as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = qnum.to_be(); let cmd = nful::MsgConfigCmd{command: command}; - nlh.put(nful::AttrConfig::CMD as u16, &cmd); + nlh.put(nful::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nflog_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, qnum: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = qnum.to_be(); @@ -130,7 +130,7 @@ fn nflog_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, qnum: u16 copy_mode: mode, _pad: 0, }; - nlh.put(nful::AttrConfig::MODE as u16, ¶ms); + nlh.put(nful::AttrConfig::MODE as u16, ¶ms).unwrap(); nlh } diff --git a/examples/netfilter/nf-log2.rs b/examples/netfilter/nf-log2.rs index ee80afa..4672263 100644 --- a/examples/netfilter/nf-log2.rs +++ b/examples/netfilter/nf-log2.rs @@ -88,40 +88,40 @@ fn log_cb(nlh: mnl::Nlmsg, _: &mut Option) -> mnl::CbRet { } fn nflog_build_cfg_pf_request<'a>(buf: &'a mut [u8], command: u8) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = libc::AF_INET as u8; nfg.version = nfnl::NFNETLINK_V0; let cmd = nful::MsgConfigCmd{command: command}; - nlh.put(nful::AttrConfig::CMD as u16, &cmd); + nlh.put(nful::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nflog_build_cfg_request<'a>(buf: &'a mut [u8], command: u8, qnum: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = libc::AF_INET as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = qnum.to_be(); let cmd = nful::MsgConfigCmd{command: command}; - nlh.put(nful::AttrConfig::CMD as u16, &cmd); + nlh.put(nful::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nflog_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, qnum: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_ULOG << 8) | nful::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = qnum.to_be(); @@ -131,7 +131,7 @@ fn nflog_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, qnum: u16 copy_mode: mode, _pad: 0, }; - nlh.put(nful::AttrConfig::MODE as u16, ¶ms); + nlh.put(nful::AttrConfig::MODE as u16, ¶ms).unwrap(); nlh } diff --git a/examples/netfilter/nf-queue-pnet.rs b/examples/netfilter/nf-queue-pnet.rs index 9e273fe..299c9ee 100644 --- a/examples/netfilter/nf-queue-pnet.rs +++ b/examples/netfilter/nf-queue-pnet.rs @@ -104,11 +104,11 @@ fn queue_cb(nlh: mnl::Nlmsg, packet_id: &mut u32) -> mnl::CbRet { } fn nfq_build_cfg_pf_request<'a>(buf: &'a mut[u8], command: u8) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; @@ -117,17 +117,17 @@ fn nfq_build_cfg_pf_request<'a>(buf: &'a mut[u8], command: u8) -> mnl::Nlmsg { pf: libc::AF_INET.to_be() as u16, ..Default::default() }; - nlh.put(nfq::AttrConfig::CMD as u16, &cmd); + nlh.put(nfq::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nfq_build_cfg_request<'a>(buf: &'a mut[u8], command: u8, queue_num: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = queue_num.to_be(); @@ -137,32 +137,32 @@ fn nfq_build_cfg_request<'a>(buf: &'a mut[u8], command: u8, queue_num: u16) -> m pf: libc::AF_INET.to_be() as u16, ..Default::default() }; - nlh.put(nfq::AttrConfig::CMD as u16, &cmd); + nlh.put(nfq::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nfq_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, queue_num: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = queue_num.to_be(); let params = nfq::MsgConfigParams { copy_range: range.to_be(), copy_mode: mode }; - nlh.put(nfq::AttrConfig::PARAMS as u16, ¶ms); + nlh.put(nfq::AttrConfig::PARAMS as u16, ¶ms).unwrap(); nlh } fn nfq_build_verdict<'a>(buf: &'a mut [u8], id: u32, queue_num: u16, verd: u32) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::VERDICT as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = queue_num.to_be(); diff --git a/examples/netfilter/nf-queue.rs b/examples/netfilter/nf-queue.rs index 69b74be..4e15afa 100644 --- a/examples/netfilter/nf-queue.rs +++ b/examples/netfilter/nf-queue.rs @@ -76,11 +76,11 @@ fn queue_cb(nlh: mnl::Nlmsg, packet_id: &mut u32) -> mnl::CbRet { } fn nfq_build_cfg_pf_request<'a>(buf: &'a mut[u8], command: u8) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; @@ -89,17 +89,17 @@ fn nfq_build_cfg_pf_request<'a>(buf: &'a mut[u8], command: u8) -> mnl::Nlmsg { pf: libc::AF_INET.to_be() as u16, ..Default::default() }; - nlh.put(nfq::AttrConfig::CMD as u16, &cmd); + nlh.put(nfq::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nfq_build_cfg_request<'a>(buf: &'a mut[u8], command: u8, queue_num: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = queue_num.to_be(); @@ -109,32 +109,32 @@ fn nfq_build_cfg_request<'a>(buf: &'a mut[u8], command: u8, queue_num: u16) -> m pf: libc::AF_INET.to_be() as u16, ..Default::default() }; - nlh.put(nfq::AttrConfig::CMD as u16, &cmd); + nlh.put(nfq::AttrConfig::CMD as u16, &cmd).unwrap(); nlh } fn nfq_build_cfg_params<'a>(buf: &'a mut [u8], mode: u8, range: u32, queue_num: u16) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::CONFIG as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = queue_num.to_be(); let params = nfq::MsgConfigParams { copy_range: range.to_be(), copy_mode: mode }; - nlh.put(nfq::AttrConfig::PARAMS as u16, ¶ms); + nlh.put(nfq::AttrConfig::PARAMS as u16, ¶ms).unwrap(); nlh } fn nfq_build_verdict<'a>(buf: &'a mut [u8], id: u32, queue_num: u16, verd: u32) -> mnl::Nlmsg { - let mut nlh = mnl::Nlmsg::new(buf); + let mut nlh = mnl::Nlmsg::new(buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_QUEUE << 8) | nfq::MsgTypes::VERDICT as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST; - let nfg = nlh.put_sized_header::(); + let nfg = nlh.put_sized_header::().unwrap(); nfg.nfgen_family = 0; // libc::AF_UNSPEC as u8; nfg.version = nfnl::NFNETLINK_V0; nfg.res_id = queue_num.to_be(); diff --git a/examples/netfilter/nfct-create-batch-check.rs b/examples/netfilter/nfct-create-batch-check.rs new file mode 100644 index 0000000..48adfad --- /dev/null +++ b/examples/netfilter/nfct-create-batch-check.rs @@ -0,0 +1,140 @@ +use std::io; +use std::net; +use std::os::unix::io::AsRawFd; +use std::mem::zeroed; + +extern crate libc; +extern crate time; +extern crate crslmnl as mnl; + +use mnl::linux::netlink as netlink; +use mnl::linux::netfilter::nfnetlink as nfnl; +use mnl::linux::netfilter::nfnetlink_conntrack as nfct; +use mnl::linux::netfilter::nf_conntrack_common as nfct_common; +use mnl::linux::netfilter::nf_conntrack_tcp as nfct_tcp; + +mod epoll; + +fn put_msg(nlh: &mut mnl::Nlmsg, i: u16, seq: u32) -> io::Result<()>{ + nlh.put_header().unwrap(); + *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_CTNETLINK << 8) | nfct::IPCTNL_MSG_CT_NEW; + *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_CREATE + | netlink::NLM_F_EXCL | netlink::NLM_F_ACK; + *nlh.nlmsg_seq = seq; + + let nfh = try!(nlh.put_sized_header::()); + nfh.nfgen_family = libc::AF_INET as u8; + nfh.version = nfnl::NFNETLINK_V0; + nfh.res_id = 0; + + let mut nest1 = try!(nlh.nest_start(nfct::CTA_TUPLE_ORIG)); + let mut nest2 = try!(nlh.nest_start(nfct::CTA_TUPLE_IP)); + try!(nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(1, 1, 1, 1)))); + try!(nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(2, 2, 2, 2)))); + nlh.nest_end(nest2); + + nest2 = try!(nlh.nest_start(nfct::CTA_TUPLE_PROTO)); + try!(nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8)); + try!(nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(i))); + try!(nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(1025))); + nlh.nest_end(nest2); + nlh.nest_end(nest1); + + nest1 = try!(nlh.nest_start(nfct::CTA_TUPLE_REPLY)); + nest2 = try!(nlh.nest_start(nfct::CTA_TUPLE_IP)); + try!(nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(2, 2, 2, 2)))); + try!(nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(1, 1, 1, 1)))); + nlh.nest_end(nest2); + + nest2 = try!(nlh.nest_start(nfct::CTA_TUPLE_PROTO)); + try!(nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8)); + try!(nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(1025))); + try!(nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(i))); + nlh.nest_end(nest2); + nlh.nest_end(nest1); + + nest1 = try!(nlh.nest_start(nfct::CTA_PROTOINFO)); + nest2 = try!(nlh.nest_start(nfct::CTA_PROTOINFO_TCP)); + try!(nlh.put_u8(nfct::CTA_PROTOINFO_TCP_STATE, nfct_tcp::TCP_CONNTRACK_SYN_SENT)); + nlh.nest_end(nest2); + nlh.nest_end(nest1); + + try!(nlh.put_u32(nfct::CTA_STATUS, u32::to_be(nfct_common::IPS_CONFIRMED))); + try!(nlh.put_u32(nfct::CTA_TIMEOUT, u32::to_be(1000))); + + Ok(()) +} + +fn error_cb(nlh: mnl::Nlmsg, _: &mut u8) -> mnl::CbRet { + let err = nlh.payload::(); + if err.error != 0 { + println!("message with seq {} has failed: {}", + nlh.nlmsg_seq, io::Error::from_raw_os_error(-err.error)); + } + mnl::CbRet::OK +} + +fn send_batch(nl: &mut mnl::Socket, b: &mut mnl::NlmsgBatch, portid: u32) { + nl.send_batch(b) + .unwrap_or_else(|errno| panic!("mnl_socket_sendto: {}", errno)); + + let rawfd = nl.as_raw_fd(); + let epoll = epoll::Epoll::create1(0) + .unwrap_or_else(|errno| panic!("epoll_create1: {}", errno)); + let event = epoll::Event::with_fd(libc::EPOLLIN as u32, rawfd); + epoll.ctl(libc::EPOLL_CTL_ADD, rawfd, event) + .unwrap_or_else(|errno| panic!("epoll_ctl: {}", errno)); + + let mut events: [epoll::Event; 1] = unsafe { zeroed() }; + let mut rcv_buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; + let ctl_cbs = [None, + None, // NLMSG_NOOP + Some(error_cb as mnl::Cb),]; // NLMSG_ERROR + loop { + let nevents = epoll.wait(&mut events[..], 0) + .unwrap_or_else(|errno| panic!("epoll_wait: {}", errno)); + if nevents == 0 { return; } + + let nrecv = nl.recvfrom(&mut rcv_buf) + .unwrap_or_else(|errno| panic!("mnl_socket_recvfrom: {}", errno)); + let rc = mnl::cb_run2(&rcv_buf[0..nrecv], 0, portid, + None, &mut 0, &ctl_cbs[..]) + .unwrap_or_else(|errno| panic!("mnl_cb_run2: {}", errno)); + if rc == mnl::CbRet::STOP { + return; + } + } +} + +fn main() { + let nl = mnl::Socket::open(netlink::Family::NETFILTER) + .unwrap_or_else(|errno| panic!("mnl_socket_open: {}", errno)); + nl.bind(0, mnl::SOCKET_AUTOPID) + .unwrap_or_else(|errno| panic!("mnl_socket_bind: {}", errno)); + let portid = nl.portid(); + + let mut snd_buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; + let mut b = mnl::NlmsgBatch::new(&mut snd_buf) + .unwrap_or_else(|errno| panic!("mnl_nlmsg_batch_start: {}", errno)); + + let seq = time::now().to_timespec().sec as u32; + let mut sport = 1024u32; + 'sports: loop { + for mut nlh in &mut b { + if let Err(_) = put_msg(&mut nlh, sport as u16, seq + sport - 1024) { + break; + } + sport += 1; + if sport >= 65535 { break 'sports; } + } + send_batch(nl, b, portid); + b.reset(); + } + + if !b.is_empty() { + b.cap(); + send_batch(nl, b, portid); + } + + let _ = nl.close(); +} diff --git a/examples/netfilter/nfct-create-batch.rs b/examples/netfilter/nfct-create-batch.rs index aa97c07..f67ddce 100644 --- a/examples/netfilter/nfct-create-batch.rs +++ b/examples/netfilter/nfct-create-batch.rs @@ -19,63 +19,58 @@ use mnl::linux::netfilter::nf_conntrack_tcp as nfct_tcp; mod timerfd; fn put_msg(nlh: &mut mnl::Nlmsg, i: u16, seq: u32) { - nlh.put_header(); + nlh.put_header().unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_CTNETLINK << 8) | nfct::IPCTNL_MSG_CT_NEW; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_CREATE | netlink::NLM_F_EXCL | netlink::NLM_F_ACK; *nlh.nlmsg_seq = seq; - let nfh = nlh.put_sized_header::(); + let nfh = nlh.put_sized_header::().unwrap(); nfh.nfgen_family = libc::AF_INET as u8; nfh.version = nfnl::NFNETLINK_V0; nfh.res_id = 0; - let mut nest1 = nlh.nest_start(nfct::CTA_TUPLE_ORIG); - let mut nest2 = nlh.nest_start(nfct::CTA_TUPLE_IP); - nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))); - nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))); + let mut nest1 = nlh.nest_start(nfct::CTA_TUPLE_ORIG).unwrap(); + let mut nest2 = nlh.nest_start(nfct::CTA_TUPLE_IP).unwrap(); + nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))).unwrap(); + nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))).unwrap(); nlh.nest_end(nest2); - nest2 = nlh.nest_start(nfct::CTA_TUPLE_PROTO); - nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8); - nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(i)); - nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(1025)); + nest2 = nlh.nest_start(nfct::CTA_TUPLE_PROTO).unwrap(); + nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8).unwrap(); + nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(i)).unwrap(); + nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(1025)).unwrap(); nlh.nest_end(nest2); nlh.nest_end(nest1); - nest1 = nlh.nest_start(nfct::CTA_TUPLE_REPLY); - nest2 = nlh.nest_start(nfct::CTA_TUPLE_IP); - nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))); - nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))); + nest1 = nlh.nest_start(nfct::CTA_TUPLE_REPLY).unwrap(); + nest2 = nlh.nest_start(nfct::CTA_TUPLE_IP).unwrap(); + nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))).unwrap(); + nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))).unwrap(); nlh.nest_end(nest2); - nest2 = nlh.nest_start(nfct::CTA_TUPLE_PROTO); - nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8); - nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(1025)); - nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(i)); + nest2 = nlh.nest_start(nfct::CTA_TUPLE_PROTO).unwrap(); + nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8).unwrap(); + nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(1025)).unwrap(); + nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(i)).unwrap(); nlh.nest_end(nest2); nlh.nest_end(nest1); - nest1 = nlh.nest_start(nfct::CTA_PROTOINFO); - nest2 = nlh.nest_start(nfct::CTA_PROTOINFO_TCP); - nlh.put_u8(nfct::CTA_PROTOINFO_TCP_STATE, nfct_tcp::TCP_CONNTRACK_SYN_SENT); + nest1 = nlh.nest_start(nfct::CTA_PROTOINFO).unwrap(); + nest2 = nlh.nest_start(nfct::CTA_PROTOINFO_TCP).unwrap(); + nlh.put_u8(nfct::CTA_PROTOINFO_TCP_STATE, nfct_tcp::TCP_CONNTRACK_SYN_SENT).unwrap(); nlh.nest_end(nest2); nlh.nest_end(nest1); - nlh.put_u32(nfct::CTA_STATUS, u32::to_be(nfct_common::IPS_CONFIRMED)); - nlh.put_u32(nfct::CTA_TIMEOUT, u32::to_be(1000)); + nlh.put_u32(nfct::CTA_STATUS, u32::to_be(nfct_common::IPS_CONFIRMED)).unwrap(); + nlh.put_u32(nfct::CTA_TIMEOUT, u32::to_be(1000)).unwrap(); } -fn ctl_cb(nlh: mnl::Nlmsg, _: &mut u8) -> mnl::CbRet { - match *nlh.nlmsg_type { - netlink::NLMSG_ERROR => { - let err = nlh.payload::(); - if err.error != 0 { - println!("message with seq {} has failed: {}", - nlh.nlmsg_seq, io::Error::from_raw_os_error(-err.error)); - } - }, - _ => {}, +fn error_cb(nlh: mnl::Nlmsg, _: &mut u8) -> mnl::CbRet { + let err = nlh.payload::(); + if err.error != 0 { + println!("message with seq {} has failed: {}", + nlh.nlmsg_seq, io::Error::from_raw_os_error(-err.error)); } mnl::CbRet::OK } @@ -96,7 +91,9 @@ fn send_batch(nl: &mut mnl::Socket, b: &mut mnl::NlmsgBatch, portid: u32) { let mut events = mio::Events::with_capacity(256); let mut rcv_buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; - + let ctl_cbs = [None, + None, // NLMSG_NOOP + Some(error_cb as mnl::Cb),]; // NLMSG_ERROR loop { timer.settime( 0, @@ -119,8 +116,7 @@ fn send_batch(nl: &mut mnl::Socket, b: &mut mnl::NlmsgBatch, portid: u32) { let nrecv = nl.recvfrom(&mut rcv_buf) .unwrap_or_else(|errno| panic!("mnl_socket_recvfrom: {}", errno)); let rc = mnl::cb_run2(&rcv_buf[0..nrecv], 0, portid, - None, &mut 0, - ctl_cb, &[netlink::NLMSG_ERROR]) + None, &mut 0, &ctl_cbs[..]) .unwrap_or_else(|errno| panic!("mnl_cb_run2: {}", errno)); if rc == mnl::CbRet::STOP { return; @@ -145,10 +141,10 @@ fn main() { let seq = time::now().to_timespec().sec as u32; for i in 1024u16..65535 { - put_msg(&mut b.current_nlmsg(), i, seq + i as u32 - 1024); + put_msg(&mut b.current_nlmsg().unwrap(), i, seq + i as u32 - 1024); // is there room for more messages in this batch? // if so, continue. - if b.next() { + if b.proceed_next() { continue; } send_batch(nl, b, portid); diff --git a/examples/netfilter/nfct-create-batch2.rs b/examples/netfilter/nfct-create-batch2.rs index b8a1c78..c33c2f3 100644 --- a/examples/netfilter/nfct-create-batch2.rs +++ b/examples/netfilter/nfct-create-batch2.rs @@ -16,63 +16,58 @@ use mnl::linux::netfilter::nf_conntrack_tcp as nfct_tcp; mod epoll; fn put_msg(nlh: &mut mnl::Nlmsg, i: u16, seq: u32) { - nlh.put_header(); + nlh.put_header_raw(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_CTNETLINK << 8) | nfct::IPCTNL_MSG_CT_NEW; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_CREATE | netlink::NLM_F_EXCL | netlink::NLM_F_ACK; *nlh.nlmsg_seq = seq; - let nfh = nlh.put_sized_header::(); + let nfh = nlh.put_sized_header_raw::(); nfh.nfgen_family = libc::AF_INET as u8; nfh.version = nfnl::NFNETLINK_V0; nfh.res_id = 0; - let mut nest1 = nlh.nest_start(nfct::CTA_TUPLE_ORIG); - let mut nest2 = nlh.nest_start(nfct::CTA_TUPLE_IP); - nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))); - nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))); + let mut nest1 = nlh.nest_start_raw(nfct::CTA_TUPLE_ORIG); + let mut nest2 = nlh.nest_start_raw(nfct::CTA_TUPLE_IP); + nlh.put_u32_raw(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))); + nlh.put_u32_raw(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))); nlh.nest_end(nest2); - nest2 = nlh.nest_start(nfct::CTA_TUPLE_PROTO); - nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8); - nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(i)); - nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(1025)); + nest2 = nlh.nest_start_raw(nfct::CTA_TUPLE_PROTO); + nlh.put_u8_raw(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8); + nlh.put_u16_raw(nfct::CTA_PROTO_SRC_PORT, u16::to_be(i)); + nlh.put_u16_raw(nfct::CTA_PROTO_DST_PORT, u16::to_be(1025)); nlh.nest_end(nest2); nlh.nest_end(nest1); - nest1 = nlh.nest_start(nfct::CTA_TUPLE_REPLY); - nest2 = nlh.nest_start(nfct::CTA_TUPLE_IP); - nlh.put_u32(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))); - nlh.put_u32(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))); + nest1 = nlh.nest_start_raw(nfct::CTA_TUPLE_REPLY); + nest2 = nlh.nest_start_raw(nfct::CTA_TUPLE_IP); + nlh.put_u32_raw(nfct::CTA_IP_V4_SRC, u32::from(net::Ipv4Addr::new(2, 2, 2, 2))); + nlh.put_u32_raw(nfct::CTA_IP_V4_DST, u32::from(net::Ipv4Addr::new(1, 1, 1, 1))); nlh.nest_end(nest2); - nest2 = nlh.nest_start(nfct::CTA_TUPLE_PROTO); - nlh.put_u8(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8); - nlh.put_u16(nfct::CTA_PROTO_SRC_PORT, u16::to_be(1025)); - nlh.put_u16(nfct::CTA_PROTO_DST_PORT, u16::to_be(i)); + nest2 = nlh.nest_start_raw(nfct::CTA_TUPLE_PROTO); + nlh.put_u8_raw(nfct::CTA_PROTO_NUM, libc::IPPROTO_TCP as u8); + nlh.put_u16_raw(nfct::CTA_PROTO_SRC_PORT, u16::to_be(1025)); + nlh.put_u16_raw(nfct::CTA_PROTO_DST_PORT, u16::to_be(i)); nlh.nest_end(nest2); nlh.nest_end(nest1); - nest1 = nlh.nest_start(nfct::CTA_PROTOINFO); - nest2 = nlh.nest_start(nfct::CTA_PROTOINFO_TCP); - nlh.put_u8(nfct::CTA_PROTOINFO_TCP_STATE, nfct_tcp::TCP_CONNTRACK_SYN_SENT); + nest1 = nlh.nest_start_raw(nfct::CTA_PROTOINFO); + nest2 = nlh.nest_start_raw(nfct::CTA_PROTOINFO_TCP); + nlh.put_u8_raw(nfct::CTA_PROTOINFO_TCP_STATE, nfct_tcp::TCP_CONNTRACK_SYN_SENT); nlh.nest_end(nest2); nlh.nest_end(nest1); - nlh.put_u32(nfct::CTA_STATUS, u32::to_be(nfct_common::IPS_CONFIRMED)); - nlh.put_u32(nfct::CTA_TIMEOUT, u32::to_be(1000)); + nlh.put_u32_raw(nfct::CTA_STATUS, u32::to_be(nfct_common::IPS_CONFIRMED)); + nlh.put_u32_raw(nfct::CTA_TIMEOUT, u32::to_be(1000)); } -fn ctl_cb(nlh: mnl::Nlmsg, _: &mut u8) -> mnl::CbRet { - match *nlh.nlmsg_type { - netlink::NLMSG_ERROR => { - let err = nlh.payload::(); - if err.error != 0 { - println!("message with seq {} has failed: {}", - nlh.nlmsg_seq, io::Error::from_raw_os_error(-err.error)); - } - }, - _ => {}, +fn error_cb(nlh: mnl::Nlmsg, _: &mut u8) -> mnl::CbRet { + let err = nlh.payload::(); + if err.error != 0 { + println!("message with seq {} has failed: {}", + nlh.nlmsg_seq, io::Error::from_raw_os_error(-err.error)); } mnl::CbRet::OK } @@ -90,27 +85,18 @@ fn send_batch(nl: &mut mnl::Socket, b: &mut mnl::NlmsgBatch, portid: u32) { let mut events: [epoll::Event; 1] = unsafe { zeroed() }; let mut rcv_buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; + let ctl_cbs = [None, + None, // NLMSG_NOOP + Some(error_cb as mnl::Cb),]; // NLMSG_ERROR loop { - let nevents = epoll.wait(&mut events[..], 1) + let nevents = epoll.wait(&mut events[..], 0) .unwrap_or_else(|errno| panic!("epoll_wait: {}", errno)); - if nevents == 0 { - break; - } - let mut found = false; - for e in &events { - if e.fd() == rawfd { - found = true; - break; - } - } - if !found { - continue; - } + if nevents == 0 { return; } + let nrecv = nl.recvfrom(&mut rcv_buf) .unwrap_or_else(|errno| panic!("mnl_socket_recvfrom: {}", errno)); let rc = mnl::cb_run2(&rcv_buf[0..nrecv], 0, portid, - None, &mut 0, - ctl_cb, &[netlink::NLMSG_ERROR]) + None, &mut 0, &ctl_cbs[..]) .unwrap_or_else(|errno| panic!("mnl_cb_run2: {}", errno)); if rc == mnl::CbRet::STOP { return; @@ -135,10 +121,10 @@ fn main() { let seq = time::now().to_timespec().sec as u32; for i in 1024u16..65535 { - put_msg(&mut b.current_nlmsg(), i, seq + i as u32 - 1024); + put_msg(&mut b.current_nlmsg().unwrap(), i, seq + i as u32 - 1024); // is there room for more messages in this batch? // if so, continue. - if b.next() { + if b.proceed_next() { continue; } send_batch(nl, b, portid); diff --git a/examples/netfilter/nfct-daemon.rs b/examples/netfilter/nfct-daemon.rs index f1efe1d..3b0f84b 100644 --- a/examples/netfilter/nfct-daemon.rs +++ b/examples/netfilter/nfct-daemon.rs @@ -246,19 +246,19 @@ fn main() { let _ = nl.setsockopt::(netlink::NETLINK_NO_ENOBUFS, 1); let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); // Counters are atomically zeroed in each dump *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_CTNETLINK << 8) | nfct::IPCTNL_MSG_CT_GET_CTRZERO; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; - let nfh = nlh.put_sized_header::(); + let nfh = nlh.put_sized_header::().unwrap(); nfh.nfgen_family = libc::AF_INET as u8; nfh.version = nfnl::NFNETLINK_V0; nfh.res_id = 0; // Filter by mark: We only want to dump entries whose mark is zero - nlh.put_u32(nfct::CTA_MARK, 0u32.to_be()); - nlh.put_u32(nfct::CTA_MARK_MASK, 0xffffffffu32.to_be()); + nlh.put_u32(nfct::CTA_MARK, 0u32.to_be()).unwrap(); + nlh.put_u32(nfct::CTA_MARK_MASK, 0xffffffffu32.to_be()).unwrap(); let mut hmap = HashMap::>::new(); diff --git a/examples/netfilter/nfct-dump.rs b/examples/netfilter/nfct-dump.rs index 0632c18..29f6034 100644 --- a/examples/netfilter/nfct-dump.rs +++ b/examples/netfilter/nfct-dump.rs @@ -252,12 +252,12 @@ fn main() { let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = (nfnl::NFNL_SUBSYS_CTNETLINK << 8) | nfct::CtnlMsgTypes::GET as u16; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; *nlh.nlmsg_seq = seq; - let nfh = nlh.put_sized_header::(); + let nfh = nlh.put_sized_header::().unwrap(); nfh.nfgen_family = libc::AF_INET as u8; nfh.version = nfnl::NFNETLINK_V0; nfh.res_id = 0; diff --git a/examples/nfct-create-batch-check.rs b/examples/nfct-create-batch-check.rs new file mode 120000 index 0000000..b0bc825 --- /dev/null +++ b/examples/nfct-create-batch-check.rs @@ -0,0 +1 @@ +netfilter/nfct-create-batch-check.rs \ No newline at end of file diff --git a/examples/rtnl-route-dump2.rs b/examples/rtnl-route-dump2.rs new file mode 120000 index 0000000..6b42b50 --- /dev/null +++ b/examples/rtnl-route-dump2.rs @@ -0,0 +1 @@ +rtnl/rtnl-route-dump2.rs \ No newline at end of file diff --git a/examples/rtnl/rtnl-addr-dump.rs b/examples/rtnl/rtnl-addr-dump.rs index a448e41..ecdd682 100644 --- a/examples/rtnl/rtnl-addr-dump.rs +++ b/examples/rtnl/rtnl-addr-dump.rs @@ -88,11 +88,11 @@ fn main() { let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_GETADDR; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; *nlh.nlmsg_seq = seq; - let rt = nlh.put_sized_header::(); + let rt = nlh.put_sized_header::().unwrap(); if args[1] == "inet" { rt.rtgen_family = AF_INET as u8; } else if args[1] == "inet6" { diff --git a/examples/rtnl/rtnl-link-dump.rs b/examples/rtnl/rtnl-link-dump.rs index 95714f8..f10adf5 100644 --- a/examples/rtnl/rtnl-link-dump.rs +++ b/examples/rtnl/rtnl-link-dump.rs @@ -97,11 +97,11 @@ fn main() { let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_GETLINK; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; *nlh.nlmsg_seq = seq; - let rt = nlh.put_sized_header::(); + let rt = nlh.put_sized_header::().unwrap(); rt.rtgen_family = AF_PACKET as u8; nl.send_nlmsg(&nlh) diff --git a/examples/rtnl/rtnl-link-dump2.rs b/examples/rtnl/rtnl-link-dump2.rs index 8fea39f..fd1d8f7 100644 --- a/examples/rtnl/rtnl-link-dump2.rs +++ b/examples/rtnl/rtnl-link-dump2.rs @@ -68,11 +68,11 @@ fn main() { let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_GETLINK; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; *nlh.nlmsg_seq = seq; - let rt = nlh.put_sized_header::(); + let rt = nlh.put_sized_header::().unwrap(); rt.rtgen_family = AF_PACKET as u8; nl.send_nlmsg(&nlh) diff --git a/examples/rtnl/rtnl-link-dump3.rs b/examples/rtnl/rtnl-link-dump3.rs index 0b0bea6..6602456 100644 --- a/examples/rtnl/rtnl-link-dump3.rs +++ b/examples/rtnl/rtnl-link-dump3.rs @@ -65,11 +65,11 @@ fn main() { let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_GETLINK; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; *nlh.nlmsg_seq = seq; - let rt = nlh.put_sized_header::(); + let rt = nlh.put_sized_header::().unwrap(); rt.rtgen_family = AF_PACKET as u8; nl.send_nlmsg(&nlh) diff --git a/examples/rtnl/rtnl-link-set.rs b/examples/rtnl/rtnl-link-set.rs index e85c49c..088d14d 100644 --- a/examples/rtnl/rtnl-link-set.rs +++ b/examples/rtnl/rtnl-link-set.rs @@ -47,16 +47,16 @@ fn main() { let seq = time::now().to_timespec().sec as u32; let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_NEWLINK; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_ACK; *nlh.nlmsg_seq = seq; - let ifm = nlh.put_sized_header::(); + let ifm = nlh.put_sized_header::().unwrap(); ifm.ifi_family = 0; // no libc::AF_UNSPEC; ifm.ifi_change = change; ifm.ifi_flags = flags; - nlh.put_str(if_link::IFLA_IFNAME, &args[1]); + nlh.put_str(if_link::IFLA_IFNAME, &args[1]).unwrap(); let my_stdout = StdoutRawFd::Dummy; nlh.fprintf(&my_stdout, size_of::()); diff --git a/examples/rtnl/rtnl-route-add.rs b/examples/rtnl/rtnl-route-add.rs index 73c706e..19165e0 100644 --- a/examples/rtnl/rtnl-route-add.rs +++ b/examples/rtnl/rtnl-route-add.rs @@ -98,12 +98,12 @@ Example: {} eth0 10.0.1.12 32 10.0.1.11 let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_NEWROUTE; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_CREATE | netlink::NLM_F_ACK; *nlh.nlmsg_seq = seq; - let rtm = nlh.put_sized_header::(); + let rtm = nlh.put_sized_header::().unwrap(); rtm.rtm_family = family as u8; rtm.rtm_dst_len = prefix as u8; rtm.rtm_src_len = 0; @@ -122,20 +122,20 @@ Example: {} eth0 10.0.1.12 32 10.0.1.11 match dst { IpAddr::V4(addr) => nlh.put_u32(rtnetlink::RTA_DST, - unsafe { transmute::<[u8; 4], u32>(addr.octets()) }), + unsafe { transmute::<[u8; 4], u32>(addr.octets()) }).unwrap(), IpAddr::V6(addr) => nlh.put(rtnetlink::RTA_DST, - &unsafe { transmute::<[u16; 8], in6_addr>(addr.segments()) }), + &unsafe { transmute::<[u16; 8], in6_addr>(addr.segments()) }).unwrap(), } - nlh.put_u32(rtnetlink::RTA_OIF, iface); + nlh.put_u32(rtnetlink::RTA_OIF, iface).unwrap(); if let Some(nh) = gw { match nh { IpAddr::V4(addr) => nlh.put_u32(rtnetlink::RTA_GATEWAY, - unsafe { transmute::<[u8; 4], u32>(addr.octets()) }), + unsafe { transmute::<[u8; 4], u32>(addr.octets()) }).unwrap(), IpAddr::V6(addr) => nlh.put(rtnetlink::RTA_GATEWAY, - &unsafe { transmute::<[u16; 8], in6_addr>(addr.segments()) }), + &unsafe { transmute::<[u16; 8], in6_addr>(addr.segments()) }).unwrap(), } } nl.send_nlmsg(&nlh) diff --git a/examples/rtnl/rtnl-route-dump.rs b/examples/rtnl/rtnl-route-dump.rs index 08d8bbb..3aa6709 100644 --- a/examples/rtnl/rtnl-route-dump.rs +++ b/examples/rtnl/rtnl-route-dump.rs @@ -268,11 +268,11 @@ fn main() { let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; let seq = time::now().to_timespec().sec as u32; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); *nlh.nlmsg_type = rtnetlink::RTM_GETROUTE; *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; *nlh.nlmsg_seq = seq; - let rtm = nlh.put_sized_header::(); + let rtm = nlh.put_sized_header::().unwrap(); if args[1] == "inet" { rtm.rtm_family = libc::AF_INET as u8; } else if args[1] == "inet6" { diff --git a/examples/rtnl/rtnl-route-dump2.rs b/examples/rtnl/rtnl-route-dump2.rs new file mode 100644 index 0000000..e97a3f5 --- /dev/null +++ b/examples/rtnl/rtnl-route-dump2.rs @@ -0,0 +1,301 @@ +use std::env; +use std::io::Write; +use std::mem::size_of; +use std::ffi::CStr; + +extern crate libc; +extern crate time; +extern crate crslmnl as mnl; +use libc::{ c_int, c_char, c_void, socklen_t }; + +use mnl::linux::netlink as netlink; +use mnl::linux::rtnetlink; + +extern { + // const char *inet_ntop(int af, const void *src, + // char *dst, socklen_t size); + fn inet_ntop(af: c_int, src: *const c_void, dst: *mut c_char, size: socklen_t) -> *const c_char; +} +pub const INET_ADDRSTRLEN: usize = 16; +pub const INET6_ADDRSTRLEN: usize = 46; + +trait AddrFamily { + fn family(&self) -> c_int; +} +impl AddrFamily for libc::in_addr { + fn family(&self) -> c_int { libc::AF_INET } +} +impl AddrFamily for libc::in6_addr { + fn family(&self) -> c_int { libc::AF_INET6 } +} + +fn _inet_ntoa(addr: &T) -> String { + let mut buf = [0u8; INET6_ADDRSTRLEN]; + unsafe { + let rs = inet_ntop(addr.family(), addr as *const _ as *const c_void, + buf.as_mut_ptr() as *mut c_char, INET6_ADDRSTRLEN as socklen_t); + CStr::from_ptr(rs).to_string_lossy().into_owned() + } +} + +macro_rules! println_stderr( + ($($arg:tt)*) => { { + let r = writeln!(&mut ::std::io::stderr(), $($arg)*); + r.expect("failed printing to stderr"); + } } +); + +fn attributes_show_ip(tb: &[Option<&mnl::Attr>]) { + tb[rtnetlink::RTA_TABLE as usize] + .map(|attr| print!("table={} ", attr.u32())); + tb[rtnetlink::RTA_DST as usize] + .map(|attr| print!("dst={} ", _inet_ntoa::(attr.payload()))); + tb[rtnetlink::RTA_SRC as usize] + .map(|attr| print!("src={} ", _inet_ntoa::(attr.payload()))); + tb[rtnetlink::RTA_OIF as usize] + .map(|attr| print!("oif={} ", attr.u32())); + tb[rtnetlink::RTA_FLOW as usize] + .map(|attr| print!("flow={} ", attr.u32())); + tb[rtnetlink::RTA_PREFSRC as usize] + .map(|attr| print!("prefsrc={} ", _inet_ntoa::(attr.payload()))); + tb[rtnetlink::RTA_GATEWAY as usize] + .map(|attr| print!("gw={} ", _inet_ntoa::(attr.payload()))); + tb[rtnetlink::RTA_PRIORITY as usize] + .map(|attr| print!("prio={} ", attr.u32())); + tb[rtnetlink::RTA_METRICS as usize] + .map(|attr| { + let mut tbx: [Option<&mnl::Attr>; rtnetlink::RTAX_MAX as usize + 1] + = [None; rtnetlink::RTAX_MAX as usize + 1]; + let _ = attr.cl_parse_nested(Box::new(move |attr| { + if let Err(_) = attr.type_valid(rtnetlink::RTAX_MAX as u16) { + return mnl::CbRet::OK; + } + + if let Err(errno) = attr.validate(mnl::AttrDataType::U32) { + println_stderr!("mnl_attr_validate: {}", errno); + return mnl::CbRet::ERROR; + } + tbx[attr.atype() as usize] = Some(attr); + mnl::CbRet::OK + })); + for i in 0..rtnetlink::RTAX_MAX as usize { + tbx[i].map(|attr| print!("metrics[{}]={} ", i, attr.u32())); + } + }); +} + +fn data_ipv4_attr_cb<'a, 'b>(tb: &'b mut [Option<&'a mnl::Attr>]) -> Box mnl::CbRet + 'b>{ + Box::new(move |attr: &'a mnl::Attr| { + // skip unsupported attribute in user-space + if let Err(_) = attr.type_valid(rtnetlink::RTA_MAX) { + return mnl::CbRet::OK; + } + + let atype = attr.atype(); + match atype { + n if (n == rtnetlink::RTA_TABLE || + n == rtnetlink::RTA_DST || + n == rtnetlink::RTA_SRC || + n == rtnetlink::RTA_DST || + n == rtnetlink::RTA_SRC || + n == rtnetlink::RTA_OIF || + n == rtnetlink::RTA_FLOW || + n == rtnetlink::RTA_PREFSRC || + n == rtnetlink::RTA_GATEWAY || + n == rtnetlink::RTA_PRIORITY) => { + if let Err(errno) = attr.validate(mnl::AttrDataType::U32) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if n == rtnetlink::RTA_METRICS => { + if let Err(errno) = attr.validate(mnl::AttrDataType::NESTED) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + _ => {}, + } + tb[atype as usize] = Some(attr); + mnl::CbRet::OK + }) +} + +fn data_ipv6_attr_cb<'a, 'b>(tb: &'b mut [Option<&'a mnl::Attr>]) -> Box mnl::CbRet + 'b>{ + Box::new(move |attr: &'a mnl::Attr| { + // skip unsupported attribute in user-space + if let Err(_) = attr.type_valid(rtnetlink::RTA_MAX) { + return mnl::CbRet::OK; + } + + let atype = attr.atype(); + match atype { + n if (n == rtnetlink::RTA_TABLE || + n == rtnetlink::RTA_OIF || + n == rtnetlink::RTA_FLOW || + n == rtnetlink::RTA_PRIORITY) => { + if let Err(errno) = attr.validate(mnl::AttrDataType::U32) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if (n == rtnetlink::RTA_DST || + n == rtnetlink::RTA_SRC || + n == rtnetlink::RTA_PREFSRC || + n == rtnetlink::RTA_GATEWAY) => { + if let Err(errno) = attr.validate2(mnl::AttrDataType::BINARY, size_of::()) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + n if n == rtnetlink::RTA_METRICS => { + if let Err(errno) = attr.validate(mnl::AttrDataType::NESTED) { + println_stderr!("mnl_attr_validate - {}: {}", atype, errno); + return mnl::CbRet::ERROR; + } + }, + _ => {}, + } + tb[atype as usize] = Some(attr); + mnl::CbRet::OK + }) +} + +// fn data_cb<'a>(nlh: mnl::Nlmsg, _: &mut Option) -> mnl::CbRet { +// fn data_cb<'a>() -> Box) -> mnl::CbRet> { +fn data_cb() -> Box mnl::CbRet> { + Box::new(move |nlh: mnl::Nlmsg| { + let rm = nlh.payload::(); + + // protocol family = AF_INET | AF_INET6 // + print!("family={} ", rm.rtm_family); + + // destination CIDR, eg. 24 or 32 for IPv4 + print!("dst_len={} ", rm.rtm_dst_len); + + // source CIDR + print!("src_len={} ", rm.rtm_src_len); + + // type of service (TOS), eg. 0 + print!("tos={} ", rm.rtm_tos); + + // table id: + // RT_TABLE_UNSPEC = 0 + // + // ... user defined values ... + // + // RT_TABLE_COMPAT = 252 + // RT_TABLE_DEFAULT = 253 + // RT_TABLE_MAIN = 254 + // RT_TABLE_LOCAL = 255 + // RT_TABLE_MAX = 0xFFFFFFFF + // + // Synonimous attribute: RTA_TABLE. + print!("table={} ", rm.rtm_table); + + // type: + // RTN_UNSPEC = 0 + // RTN_UNICAST = 1 + // RTN_LOCAL = 2 + // RTN_BROADCAST = 3 + // RTN_ANYCAST = 4 + // RTN_MULTICAST = 5 + // RTN_BLACKHOLE = 6 + // RTN_UNREACHABLE = 7 + // RTN_PROHIBIT = 8 + // RTN_THROW = 9 + // RTN_NAT = 10 + // RTN_XRESOLVE = 11 + // __RTN_MAX = 12 + print!("type={} ", rm.rtm_type); + + // scope: + // RT_SCOPE_UNIVERSE = 0 : everywhere in the universe + // + // ... user defined values ... + // + // RT_SCOPE_SITE = 200 + // RT_SCOPE_LINK = 253 : destination attached to link + // RT_SCOPE_HOST = 254 : local address + // RT_SCOPE_NOWHERE = 255 : not existing destination + print!("scope={} ", rm.rtm_scope); + + // protocol: + // RTPROT_UNSPEC = 0 + // RTPROT_REDIRECT = 1 + // RTPROT_KERNEL = 2 : route installed by kernel + // RTPROT_BOOT = 3 : route installed during boot + // RTPROT_STATIC = 4 : route installed by administrator + // + // Values >= RTPROT_STATIC are not interpreted by kernel, they are + // just user-defined. + print!("proto={} ", rm.rtm_protocol); + + // flags: + // RTM_F_NOTIFY = 0x100: notify user of route change + // RTM_F_CLONED = 0x200: this route is cloned + // RTM_F_EQUALIZE = 0x400: Multipath equalizer: NI + // RTM_F_PREFIX = 0x800: Prefix addresses + print!("flags={:x} ", rm.rtm_flags); + + let mut tb: [Option<&mnl::Attr>; rtnetlink::RTA_MAX as usize + 1] + = [None; rtnetlink::RTA_MAX as usize + 1]; + match rm.rtm_family as c_int { + libc::AF_INET => { + let _ = nlh.cl_parse(size_of::(), data_ipv4_attr_cb(&mut tb)); + attributes_show_ip::(&tb); + }, + libc::AF_INET6 => { + let _ = nlh.cl_parse(size_of::(), data_ipv6_attr_cb(&mut tb)); + attributes_show_ip::(&tb); + }, + _ => unreachable!() + } + + println!(""); + mnl::CbRet::OK + }) +} + +fn main() { + let args: Vec<_> = env::args().collect(); + if args.len() != 2 { + panic!("Usage: {} ", args[0]); + } + + let nl = mnl::Socket::open(netlink::Family::ROUTE) + .unwrap_or_else(|errno| panic!("mnl_socket_open: {}", errno)); + nl.bind(0, mnl::SOCKET_AUTOPID) + .unwrap_or_else(|errno| panic!("mnl_socket_bind: {}", errno)); + let portid = nl.portid(); + + let mut buf = vec![0u8; mnl::SOCKET_BUFFER_SIZE()]; + let seq = time::now().to_timespec().sec as u32; + { + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + *nlh.nlmsg_type = rtnetlink::RTM_GETROUTE; + *nlh.nlmsg_flags = netlink::NLM_F_REQUEST | netlink::NLM_F_DUMP; + *nlh.nlmsg_seq = seq; + let rtm = nlh.put_sized_header::().unwrap(); + if args[1] == "inet" { + rtm.rtm_family = libc::AF_INET as u8; + } else if args[1] == "inet6" { + rtm.rtm_family = libc::AF_INET6 as u8; + } + nl.send_nlmsg(&nlh) + .unwrap_or_else(|errno| panic!("mnl_socket_sendto: {}", errno)); + } + + loop { + let nrecv = nl.recvfrom(&mut buf) + .unwrap_or_else(|errno| panic!("mnl_socket_recvfrom: {}", errno)); + + // if mnl::cb_run(&buf[0..nrecv], seq, portid, Some(data_cb), &mut None) + if mnl::cl_run(&buf[0..nrecv], seq, portid, Some(data_cb())) + .unwrap_or_else(|errno| panic!("mnl_cb_run: {}", errno)) + == mnl::CbRet::STOP { + break; + } + } + let _ = nl.close(); +} diff --git a/examples/timerfd.rs b/examples/timerfd.rs index 0878be2..076dae5 100644 --- a/examples/timerfd.rs +++ b/examples/timerfd.rs @@ -112,21 +112,17 @@ impl AsRawFd for Timerfd { */ extern crate mio; -use mio::{ Ready, Poll, PollOpt, Token }; -use mio::unix::EventedFd; -use mio::event::Evented; - -impl Evented for Timerfd { - fn register(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { - EventedFd(&self.0).register(poll, token, interest, opts) +impl mio::event::Evented for Timerfd { + fn register(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready, opts: mio::PollOpt) -> io::Result<()> { + mio::unix::EventedFd(&self.0).register(poll, token, interest, opts) } - fn reregister(&self, poll: &Poll, token: Token, interest: Ready, opts: PollOpt) -> io::Result<()> { - EventedFd(&self.0).reregister(poll, token, interest, opts) + fn reregister(&self, poll: &mio::Poll, token: mio::Token, interest: mio::Ready, opts: mio::PollOpt) -> io::Result<()> { + mio::unix::EventedFd(&self.0).reregister(poll, token, interest, opts) } - fn deregister(&self, poll: &Poll) -> io::Result<()> { - EventedFd(&self.0).deregister(poll) + fn deregister(&self, poll: &mio::Poll) -> io::Result<()> { + mio::unix::EventedFd(&self.0).deregister(poll) } } diff --git a/src/lib.rs b/src/lib.rs index 9cde1a1..b94e961 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ // no effect? #![link(name = "mnl")] use std::io; -use std::mem::{ size_of, size_of_val, zeroed }; +use std::mem::{ size_of, size_of_val, zeroed, forget }; use std::os::unix::io::{ RawFd, AsRawFd }; use std::ffi::{ CString, CStr }; use std::fmt; @@ -46,6 +46,15 @@ macro_rules! cvt_cbret { } ) } +macro_rules! cvt_put_check { + ($f:expr) => ( { + match unsafe { $f } { + true => Ok(()), + false => Err(io::Error::from_raw_os_error(libc::EINVAL)), + } + } ) +} + pub const ALIGNTO: u32 = 4; #[allow(non_snake_case)] pub fn ALIGN(len: u32) -> u32 { @@ -116,7 +125,7 @@ extern { fn mnl_nlmsg_batch_stop(b: *mut NlmsgBatch); // fn mnl_nlmsg_batch_size(b: *mut NlmsgBatch) -> size_t; fn mnl_nlmsg_batch_size(b: *const NlmsgBatch) -> size_t; - fn mnl_nlmsg_batch_reset(b: *mut NlmsgBatch); + // fn mnl_nlmsg_batch_reset(b: *mut NlmsgBatch); fn mnl_nlmsg_batch_head(b: *mut NlmsgBatch) -> *mut c_void; fn mnl_nlmsg_batch_current(b: *mut NlmsgBatch) -> *mut c_void; // fn mnl_nlmsg_batch_is_empty(b: *mut NlmsgBatch) -> bool; @@ -124,7 +133,14 @@ extern { } extern { // arbitrary function + fn mnl_nlmsg_put_header_check(buf: *mut c_void, buflen: size_t) -> *mut netlink::Nlmsghdr; + fn mnl_nlmsg_put_extra_header_check(nlh: *mut netlink::Nlmsghdr, buflen: size_t, size: size_t) -> *mut c_void; fn mnl_nlmsg_batch_rest(b: *const NlmsgBatch) -> size_t; + fn rsmnl_nlmsg_batch_start(buf: *mut c_void, bufsiz: size_t) -> *mut NlmsgBatch; + fn rsmnl_nlmsg_batch_reset(b: *mut NlmsgBatch); + fn rsmnl_nlmsg_batch_next(b: *mut NlmsgBatch) -> *mut netlink::Nlmsghdr; + fn rsmnl_nlmsg_batch_cap(b: *mut NlmsgBatch); + fn rsmnl_nlmsg_batch_put_back(b: *mut NlmsgBatch); } @@ -219,10 +235,10 @@ pub enum CbRet { type CbT = extern "C" fn(nlh: *const netlink::Nlmsghdr, data: *mut c_void) -> c_int; pub type Cb<'a, T: ?Sized> = fn(nlh: Nlmsg, data: &'a mut T) -> CbRet; -struct CbData <'a, 'b, T: 'a + 'b + ?Sized> { - cb: Option>, - ctl_cb: Option>, - data: &'b mut T, +struct CbData <'a, 'b: 'a, T: 'b + ?Sized> { + cb: Option>, + ctl_cbs: &'a [Option>], + data: &'a mut T, } @@ -457,7 +473,7 @@ impl <'a> Nlmsg <'a> { self.buf.len() } - fn as_raw_ref(&self) -> &netlink::Nlmsghdr { + pub fn as_raw_ref(&self) -> &netlink::Nlmsghdr { unsafe { (self.buf.as_ptr() as *const netlink::Nlmsghdr).as_ref().unwrap() } } @@ -487,8 +503,10 @@ impl <'a> Nlmsg <'a> { unsafe { mnl_nlmsg_get_payload_len(self.as_raw_ref()) } } - pub fn from_bytes(buf: &mut [u8]) -> Nlmsg { - // XXX: check buf len > sizeof(Nlmsg) + pub fn from_bytes(buf: &'a mut [u8]) -> io::Result { + if buf.len() < NLMSG_HDRLEN() as usize { + return Err(io::Error::from_raw_os_error(libc::EINVAL)); + } let p = buf.as_mut_ptr(); let nlh = Nlmsg { buf: buf, @@ -498,7 +516,7 @@ impl <'a> Nlmsg <'a> { nlmsg_seq: unsafe { (p as *mut u32).offset(2).as_mut().unwrap() }, nlmsg_pid: unsafe { (p as *mut u32).offset(3).as_mut().unwrap() }, }; - nlh + Ok(nlh) } /// create, reserve and prepare room for Netlink header @@ -511,13 +529,13 @@ impl <'a> Nlmsg <'a> { /// header in the memory buffer passed as parameter. This function also /// initializes the nlmsg_len field to the size of the Netlink header. This /// function returns a Netlink header structure. - pub fn new(buf: &mut [u8]) -> Nlmsg { - let mut nlh = Self::from_bytes(buf); - nlh.put_header(); - nlh + pub fn new(buf: &'a mut [u8]) -> io::Result { + let mut nlh = try!(Self::from_bytes(buf)); + try!(nlh.put_header()); + Ok(nlh) } - fn from_raw(nlh: *const netlink::Nlmsghdr) -> Self { + fn from_raw(nlh: *const netlink::Nlmsghdr) -> io::Result { let buf: &'a mut[u8] = unsafe { std::slice::from_raw_parts_mut((nlh as *mut u8), (*nlh).nlmsg_len as usize) @@ -525,7 +543,7 @@ impl <'a> Nlmsg <'a> { Self::from_bytes(buf) } - fn from_raw_parts(p: *mut u8, size: usize) -> Self { + fn from_raw_parts(p: *mut u8, size: usize) -> io::Result { let buf: &'a mut[u8] = unsafe { std::slice::from_raw_parts_mut(p, size) }; @@ -537,10 +555,18 @@ impl <'a> Nlmsg <'a> { /// This function sets to zero the room that is required to put the Netlink /// header in the memory buffer passed as parameter. This function also /// initializes the nlmsg_len field to the size of the Netlink header. - pub fn put_header(&mut self) { + pub fn put_header_raw(&mut self) { unsafe { &mut(*mnl_nlmsg_put_header(self.as_raw_mut() as *mut _ as *mut c_void)); } } + pub fn put_header(&mut self) -> io::Result<()> { + match cvt_null!(mnl_nlmsg_put_header_check(self.as_raw_mut() as *mut _ as *mut c_void, + self.buf.len() as size_t)) { + Ok(_) => Ok(()), + Err(e) => Err(e), + } + } + /// reserve and prepare room for an extra header /// /// # Arguments @@ -551,24 +577,37 @@ impl <'a> Nlmsg <'a> { /// the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before /// you call this function. This function returns a pointer to the extra /// header. - pub fn put_extra_header(&mut self, size: usize) -> &'a mut T { + pub fn put_extra_header_raw(&mut self, size: usize) -> &'a mut T { unsafe { &mut(*(mnl_nlmsg_put_extra_header(self.as_raw_mut(), size as usize) as *mut T)) } } + pub fn put_extra_header(&mut self, size: usize) -> io::Result<&'a mut T> { + cvt_null!(mnl_nlmsg_put_extra_header_check(self.as_raw_mut(), + self.buf.len(), + size as usize) as *mut T) + } - pub fn put_sized_header(&mut self) -> &'a mut T { + pub fn put_sized_header_raw(&mut self) -> &'a mut T { unsafe { &mut(*(mnl_nlmsg_put_extra_header(self.as_raw_mut(), size_of::()) as *mut T)) } } + pub fn put_sized_header(&mut self) -> io::Result<&'a mut T> { + cvt_null!(mnl_nlmsg_put_extra_header_check(self.as_raw_mut(), + self.buf.len() as size_t, + size_of::()) as *mut T) + } - pub fn ok(&self, len: usize) -> bool { - unsafe { mnl_nlmsg_ok(self.as_raw_ref(), len as c_int) } + pub fn ok(&self) -> bool { + unsafe { mnl_nlmsg_ok(self.as_raw_ref(), self.buf.len() as c_int) } } - pub fn next(&mut self, len: isize) -> (Nlmsg, isize) { - let mut rest = len as c_int; - // let nlh = unsafe { &mut(*mnl_nlmsg_next(self.as_raw_mut(), &mut rest)) }; - let _ = unsafe { &mut(*mnl_nlmsg_next(self.as_raw_mut(), &mut rest)) }; - let u = self.buf.len() - rest as usize; - (Self::from_bytes(&mut self.buf[u..]), rest as isize) + pub fn next<'b: 'a>(&'b mut self) -> Option { + let mut rest = self.buf.len() as c_int; + let buflen = self.buf.len(); + if !self.ok() { + return None; + } + let _ = unsafe { mnl_nlmsg_next(self.as_raw_mut(), &mut rest) }; + // buflen has already checked by ok() + Some(Self::from_bytes(&mut self.buf[buflen - (rest as usize)..]).unwrap()) } /// perform sequence tracking @@ -618,6 +657,15 @@ impl <'a> Nlmsg <'a> { unsafe { &mut(*(mnl_nlmsg_get_payload(self.as_raw_mut()) as *mut T)) } } + pub fn payload_bytes(&mut self) -> &'a [u8] { + unsafe { + std::slice::from_raw_parts_mut( + mnl_nlmsg_get_payload(self.as_raw_mut()) as *mut u8, + self.payload_len(), + ) + } + } + /// get a pointer to the payload of the message /// /// # Arguments @@ -693,7 +741,7 @@ impl <'a> Nlmsg <'a> { unsafe { let f = libc::fdopen(fd.as_raw_fd(), mode.as_ptr()); mnl_nlmsg_fprintf(f, self.as_raw_ref() as *const _ as *const c_void, - *self.nlmsg_len as size_t, extra_header_size as size_t) + self.buf.len() as size_t, extra_header_size as size_t) } } @@ -707,7 +755,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put(&mut self, atype: u16, data: &T) { + pub fn put_raw(&mut self, atype: u16, data: &T) { // ???: data must be a #[repr(C)] unsafe { mnl_attr_put(self.as_raw_mut(), atype, size_of_val(data), data as *const T as *const c_void) } } @@ -720,7 +768,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u8(&mut self, atype: u16, data: u8) { + pub fn put_u8_raw(&mut self, atype: u16, data: u8) { unsafe { mnl_attr_put_u8(self.as_raw_mut(), atype, data) } } @@ -732,7 +780,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u16(&mut self, atype: u16, data: u16) { + pub fn put_u16_raw(&mut self, atype: u16, data: u16) { unsafe { mnl_attr_put_u16(self.as_raw_mut(), atype, data) } } @@ -744,7 +792,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u32(&mut self, atype: u16, data: u32) { + pub fn put_u32_raw(&mut self, atype: u16, data: u32) { unsafe { mnl_attr_put_u32(self.as_raw_mut(), atype, data) } } @@ -755,7 +803,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u64(&mut self, atype: u16, data: u64) { + pub fn put_u64_raw(&mut self, atype: u16, data: u64) { unsafe { mnl_attr_put_u64(self.as_raw_mut(), atype, data) } } @@ -767,7 +815,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_str(&mut self, atype: u16, data: &str) { + pub fn put_str_raw(&mut self, atype: u16, data: &str) { let cs = CString::new(data).unwrap(); unsafe { mnl_attr_put_str(self.as_raw_mut(), atype, cs.as_ptr()) @@ -785,7 +833,7 @@ impl <'a> Nlmsg <'a> { /// /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_strz(&mut self, atype: u16, data: &str) { + pub fn put_strz_raw(&mut self, atype: u16, data: &str) { let cs = CString::new(data).unwrap(); unsafe { mnl_attr_put_strz(self.as_raw_mut(), atype, cs.as_ptr()) @@ -804,9 +852,9 @@ impl <'a> Nlmsg <'a> { /// message (nlmsg_len) by adding the size (header + payload) of the new /// attribute. The function returns true if the attribute could be added /// to the message, otherwise false is returned. - pub fn put_check(&mut self, atype: u16, data: &T) -> bool { - unsafe { mnl_attr_put_check(self.as_raw_mut(), self.buf.len() as size_t, atype, - size_of_val(data), data as *const T as *const c_void) } + pub fn put(&mut self, atype: u16, data: &T) -> io::Result<()> { + cvt_put_check!(mnl_attr_put_check(self.as_raw_mut(), self.buf.len() as size_t, atype, + size_of_val(data), data as *const T as *const c_void)) } /// mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message @@ -820,8 +868,8 @@ impl <'a> Nlmsg <'a> { /// message (nlmsg_len) by adding the size (header + payload) of the new /// attribute. The function returns true if the attribute could be added /// to the message, otherwise false is returned. - pub fn put_u8_check(&mut self, atype: u16, data: u8) -> bool { - unsafe { mnl_attr_put_u8_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data) } + pub fn put_u8(&mut self, atype: u16, data: u8) -> io::Result<()> { + cvt_put_check!(mnl_attr_put_u8_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data)) } /// add 16-bit unsigned int attribute to netlink message @@ -837,8 +885,8 @@ impl <'a> Nlmsg <'a> { /// to the message, otherwise false is returned. /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u16_check(&mut self, atype: u16, data: u16) -> bool { - unsafe { mnl_attr_put_u16_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data) } + pub fn put_u16(&mut self, atype: u16, data: u16) -> io::Result<()> { + cvt_put_check!(mnl_attr_put_u16_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data)) } /// add 32-bit unsigned int attribute to netlink message @@ -854,8 +902,8 @@ impl <'a> Nlmsg <'a> { /// to the message, otherwise false is returned. /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u32_check(&mut self, atype: u16, data: u32) -> bool { - unsafe { mnl_attr_put_u32_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data) } + pub fn put_u32(&mut self, atype: u16, data: u32) -> io::Result<()> { + cvt_put_check!(mnl_attr_put_u32_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data)) } /// add 64-bit unsigned int attribute to netlink message @@ -871,8 +919,8 @@ impl <'a> Nlmsg <'a> { /// to the message, otherwise false is returned. /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_u64_check(&mut self, atype: u16, data: u64) -> bool { - unsafe { mnl_attr_put_u64_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data) } + pub fn put_u64(&mut self, atype: u16, data: u64) -> io::Result<()> { + cvt_put_check!(mnl_attr_put_u64_check(self.as_raw_mut(), self.buf.len() as size_t, atype, data)) } /// add string attribute to netlink message @@ -888,11 +936,11 @@ impl <'a> Nlmsg <'a> { /// to the message, otherwise false is returned. /// This function updates the length field of the Netlink message (nlmsg_len) /// by adding the size (header + payload) of the new attribute. - pub fn put_str_check(&mut self, atype: u16, data: &str) -> bool { + pub fn put_str(&mut self, atype: u16, data: &str) -> io::Result<()> { let cs = CString::new(data).unwrap(); - unsafe { + cvt_put_check!( mnl_attr_put_str_check(self.as_raw_mut(), self.buf.len() as size_t, atype, cs.as_ptr()) - } + ) } /// add string attribute to netlink message @@ -909,11 +957,11 @@ impl <'a> Nlmsg <'a> { /// message (nlmsg_len) by adding the size (header + payload) of the new /// attribute. The function returns true if the attribute could be added /// to the message, otherwise false is returned. - pub fn put_strz_check(&mut self, atype: u16, data: &str) -> bool { + pub fn put_strz(&mut self, atype: u16, data: &str) -> io::Result<()> { let cs = CString::new(data).unwrap(); - unsafe { + cvt_put_check!( mnl_attr_put_strz_check(self.as_raw_mut(), self.buf.len() as size_t, atype, cs.as_ptr()) - } + ) } /// start an attribute nest @@ -927,7 +975,7 @@ impl <'a> Nlmsg <'a> { /// #Return value /// This function always returns a valid pointer to the /// beginning of the nest. - pub fn nest_start(&mut self, atype: u16) -> &'a mut Attr { + pub fn nest_start_raw(&mut self, atype: u16) -> &'a mut Attr { unsafe { &mut *mnl_attr_nest_start(self.as_raw_mut(), atype) } } @@ -939,10 +987,10 @@ impl <'a> Nlmsg <'a> { /// This function adds the attribute header that identifies the beginning of /// an attribute nest. If the nested attribute cannot be added then NULL, /// otherwise valid pointer to the beginning of the nest is returned. - pub fn nest_start_check(&mut self, atype: u16) -> Option<&'a mut Attr> { + pub fn nest_start(&mut self, atype: u16) -> io::Result<&'a mut Attr> { let p = unsafe { mnl_attr_nest_start_check(self.as_raw_mut(), self.buf.len() as size_t, atype) }; - if p.is_null() { return None; } - unsafe { Some(&mut *p) } + if p.is_null() { return Err(io::Error::from_raw_os_error(libc::EINVAL)); } + unsafe { Ok(&mut *p) } } /// end an attribute nest @@ -985,32 +1033,69 @@ impl <'a> Nlmsg <'a> { cvt_cbret!(mnl_attr_parse(self.as_raw_ref(), offset as c_uint, attr_parse_cb::, pdata)) } + pub fn cl_parse<'b, 'c>(&self, offset: usize, cb: Box CbRet + 'c>) -> io::Result<(CbRet)> { + cvt_cbret!(mnl_attr_parse(self.as_raw_ref(), offset as c_uint, attr_parse_cb2, + Box::into_raw(Box::new(cb)) as *mut c_void)) + } + pub fn attrs(&'a self, offset: usize) -> Box + 'a> { Box::new(AttrIterator { attr: self.payload_offset::(offset), tail: self.payload_tail::() as *const _ as uintptr_t }) } } -struct AttrIterator<'a> { - attr: &'a Attr, - tail: uintptr_t, +pub struct NlmsgIterator<'a> { + nlh: &'a mut netlink::Nlmsghdr, + remaining: usize, } -impl <'a> AttrIterator <'a> { - fn ok(&self) -> bool { - self.attr.ok( - self.tail - self.attr as *const _ as uintptr_t - ) +impl <'a> Iterator for NlmsgIterator<'a> { + type Item = Nlmsg<'a>; + + fn next(&mut self) -> Option> { + let ret_nlh = self.nlh as *mut _ as *mut u8; + let (ret_remaining, mut remaining) = (self.remaining, self.remaining as c_int); + unsafe { + if ! mnl_nlmsg_ok(self.nlh, self.remaining as c_int) { + return None; + } + + let nlh = &mut *(mnl_nlmsg_next(self.nlh, &mut remaining)); + self.remaining = remaining as usize; + self.nlh = nlh; + } + Some(Nlmsg::from_raw_parts(ret_nlh, ret_remaining).unwrap()) } } -impl <'a> Iterator for AttrIterator <'a> { +impl <'a> IntoIterator for Nlmsg<'a> { + type Item = Nlmsg<'a>; + type IntoIter = NlmsgIterator<'a>; + + fn into_iter(self) -> NlmsgIterator<'a> { + let buflen = self.buf.len(); + NlmsgIterator { + nlh: unsafe { + &mut *(self.buf.as_mut_ptr() as *mut netlink::Nlmsghdr) + }, + remaining: buflen + } + } +} + +struct AttrIterator<'a> { + attr: &'a Attr, + tail: uintptr_t, +} + +impl <'a> Iterator for AttrIterator<'a> { type Item = &'a Attr; fn next(&mut self) -> Option<&'a Attr> { - if !self.ok() { + if !self.attr.ok(self.tail - self.attr as *const _ as uintptr_t) { return None; } + let curr = self.attr; self.attr = curr.next(); Some(curr) @@ -1051,7 +1136,7 @@ impl NlmsgBatch { /// /// You have to put at least one message in the batch before calling this /// function, otherwise your application is likely to crash. - pub fn next(&self) -> bool { + pub fn proceed_next(&self) -> bool { unsafe { mnl_nlmsg_batch_next(self) } } @@ -1071,7 +1156,7 @@ impl NlmsgBatch { /// new one. This function moves the last message which does not fit the /// batch to the head of the buffer, if any. pub fn reset(&mut self) { - unsafe { mnl_nlmsg_batch_reset(self) } + unsafe { rsmnl_nlmsg_batch_reset(self) } } /// get head of this batch @@ -1092,7 +1177,7 @@ impl NlmsgBatch { unsafe { &mut(*(mnl_nlmsg_batch_current(self) as *mut T)) } } - pub fn current_nlmsg(&mut self) -> Nlmsg { + pub fn current_nlmsg(&mut self) -> io::Result { let p = unsafe { mnl_nlmsg_batch_current(self) as *mut u8 }; Nlmsg::from_raw_parts(p, self.rest()) } @@ -1105,9 +1190,36 @@ impl NlmsgBatch { unsafe { mnl_nlmsg_batch_is_empty(self) } } + /// Not in original libmnl + pub fn new<'a>(buf: &'a mut [u8]) -> io::Result<&'a mut NlmsgBatch> { + cvt_null!(rsmnl_nlmsg_batch_start(buf.as_ptr() as *mut c_void, buf.len() as size_t)) + } + pub fn rest(&self) -> usize { unsafe { mnl_nlmsg_batch_rest(self) as usize } } + + pub fn cap(&mut self) { + unsafe { rsmnl_nlmsg_batch_cap(self) }; + } + + pub fn put_back(&mut self) { + unsafe { rsmnl_nlmsg_batch_put_back(self) }; + } +} + +impl <'a> Iterator for &'a mut NlmsgBatch { + type Item = Nlmsg<'a>; + + fn next(&mut self) -> Option> { + // Here is why I rewrite rsmnl_nlmsg_batch_start() and + // rsmnl_nlmsg_batch_reset() using memset() + let nlh = unsafe { rsmnl_nlmsg_batch_next(*self) }; + if nlh.is_null() { + return None; + } + Some(Nlmsg::from_raw_parts(nlh as *mut u8, self.rest()).unwrap()) + } } pub type Attr = netlink::Nlattr; @@ -1306,6 +1418,10 @@ impl <'a> Attr { cvt_cbret!(mnl_attr_parse_nested(self, attr_parse_cb::, pdata)) } + pub fn cl_parse_nested<'b>(&self, cb: Box CbRet + 'b>) -> io::Result<(CbRet)> { + cvt_cbret!(mnl_attr_parse_nested(self, attr_parse_cb2, Box::into_raw(Box::new(cb)) as *mut c_void)) + } + pub fn nesteds(&'a self) -> Box + 'a> { Box::new(AttrIterator { attr: self.payload::(), tail: self.payload::() as *const _ as uintptr_t @@ -1321,6 +1437,15 @@ extern fn attr_parse_cb(attr: *const netlink::Nlattr, data: *mut c_vo } } +extern fn attr_parse_cb2(attr: *const netlink::Nlattr, data: *mut c_void) -> c_int { + unsafe { + let mut cb = Box::from_raw(data as *mut Box CbRet>); + let rc = (cb)(attr.as_ref().unwrap()) as c_int; + forget(cb); + rc + } +} + /// parse attributes in payload of Netlink message /// /// # Arguments @@ -1341,42 +1466,82 @@ extern fn attr_parse_cb(attr: *const netlink::Nlattr, data: *mut c_vo /// # Return values /// This function propagates the return value of the callback, which can be /// MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP. -pub fn parse_payload<'a, T: 'a + ?Sized>(payload: &[u8], payload_len: usize, cb: AttrCb<'a, T>, data: &mut T) -> io::Result<(CbRet)> { +pub fn parse_attrs<'a, T: 'a + ?Sized>(payload: &[u8], cb: AttrCb<'a, T>, data: &mut T) -> io::Result<(CbRet)> { let mut cbdata = AttrCbData{ cb: cb, data: data }; let pdata = &mut cbdata as *mut _ as *mut c_void; cvt_cbret!(mnl_attr_parse_payload(payload.as_ptr() as *const c_void, - payload_len as size_t, attr_parse_cb::, pdata)) + payload.len() as size_t, attr_parse_cb::, pdata)) +} + +pub fn cl_parse_attrs<'a>(payload: &[u8], cb: Box CbRet>) -> io::Result<(CbRet)> { + cvt_cbret!(mnl_attr_parse_payload(payload.as_ptr() as *const c_void, payload.len() as size_t, + attr_parse_cb2, Box::into_raw(Box::new(cb)) as *mut c_void)) } extern fn nlmsg_parse_cb(nlh: *const netlink::Nlmsghdr, data: *mut c_void) -> c_int { unsafe { let arg = &mut *(data as *mut CbData); if let Some(cb) = arg.cb { - return cb(Nlmsg::from_raw(nlh), arg.data) as c_int; + return cb(Nlmsg::from_raw(nlh).unwrap(), arg.data) as c_int; } CbRet::OK as c_int // MNL_CB_OK } } +extern fn nlmsg_parse_cb2(nlh: *const netlink::Nlmsghdr, data: *mut c_void) -> c_int { + unsafe { + let mut op = Box::from_raw(data as *mut (Option CbRet>>, + &[Option CbRet>>])); + let mut rc = CbRet::OK as c_int; + if let Some(ref mut cb) = op.0.as_mut() { + rc = cb(Nlmsg::from_raw(nlh).unwrap()) as c_int; + } + forget(op); + rc + } +} + extern fn nlmsg_ctl_cb(nlh: *const netlink::Nlmsghdr, data: *mut c_void) -> c_int { unsafe { let arg = &mut *(data as *mut CbData); - if let Some(ctl_cb) = arg.ctl_cb { - return ctl_cb(Nlmsg::from_raw(nlh), arg.data) as c_int; + if let Some(ctl_cb) = arg.ctl_cbs[(*nlh).nlmsg_type as usize] { + return ctl_cb(Nlmsg::from_raw(nlh).unwrap(), arg.data) as c_int; } CbRet::OK as c_int // MNL_CB_OK } } -pub fn cb_run<'a, 'b, T: 'a + 'b + ?Sized>(buf: &[u8], seq: u32, portid: u32, - cb_data: Option>, data: &'b mut T) - -> io::Result<(CbRet)> { - let mut arg = CbData{ cb: cb_data, ctl_cb: None, data: data }; +extern fn nlmsg_ctl_cb2(nlh: *const netlink::Nlmsghdr, data: *mut c_void) -> c_int { + unsafe { + let mut cbs = Box::from_raw(data as *mut (Option CbRet>>, + &mut [Option CbRet>>])); + let rc = match cbs.1[(*nlh).nlmsg_type as usize] { + Some(ref mut cb) => cb(Nlmsg::from_raw(nlh).unwrap()) as c_int, + None => CbRet::OK as c_int, + }; + forget(cbs); + rc + } +} + +pub fn cb_run<'a, T>(buf: &[u8], seq: u32, portid: u32, + cb_data: Option>, data: &mut T) + -> io::Result<(CbRet)> { + let nil = [None::>]; + let mut arg = CbData{ cb: cb_data, ctl_cbs: &nil, data: data }; let argp = &mut arg as *mut _ as *mut c_void; cvt_cbret!(mnl_cb_run(buf.as_ptr() as *const c_void, buf.len() as size_t, seq, portid, nlmsg_parse_cb::, argp)) } +pub fn cl_run(buf: &[u8], seq: u32, portid: u32, + cb_data: Option CbRet>>) + -> io::Result<(CbRet)> { + cvt_cbret!(mnl_cb_run(buf.as_ptr() as *const c_void, buf.len() as size_t, + seq, portid, nlmsg_parse_cb2, + Box::into_raw(Box::new((cb_data, &[None:: CbRet>>]))) as *mut c_void)) +} + /// callback runqueue for netlink messages /// # Arguments /// * `buf` buffer that contains the netlink messages @@ -1398,22 +1563,27 @@ pub fn cb_run<'a, 'b, T: 'a + 'b + ?Sized>(buf: &[u8], seq: u32, portid: u32, /// is set to ESRCH. If the sequence number is not the expected, errno is set /// to EPROTO. If the dump was interrupted, errno is set to EINTR and you should /// request a new fresh dump again. -pub fn cb_run2<'a, 'b, T: 'a + 'b + ?Sized>(buf: &[u8], seq: u32, portid: u32, - cb_data: Option>, data: &'b mut T, - cb_ctl: Cb<'a, T>, ctltypes: &[u16]) - -> io::Result<(CbRet)> { - - // XXX: can not assign NULL? - // let mut cb_ctl_array: [CbT; netlink::NLMSG_MIN_TYPE as usize] - // = [std::ptr::null() as CbT; netlink::NLMSG_MIN_TYPE as usize]; - let mut cb_ctl_array: [CbT; netlink::NLMSG_MIN_TYPE as usize - 1] = unsafe { zeroed() }; - - for i in ctltypes.into_iter() { - cb_ctl_array[*i as usize] = nlmsg_ctl_cb::; - } - let mut arg = CbData{ cb: cb_data, ctl_cb: Some(cb_ctl), data: data }; +pub fn cb_run2<'a, T: 'a>(buf: &[u8], seq: u32, portid: u32, + cb_data: Option>, data: &mut T, + ctl_cbs: &'a [Option>]) + -> io::Result<(CbRet)> { + let ctlen = ctl_cbs.len(); + let raw_ctl_cbs = vec![nlmsg_ctl_cb:: as CbT; ctlen]; + let mut arg = CbData{ cb: cb_data, ctl_cbs: ctl_cbs, data: data }; let argp = &mut arg as *mut _ as *mut c_void; cvt_cbret!(mnl_cb_run2(buf.as_ptr() as *const c_void, buf.len() as size_t, seq, portid, nlmsg_parse_cb::, argp, - cb_ctl_array.as_ptr() as *const CbT, netlink::NLMSG_MIN_TYPE as c_uint)) + raw_ctl_cbs.as_ptr() as *const CbT, ctlen as c_uint)) +} + +pub fn cl_run2(buf: &[u8], seq: u32, portid: u32, + cb_data: Option CbRet>>, + cb_ctl_array: &mut [Option CbRet>>]) + -> io::Result<(CbRet)> { + let ctlen = cb_ctl_array.len(); + let raw_ctl_cbs = vec![nlmsg_ctl_cb2 as CbT; ctlen]; + let data = Box::into_raw(Box::new((cb_data, cb_ctl_array))) as *mut c_void; + cvt_cbret!(mnl_cb_run2(buf.as_ptr() as *const c_void, buf.len() as size_t, + seq, portid, nlmsg_parse_cb2, data, + raw_ctl_cbs.as_ptr() as *const CbT, ctlen as c_uint)) } diff --git a/src/nlmsg_ext.c b/src/nlmsg_ext.c index d93470c..1d34dce 100644 --- a/src/nlmsg_ext.c +++ b/src/nlmsg_ext.c @@ -1,5 +1,58 @@ +#include #include #include +#include +#include +#include + +#define EXPORT_SYMBOL(x) + +/** + * mnl_nlmsg_put_header_check - reserve and prepare room for Netlink header + * \param buf memory already allocated to store the Netlink header + * \param buflen size of buffer which stores the message + * + * This function first checks that the Netlink header can be added to the memory + * buffer passed as parameterthen sets to zero the buffer that is required to + * put the Netlink header in it. This function also initializes the nlmsg_len + * field to the size of the Netlink header. This function returns a pointer to + * the Netlink header structure. + * This function returns NULL on error and errno is set to EINVAL. + */ +EXPORT_SYMBOL(mnl_nlmsg_put_header_check); +struct nlmsghdr *mnl_nlmsg_put_header_check(void *buf, size_t buflen) +{ + if (buflen < MNL_NLMSG_HDRLEN) { + errno = EINVAL; + return NULL; + } + + return mnl_nlmsg_put_header(buf); +} + +/** + * mnl_nlmsg_put_extra_header_check - reserve and prepare room for an extra header + * \param nlh pointer to Netlink header + * \param buflen size of buffer which stores the message + * \param size size of the extra header that we want to put + * + * This function first checks the room that is required to put the extra header + * after the initial Netlink header can be added (fits into the buffer) and then + * sets to zero the room. This function also increases the nlmsg_len field. You + * have to invoke mnl_nlmsg_put_header() before you call this function. This + * function returns a pointer to the extra header. + * This function returns NULL on error and errno is set to EINVAL. + */ +EXPORT_SYMBOL(mnl_nlmsg_put_extra_header_check); +void *mnl_nlmsg_put_extra_header_check(struct nlmsghdr *nlh, size_t buflen, size_t size) +{ + if (nlh->nlmsg_len + MNL_ALIGN(size) > buflen) { + errno = EINVAL; + return NULL; + } + + return mnl_nlmsg_put_extra_header(nlh, size); +} struct mnl_nlmsg_batch { /* the buffer that is used to store the batch. */ @@ -11,7 +64,84 @@ struct mnl_nlmsg_batch { bool overflow; }; +/** + * mnl_nlmsg_batch_rest - get the rest of the batch buffer size + * \param b pointer to batch + * + * This function returns the rest of the batch buffer size + */ +EXPORT_SYMBOL(mnl_nlmsg_batch_rest); size_t mnl_nlmsg_batch_rest(const struct mnl_nlmsg_batch *b) { return b->limit - b->buflen; } + +/* + * Belows will not be merged to master. + * Assume never overflow buffer. + */ +struct nlmsghdr *rsmnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b) +{ + struct nlmsghdr *nlh = b->cur; + + if (b->buflen + nlh->nlmsg_len + MNL_NLMSG_HDRLEN > b->limit) + return NULL; + + b->cur = b->buf + b->buflen + nlh->nlmsg_len; + b->buflen += nlh->nlmsg_len; + + return (struct nlmsghdr *)b->cur; +} + +/* adding clearing buffer to the original */ +struct mnl_nlmsg_batch *rsmnl_nlmsg_batch_start(void *buf, size_t limit) +{ + struct mnl_nlmsg_batch *b; + + b = malloc(sizeof(struct mnl_nlmsg_batch)); + if (b == NULL) + return NULL; + + b->buf = buf; + b->limit = limit; + b->buflen = 0; + b->cur = buf; + b->overflow = false; + memset(b->buf, 0, b->limit); + + return b; +} + +/* adding clearing buffer to the original */ +struct nlmsghdr *rsmnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b) +{ + if (b->overflow) { + struct nlmsghdr *nlh = b->cur; + memcpy(b->buf, b->cur, nlh->nlmsg_len); + b->buflen = nlh->nlmsg_len; + b->cur = b->buf + b->buflen; + b->overflow = false; + memset(b->buf + b->buflen, 0, b->limit - b->buflen); + } else { + b->buflen = 0; + b->cur = b->buf; + memset(b->buf, 0, b->limit); + } +} + +bool rsmnl_nlmsg_batch_cap(struct mnl_nlmsg_batch *b) +{ + struct nlmsghdr *nlh = b->cur; + + if (b->buflen + nlh->nlmsg_len > b->limit) + return; + + b->cur = b->buf + b->buflen + nlh->nlmsg_len; + b->buflen += nlh->nlmsg_len; +} + +void rsmnl_nlmsg_batch_put_back(struct mnl_nlmsg_batch *b) +{ + struct nlmsghdr *nlh = b->cur; + nlh->nlmsg_len = 0; +} diff --git a/tests/lib.rs b/tests/lib.rs index 48e79bf..c2e2647 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -2,6 +2,7 @@ use std::os::unix::io::AsRawFd; use std::mem::size_of; use std::iter::repeat; // use std::io::Cursor; +use std::iter::Iterator; extern crate crslmnl as mnl; use mnl::linux as linux; @@ -117,17 +118,31 @@ fn nlmsg_size() { #[test] fn nlmsg_put_header() { let mut buf = vec![123 as u8; mnl::SOCKET_BUFFER_SIZE()]; - let nlh = mnl::Nlmsg::new(&mut buf); + let nlh = mnl::Nlmsg::new(&mut buf).unwrap(); assert!(*nlh.nlmsg_len == 16); } +#[test] +fn nlmsg_put_extra_header_raw() { + let mut buf = vec![123 as u8; mnl::SOCKET_BUFFER_SIZE()]; + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + { + let exthdr: &mut linux::netfilter::nfnetlink::Nfgenmsg + = nlh.put_extra_header_raw(size_of::()); + assert!(exthdr.nfgen_family == 0); + assert!(exthdr.version == 0); + assert!(exthdr.res_id == 0); + } + assert!(*nlh.nlmsg_len as usize == 16 + size_of::()); +} + #[test] fn nlmsg_put_extra_header() { let mut buf = vec![123 as u8; mnl::SOCKET_BUFFER_SIZE()]; - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); { let exthdr: &mut linux::netfilter::nfnetlink::Nfgenmsg - = nlh.put_extra_header(size_of::()); + = nlh.put_extra_header(size_of::()).unwrap(); assert!(exthdr.nfgen_family == 0); assert!(exthdr.version == 0); assert!(exthdr.res_id == 0); @@ -135,13 +150,15 @@ fn nlmsg_put_extra_header() { assert!(*nlh.nlmsg_len as usize == 16 + size_of::()); } + #[test] fn nlmsg_ok() { let mut buf = vec![0; mnl::NLMSG_HDRLEN() as usize]; - let nlh = mnl::Nlmsg::new(&mut buf); - assert!(!nlh.ok(15)); - assert!(nlh.ok(16)); - assert!(nlh.ok(17)); + let nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); + *nlh.nlmsg_len = 16; + assert!(nlh.ok()); + *nlh.nlmsg_len = 17; + assert!(!nlh.ok()); } #[test] @@ -149,11 +166,12 @@ fn nlmsg_next_header() { let hdrlen = mnl::NLMSG_HDRLEN() as usize; let mut buf: Vec = repeat(0u8).take(512).collect(); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - let (next_nlh, rest) = nlh.next(512); - assert!(rest == 512 - hdrlen as isize); - assert!(*next_nlh.nlmsg_len == 0); - *next_nlh.nlmsg_len = 0x11111111; + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + let mut nnlh = nlh.next().unwrap(); + assert!(nnlh.buflen() == 512 - hdrlen); + assert!(*nnlh.nlmsg_len == 0); + *nnlh.nlmsg_len = 0x11111111; + assert!(nnlh.next().is_none()); } assert_eq!(buf[hdrlen..(hdrlen + 4)], [0x11, 0x11, 0x11, 0x11]); } @@ -162,12 +180,12 @@ fn nlmsg_next_header() { fn nlmsg_seq_ok() { let mut buf =vec![0u8; 512]; { - let nlh = mnl::Nlmsg::new(&mut buf); + let nlh = mnl::Nlmsg::new(&mut buf).unwrap(); assert!(nlh.seq_ok(0)); } set_nlmsg_seq(&mut buf, 1234567890); { - let nlh = mnl::Nlmsg::new(&mut buf); + let nlh = mnl::Nlmsg::new(&mut buf).unwrap(); assert!(nlh.seq_ok(1234567890)); } } @@ -176,12 +194,12 @@ fn nlmsg_seq_ok() { fn nlmsg_porid_ok() { let mut buf =vec![0u8; 512]; { - let nlh = mnl::Nlmsg::new(&mut buf); + let nlh = mnl::Nlmsg::new(&mut buf).unwrap(); assert!(nlh.portid_ok(0)); } set_nlmsg_seq(&mut buf, 1234567890); { - let nlh = mnl::Nlmsg::new(&mut buf); + let nlh = mnl::Nlmsg::new(&mut buf).unwrap(); assert!(nlh.portid_ok(1234567890)); } } @@ -190,7 +208,7 @@ fn nlmsg_porid_ok() { fn nlmsg_payload() { let mut buf =vec![0u8; 512]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); let v: &mut u64 = nlh.payload_mut(); *v = std::u64::MAX; assert!(*nlh.payload::() == std::u64::MAX); @@ -203,7 +221,7 @@ fn nlmsg_payload() { fn nlmsg_payload_offset() { let mut buf =vec![0u8; 512]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); let v: &mut u64 = nlh.payload_offset_mut(128); *v = std::u64::MAX; assert!(*nlh.payload_offset::(128) == std::u64::MAX); @@ -218,7 +236,7 @@ fn nlmsg_payload_tail() { let mut buf =vec![0u8; 512]; set_nlmsg_len(&mut buf, 64); { - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let v: &mut u64 = nlh.payload_tail_mut(); *v = std::u64::MAX; assert!(*nlh.payload_tail::() == std::u64::MAX); @@ -228,12 +246,12 @@ fn nlmsg_payload_tail() { } #[test] -fn nlmsg_put() { +fn nlmsg_put_raw() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put(123, &std::u64::MAX); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_raw(123, &std::u64::MAX); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -246,12 +264,12 @@ fn nlmsg_put() { } #[test] -fn nlmsg_put_u8() { +fn nlmsg_put_u8_raw() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u8(12, 34); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u8_raw(12, 34); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -263,9 +281,9 @@ fn nlmsg_put_u8() { assert!(*buf_offset_as::(&buf, 20) == 34); { - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let attr = nlh.payload_tail::(); - nlh.put_u8(56, 78); + nlh.put_u8_raw(56, 78); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN((attr_len) as u32) * 2); assert!(attr.nla_len == attr_len); @@ -277,12 +295,12 @@ fn nlmsg_put_u8() { } #[test] -fn nlmsg_put_u16() { +fn nlmsg_put_u16_raw() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u16(1234, 5678); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u16_raw(1234, 5678); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -294,9 +312,9 @@ fn nlmsg_put_u16() { assert!(*buf_offset_as::(&buf, 20) == 5678); { - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let attr = nlh.payload_tail::(); - nlh.put_u16(9012, 3456); + nlh.put_u16_raw(9012, 3456); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN((attr_len) as u32) * 2); assert!(attr.nla_len == attr_len); @@ -308,12 +326,12 @@ fn nlmsg_put_u16() { } #[test] -fn nlmsg_put_u32() { +fn nlmsg_put_u32_raw() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u32(1234, 56789012); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u32_raw(1234, 56789012); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -325,9 +343,9 @@ fn nlmsg_put_u32() { assert!(*buf_offset_as::(&buf, 20) == 56789012); { - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let attr = nlh.payload_tail::(); - nlh.put_u32(3456, 78901234); + nlh.put_u32_raw(3456, 78901234); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN((attr_len) as u32) * 2); assert!(attr.nla_len == attr_len); @@ -339,12 +357,12 @@ fn nlmsg_put_u32() { } #[test] -fn nlmsg_put_u64() { +fn nlmsg_put_u64_raw() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u64(1234, 0x567890abcdef0123); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u64_raw(1234, 0x567890abcdef0123); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -356,9 +374,9 @@ fn nlmsg_put_u64() { assert!(*buf_offset_as::(&buf, 20) == 0x567890abcdef0123); { - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let attr = nlh.payload_tail::(); - nlh.put_u64(4567, 0x890abcdef0123456); + nlh.put_u64_raw(4567, 0x890abcdef0123456); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN((attr_len) as u32) * 2); assert!(attr.nla_len == attr_len); @@ -370,14 +388,14 @@ fn nlmsg_put_u64() { } #[test] -fn nlmsg_put_str() { +fn nlmsg_put_str_raw() { let mut buf = vec![0u8; 512]; let s1 = "Hello, world!"; let b1 = s1.as_bytes(); // .len() == 13 let attr_len1 = linux::netlink::NLA_HDRLEN() + (b1.len() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_str(1234, s1); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_str_raw(1234, s1); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len1 as u32)); let attr = nlh.payload::(); @@ -393,10 +411,10 @@ fn nlmsg_put_str() { let attr_len2 = linux::netlink::NLA_HDRLEN() + (b2.len() as u16); let bi: isize; { - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let attr = nlh.payload_tail::(); bi = *nlh.nlmsg_len as isize; - nlh.put_str(5678, s2); + nlh.put_str_raw(5678, s2); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len1 as u32) + mnl::ALIGN(attr_len2 as u32)); @@ -409,15 +427,15 @@ fn nlmsg_put_str() { } #[test] -fn nlmsg_put_strz() { +fn nlmsg_put_strz_raw() { let mut buf = vec![0u8; 512]; let s1 = "Hello, world!"; let b1 = s1.as_bytes(); // .len() == 13 let attr_len1 = linux::netlink::NLA_HDRLEN() + (b1.len() as u16) + 1; let mut nlmsg_len = mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len1 as u32); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_strz(1234, s1); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_strz_raw(1234, s1); assert!(*nlh.nlmsg_len == nlmsg_len); let attr = nlh.payload::(); @@ -437,10 +455,10 @@ fn nlmsg_put_strz() { let bi: isize; { set_buf(&mut buf, attr_tail, 0xffu8); - let mut nlh = mnl::Nlmsg::from_bytes(&mut buf); + let mut nlh = mnl::Nlmsg::from_bytes(&mut buf).unwrap(); let attr = nlh.payload_tail::(); bi = *nlh.nlmsg_len as isize; - nlh.put_strz(5678, s2); + nlh.put_strz_raw(5678, s2); assert!(*nlh.nlmsg_len == nlmsg_len); assert!(attr.nla_len == attr_len2); @@ -457,8 +475,8 @@ fn nlmsg_put_check() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_check(123, &std::u64::MAX)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put(123, &std::u64::MAX).is_ok()); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -472,15 +490,15 @@ fn nlmsg_put_check() { { let mut buf = vec![0u8; 39]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_check(123, &std::u64::MAX)); - assert!(!nlh.put_check(234, &std::u64::MAX)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put(123, &std::u64::MAX).is_ok()); + assert!(nlh.put(234, &std::u64::MAX).is_err()); } { let mut buf = vec![0u8; 40]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_check(123, &std::u64::MAX)); - assert!(nlh.put_check(234, &std::u64::MAX)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put(123, &std::u64::MAX).is_ok()); + assert!(nlh.put(234, &std::u64::MAX).is_ok()); } } @@ -489,8 +507,8 @@ fn nlmsg_put_u8_check() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u8_check(12, 34)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u8(12, 34).is_ok()); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -503,17 +521,17 @@ fn nlmsg_put_u8_check() { { let mut buf = vec![0u8; 31]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u8_check(12, 34)); - assert!(!nlh.put_u8_check(56, 78)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u8(12, 34).is_ok()); + assert!(nlh.put_u8(56, 78).is_err()); } buf = vec![0u8; 32]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u8_check(12, 34)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u8(12, 34).is_ok()); let attr = nlh.payload_tail::(); - assert!(nlh.put_u8_check(56, 78)); + assert!(nlh.put_u8(56, 78).is_ok()); assert!(attr.nla_len == attr_len); assert!(attr.nla_type == 56); @@ -528,8 +546,8 @@ fn nlmsg_put_u16_check() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u16_check(1234, 5678)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u16(1234, 5678).is_ok()); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -542,17 +560,17 @@ fn nlmsg_put_u16_check() { { let mut buf = vec![0u8; 31]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u16_check(1234, 5678)); - assert!(!nlh.put_u16_check(9012, 3456)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u16(1234, 5678).is_ok()); + assert!(nlh.put_u16(9012, 3456).is_err()); } let mut buf = vec![0u8; 32]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u16_check(1234, 5678)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u16(1234, 5678).is_ok()); let attr = nlh.payload_tail::(); - assert!(nlh.put_u16_check(9012, 3456)); + assert!(nlh.put_u16(9012, 3456).is_ok()); assert!(attr.nla_len == attr_len); assert!(attr.nla_type == 9012); @@ -567,8 +585,8 @@ fn nlmsg_put_u32_check() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u32_check(1234, 56789012)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u32(1234, 56789012).is_ok()); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -581,17 +599,17 @@ fn nlmsg_put_u32_check() { { let mut buf = vec![0u8; 31]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u32_check(1234, 56789012)); - assert!(!nlh.put_u32_check(3456, 78901234)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u32(1234, 56789012).is_ok()); + assert!(nlh.put_u32(3456, 78901234).is_err()); } buf = vec![0u8; 32]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u32_check(1234, 56789012)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u32(1234, 56789012).is_ok()); let attr = nlh.payload_tail::(); - assert!(nlh.put_u32_check(3456, 78901234)); + assert!(nlh.put_u32(3456, 78901234).is_ok()); assert!(attr.nla_len == attr_len); assert!(attr.nla_type == 3456); @@ -606,8 +624,8 @@ fn nlmsg_put_u64_check() { let mut buf = vec![0u8; 512]; let attr_len = linux::netlink::NLA_HDRLEN() + (size_of::() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u64_check(1234, 0x567890abcdef0123)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u64(1234, 0x567890abcdef0123).is_ok()); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len as u32)); let attr = nlh.payload::(); @@ -620,17 +638,17 @@ fn nlmsg_put_u64_check() { { let mut buf = vec![0u8; 39]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u64_check(1234, 0x567890abcdef0123)); - assert!(!nlh.put_u64_check(4567, 0x890abcdef0123456)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u64(1234, 0x567890abcdef0123).is_ok()); + assert!(nlh.put_u64(4567, 0x890abcdef0123456).is_err()); } buf = vec![0u8; 40]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_u64_check(1234, 0x567890abcdef0123)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_u64(1234, 0x567890abcdef0123).is_ok()); let attr = nlh.payload_tail::(); - assert!(nlh.put_u64_check(4567, 0x890abcdef0123456)); + assert!(nlh.put_u64(4567, 0x890abcdef0123456).is_ok()); assert!(attr.nla_len == attr_len); assert!(attr.nla_type == 4567); @@ -647,8 +665,8 @@ fn nlmsg_put_str_check() { let b1 = s1.as_bytes(); // .len() == 13 let attr_len1 = linux::netlink::NLA_HDRLEN() + (b1.len() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_str_check(1234, s1)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_str(1234, s1).is_ok()); assert!(*nlh.nlmsg_len == mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len1 as u32)); let attr = nlh.payload::(); @@ -663,9 +681,9 @@ fn nlmsg_put_str_check() { { let mut buf = vec![0u8; 51]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_str_check(1234, s1)); - assert!(!nlh.put_str_check(5678, s2)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_str(1234, s1).is_ok()); + assert!(nlh.put_str(5678, s2).is_err()); } buf = vec![0u8; 52]; @@ -673,11 +691,11 @@ fn nlmsg_put_str_check() { let b2 = s2.as_bytes(); // .len() == 10 let attr_len2 = linux::netlink::NLA_HDRLEN() + (b2.len() as u16); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_str_check(1234, s1)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_str(1234, s1).is_ok()); let attr = nlh.payload_tail::(); bi = *nlh.nlmsg_len as isize; - assert!(nlh.put_str_check(5678, s2)); + assert!(nlh.put_str(5678, s2).is_ok()); assert!(attr.nla_len == attr_len2); assert!(attr.nla_type == 5678); @@ -695,8 +713,8 @@ fn nlmsg_put_strz_check() { let attr_len1 = linux::netlink::NLA_HDRLEN() + (b1.len() as u16) + 1; let mut nlmsg_len = mnl::NLMSG_HDRLEN() + mnl::ALIGN(attr_len1 as u32); { - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_strz_check(1234, s1)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_strz(1234, s1).is_ok()); assert!(*nlh.nlmsg_len == nlmsg_len); let attr = nlh.payload::(); @@ -711,10 +729,10 @@ fn nlmsg_put_strz_check() { let s2 = "My name is"; { let mut buf = vec![0u8; 51]; - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); - assert!(nlh.put_strz_check(1234, s1)); - assert!(!nlh.put_strz_check(5678, s2)); + assert!(nlh.put_strz(1234, s1).is_ok()); + assert!(nlh.put_strz(5678, s2).is_err()); } let b2 = s2.as_bytes(); // .len() == 10 @@ -725,11 +743,11 @@ fn nlmsg_put_strz_check() { buf = vec![0u8; 52]; { set_buf(&mut buf, attr_tail, 0xffu8); - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.put_strz_check(1234, s1)); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.put_strz(1234, s1).is_ok()); let attr = nlh.payload_tail::(); bi = *nlh.nlmsg_len as isize; - assert!(nlh.put_strz_check(5678, s2)); + assert!(nlh.put_strz(5678, s2).is_ok()); assert!(*nlh.nlmsg_len == nlmsg_len); assert!(attr.nla_len == attr_len2); @@ -745,8 +763,8 @@ fn nlmsg_put_strz_check() { fn nlmsg_nest_start() { let mut buf = vec![0u8; 512]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - let attr = nlh.nest_start(0x123); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + let attr = nlh.nest_start_raw(0x123); assert!(*nlh.nlmsg_len == linux::netlink::NLMSG_LENGTH(linux::netlink::NLA_HDRLEN() as u32)); assert!(attr.nla_len == 0); // will update after _end @@ -761,13 +779,13 @@ fn nlmsg_nest_start_check() { let mut buf: std::vec::Vec; { buf = vec![0u8; 19]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - assert!(nlh.nest_start_check(0x123).is_none()); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + assert!(nlh.nest_start(0x123).is_err()); } { buf = vec![0u8; 20]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - if let Some(attr) = nlh.nest_start_check(0x123) { + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + if let Ok(attr) = nlh.nest_start(0x123) { assert!(*nlh.nlmsg_len == linux::netlink::NLMSG_LENGTH(linux::netlink::NLA_HDRLEN() as u32)); assert!(attr.nla_len == 0); // will update after _end assert!(attr.nla_type & linux::netlink::NLA_F_NESTED != 0); @@ -783,10 +801,10 @@ fn nlmsg_nest_start_check() { fn nlmsg_nest_end() { let mut buf = vec![0u8; 512]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - let attr = nlh.nest_start(0x123); - nlh.put_u8(0x4567, 0x89); - nlh.put_u64(0xabcd, 0xef01234567890abc); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + let attr = nlh.nest_start(0x123).unwrap(); + nlh.put_u8(0x4567, 0x89).unwrap(); + nlh.put_u64(0xabcd, 0xef01234567890abc).unwrap(); nlh.nest_end(attr); assert!(*nlh.nlmsg_len == 16 + 4 + 8 + 12); @@ -806,14 +824,14 @@ fn nlmsg_nest_end() { fn nlmsg_nest_cancel() { let mut buf = vec![0u8; 512]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); - let mut attr = nlh.nest_start(0x123); + let mut attr = nlh.nest_start(0x123).unwrap(); nlh.nest_cancel(attr); assert!(*nlh.nlmsg_len == 16); - nlh.put_u8(0x2345, 0x67); - attr = nlh.nest_start(0x234); + nlh.put_u8(0x2345, 0x67).unwrap(); + attr = nlh.nest_start(0x234).unwrap(); nlh.nest_cancel(attr); assert!(*nlh.nlmsg_len == 24); } @@ -837,28 +855,67 @@ fn nlmsg_parse_cb1(attr: &mnl::Attr, data: &mut u8) -> mnl::CbRet { fn nlmsg_parse() { let mut buf = vec![0u8; 512]; { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u8(1, 0x11); - nlh.put_u8(2, 0x12); - nlh.put_u8(3, 0x13); - nlh.put_u8(4, 0x14); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u8(1, 0x11).unwrap(); + nlh.put_u8(2, 0x12).unwrap(); + nlh.put_u8(3, 0x13).unwrap(); + nlh.put_u8(4, 0x14).unwrap(); assert!(nlh.parse(0, nlmsg_parse_cb1, &mut 1).unwrap() == mnl::CbRet::OK); } { - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u8(0, 0x0); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u8(0, 0x0).unwrap(); assert!(nlh.parse(0, nlmsg_parse_cb1, &mut 1).is_err()); } } +#[test] +fn nlmsg_parse_2() { + let mut buf = vec![0u8; 512]; + { + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u8(1, 0x11).unwrap(); + nlh.put_u8(2, 0x12).unwrap(); + nlh.put_u8(3, 0x13).unwrap(); + nlh.put_u8(4, 0x14).unwrap(); + let mut data = 1; + assert!(nlh.cl_parse(0, Box::new(|attr| { + if attr.nla_type as u8 != data { + return mnl::CbRet::ERROR; + } + if attr.u8() != 0x10 + data { + return mnl::CbRet::ERROR; + } + data += 1; + mnl::CbRet::OK + })).unwrap() == mnl::CbRet::OK); + } + { + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u8(0, 0x0).unwrap(); + let mut data = 1; + assert!(nlh.cl_parse(0, Box::new(|attr| { + if attr.nla_type as u8 != data { + return mnl::CbRet::ERROR; + } + if attr.u8() != 0x10 + data { + return mnl::CbRet::ERROR; + } + data += 1; + mnl::CbRet::OK + })).is_err()); + } +} + + #[test] fn nlmsg_attrs() { let mut buf = vec![0u8; 512]; - let mut nlh = mnl::Nlmsg::new(&mut buf); - nlh.put_u8(0, 0x10); - nlh.put_u8(1, 0x11); - nlh.put_u8(2, 0x12); - nlh.put_u8(3, 0x13); + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + nlh.put_u8(0, 0x10).unwrap(); + nlh.put_u8(1, 0x11).unwrap(); + nlh.put_u8(2, 0x12).unwrap(); + nlh.put_u8(3, 0x13).unwrap(); for (i, attr) in nlh.attrs(0).enumerate() { assert!(attr.nla_type == i as u16); @@ -876,48 +933,51 @@ fn nlmsg_batch_start() { fn nlmsg_batch_next() { let mut buf = vec![0u8; 512]; let b = mnl::NlmsgBatch::start(&mut buf, 512 / 2).unwrap(); - assert!(b.next() == true); + assert!(b.proceed_next() == true); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 256; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); - { - let mut nlh = b.current_nlmsg(); - *nlh.nlmsg_len = 1; - } - assert!(b.next() == false); + // The original will success + // since assumes buf size limit is the half of the buf. + // But this limits equals to the size of buffer + // { + // let mut nlh = b.current_nlmsg().unwrap(); + // *nlh.nlmsg_len = 1; + // } + // assert!(b.proceed_next() == false); } #[test] fn nlmsg_batch_size() { let mut buf = vec![0u8; 512]; let b = mnl::NlmsgBatch::start(&mut buf, 512 / 2).unwrap(); - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.size() == 0); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 128; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.size() == 128); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 128; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.size() == 256); - { - let mut nlh = b.current_nlmsg(); - *nlh.nlmsg_len = 1; - } - assert!(b.next() == false); - assert!(b.size() == 256); + // { + // let mut nlh = b.current_nlmsg().unwrap(); + // *nlh.nlmsg_len = 1; + // } + // assert!(b.proceed_next() == false); + // assert!(b.size() == 256); } #[test] @@ -925,26 +985,27 @@ fn nlmsg_batch_reset() { let mut buf = vec![0u8; 512]; let b = mnl::NlmsgBatch::start(&mut buf, 512 / 2).unwrap(); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 256; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.size() == 256); b.reset(); assert!(b.size() == 0); { - let mut nlh = b.current_nlmsg(); - *nlh.nlmsg_len = 256; - } - assert!(b.next() == true); - { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 256; } - assert!(b.next() == false); - b.reset(); - assert!(b.size() == 256); + assert!(b.proceed_next() == true); + + // { + // let mut nlh = b.current_nlmsg().unwrap(); + // *nlh.nlmsg_len = 256; + // } + // assert!(b.proceed_next() == false); + // b.reset(); + // assert!(b.size() == 256); } #[test] @@ -955,10 +1016,10 @@ fn nlmsg_batch_head() { assert!(b.head::() as *const u8 == bufptr); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 256; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.head::() as *const u8 == bufptr); } @@ -970,10 +1031,10 @@ fn nlmsg_batch_current() { assert!(b.current::() as *const u8 == bufptr); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 256; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.current::() as *const u8 == unsafe { bufptr.offset(256) }); } @@ -985,11 +1046,191 @@ fn nlmsg_batch_is_empty() { assert!(b.is_empty() == true); { - let mut nlh = b.current_nlmsg(); + let mut nlh = b.current_nlmsg().unwrap(); *nlh.nlmsg_len = 256; } - assert!(b.next() == true); + assert!(b.proceed_next() == true); assert!(b.is_empty() == false); b.reset(); assert!(b.is_empty() == true); } + +// fn nlmsg_cb_ok<'a>() -> Box) -> mnl::CbRet> { +fn nlmsg_cb_ok() -> Box mnl::CbRet> { + Box::new(|_| mnl::CbRet::OK) +} + +// fn nlmsg_cb_stop<'a>() -> Box) -> mnl::CbRet> { +fn nlmsg_cb_stop() -> Box mnl::CbRet> { + Box::new(|_| mnl::CbRet::STOP) +} + +// fn nlmsg_cb_error<'a>() -> Box) -> mnl::CbRet> { +fn nlmsg_cb_error() -> Box mnl::CbRet> { + Box::new(|_| mnl::CbRet::ERROR) +} + +#[test] +fn nlmsg_cb_run4() { + let mut buf = vec![0u8; 512]; + let b = mnl::NlmsgBatch::start(&mut *buf, 512 / 2).unwrap(); + { + let mut nlh = b.current_nlmsg().unwrap(); + nlh.put_header().unwrap(); + *nlh.nlmsg_type = linux::netlink::NLMSG_NOOP; // 0x1 + } + + let _ = b.proceed_next(); + { + let mut nlh = b.current_nlmsg().unwrap(); + nlh.put_header().unwrap(); + *nlh.nlmsg_type = linux::netlink::NLMSG_ERROR; // 0x2 + } + + let _ = b.proceed_next(); + { + let mut nlh = b.current_nlmsg().unwrap(); + nlh.put_header().unwrap(); + *nlh.nlmsg_type = linux::netlink::NLMSG_DONE; // 0x3 + } + + let _ = b.proceed_next(); + { + let mut nlh = b.current_nlmsg().unwrap(); + nlh.put_header().unwrap(); + *nlh.nlmsg_type = linux::netlink::NLMSG_OVERRUN;// 0x4 + } + + let mut ctlcbs + = [None, + Some(nlmsg_cb_ok()), // NLMSG_NOOP + Some(nlmsg_cb_ok()), // NLMSG_ERROR + Some(nlmsg_cb_ok()), // NLMSG_DONE + Some(nlmsg_cb_ok()), ]; // NLMSG_OVERRUN + // bufsize = 16 * 4 + assert!(mnl::cl_run2(b.head::<[u8; 48]>(), 0, 0, None, &mut ctlcbs[..]).unwrap() == mnl::CbRet::OK); + + ctlcbs + = [None, + Some(nlmsg_cb_ok()), // NLMSG_NOOP + Some(nlmsg_cb_error()), // NLMSG_ERROR + Some(nlmsg_cb_ok()), // NLMSG_DONE + Some(nlmsg_cb_ok()), ]; // NLMSG_OVERRUN + assert!(mnl::cl_run2(b.head::<[u8; 48]>(), 0, 0, None, &mut ctlcbs[..]).is_err()); + + ctlcbs + = [None, + Some(nlmsg_cb_ok()), // NLMSG_NOOP + Some(nlmsg_cb_ok()), // NLMSG_ERROR + Some(nlmsg_cb_stop()), // NLMSG_DONE + Some(nlmsg_cb_ok()), ]; // NLMSG_OVERRUN + assert!(mnl::cl_run2(b.head::<[u8; 48]>(), 0, 0, None, &mut ctlcbs[..]).unwrap() == mnl::CbRet::STOP); +} + +#[test] +fn nlmsg_batch_iterator() { + let mut buf = [0u8; 64]; + { + let b = mnl::NlmsgBatch::new(&mut buf[..]).unwrap(); + for (i, mut nlh) in b.enumerate() { + nlh.put_header().unwrap(); // *nlh.nlmsg_len = 16; + *nlh.nlmsg_type = i as u16; + } + b.cap(); + assert!(b.size() == 64); + } + { + for (i, nlh) in mnl::Nlmsg::from_bytes(&mut buf[..]).unwrap().into_iter().enumerate() { + assert!(*nlh.nlmsg_type == i as u16); + for (j, my) in nlh.into_iter().enumerate() { + assert!(*my.nlmsg_type == (i + j) as u16); + } + } + } + + { + let b = mnl::NlmsgBatch::new(&mut buf[..]).unwrap(); + for (i, mut nlh) in b.enumerate() { + nlh.put_header().unwrap(); // *nlh.nlmsg_len = 16; + *nlh.nlmsg_type = i as u16; + } + b.put_back(); + b.cap(); + assert!(b.size() == 48); + } + { + for (i, nlh) in mnl::Nlmsg::from_bytes(&mut buf[..]).unwrap().into_iter().enumerate() { + assert!(*nlh.nlmsg_type == i as u16); + } + } +} + +#[test] +fn nlmsg_put_extra_header_check() { + let mut buf = [0u8; 32]; + let mut nlh = mnl::Nlmsg::new(&mut buf[..]).unwrap(); + { + assert!(nlh.put_extra_header::(16).is_ok()); + } + { + assert!(nlh.put_extra_header::(16).is_err()); + } +} + +#[test] +fn nlmsg_put_sized_header_check() { + let mut buf = [0u8; 32]; + let mut nlh = mnl::Nlmsg::new(&mut buf[..]).unwrap(); + { + assert!(nlh.put_sized_header::().is_ok()); + } + { + assert!(nlh.put_sized_header::().is_err()); + } +} + +fn attr_cb1(attr: &mnl::Attr, data: &mut u16) -> mnl::CbRet { + if attr.nla_type < *data { + return mnl::CbRet::OK; + } + mnl::CbRet::ERROR +} + +#[test] +fn attr_parse_attrs() { + let mut buf = [0u8; 512]; + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + for i in 0..4 { + nlh.put_u8(i as u16, i).unwrap(); + } + + assert!(mnl::parse_attrs(nlh.payload_bytes(), attr_cb1, &mut 4u16).unwrap() == mnl::CbRet::OK); + assert!(mnl::parse_attrs(nlh.payload_bytes(), attr_cb1, &mut 3u16).is_err()); +} + +#[test] +fn attr_cl_parse_payload() { + let mut buf = [0u8; 512]; + let mut nlh = mnl::Nlmsg::new(&mut buf).unwrap(); + for i in 0..4 { + nlh.put_u8(i as u16, i).unwrap(); + } + + let mut data = 4; + assert!(mnl::cl_parse_attrs(nlh.payload_bytes(), + Box::new(move |attr| { + if attr.nla_type < data { + return mnl::CbRet::OK; + } + mnl::CbRet::ERROR + })).unwrap() == mnl::CbRet::OK); + + data = 3; + assert!(mnl::cl_parse_attrs(nlh.payload_bytes(), + Box::new(move |attr| { + if attr.nla_type < data { + return mnl::CbRet::OK; + } + mnl::CbRet::ERROR + })).is_err()); +}