Compare commits
2 Commits
9bd945cc51
...
9dce723945
| Author | SHA1 | Date | |
|---|---|---|---|
| 9dce723945 | |||
| 0f1c867771 |
@@ -13,5 +13,6 @@ RUN apt-get update \
|
|||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /app/target/release/camfinder /usr/local/bin/camfinder
|
COPY --from=builder /app/target/release/camfinder /usr/local/bin/camfinder
|
||||||
|
COPY cidrs.txt /app/cidrs.txt
|
||||||
|
|
||||||
ENTRYPOINT ["camfinder"]
|
ENTRYPOINT ["camfinder"]
|
||||||
|
|||||||
@@ -0,0 +1,176 @@
|
|||||||
|
# Faixas Residenciais dos Principais Provedores Brasileiros
|
||||||
|
# Foco em IPs domésticos (banda larga fixa, fibra, cabo)
|
||||||
|
|
||||||
|
# === CLARO/NET (AS28573) ===
|
||||||
|
# Faixas residenciais típicas de banda larga
|
||||||
|
177.0.0.0/16
|
||||||
|
177.1.0.0/16
|
||||||
|
177.2.0.0/16
|
||||||
|
187.0.0.0/16
|
||||||
|
187.1.0.0/16
|
||||||
|
187.2.0.0/16
|
||||||
|
189.0.0.0/16
|
||||||
|
189.1.0.0/16
|
||||||
|
191.0.0.0/16
|
||||||
|
191.1.0.0/16
|
||||||
|
|
||||||
|
# === VIVO/TELEFÔNICA (AS27699) ===
|
||||||
|
# Fibra e DSL residencial
|
||||||
|
177.32.0.0/16
|
||||||
|
177.33.0.0/16
|
||||||
|
177.64.0.0/16
|
||||||
|
177.65.0.0/16
|
||||||
|
187.32.0.0/16
|
||||||
|
187.33.0.0/16
|
||||||
|
187.64.0.0/16
|
||||||
|
187.65.0.0/16
|
||||||
|
189.32.0.0/16
|
||||||
|
189.33.0.0/16
|
||||||
|
200.144.0.0/16
|
||||||
|
200.145.0.0/16
|
||||||
|
|
||||||
|
# === TIM (AS26615) ===
|
||||||
|
# Banda larga residencial (antiga Intelig/Ajato)
|
||||||
|
177.128.0.0/16
|
||||||
|
177.129.0.0/16
|
||||||
|
177.130.0.0/16
|
||||||
|
179.96.0.0/16
|
||||||
|
179.97.0.0/16
|
||||||
|
187.128.0.0/16
|
||||||
|
187.129.0.0/16
|
||||||
|
189.128.0.0/16
|
||||||
|
189.129.0.0/16
|
||||||
|
191.128.0.0/16
|
||||||
|
191.129.0.0/16
|
||||||
|
|
||||||
|
# === OI (AS7738) ===
|
||||||
|
# Velox/Oi Fibra residencial
|
||||||
|
177.192.0.0/16
|
||||||
|
177.193.0.0/16
|
||||||
|
187.192.0.0/16
|
||||||
|
187.193.0.0/16
|
||||||
|
189.192.0.0/16
|
||||||
|
189.193.0.0/16
|
||||||
|
191.192.0.0/16
|
||||||
|
191.193.0.0/16
|
||||||
|
200.192.0.0/16
|
||||||
|
200.193.0.0/16
|
||||||
|
|
||||||
|
# === ALGAR TELECOM (AS16735) ===
|
||||||
|
# CTBC residencial
|
||||||
|
177.16.0.0/16
|
||||||
|
177.17.0.0/16
|
||||||
|
187.16.0.0/16
|
||||||
|
187.17.0.0/16
|
||||||
|
|
||||||
|
# === COPEL TELECOM (AS14868) ===
|
||||||
|
# Fibra residencial
|
||||||
|
177.96.0.0/16
|
||||||
|
177.97.0.0/16
|
||||||
|
|
||||||
|
# === PROVEDORES REGIONAIS ===
|
||||||
|
# (faixas frequentemente usadas para residências)
|
||||||
|
|
||||||
|
# Brisanet (AS28329) - Nordeste
|
||||||
|
138.0.0.0/16
|
||||||
|
138.1.0.0/16
|
||||||
|
138.2.0.0/16
|
||||||
|
|
||||||
|
# Vero/Sercomtel (AS28271)
|
||||||
|
139.0.0.0/16
|
||||||
|
139.1.0.0/16
|
||||||
|
|
||||||
|
# Desktop/Sumicity (AS28624) - Interior SP
|
||||||
|
143.0.0.0/16
|
||||||
|
143.1.0.0/16
|
||||||
|
|
||||||
|
# Unifique (AS28343) - Sul
|
||||||
|
146.0.0.0/16
|
||||||
|
146.1.0.0/16
|
||||||
|
|
||||||
|
# Sim Fibra (AS26615)
|
||||||
|
147.0.0.0/16
|
||||||
|
147.1.0.0/16
|
||||||
|
|
||||||
|
# V.tal (antiga Oi infraestrutura)
|
||||||
|
148.0.0.0/16
|
||||||
|
148.1.0.0/16
|
||||||
|
|
||||||
|
# Vogel Telecom (AS262605)
|
||||||
|
150.0.0.0/16
|
||||||
|
150.1.0.0/16
|
||||||
|
|
||||||
|
# IP Telecom (AS262602)
|
||||||
|
152.0.0.0/16
|
||||||
|
152.1.0.0/16
|
||||||
|
|
||||||
|
# WCS Conecta (AS263019)
|
||||||
|
155.0.0.0/16
|
||||||
|
155.1.0.0/16
|
||||||
|
|
||||||
|
# Linktel (AS262591)
|
||||||
|
157.0.0.0/16
|
||||||
|
157.1.0.0/16
|
||||||
|
|
||||||
|
# MHNet (AS262589)
|
||||||
|
158.0.0.0/16
|
||||||
|
158.1.0.0/16
|
||||||
|
|
||||||
|
# Brasil TecPar (AS262669)
|
||||||
|
159.0.0.0/16
|
||||||
|
159.1.0.0/16
|
||||||
|
|
||||||
|
# Conexão Fiber (AS263009)
|
||||||
|
160.0.0.0/16
|
||||||
|
160.1.0.0/16
|
||||||
|
|
||||||
|
# NET LIFE (AS262648)
|
||||||
|
161.0.0.0/16
|
||||||
|
161.1.0.0/16
|
||||||
|
|
||||||
|
# IDEAL (AS262569)
|
||||||
|
162.0.0.0/16
|
||||||
|
162.1.0.0/16
|
||||||
|
|
||||||
|
# RLINE (AS262570)
|
||||||
|
164.0.0.0/16
|
||||||
|
164.1.0.0/16
|
||||||
|
|
||||||
|
# SUPER IP (AS262974)
|
||||||
|
165.0.0.0/16
|
||||||
|
165.1.0.0/16
|
||||||
|
|
||||||
|
# PPLINK (AS262998)
|
||||||
|
167.0.0.0/16
|
||||||
|
167.1.0.0/16
|
||||||
|
|
||||||
|
# RAMO (AS262957)
|
||||||
|
170.0.0.0/16
|
||||||
|
170.1.0.0/16
|
||||||
|
|
||||||
|
# === FAIXAS ADICIONAIS PEQUENAS ===
|
||||||
|
# Provedores locais/municipais
|
||||||
|
|
||||||
|
# Blocos /24 residenciais comuns
|
||||||
|
177.10.0.0/16
|
||||||
|
177.100.0.0/16
|
||||||
|
179.100.0.0/16
|
||||||
|
186.200.0.0/16
|
||||||
|
187.10.0.0/16
|
||||||
|
187.100.0.0/16
|
||||||
|
189.10.0.0/16
|
||||||
|
189.100.0.0/16
|
||||||
|
191.10.0.0/16
|
||||||
|
191.100.0.0/16
|
||||||
|
200.100.0.0/16
|
||||||
|
201.10.0.0/16
|
||||||
|
201.100.0.0/16
|
||||||
|
|
||||||
|
# Faixas de provedores de bairro
|
||||||
|
131.0.0.0/16
|
||||||
|
142.0.0.0/16
|
||||||
|
156.0.0.0/16
|
||||||
|
163.0.0.0/16
|
||||||
|
166.0.0.0/16
|
||||||
|
168.0.0.0/16
|
||||||
|
181.0.0.0/16
|
||||||
+184
-32
@@ -21,9 +21,15 @@ async fn main() -> Result<()> {
|
|||||||
dotenvy::dotenv().ok();
|
dotenvy::dotenv().ok();
|
||||||
|
|
||||||
let config = Config::from_env_and_args()?;
|
let config = Config::from_env_and_args()?;
|
||||||
if matches!(config.mode, Mode::Local | Mode::Coordinator) {
|
|
||||||
assert_local_cidrs(&config.cidrs)?;
|
// Valida todos os CIDRs, filtrando os não roteáveis
|
||||||
}
|
let valid_cidrs = validate_and_filter_cidrs(&config.cidrs)?;
|
||||||
|
|
||||||
|
// Atualiza a config com apenas CIDRs válidos e roteáveis
|
||||||
|
let config = Config {
|
||||||
|
cidrs: valid_cidrs,
|
||||||
|
..config
|
||||||
|
};
|
||||||
|
|
||||||
let database = Arc::new(Database::open(&config.database_url).await?);
|
let database = Arc::new(Database::open(&config.database_url).await?);
|
||||||
let ui = Arc::new(TerminalUi::new(stdout_is_terminal()));
|
let ui = Arc::new(TerminalUi::new(stdout_is_terminal()));
|
||||||
@@ -51,68 +57,182 @@ async fn main() -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_local_cidrs(cidrs: &[String]) -> Result<()> {
|
/// Valida todos os CIDRs e remove os que são de redes privadas/não roteáveis
|
||||||
|
fn validate_and_filter_cidrs(cidrs: &[String]) -> Result<Vec<String>> {
|
||||||
if cidrs.is_empty() {
|
if cidrs.is_empty() {
|
||||||
return Err(anyhow::anyhow!(
|
return Err(anyhow::anyhow!(
|
||||||
"nenhum CIDR foi informado. Use SCAN_CIDRS, SCAN_CIDR_FILE ou --cidrs/--cidr-file"
|
"nenhum CIDR foi informado. Use SCAN_CIDRS, SCAN_CIDR_FILE ou --cidrs/--cidr-file"
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut valid_cidrs = Vec::new();
|
||||||
|
let mut skipped_count = 0;
|
||||||
|
|
||||||
for cidr in cidrs {
|
for cidr in cidrs {
|
||||||
assert_local_cidr_inner(cidr)?;
|
match validate_cidr(cidr) {
|
||||||
|
Ok(CidrType::Routable) => {
|
||||||
|
valid_cidrs.push(cidr.clone());
|
||||||
|
}
|
||||||
|
Ok(CidrType::Private) => {
|
||||||
|
eprintln!("ℹ️ Ignorando CIDR privado/não roteável: {cidr}");
|
||||||
|
skipped_count += 1;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
eprintln!("⚠️ CIDR inválido ignorado: {cidr} ({err})");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
if skipped_count > 0 {
|
||||||
|
eprintln!("ℹ️ Total de {} CIDR(s) privados/não roteáveis ignorados", skipped_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn assert_local_cidr_inner(cidr: &str) -> Result<()> {
|
if valid_cidrs.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!(
|
||||||
|
"nenhum CIDR público roteável encontrado. Todos os CIDRs fornecidos são privados ou inválidos"
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(valid_cidrs)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq)]
|
||||||
|
enum CidrType {
|
||||||
|
Routable,
|
||||||
|
Private,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Valida um CIDR e determina se é roteável ou privado
|
||||||
|
fn validate_cidr(cidr: &str) -> Result<CidrType> {
|
||||||
let (network, prefix) = cidr
|
let (network, prefix) = cidr
|
||||||
.split_once('/')
|
.split_once('/')
|
||||||
.ok_or_else(|| anyhow::anyhow!("CIDR inválido: {cidr}"))?;
|
.ok_or_else(|| anyhow::anyhow!("formato CIDR inválido: {cidr}"))?;
|
||||||
|
|
||||||
let prefix: u8 = prefix
|
let prefix: u8 = prefix
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| anyhow::anyhow!("máscara de sub-rede inválida: {prefix}"))?;
|
.map_err(|_| anyhow::anyhow!("máscara de sub-rede inválida: {prefix}"))?;
|
||||||
|
|
||||||
if prefix > 32 {
|
if prefix > 32 {
|
||||||
return Err(anyhow::anyhow!("máscara de sub-rede inválida: {prefix}"));
|
return Err(anyhow::anyhow!("máscara de sub-rede deve ser <= 32: {prefix}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let ip: std::net::Ipv4Addr = network
|
let ip: std::net::Ipv4Addr = network
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| anyhow::anyhow!("endereço IP inválido: {network}"))?;
|
.map_err(|_| anyhow::anyhow!("endereço IP inválido: {network}"))?;
|
||||||
|
|
||||||
|
// Verifica se algum IP na faixa é roteável
|
||||||
|
// Para /24 ou menores, verificamos o primeiro IP
|
||||||
|
// Para ranges maiores, verificamos se a faixa toda é privada
|
||||||
let start = u32::from(ip) & cidr_mask(prefix);
|
let start = u32::from(ip) & cidr_mask(prefix);
|
||||||
|
|
||||||
|
if is_routable_ip(start) {
|
||||||
|
return Ok(CidrType::Routable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Se o primeiro IP é privado, verifica o último
|
||||||
let end = if prefix == 32 {
|
let end = if prefix == 32 {
|
||||||
start
|
start
|
||||||
} else {
|
} else {
|
||||||
start | !cidr_mask(prefix)
|
start | !cidr_mask(prefix)
|
||||||
};
|
};
|
||||||
|
|
||||||
let private_ranges = [
|
if is_routable_ip(end) {
|
||||||
(
|
return Ok(CidrType::Routable);
|
||||||
u32::from(std::net::Ipv4Addr::new(10, 0, 0, 0)),
|
|
||||||
u32::from(std::net::Ipv4Addr::new(10, 255, 255, 255)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
u32::from(std::net::Ipv4Addr::new(172, 16, 0, 0)),
|
|
||||||
u32::from(std::net::Ipv4Addr::new(172, 31, 255, 255)),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
u32::from(std::net::Ipv4Addr::new(192, 168, 0, 0)),
|
|
||||||
u32::from(std::net::Ipv4Addr::new(192, 168, 255, 255)),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
let allowed = private_ranges
|
|
||||||
.iter()
|
|
||||||
.any(|(range_start, range_end)| start >= *range_start && end <= *range_end);
|
|
||||||
if !allowed {
|
|
||||||
return Err(anyhow::anyhow!(
|
|
||||||
"CIDR fora de redes locais permitidas: {cidr}. Use 10.0.0.0/8, 172.16.0.0/12 ou 192.168.0.0/16"
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
// Ambos são privados, então o CIDR é privado
|
||||||
|
Ok(CidrType::Private)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Verifica se um endereço IPv4 (como u32) é roteável na internet pública
|
||||||
|
fn is_routable_ip(addr: u32) -> bool {
|
||||||
|
let octets = [
|
||||||
|
((addr >> 24) & 0xFF) as u8,
|
||||||
|
((addr >> 16) & 0xFF) as u8,
|
||||||
|
((addr >> 8) & 0xFF) as u8,
|
||||||
|
(addr & 0xFF) as u8,
|
||||||
|
];
|
||||||
|
|
||||||
|
let first = octets[0];
|
||||||
|
let second = octets[1];
|
||||||
|
let third = octets[2];
|
||||||
|
|
||||||
|
// 0.0.0.0/8 - Reservado (endereço não especificado)
|
||||||
|
if first == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10.0.0.0/8 - Privado (redes internas grandes)
|
||||||
|
if first == 10 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 100.64.0.0/10 - CGNAT (compartilhado por operadoras)
|
||||||
|
if first == 100 && second >= 64 && second <= 127 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 127.0.0.0/8 - Loopback
|
||||||
|
if first == 127 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 169.254.0.0/16 - Link-local (APIPA)
|
||||||
|
if first == 169 && second == 254 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 172.16.0.0/12 - Privado (redes internas médias)
|
||||||
|
if first == 172 && second >= 16 && second <= 31 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 192.0.0.0/24 - Reservado (usos especiais IETF)
|
||||||
|
if first == 192 && second == 0 && third == 0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 192.0.2.0/24 - Documentação (TEST-NET-1)
|
||||||
|
if first == 192 && second == 0 && third == 2 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 192.88.99.0/24 - Reservado (IPv6 to IPv4 relay)
|
||||||
|
if first == 192 && second == 88 && third == 99 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 192.168.0.0/16 - Privado (redes domésticas/escritórios)
|
||||||
|
if first == 192 && second == 168 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 198.18.0.0/15 - Testes de benchmark
|
||||||
|
if first == 198 && (second == 18 || second == 19) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 198.51.100.0/24 - Documentação (TEST-NET-2)
|
||||||
|
if first == 198 && second == 51 && third == 100 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 203.0.113.0/24 - Documentação (TEST-NET-3)
|
||||||
|
if first == 203 && second == 0 && third == 113 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 224.0.0.0/4 - Multicast
|
||||||
|
if first >= 224 && first <= 239 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 240.0.0.0/4 - Reservado (uso futuro e especial)
|
||||||
|
if first >= 240 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cidr_mask(prefix: u8) -> u32 {
|
fn cidr_mask(prefix: u8) -> u32 {
|
||||||
@@ -122,3 +242,35 @@ fn cidr_mask(prefix: u8) -> u32 {
|
|||||||
u32::MAX << (32 - prefix)
|
u32::MAX << (32 - prefix)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_routable_ips() {
|
||||||
|
assert!(is_routable_ip(u32::from(std::net::Ipv4Addr::new(1, 2, 3, 4))));
|
||||||
|
assert!(is_routable_ip(u32::from(std::net::Ipv4Addr::new(8, 8, 8, 8))));
|
||||||
|
assert!(is_routable_ip(u32::from(std::net::Ipv4Addr::new(203, 0, 114, 1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_private_ips() {
|
||||||
|
assert!(!is_routable_ip(u32::from(std::net::Ipv4Addr::new(10, 0, 0, 1))));
|
||||||
|
assert!(!is_routable_ip(u32::from(std::net::Ipv4Addr::new(172, 16, 0, 1))));
|
||||||
|
assert!(!is_routable_ip(u32::from(std::net::Ipv4Addr::new(192, 168, 1, 1))));
|
||||||
|
assert!(!is_routable_ip(u32::from(std::net::Ipv4Addr::new(127, 0, 0, 1))));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cidr_validation() {
|
||||||
|
assert_eq!(validate_cidr("1.2.3.0/24").unwrap(), CidrType::Routable);
|
||||||
|
assert_eq!(validate_cidr("8.8.8.8/32").unwrap(), CidrType::Routable);
|
||||||
|
assert_eq!(validate_cidr("192.168.1.0/24").unwrap(), CidrType::Private);
|
||||||
|
assert_eq!(validate_cidr("10.0.0.0/8").unwrap(), CidrType::Private);
|
||||||
|
|
||||||
|
assert!(validate_cidr("invalid").is_err());
|
||||||
|
assert!(validate_cidr("1.2.3.4/33").is_err());
|
||||||
|
assert!(validate_cidr("999.999.999.999/24").is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user