mirror of
https://github.com/DaLaw2/NetGuardia.git
synced 2026-08-24 14:10:28 +09:00
fix: P0 bugs — IPv4 IHL parsing, TX frame leak, SSH whitelist logic
IPv4 IHL: L4 header offset was hardcoded to 34 (20-byte IPv4 header). Now reads IHL field dynamically (20-60 bytes) so IP options don't cause wrong port/flag parsing. Attackers could previously bypass port-based rules by adding IP options. TX frame leak: tx.produce() may submit fewer frames than provided. Unsubmitted FrameDescs were lost, permanently shrinking frame_pool. Now returns unsubmitted frames to pool. SSH whitelist: Array<PlaceHolder>.get(0).is_some() always returns true (zero-initialized entries exist). Changed to check actual value != 0, matching userspace enable(1)/disable(0) semantics. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ac56b7b480
commit
a14812df94
@ -31,6 +31,16 @@ unsafe fn parse_ipv4_packet(start: usize, end: usize, target: *mut ParsedPacket)
|
||||
let ipv4 = &*((start + IPV4_HEADER_START) as *const Ipv4Hdr);
|
||||
let packet_length = (end - start) as u32;
|
||||
|
||||
// Compute actual IPv4 header length from the IHL field
|
||||
let ihl = (*((start + IPV4_HEADER_START) as *const u8) & 0x0F) as usize * 4;
|
||||
if ihl < 20 || ihl > 60 {
|
||||
return Err(());
|
||||
}
|
||||
let l4_start = ETHER_HEADER_END + ihl;
|
||||
if start + l4_start > end {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let t = &mut *target;
|
||||
t.timestamp_ns = bpf_ktime_get_ns();
|
||||
core::ptr::copy_nonoverlapping(ipv4.src_addr.as_ptr(), t.src_ip.as_mut_ptr(), 4);
|
||||
@ -39,13 +49,16 @@ unsafe fn parse_ipv4_packet(start: usize, end: usize, target: *mut ParsedPacket)
|
||||
t.ip_version = 4;
|
||||
t.protocol = ipv4.proto;
|
||||
|
||||
let tcp_min_end = l4_start + core::mem::size_of::<TcpHdr>();
|
||||
let udp_min_end = l4_start + core::mem::size_of::<UdpHdr>();
|
||||
|
||||
let (src_port, dst_port, tcp_flags, l4_header_len) = match ipv4.proto {
|
||||
IpProto::Tcp => parse_tcp(start, end, IPV4_TCP_HEADER_START, IPV4_TCP_HEADER_END)?,
|
||||
IpProto::Udp => parse_udp(start, end, IPV4_UDP_HEADER_START, IPV4_UDP_HEADER_END)?,
|
||||
IpProto::Tcp => parse_tcp(start, end, l4_start, tcp_min_end)?,
|
||||
IpProto::Udp => parse_udp(start, end, l4_start, udp_min_end)?,
|
||||
_ => (0, 0, 0, 0),
|
||||
};
|
||||
|
||||
t.payload_length = packet_length.saturating_sub((IPV4_HEADER_END + l4_header_len) as u32);
|
||||
t.payload_length = packet_length.saturating_sub((l4_start + l4_header_len) as u32);
|
||||
t.src_port = src_port;
|
||||
t.dst_port = dst_port;
|
||||
t.tcp_flags = tcp_flags;
|
||||
|
||||
@ -109,7 +109,7 @@ fn get_http_request_method(start: usize, end: usize, offset: usize) -> Option<Ht
|
||||
fn ipv4_ssh_service_violation(source: &AddrPortV4, destination: &AddrPortV4) -> bool {
|
||||
unsafe {
|
||||
if IPV4_SSH_SERVICE.get(destination).is_some() {
|
||||
if SSH_WHITE_LIST_ENABLE.get(0).is_some() {
|
||||
if matches!(SSH_WHITE_LIST_ENABLE.get(0), Some(&v) if v != 0) {
|
||||
IPV4_SSH_WHITE_LIST.get(&source.ip()).is_none()
|
||||
} else {
|
||||
IPV4_SSH_BLACK_LIST.get(&source.ip()).is_some()
|
||||
@ -124,7 +124,7 @@ fn ipv4_ssh_service_violation(source: &AddrPortV4, destination: &AddrPortV4) ->
|
||||
fn ipv6_ssh_service_violation(source: &AddrPortV6, destination: &AddrPortV6) -> bool {
|
||||
unsafe {
|
||||
if IPV6_SSH_SERVICE.get(destination).is_some() {
|
||||
if SSH_WHITE_LIST_ENABLE.get(0).is_some() {
|
||||
if matches!(SSH_WHITE_LIST_ENABLE.get(0), Some(&v) if v != 0) {
|
||||
IPV6_SSH_WHITE_LIST.get(&source.ip()).is_none()
|
||||
} else {
|
||||
IPV6_SSH_BLACK_LIST.get(&source.ip()).is_some()
|
||||
|
||||
@ -422,6 +422,13 @@ impl XskPair {
|
||||
|
||||
let nb_submitted = unsafe { self.tx.produce(&frames) };
|
||||
|
||||
// Return unsubmitted frames to pool to prevent frame leak
|
||||
if nb_submitted < frames.len() {
|
||||
for frame in frames[nb_submitted..].iter() {
|
||||
self.frame_pool.push(*frame);
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = self.tx.wakeup() {
|
||||
if e.kind() != std::io::ErrorKind::WouldBlock {
|
||||
log!(EbpfLog::TXWakeupFailed(e.to_string()));
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user