implant feed-block

Baixa listas públicas de redes hostis (padrão: Spamhaus DROP, v4 e v6), valida, filtra e carrega o resultado em ipsets dedicados, julgados na INPUT (serviços do host) e na DOCKER-USER (portas publicadas pelo Docker). Um systemd-timer semanal mantém a lista atualizada. Opt-in (v2.60.0+).

Uso

implant feed-block <SUBCOMANDO> [OPTIONS]
sudo implant feed-block apply                    # baixa, valida, filtra e aplica
sudo implant feed-block apply --dry-run          # plano a partir do cache; nada muda
implant feed-block status
sudo implant feed-block update                   # o que o timer roda
sudo implant feed-block service install          # timer semanal (systemd)
sudo implant feed-block revert                   # tira os ganchos e esvazia os sets

Subcomandos

Subcomando Descrição
apply [--force] Baixa os feeds, valida, filtra e popula IMPLANT_FEED_BLOCK / IMPLANT_FEED_BLOCK6; instala as chains IMPLANT_FEED_IN (INPUT) e IMPLANT_FEED_FWD (DOCKER-USER)
update [--force] Baixa de novo e repopula, só se o feed estiver aplicado (é o que o timer roda). Falha mantém o conteúdo anterior
revert Remove os ganchos da INPUT e da DOCKER-USER e esvazia os sets. Cache e config são preservados
status Aplicado, entradas por set, ganchos, último download, stale, last_error, timer
service install / uninstall Cria (e habilita) ou remove o timer e o service
service status Estado do timer
service logs [--lines N] journalctl do service (execuções do update); padrão 50 linhas

--force em apply/update: baixa mesmo que o último download bom tenha menos de 1 h (ver Termos de uso).

Todos aceitam --output json; em falha, a saída JSON é o envelope de erro (success: false, error.code, error.message) e o exit é diferente de 0 (v2.60.1+). --quiet suprime a saída human (para timers e scripts).

Configuração

Seção [feed_block] do config.toml (padrão /etc/protocolo-implant/config.toml). Sem a seção, valem os padrões:

[feed_block]
urls = [
  "https://www.spamhaus.org/drop/drop_v4.json",
  "https://www.spamhaus.org/drop/drop_v6.json",
]
max_entries = 100000         # teto (v4 + v6) depois do filtro; máx. 262144
min_prefix_v4 = 8            # entrada mais ampla que isto é descartada
min_prefix_v6 = 16
fetch_timeout_seconds = 30
  • Formatos aceitos: NDJSON do Spamhaus (com uma linha de metadata que traz a contagem de registros) e texto simples, um IP/CIDR por linha, com comentário depois de ; ou #.
  • Só https://: a lista decide bloqueio, então não pode vir por um canal adulterável.

Onde bloqueia

Os ganchos do implant seguem uma precedência única na INPUT e na DOCKER-USER:

WL (whitelist)  >  BL (blocklist/ban)  >  FEED (feed-block)  >  GEO (geo-block)  >  RL (rate-limit)
  • Depois do BL: o ban do operador é o julgamento mais específico, e é o contador dele que o auto-ban lê.
  • Antes do GEO: o feed é uma lista curta de redes sabidamente hostis; o DROP fica contado como "feed", não diluído no país.
  • Entre DROPs a ordem não muda o veredito, só quem conta o pacote. O que importa é a whitelist antes de todos.

A posição é calculada sobre a listagem da chain, então qualquer ordem de apply entre as features dá a mesma chain.

Corpo das chains IMPLANT_FEED_IN e IMPLANT_FEED_FWD:

  1. RETURN em ESTABLISHED,RELATED;
  2. RETURN nos prefixos locais/privados;
  3. RETURN para IMPLANT_RL_WHITELIST[6] e IMPLANT_AB_ALLOW[6] (a whitelist vale mesmo sem o rate-limit aplicado);
  4. DROP para quem está no set.

O set v6 (IMPLANT_FEED_BLOCK6) só ganha gancho se o feed tiver entradas v6.

Antes de mexer, o apply tira um snapshot do iptables (ver iptables). Os sets são salvos em /etc/iptables/ipsets e voltam no boot pela unit de firewall-restore; as regras, pelo netfilter-persistent ou, sem ele (v2.61.0+), pela reaplicação da própria unit, que refaz os ganchos sobre os sets restaurados. Sem nenhum mecanismo, o apply avisa em warnings.

Proteções

Feed ruim não esvazia o set

O conteúdo novo é recusado inteiro — nunca truncado, nunca parcial; uma URL ruim recusa todas — quando há:

  • download falho ou HTTP de erro;
  • resposta acima de 32 MB;
  • feed vazio ou truncado (a contagem da metadata não bate);
  • mais de 10% de linhas inválidas;
  • mais entradas que max_entries;
  • nenhuma entrada restante depois do filtro.

Nesses casos o set fica com o conteúdo anterior. A recusa fica registrada em last_error (no status), no evento feed_kept_previous de /var/lib/implant/feed-block-events.jsonl e no kept_previous do JSON. No primeiro apply (sem conteúdo anterior), é erro e nada muda.

