Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions src/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
// SPDX-License-Identifier: MIT

use crate::{
conntrack::ConntrackMessage,
message::{
NetfilterHeader, NetfilterMessage, NetfilterMessageInner,
NetfilterHeader, NetfilterMessage, NetfilterMessageInner, Subsystem,
NETFILTER_HEADER_LEN,
},
nflog::NfLogMessage,
Expand Down Expand Up @@ -52,15 +53,19 @@ impl<'a, T: AsRef<[u8]> + ?Sized>
.context("failed to parse netfilter header")?;
let subsys = (message_type >> 8) as u8;
let message_type = message_type as u8;
let inner = match subsys {
NfLogMessage::SUBSYS => NetfilterMessageInner::NfLog(
let inner = match Subsystem::from(subsys) {
Subsystem::NfLog => NetfilterMessageInner::NfLog(
NfLogMessage::parse_with_param(buf, message_type)
.context("failed to parse nflog payload")?,
),
_ => NetfilterMessageInner::Other {
subsys,
Subsystem::Conntrack => NetfilterMessageInner::Conntrack(
ConntrackMessage::parse_with_param(buf, message_type)
.context("failed to parse conntrack payload")?,
),
subsys_enum @ Subsystem::Other(_) => NetfilterMessageInner::Other {
subsys: subsys_enum,
message_type,
nlas: buf.default_nlas()?,
attributes: buf.default_nlas()?,
},
};
Ok(NetfilterMessage::new(header, inner))
Expand Down
96 changes: 96 additions & 0 deletions src/conntrack/attributes/attribute.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-License-Identifier: MIT

use netlink_packet_core::{
DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
NlasIterator, Parseable,
};

use crate::conntrack::attributes::{protoinfo::ProtoInfo, tuple::Tuple};

const CTA_TUPLE_ORIG: u16 = 1;
const CTA_PROTOINFO: u16 = 4;

#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ConntrackNla {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how about ContrackAttribute like LinkAttribute in netlink-packet-route.

CtaTupleOrig(Vec<Tuple>),
CtaProtoInfo(Vec<ProtoInfo>),
Other(DefaultNla),
}

impl Nla for ConntrackNla {
fn value_len(&self) -> usize {
match self {
ConntrackNla::CtaTupleOrig(attr) => {
attr.iter().map(|op| op.buffer_len()).sum()
}
ConntrackNla::CtaProtoInfo(attr) => {
attr.iter().map(|op| op.buffer_len()).sum()
}
ConntrackNla::Other(attr) => attr.value_len(),
}
}

fn kind(&self) -> u16 {
match self {
ConntrackNla::CtaTupleOrig(_) => CTA_TUPLE_ORIG,
ConntrackNla::CtaProtoInfo(_) => CTA_PROTOINFO,
ConntrackNla::Other(attr) => attr.kind(),
}
}

fn emit_value(&self, buffer: &mut [u8]) {
match self {
ConntrackNla::CtaTupleOrig(attr) => {
let mut len = 0;
for op in attr {
op.emit(&mut buffer[len..]);
len += op.buffer_len();
}
}
ConntrackNla::CtaProtoInfo(attr) => {
let mut len = 0;
for op in attr {
op.emit(&mut buffer[len..]);
len += op.buffer_len();
}
}
ConntrackNla::Other(attr) => attr.emit_value(buffer),
}
}
fn is_nested(&self) -> bool {
matches!(
self,
ConntrackNla::CtaTupleOrig(_) | ConntrackNla::CtaProtoInfo(_)
)
}
}

impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>>
for ConntrackNla
{
fn parse(buf: &NlaBuffer<&'buffer T>) -> Result<Self, DecodeError> {
let kind = buf.kind();
let payload = buf.value();
let nla = match kind {
CTA_TUPLE_ORIG => {
let mut tuples = Vec::new();
for nlas in NlasIterator::new(payload) {
let nlas = &nlas.context("invalid CTA_TUPLE_ORIG value")?;
tuples.push(Tuple::parse(nlas)?);
}
ConntrackNla::CtaTupleOrig(tuples)
}
CTA_PROTOINFO => {
let mut proto_infos = Vec::new();
for nlas in NlasIterator::new(payload) {
let nlas = &nlas.context("invalid CTA_PROTOINFO value")?;
proto_infos.push(ProtoInfo::parse(nlas)?);
}
ConntrackNla::CtaProtoInfo(proto_infos)
}
_ => ConntrackNla::Other(DefaultNla::parse(buf)?),
};
Ok(nla)
}
}
91 changes: 91 additions & 0 deletions src/conntrack/attributes/iptuple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// SPDX-License-Identifier: MIT

use netlink_packet_core::{
parse_ip, DecodeError, DefaultNla, ErrorContext, Nla, NlaBuffer, Parseable,
};
use std::net::IpAddr;

const CTA_IP_V4_SRC: u16 = 1;
const CTA_IP_V6_SRC: u16 = 3;
const CTA_IP_V4_DST: u16 = 2;
const CTA_IP_V6_DST: u16 = 4;

#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum IPTuple {
SourceAddress(IpAddr),
DestinationAddress(IpAddr),
Other(DefaultNla),
}

const IPV4_LEN: usize = 4;
const IPV6_LEN: usize = 16;

// Helper function needed for implementing the Nla trait
pub fn emit_ip(addr: &IpAddr, buf: &mut [u8]) {
match addr {
IpAddr::V4(ip) => {
buf[..IPV4_LEN].copy_from_slice(ip.octets().as_slice());
}
IpAddr::V6(ip) => {
buf[..IPV6_LEN].copy_from_slice(ip.octets().as_slice());
}
}
}

impl Nla for IPTuple {
fn value_len(&self) -> usize {
match self {
IPTuple::SourceAddress(attr) => match *attr {
IpAddr::V4(_) => IPV4_LEN,
IpAddr::V6(_) => IPV6_LEN,
},
IPTuple::DestinationAddress(attr) => match *attr {
IpAddr::V4(_) => IPV4_LEN,
IpAddr::V6(_) => IPV6_LEN,
},
IPTuple::Other(attr) => attr.value_len(),
}
}

fn kind(&self) -> u16 {
match self {
IPTuple::SourceAddress(attr) => match *attr {
IpAddr::V4(_) => CTA_IP_V4_SRC,
IpAddr::V6(_) => CTA_IP_V6_SRC,
},
IPTuple::DestinationAddress(attr) => match *attr {
IpAddr::V4(_) => CTA_IP_V4_DST,
IpAddr::V6(_) => CTA_IP_V6_DST,
},
IPTuple::Other(attr) => attr.kind(),
}
}

fn emit_value(&self, buffer: &mut [u8]) {
match self {
IPTuple::SourceAddress(attr) => emit_ip(attr, buffer),
IPTuple::DestinationAddress(attr) => emit_ip(attr, buffer),
IPTuple::Other(attr) => attr.emit_value(buffer),
}
}
}
impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>>
for IPTuple
{
fn parse(buf: &NlaBuffer<&'buffer T>) -> Result<Self, DecodeError> {
let kind = buf.kind();
let payload = buf.value();
let nla = match kind {
CTA_IP_V4_SRC | CTA_IP_V6_SRC => Self::SourceAddress(
parse_ip(payload).context("invalid SourceAddress value")?,
),
CTA_IP_V4_DST | CTA_IP_V6_DST => Self::DestinationAddress(
parse_ip(payload)
.context("invalid DestinationAddress value")?,
),
_ => IPTuple::Other(DefaultNla::parse(buf)?),
};
Ok(nla)
}
}
17 changes: 17 additions & 0 deletions src/conntrack/attributes/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: MIT

mod attribute;
mod iptuple;
mod protoinfo;
mod protoinfotcp;
mod prototuple;
mod tcp_flags;
mod tuple;

pub use attribute::ConntrackNla;
pub use iptuple::IPTuple;
pub use protoinfo::ProtoInfo;
pub use protoinfotcp::ProtoInfoTCP;
pub use prototuple::{ProtoTuple, Protocol};
pub use tcp_flags::TCPFlags;
pub use tuple::Tuple;
69 changes: 69 additions & 0 deletions src/conntrack/attributes/protoinfo.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT

use netlink_packet_core::{
DecodeError, DefaultNla, Emitable, ErrorContext, Nla, NlaBuffer,
NlasIterator, Parseable,
};

use crate::conntrack::attributes::protoinfotcp::ProtoInfoTCP;

const CTA_PROTOINFO_TCP: u16 = 1;

#[derive(Clone, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum ProtoInfo {
TCP(Vec<ProtoInfoTCP>),
Other(DefaultNla),
}
impl Nla for ProtoInfo {
fn value_len(&self) -> usize {
match self {
ProtoInfo::TCP(nlas) => nlas.iter().map(|op| op.buffer_len()).sum(),
ProtoInfo::Other(attr) => attr.value_len(),
}
}

fn kind(&self) -> u16 {
match self {
ProtoInfo::TCP(_) => CTA_PROTOINFO_TCP,
ProtoInfo::Other(attr) => attr.kind(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
match self {
ProtoInfo::TCP(nlas) => {
let mut len = 0;
for op in nlas {
op.emit(&mut buffer[len..]);
len += op.buffer_len();
}
}
ProtoInfo::Other(attr) => attr.emit_value(buffer),
}
}
fn is_nested(&self) -> bool {
matches!(self, ProtoInfo::TCP(_))
}
}

impl<'buffer, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'buffer T>>
for ProtoInfo
{
fn parse(buf: &NlaBuffer<&'buffer T>) -> Result<Self, DecodeError> {
let kind = buf.kind();
let payload = buf.value();
let nla = match kind {
CTA_PROTOINFO_TCP => {
let mut proto_info_tcps = Vec::new();
for nlas in NlasIterator::new(payload) {
let nlas =
&nlas.context("invailid CTA_PROTOINFO_TCP value")?;
proto_info_tcps.push(ProtoInfoTCP::parse(nlas)?);
}
ProtoInfo::TCP(proto_info_tcps)
}
_ => ProtoInfo::Other(DefaultNla::parse(buf)?),
};
Ok(nla)
}
}
Loading