Esqueleto inicial: sabia-core + sabia-cli + UI local, OpenWolf
- sabia-core: descoberta de interfaces, controle de modo monitor/canal via iw (ponte até ter nl80211 nativo), captura crua 802.11 via AF_PACKET (sem libpcap), parsing de radiotap e quadros de gerenciamento (beacon/probe/EAPOL), agregação em tabela de APs/ clientes, escrita de .pcap, trilha de auditoria encadeada por hash, auto-atualização via GitHub releases (curl, sem dependências de rede extras) - sabia-cli: `sabia iface`, `sabia scan`, `sabia update`, `sabia audit-verify`, `sabia ui` (servidor local + navegador, protegido por token, mesma filosofia do Guará) - OpenWolf inicializado para memória de projeto entre agentes
This commit is contained in:
commit
e989413018
76 files changed
+8386
No files matched your search
@@ -0,0 +1,103 @@
|
||||
//! Parser mínimo de cabeçalho Radiotap — só os campos que usamos
|
||||
//! (canal/frequência e força de sinal). Especificação:
|
||||
//! <https://www.radiotap.org/>
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct RadiotapInfo {
|
||||
pub freq_mhz: Option<u16>,
|
||||
pub signal_dbm: Option<i8>,
|
||||
pub header_len: usize,
|
||||
}
|
||||
|
||||
// Índices de bit no bitmap "present" que nos interessam.
|
||||
const BIT_FLAGS: u32 = 1 << 1;
|
||||
const BIT_RATE: u32 = 1 << 2;
|
||||
const BIT_CHANNEL: u32 = 1 << 3;
|
||||
const BIT_ANTSIGNAL: u32 = 1 << 5;
|
||||
|
||||
/// Retorna as infos extraídas e quantos bytes o cabeçalho ocupa (para o
|
||||
/// chamador saber onde o frame 802.11 propriamente começa).
|
||||
pub fn parse(buf: &[u8]) -> Option<RadiotapInfo> {
|
||||
if buf.len() < 8 || buf[0] != 0 {
|
||||
return None; // version deve ser 0
|
||||
}
|
||||
let header_len = u16::from_le_bytes([buf[2], buf[3]]) as usize;
|
||||
if header_len > buf.len() || header_len < 8 {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Pode haver múltiplas palavras de "present" (bit 31 = continua).
|
||||
let mut present_words = Vec::new();
|
||||
let mut offset = 4;
|
||||
loop {
|
||||
if offset + 4 > buf.len() {
|
||||
return None;
|
||||
}
|
||||
let word = u32::from_le_bytes([buf[offset], buf[offset + 1], buf[offset + 2], buf[offset + 3]]);
|
||||
present_words.push(word);
|
||||
offset += 4;
|
||||
if word & (1 << 31) == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
let present = present_words[0]; // só o primeiro conjunto de campos padrão nos interessa
|
||||
|
||||
let mut info = RadiotapInfo { header_len, ..Default::default() };
|
||||
let mut cursor = offset;
|
||||
|
||||
// TSFT (u64, align 8) viria antes de Flags; para o nosso subconjunto de
|
||||
// campos simplificamos assumindo captura via mac80211 (ordem padrão:
|
||||
// TSFT, Flags, Rate, Channel, ..., AntSignal). Avançamos campo a campo
|
||||
// respeitando alinhamento, sem travar se algum bit não estiver setado.
|
||||
macro_rules! align {
|
||||
($a:expr) => {{
|
||||
let rem = cursor % $a;
|
||||
if rem != 0 {
|
||||
cursor += $a - rem;
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
if present & (1 << 0) != 0 {
|
||||
align!(8);
|
||||
cursor += 8; // TSFT
|
||||
}
|
||||
if present & BIT_FLAGS != 0 {
|
||||
align!(1);
|
||||
cursor += 1;
|
||||
}
|
||||
if present & BIT_RATE != 0 {
|
||||
align!(1);
|
||||
cursor += 1;
|
||||
}
|
||||
if present & BIT_CHANNEL != 0 {
|
||||
align!(2);
|
||||
if cursor + 4 <= buf.len() {
|
||||
let freq = u16::from_le_bytes([buf[cursor], buf[cursor + 1]]);
|
||||
info.freq_mhz = Some(freq);
|
||||
}
|
||||
cursor += 4;
|
||||
}
|
||||
// FHSS (bit 4) — raro, ignorado.
|
||||
if present & (1 << 4) != 0 {
|
||||
align!(2);
|
||||
cursor += 2;
|
||||
}
|
||||
if present & BIT_ANTSIGNAL != 0 {
|
||||
align!(1);
|
||||
if cursor < buf.len() {
|
||||
info.signal_dbm = Some(buf[cursor] as i8);
|
||||
}
|
||||
}
|
||||
|
||||
Some(info)
|
||||
}
|
||||
|
||||
pub fn freq_to_channel(freq_mhz: u16) -> Option<u32> {
|
||||
match freq_mhz {
|
||||
2412..=2472 => Some(((freq_mhz - 2412) / 5 + 1) as u32),
|
||||
2484 => Some(14),
|
||||
5000..=5900 => Some(((freq_mhz - 5000) / 5) as u32),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user