Skip to content

Commit b73963c

Browse files
authored
feat: Add support for IGMP (#78)
1 parent a740fbf commit b73963c

21 files changed

Lines changed: 940 additions & 216 deletions

File tree

Cargo.lock

Lines changed: 68 additions & 80 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ repository = "https://github.com/pythops/oryx"
1313
homepage = "https://github.com/pythops/oryx"
1414

1515
[workspace.dependencies]
16-
network-types = { git = "https://github.com/vadorovsky/network-types", rev = "b78424c" }
16+
network-types = { git = "https://github.com/vadorovsky/network-types", rev = "c6f9c28" }
1717

1818
[profile.release]
1919
opt-level = 3

oryx-common/src/lib.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,14 @@
44
use core::mem;
55

66
use network_types::{
7-
arp::ArpHdr, eth::EthHdr, icmp::Icmp, ip::IpHdr, sctp::SctpHdr, tcp::TcpHdr, udp::UdpHdr,
7+
arp::ArpHdr,
8+
eth::EthHdr,
9+
icmp::Icmp,
10+
igmp::{IGMPv1Hdr, IGMPv2Hdr, IGMPv3MembershipQueryHdr, IGMPv3MembershipReportHdr},
11+
ip::IpHdr,
12+
sctp::SctpHdr,
13+
tcp::TcpHdr,
14+
udp::UdpHdr,
815
};
916

1017
pub mod protocols;
@@ -65,4 +72,20 @@ pub enum ProtoHdr {
6572
Udp(UdpHdr),
6673
Sctp(SctpHdr),
6774
Icmp(Icmp),
75+
Igmp(IgmpHdr),
76+
}
77+
78+
#[derive(Copy, Clone)]
79+
#[repr(C)]
80+
pub enum IgmpHdr {
81+
V1(IGMPv1Hdr),
82+
V2(IGMPv2Hdr),
83+
V3(IGMPv3Hdr),
84+
}
85+
86+
#[derive(Copy, Clone)]
87+
#[repr(C)]
88+
pub enum IGMPv3Hdr {
89+
Query(IGMPv3MembershipQueryHdr),
90+
Report(IGMPv3MembershipReportHdr),
6891
}

oryx-common/src/protocols.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ impl TransportProtocol {
4040

4141
// Network Protocols
4242

43-
pub const NB_NETWORK_PROTOCOL: u16 = 4;
43+
pub const NB_NETWORK_PROTOCOL: u16 = 5;
4444

4545
#[derive(Debug, Copy, Clone, PartialEq, AsRefStr, Display, EnumString)]
4646
#[repr(C)]
@@ -56,15 +56,19 @@ pub enum NetworkProtocol {
5656

5757
#[strum(ascii_case_insensitive)]
5858
Icmpv6 = 3,
59+
60+
#[strum(ascii_case_insensitive)]
61+
Igmp = 4,
5962
}
6063

6164
impl NetworkProtocol {
62-
pub fn all() -> [NetworkProtocol; 4] {
65+
pub fn all() -> [NetworkProtocol; 5] {
6366
[
6467
NetworkProtocol::Ipv4,
6568
NetworkProtocol::Ipv6,
6669
NetworkProtocol::Icmpv4,
6770
NetworkProtocol::Icmpv6,
71+
NetworkProtocol::Igmp,
6872
]
6973
}
7074
}

oryx-ebpf/Cargo.lock

Lines changed: 13 additions & 31 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

oryx-ebpf/Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ homepage = "https://github.com/pythops/oryx"
1010
[dependencies]
1111
aya-ebpf = "0.1.1"
1212
oryx-common = { path = "../oryx-common" }
13-
network-types = { git = "https://github.com/vadorovsky/network-types", rev = "b78424c" }
14-
branches = { version = "0.3", default-features = false }
13+
network-types = { git = "https://github.com/vadorovsky/network-types", rev = "c6f9c28" }
14+
branches = { version = "0.4", default-features = false }
1515

1616
[[bin]]
1717
name = "oryx"

oryx-ebpf/src/main.rs

Lines changed: 136 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ use network_types::{
1414
arp::ArpHdr,
1515
eth::{EthHdr, EtherType},
1616
icmp::{Icmp, IcmpHdr, IcmpV6Hdr},
17+
igmp::{IGMPv1Hdr, IGMPv2Hdr, IGMPv3MembershipQueryHdr, IGMPv3MembershipReportHdr},
1718
ip::{IpHdr, IpProto, Ipv4Hdr, Ipv6Hdr},
1819
sctp::SctpHdr,
1920
tcp::TcpHdr,
2021
udp::UdpHdr,
2122
};
2223
use oryx_common::{
23-
MAX_FIREWALL_RULES, MAX_RULES_PORT, ProtoHdr, RawData, RawFrame, RawPacket,
24+
IGMPv3Hdr, IgmpHdr, MAX_FIREWALL_RULES, MAX_RULES_PORT, ProtoHdr, RawData, RawFrame, RawPacket,
2425
protocols::{LinkProtocol, NetworkProtocol, Protocol, TransportProtocol},
2526
};
2627

@@ -304,6 +305,140 @@ fn process(ctx: TcContext) -> Result<i32, ()> {
304305
});
305306
}
306307
}
308+
309+
IpProto::Igmp => {
310+
if filter_packet(Protocol::Network(NetworkProtocol::Igmp)) {
311+
return Ok(TC_ACT_PIPE);
312+
}
313+
314+
let payload_length = unsafe {
315+
u16::from_be_bytes((*ipv4_header).tot_len) - (*ipv4_header).ihl() as u16
316+
};
317+
318+
let ihl: u8 = ctx.load(EthHdr::LEN).map_err(|_| ())?;
319+
let ihl = (ihl & 0x0F) * 4;
320+
321+
let igmp_type: u8 = ctx.load(EthHdr::LEN + ihl as usize).map_err(|_| ())?;
322+
323+
match igmp_type {
324+
0x11 => {
325+
if payload_length == 8 {
326+
// v1 or v2
327+
let max_response_time: u8 =
328+
ctx.load(EthHdr::LEN + ihl as usize + 1).map_err(|_| ())?;
329+
330+
if max_response_time == 0 {
331+
//v1
332+
let igmp_header: *const IGMPv1Hdr =
333+
ptr_at(&ctx, EthHdr::LEN + ihl as usize)?;
334+
335+
unsafe {
336+
submit(RawData {
337+
frame: RawFrame {
338+
header: *eth_header,
339+
payload: RawPacket::Ip(
340+
IpHdr::V4(*ipv4_header),
341+
ProtoHdr::Igmp(IgmpHdr::V1(*igmp_header)),
342+
),
343+
},
344+
pid,
345+
});
346+
}
347+
} else {
348+
// v2
349+
let igmp_header: *const IGMPv2Hdr =
350+
ptr_at(&ctx, EthHdr::LEN + ihl as usize)?;
351+
352+
unsafe {
353+
submit(RawData {
354+
frame: RawFrame {
355+
header: *eth_header,
356+
payload: RawPacket::Ip(
357+
IpHdr::V4(*ipv4_header),
358+
ProtoHdr::Igmp(IgmpHdr::V2(*igmp_header)),
359+
),
360+
},
361+
pid,
362+
});
363+
}
364+
}
365+
} else {
366+
// v3
367+
let igmp_header: *const IGMPv3MembershipQueryHdr =
368+
ptr_at(&ctx, EthHdr::LEN + ihl as usize)?;
369+
370+
unsafe {
371+
submit(RawData {
372+
frame: RawFrame {
373+
header: *eth_header,
374+
payload: RawPacket::Ip(
375+
IpHdr::V4(*ipv4_header),
376+
ProtoHdr::Igmp(IgmpHdr::V3(IGMPv3Hdr::Query(
377+
*igmp_header,
378+
))),
379+
),
380+
},
381+
pid,
382+
});
383+
}
384+
}
385+
}
386+
0x12 => {
387+
let igmp_header: *const IGMPv1Hdr =
388+
ptr_at(&ctx, EthHdr::LEN + ihl as usize)?;
389+
390+
unsafe {
391+
submit(RawData {
392+
frame: RawFrame {
393+
header: *eth_header,
394+
payload: RawPacket::Ip(
395+
IpHdr::V4(*ipv4_header),
396+
ProtoHdr::Igmp(IgmpHdr::V1(*igmp_header)),
397+
),
398+
},
399+
pid,
400+
});
401+
}
402+
}
403+
0x16 | 0x17 => {
404+
let igmp_header: *const IGMPv2Hdr =
405+
ptr_at(&ctx, EthHdr::LEN + ihl as usize)?;
406+
407+
unsafe {
408+
submit(RawData {
409+
frame: RawFrame {
410+
header: *eth_header,
411+
payload: RawPacket::Ip(
412+
IpHdr::V4(*ipv4_header),
413+
ProtoHdr::Igmp(IgmpHdr::V2(*igmp_header)),
414+
),
415+
},
416+
pid,
417+
});
418+
}
419+
}
420+
0x22 => {
421+
let igmp_header: *const IGMPv3MembershipReportHdr =
422+
ptr_at(&ctx, EthHdr::LEN + ihl as usize)?;
423+
424+
unsafe {
425+
submit(RawData {
426+
frame: RawFrame {
427+
header: *eth_header,
428+
payload: RawPacket::Ip(
429+
IpHdr::V4(*ipv4_header),
430+
ProtoHdr::Igmp(IgmpHdr::V3(IGMPv3Hdr::Report(
431+
*igmp_header,
432+
))),
433+
),
434+
},
435+
pid,
436+
});
437+
}
438+
}
439+
_ => {}
440+
}
441+
}
307442
_ => {}
308443
}
309444
}