Swap atômico

A troca do conteúdo é feita por ipset swap: não há instante em que o set fique vazio. O último conteúdo bom fica em cache em /var/lib/implant/feed-block/.

Anti-tranca

Sai do feed (e aparece em filtered_out, com o motivo) toda entrada que cobre:

  • o IP da sessão SSH atual;
  • o IP das sessões SSH dos últimos apply (o timer roda sem sessão e continua protegendo-os);
  • os security.trusted_ips do config;
  • qualquer entrada da whitelist do rate-limit ou da allowlist do auto-ban;
  • faixa privada, loopback ou link-local.

Também sai a entrada mais ampla que min_prefix_v4 / min_prefix_v6.

Limites

  • max_entries (padrão 100000, máximo 262144) conta v4 + v6 depois do filtro; acima dele, o feed é recusado.
  • Resposta HTTP limitada a 32 MB; fetch_timeout_seconds por download.

Intervalo mínimo de 1 h

Sem --force, o feed não é baixado de novo se o último download bom tem menos de 1 h: o apply usa o cache e o update não faz nada.

Simular (`--dry-run`)

Vale em apply, update, revert e service install/uninstall: não baixa, não grava cache, state nem evento, não toca ipset, regra ou unit.

  • apply/update mostram o plano (contagens, entradas filtradas, aviso de recusa) a partir do cache do último download bom;
  • revert lista os comandos que rodaria.

Timer semanal

service install cria protocolo-implant-feed-block.timer: semanal, Persistent=true (execução perdida roda no próximo boot), atraso aleatório de até 6 h. Ele roda implant feed-block --quiet update, que só age se o feed estiver aplicado e, em falha, não mexe no host.

O status marca stale quando não há download bom há 14 dias.

`revert`

Tira os ganchos da INPUT e da DOCKER-USER e esvazia os sets IMPLANT_FEED_BLOCK / IMPLANT_FEED_BLOCK6 — eles continuam existindo, vazios, e não são destruídos. Cache e config ficam; o próximo apply volta a popular os sets.

Com o resto do implant

  • ban test: `implant ban test ` mostra feed, feed_entry (a entrada do feed que cobre o IP) e feed_enforced, e blocked passa a contar o feed.

  • unban não tira do feed: o IP voltaria no próximo update. O unban responde in_feed/feed_entry e avisa que a saída é a whitelist, que vale acima do feed:

    sudo implant rate-limit whitelist-ip --ip 203.0.113.10
  • threat-status: iptables_drops.feed_block (DROPs da IMPLANT_FEED_IN, somados em input_total) e hardening_state.feed_block_applied / feed_block_entries.

  • emergency-mode: feed-block é uma feature opt-in. Sai por revert (chains IMPLANT_FEED_* removidas, sets esvaziados) e volta por apply, que reusa o cache do último download bom se o download falhar.

Termos de uso do Spamhaus DROP

Os feeds padrão são do Spamhaus. Confira a versão vigente dos termos em https://www.spamhaus.org/drop/terms/. Em resumo:

  • Uso para a própria rede: o DROP é fornecido sem custo para filtrar tráfego no próprio firewall/roteador.
  • Sem redistribuição: o conteúdo é protegido por direito autoral e de base de dados, e os termos não concedem licença sobre ele. Não repasse a lista (nem cópia, nem espelho, nem a terceiros) e não use o nome "Spamhaus" em material comercial ou promocional.
  • Manter atualizado: alocações mudam, e uma lista velha bloqueia rede que já trocou de dono. O timer semanal e o stale do status existem por isso.

O implant baixa direto da fonte em cada servidor e guarda só o cache local de uso próprio. O intervalo mínimo de 1 h entre downloads segue a etiqueta com o provedor. Uso fora disso (por exemplo, um serviço que repassa a lista) exige acordo com o Spamhaus.

Saída JSON

Envelope 1.0, comandos:

  • feed-block.apply / feed-block.update: applied, changed, dry_run, source (nova | anterior), fetched, urls, entries_v4, entries_v6, filtered_out_total, filtered_out (até 50 itens {entrada, motivo}), kept_previous, skipped, warnings;
  • feed-block.revert;
  • feed-block.status: entries_v4/entries_v6 (lidos do ipset), hook_input, hook_docker_user, last_fetch_ok, stale, last_error, timer, warnings;
  • feed-block.service.*.

Exemplos

# Ativar: aplicar e instalar o timer semanal
sudo implant feed-block apply
sudo implant feed-block service install

# Conferir
implant feed-block status
sudo implant ban test 198.51.100.20         # está no feed? bloqueado de fato?

# Isentar um IP que o feed cobre
sudo implant rate-limit whitelist-ip --ip 198.51.100.20

# Forçar um download novo (respeite o intervalo do provedor)
sudo implant feed-block update --force

# Desligar
sudo implant feed-block service uninstall
sudo implant feed-block revert

Veja também