Saltar al contenido principal
Version: 1.0.0

bitscanner

bitscanner encuentra los dispositivos que su inventario no contiene.

bitcollector lee el host en el que se ejecuta. bitscanner mira hacia fuera desde ese host, hacia el segmento que lo rodea — y la respuesta que importa es la que nada de su lista de activos explica.

Versión0.1.3-ga, commit 7db3d4c, compilada con go1.25.12
PlataformasLinux amd64/arm64 únicamente — macOS y Windows no se publican, y por qué
Cadena de suministroCompilación reproducible (se compila dos veces y se rechaza salvo que sea idéntica byte a byte), SBOM CycloneDX y atestación cosign por binario, control de vulnerabilidades, firma cosign por binario y sobre SHA256SUMS
Superficie de red entranteNingún servicio a la escucha. Sin puerto de salud, de métricas ni de administración, y sin clave que abra uno. Medido con el escaneo desactivado: cero sockets a la escucha. service_discovery, una vez armado, usa sockets UDP efímeros y no ligados; un datagrama que llega a uno de ellos solo se convierte en registro de inventario si responde a la consulta recién enviada y procede de allowed_cidrs — no comprobado en 0.1.3-ga ni en versiones anteriores, véase más abajo
SalienteSolo https, hacia los endpoints que usted configure. Nunca se sigue una redirección
Escrituras en el hostSu propio directorio de datos (agent.data_dir), que guarda la clave de enrolamiento y el token del agente, en 0600 dentro de un directorio forzado a 0700
Paquetes en la red por defectoCero. Ambos interruptores de armado se distribuyen desactivados

Antes de ejecutarlo, verifique la descarga — los pasos específicos de bitscanner están más abajo.

Dos temas son lo bastante grandes como para tener su propia página: el escaneo y el modelo de armado de dos interruptores — la escalera de sondas, qué pone cada una en el cable y el guardián que autoriza cada paquete — y qué sale del host, incluidos el enrolamiento, la salida de datos y los límites con los que se distribuye esta versión.

La pregunta que bitcollector no puede responder​

Un inventario ensamblado a partir de agentes solo puede contener máquinas en las que alguien instaló un agente. La impresora, el switch del laboratorio, el portátil del contratista, la VM que un equipo levantó para una migración y de la que nunca informó a nadie — ninguno de ellos se reportará por sí mismo, y ninguno falta por un fallo técnico. Faltan porque nadie sabía que había que mirar.

Así que los dos binarios responden a dos preguntas distintas, y la frontera es la dirección hacia la que miran:

bitcollectorbitscanner
MiraHacia dentro — el host en el que se ejecutaHacia fuera — el segmento en el que está ese host
Responde«¿Qué es esta máquina y en qué estado está?»«¿Qué más hay en este cable, y hay algo sin explicación?»
Ve un dispositivo solo sitiene un agente instaladoes visible desde un host que sí lo tiene
Envía paquetesNunca — lee el hostSolo si usted lo arma, sonda a sonda

Ninguno sustituye al otro. Un dispositivo que bitscanner descubre es una pista: una dirección, una MAC, un fabricante, una fecha de primera observación. Convertir esa pista en un activo con propietario es trabajo que usted hace en Gestión de activos — la tarea de bitscanner es asegurar que la pista exista siquiera.

Qué reporta con todo desactivado​

La configuración por defecto no arma ninguna sonda, y el agente aun así tiene algo que decir, porque el propio kernel del host ya conoce a sus vecinos.

Medido, en un host Linux corriente con el escaneo activo completamente deshabilitado — el valor por defecto distribuido:

INFO scanguard active scanning is disabled; every probe will be denied
INFO network_collector network intelligence collector starting {"interval": "20s"}
INFO network_collector collection cycle complete
{"queued_for_delivery": ["network_state", "neighbor_table"]}

Ambos proceden de ficheros que el host ya tiene — /proc/net/arp y la tabla de rutas — de modo que este estado no emite ningún paquete en absoluto.

RegistroQué contieneNecesita
network_stateLa tabla de rutas: destino, pasarela, interfaz, métrica, flagsnada
neighbor_tableLa caché ARP/NDP del kernel: dirección, MAC, interfaz, estadonada
neighbor_discoveryEl inventario enriquecido de vecinos: dirección, MAC, fabricante, tipo de dispositivo, alcanzabilidad, primera/última observación — más las subredes en las que se encontraronscanning.probes.neighbor_discovery
gateway_discoveryLos primeros saltos de salida de este host, con atribución de MACscanning.probes.gateway_discovery
service_discoveryRespondedores mDNS/SSDP, atribuidos al vecino que contestóscanning.probes.service_discovery

Cada registro va envuelto en el mismo sobre — schema_version, type, agent_id, timestamp, sequence, payload, checksum — y la suma de comprobación es una verificación de integridad SHA-256 sobre la cabecera y la carga útil del sobre, no una firma. bitscanner no tiene la cadena de evidencia firmada y encadenada por hash de bitcollector; si necesita un artefacto que un auditor pueda verificar sin conexión, ese es el trabajo del recopilador, no de este.