oryx-tui/src/cli.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ pub fn cli() -> Command {
5454
.value_delimiter(',')
5555
.num_args(1..)
5656
.default_value("all")
57-
.value_parser(["ipv4", "ipv6", "icmp", "all"]),
57+
.value_parser(["ipv4", "ipv6", "icmpv4", "icmpv6", "igmp", "all"]),
5858
)
5959
.arg(
6060
arg!(--link <link>)

oryx-tui/src/export.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,13 @@ pub fn export(packets: &PacketStore) -> Result<()> {
136136
ipv4_packet.src_ip, "-", ipv4_packet.dst_ip, "-", "ICMPv4", pid, date
137137
)?;
138138
}
139+
IpProto::Igmp(_) => {
140+
writeln!(
141+
file,
142+
"{:39} {:^11} {:39} {:^11} {:10} {:10} {:10}",
143+
ipv4_packet.src_ip, "-", ipv4_packet.dst_ip, "-", "IGMP", pid, date
144+
)?;
145+
}
139146
},
140147
IpPacket::V6(ipv6_packet) => match ipv6_packet.proto {
141148
IpProto::Tcp(p) => {
@@ -184,6 +191,10 @@ pub fn export(packets: &PacketStore) -> Result<()> {
184191
ipv6_packet.src_ip, "-", ipv6_packet.dst_ip, "-", "ICMPv6", pid, date
185192
)?;
186193
}
194+
IpProto::Igmp(_) => {
195+
//IGMP is for IPv4 only
196+
unreachable!()
197+
}
187198
},
188199
},
189200
}

oryx-tui/src/filter/network.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,16 @@ impl NetworkFilter {
150150
},
151151
"ICMPv6",
152152
]),
153+
Row::new(vec![
154+
{
155+
if self.selected_protocols.contains(&NetworkProtocol::Igmp) {
156+
" "
157+
} else {
158+
""
159+
}
160+
},
161+
"IGMP",
162+
]),
153163
];
154164

155165
let network_filters_table = Table::new(network_filters, widths)

0 commit comments

Comments
 (0)