Cómo ejecutarlo​

bitscanner es un único binario estático. Verifíquelo primero y después:

# What you have
bitscanner version
# BitScanner 0.1.3-ga (commit: 7db3d4c, built: 2026-08-09T09:54:40Z, go1.25.12, linux/amd64)

# Write a fully commented starting configuration
bitscanner config init --config /etc/bitscanner/config.yaml

# Check it BEFORE you start anything
bitscanner config validate --config /etc/bitscanner/config.yaml
# Configuration is valid.

# Run in the foreground
bitscanner run --config /etc/bitscanner/config.yaml

# Turn up the detail while you are setting it up
bitscanner run --config /etc/bitscanner/config.yaml --log-level debug --log-format console

config init escribe el mismo fichero comentado que describe esta página: cada clave de escaneo, qué envía realmente cada sonda y por qué los valores por defecto son los que son. Está pensado para leerse.

--log-level y --log-format son opciones, y solo opciones

No hay bloque logging:. Lo hubo — level, format, output_path, max_size, max_backups, max_age — y ni una sola de esas claves era leída por código alguno, así que el registrador se configuraba enteramente desde la línea de comandos dijera lo que dijera el fichero. El bloque ha desaparecido, y una configuración que todavía lo contenga se rechaza por su nombre:

Error: configuration validation failed: failed to load config: logging is set but no
longer exists: the whole `logging` block was parsed and read by nobody […] Use the
flags, which do work: `--log-level` (debug|info|warn|error) and `--log-format`
(json|console). There is no replacement for output_path or for the rotation keys — log
rotation was never implemented […]

El mismo trato se aplica a control_plane.retry_interval, control_plane.max_retries, security.allow_root_only, security.secure_bootstrap, security.audit_log_path y security.encrypt_local_data. Dos de ellas valían true por defecto, de modo que el fichero distribuido se leía como un arranque seguro y un cifrado en reposo cuando no existía ninguno de los dos. Una clave que no hace nada no se distribuye, y su eliminación se anuncia a la persona cuyo fichero la contiene en lugar de ignorarse en silencio.

Qué cuesta en el host​

  • Ninguna superficie entrante. Verificado en un agente en ejecución: el proceso posee cero sockets a la escucha. No hay puerto de salud, ni puerto de métricas, ni clave de configuración que abra uno. Una salvedad honesta: con service_discovery armado, el agente abre sockets UDP efímeros y no ligados para enviar las consultas mDNS y SSDP y leer las respuestas. Existen solo mientras dura una sonda — pero «cero sockets a la escucha» es cierto de la configuración por defecto, no de todas las configuraciones.
  • Barato cuando está tranquilo. En un host con 118 vecinos ARP repartidos en 27 subredes conectadas, una pasada completa de descubrimiento de vecinos tardó 71–189 ms por ciclo a lo largo de cuatro ciclos consecutivos. El valor por defecto de modules.network_intelligence.interval es 1m.
  • Un ciclo es un ciclo de escaneo. El presupuesto de hosts por ciclo y el plazo de escaneo en tiempo real se reinician al comienzo de una recopilación y en ningún otro sitio, de modo que un segmento lento o con tarpit no puede dejar que el sondeo de un ciclo invada el siguiente.
  • Ni store-and-forward ni reintento. Un lote que no se puede entregar se registra como error y se descarta: no se guarda en disco ni se reintenta. Si el destino no es alcanzable durante diez minutos, son diez minutos de observaciones que usted no tiene. Se registra una línea queued_for_delivery en cada ciclo, con o sin escaneo activo, de modo que un fallo de entrega no pueda confundirse con un recopilador detenido — pero «en cola» no es «entregado», y el agente no puede afirmar más de lo que el destino le respondió.
Estos sockets aceptaban cualquier cosa, en 0.1.3-ga y versiones anteriores

Esta página afirmaba que los sockets de descubrimiento «no aceptan nada que usted no haya solicitado». Esa comprobación nunca se implementó. Los sockets usan un enlace comodín, de modo que el núcleo les entrega cualquier datagrama que alcance el puerto, y nada comparaba el remitente ni el contenido con la consulta recién enviada: un datagrama SSDP se convertía en un dispositivo por el mero hecho de contener el texto ST:. Cualquier cosa capaz de alcanzar ese puerto podía añadir a su inventario equipos que no existen, en las direcciones que eligiera, registrados como observaciones hechas por este agente.

La comprobación ya existe en el código fuente y plantea dos preguntas. De quién: el remitente debe estar dentro de sus scanning.allowed_cidrs y superar todas las demás reglas que el guardián aplica a un objetivo de sonda. Qué: el datagrama debe responder a la consulta recién enviada — para mDNS, desde el puerto 5353, con el bit de respuesta activo y el identificador de transacción impredecible que generó este agente; para SSDP, una respuesta M-SEARCH HTTP 200 que lleve tanto ST como USN, nunca un NOTIFY no solicitado.

Todavía no está en un binario publicado. Si ejecuta 0.1.3-ga o una versión anterior, trate los resultados de service_discovery como pistas no autenticadas: son atribuibles a quien envió el paquete, que no es necesariamente el dispositivo nombrado. Las demás sondas no se ven afectadas — registran lo que devolvió una conexión abierta por este agente.

Esta versión no tiene ningún techo configurable de memoria o CPU

A diferencia de bitcollector, bitscanner no tiene una clave max_memory_mb / max_cpu_percent. Una comprobación de salud periódica registra las asignaciones y el número de goroutines, y avisa por encima de 50 MB y 1000 goroutines, y eso es todo. Acótelo con los controles de su propio sistema de arranque (MemoryMax=, CPUQuota= en una unidad de systemd) si necesita un límite duro en un host que importa.

Verificar esta versión​

El directorio de la versión de bitscanner incluye los binarios, SHA256SUMS, una firma cosign sobre ese manifiesto y — por cada binario — un .sig, una atestación .att y un .sbom.json. Verifique primero la firma sobre el manifiesto y después las sumas de comprobación:

cosign verify-blob --key cosign.pub --bundle SHA256SUMS.sig \
--insecure-ignore-tlog=true SHA256SUMS
# WARNING: Skipping tlog verification is an insecure practice […]
# Verified OK

sha256sum -c SHA256SUMS
# bitscanner-linux-amd64: OK
# bitscanner-linux-arm64: OK

Ambos comandos se ejecutaron contra los artefactos 0.1.3-ga distribuidos, igual que el control negativo: alterar un solo byte de SHA256SUMS hace que el mismo comando verify-blob salga con código distinto de cero y el mensaje invalid signature when validating ASN.1 encoded signature. Un paso de verificación que nunca ha visto fallar no es un paso de verificación.

Es la misma clave que el resto de la familia

bitscanner está firmado con la clave de la familia bits — la que usan bitcollector y bitenforcer, y la publicada en cosign.pub. Si ya verificó una versión de bits, ya tiene el ancla de confianza, y no debería haber cambiado. Por qué la comprobación de la clave es el paso que sostiene todo, incluida la comprobación cruzada de la huella, merece una lectura.

Desde 0.1.3-ga, bitscanner incluye el mismo conjunto de artefactos que el resto de la familia — un .sig, una atestación .att y un .sbom.json junto a cada binario, más un SHA256SUMS.sig sobre el manifiesto — así que todos los pasos de esa página se le aplican, incluidos los pasos 4 y 5. Las versiones anteriores solo incluían el manifiesto firmado; si está verificando 0.1.2-ga o una versión más antigua, esos dos pasos no tienen nada contra lo que comprobar.

Puede obtener la clave por DNS en lugar de por HTTPS

La clave pública completa se publica como registro TXT, lo que resulta útil en un script de instalación:

dig +short TXT _cosign-key.cert-ix.com | tr -d '"' | sed 's/.*key=//' \
| base64 -d | openssl pkey -pubin -inform DER -out cosign.pub

El DNS es un sistema distinto del servidor web, así que una clave obtenida de este modo y otra descargada del sitio son dos fuentes independientes que deben coincidir — que es exactamente la comprobación cruzada que le pide verificar sus descargas. El registro complementario _cosign.cert-ix.com lleva solo la huella, si únicamente quiere comparar eso.

Plataformas​

0.1.3-ga publica dos binarios firmados, y el hueco es deliberado:

PlataformaPublicadaPor qué
Linux amd64Sí
Linux arm64Sí
macOS amd64/arm64NoRetenida — ver abajo
Windows amd64NoRetenida — ver abajo

bitscanner es solo para Linux porque los lectores que hay debajo son implementaciones de Linux. Los dos registros que produce con todas las sondas desactivadas — neighbor_table y network_state — proceden de la caché ARP/NDP del kernel y de la tabla de rutas tal y como las expone Linux. Eso es lo que permite que la configuración por defecto informe de algo real poniendo cero paquetes en la red, y es la propiedad sobre la que se apoya todo el modelo de armado de dos interruptores.

macOS y Windows exponen la misma información, a través de interfaces completamente distintas. Portar esos lectores es un trabajo real, con su propia carga de pruebas, y no se ha hecho. Una compilación para esas plataformas funcionaría y luego informaría de una tabla de vecinos vacía en un host que sí tiene vecinos — indistinguible, para quien lea la salida, de un segmento tranquilo. Un resultado vacío que significa «no implementado aquí» es la salida más peligrosa que este agente podría producir, porque su razón de ser es decirle cuándo hay algo en la red que su inventario no explica.

Así que no hay compilación de macOS ni de Windows que descargar. Si necesita observar un segmento en el que solo hay hosts macOS o Windows, ponga bitscanner en cualquier host Linux conectado a él: informa sobre el segmento, no sobre sí mismo, así que un solo host Linux basta para cubrir el dominio de difusión.

Próximos pasos​

¿Te resultó útil esta página?