Comment bitmapper capture
Cette page décrit le pipeline réel de la commande capture : ce qu'elle ouvre, ce qu'elle
filtre, ce qu'elle retient, et ce que chaque réglage vous coûte.
Tout ce qui suit se passe sur l'hôte. Les paquets eux-mêmes n'en sortent jamais — ce qui en sort est un enregistrement de flux résumant chaque connexion suivie. Voir ce qui quitte l'hôte.
interfaces → BPF filter (kernel) → worker pool → connection tracker → flow record → platform
│ │
│ └→ une dernière
│ tentative d'attribution
├→ attribution de processus, réessayée sur
│ les paquets suivants avec backoff
└→ statistics (structured JSON log)
Choisir les interfaces
bitmapper interfaces liste ce sur quoi cet hôte peut capturer. Ensuite, soit vous les nommez,
soit vous n'en nommez aucune et laissez l'agent choisir :
capture:
interfaces: ["eth0", "eth1"] # empty = every interface that is up and not loopback
Avec capture.interfaces vide, l'agent capture sur toute interface qui est active et qui
n'est pas la boucle locale. Sur un hôte doté de plusieurs cartes réseau, d'un pont et
d'interfaces virtuelles de conteneurs, cela fait généralement plus que ce que vous vouliez — le
même paquet peut être vu plusieurs fois lorsqu'il traverse un pont. Nommez les interfaces qui
vous intéressent réellement.
capture.exclude_interfaces retire des noms de la liste que vous obtenez au final, quelle
qu'elle soit :
capture:
interfaces: [] # auto-detect: every interface up and non-loopback
exclude_interfaces: ["docker0", "veth0"]
Elle s'applique aussi bien à une liste capture.interfaces explicite qu'à l'ensemble
auto-détecté, et la correspondance est insensible à la casse, les espaces environnants étant
ignorés. C'est donc l'outil qu'il faut pour le cas courant : laisser l'agent trouver les
interfaces, puis soustraire les ponts et les interfaces virtuelles dont vous ne voulez pas de
doublons.
Filtrage : quatre clés, un seul filtre noyau
Quatre clés décident des paquets que bitmapper verra un jour, et les quatre sont compilées en une seule expression BPF remise à libpcap avant le démarrage de la capture. Tout ce qu'elles excluent est abandonné par le noyau — ce n'est pas retiré de la sortie après coup, ce n'est pas copié dans l'agent du tout.
| Clé | Défaut | Ce qu'elle apporte |
|---|---|---|
capture.filter | "" — aucun | Une expression BPF brute, reprise telle quelle, entre parenthèses |
capture.protocols | ["tcp", "udp"] | Une liste d'autorisation : (tcp or udp). N'accepte que tcp, udp, icmp, all |
capture.ports | [] — aucun | Une liste d'autorisation : (port 80 or port 443) |
capture.exclude_ports | [] — aucun | Une liste d'exclusion : not (port 22) |
Les clauses sont jointes par and, dans cet ordre. La configuration livrée avec bitmapper
(configs/bitmapper.yaml) fixe protocols: [tcp, udp] et exclude_ports: [22], ce qui se
compile en :
(tcp or udp) and not (port 22)
Renseignez les quatre et vous obtenez une seule expression — par exemple
filter: "host 10.0.0.1", protocols: [tcp], ports: [443], exclude_ports: [22] se compile
en (host 10.0.0.1) and (tcp) and (port 443) and not (port 22).
L'agent journalise l'expression compilée au démarrage dès qu'elle diffère de ce que vous avez
écrit dans capture.filter : vous pouvez donc relire exactement ce qui a été remis au noyau au
lieu de le déduire. Un port hors de l'intervalle 1–65535 dans l'une ou l'autre liste est refusé
au démarrage, plutôt que d'échouer plus tard à l'intérieur de libpcap.
Une version antérieure de cette page portait un avertissement intitulé « Trois clés de filtrage
qui ne sont lues par personne », qui indiquait que capture.protocols, capture.ports et
capture.exclude_ports étaient validées puis ignorées. C'était faux. Les trois sont
compilées dans le filtre BPF décrit ci-dessus et appliquées par le noyau.
L'erreur allait dans le sens qui vous coûte, et capture.exclude_ports est la raison de relire
votre configuration dès maintenant. La configuration livrée contient exclude_ports: [22] — « ne
pas capturer SSH » — et cette exclusion est réelle : les paquets SSH sont abandonnés avant
d'atteindre l'agent. Si vous avez lu l'ancien avertissement et supprimé cette clé comme du
poids mort, vous avez désactivé un contrôle de confidentialité qui fonctionnait et commencé à
collecter du trafic que vous aviez délibérément exclu. Rien ne vous en aurait averti, car du
point de vue de l'agent vous aviez simplement demandé davantage de trafic.
Le contre-exemple de l'ancien avertissement était lui aussi exactement inversé.
capture.ports: [443] ne capture pas tout. Avec les protocoles par défaut, cela se compile en
(tcp or udp) and (port 443) et capture uniquement le port 443 :
# This captures TCP/UDP port 443 and nothing else — the ports key is applied, in the kernel
capture:
ports: [443]
Le défaut est tcp + udp : ICMP n'est donc pas capturé
capture.protocols vaut par défaut ["tcp", "udp"] même si votre fichier de configuration ne
la mentionne jamais. Un hôte qui tourne avec une configuration d'origine ne voit donc jamais
ICMP, ICMPv6, SCTP, GRE, ESP ni AH : le noyau les abandonne, l'agent ne les reçoit jamais, et
aucun compteur n'enregistre ce qui a été écarté. Dans la sortie, une absence et un silence se
ressemblent exactement.
C'est un véritable angle mort si vous utilisez bitmapper pour voir des balayages ping, du trafic tunnelisé ou de l'IPsec. Pour le supprimer, demandez l'absence totale de contrainte de protocole :
capture:
protocols: ["all"]
Deux détails faciles à manquer :
protocols: ["icmp"]couvre les deux familles — cela se compile en(icmp or icmp6), si bien que demander ICMP ne vous donne pas discrètement l'IPv4 seul.- Il n'existe aucune valeur pour SCTP, GRE, ESP ou AH.
protocolsn'accepte quetcp,udp,icmpetall; toute autre valeur est refusée au démarrage avecinvalid protocol: … (valid: tcp, udp, icmp, all). S'il vous en faut un précisément, fixezprotocols: ["all"]et exprimez le protocole danscapture.filter.
capture.exclude_ports seule ne crée pas cet angle mort. Elle se rend en not (port 22), et
un test de port BPF est également vrai pour les paquets qui n'ont aucun port : exclure SSH
n'abandonne donc pas ICMP au passage. Seule la liste d'autorisation de protocoles fait cela.
Préférez le filtre le plus étroit, quelle que soit la clé qui l'exprime
BPF vaut d'être appris dans tous les cas. tcp and not port 22, port 443 or port 8443,
not net 10.0.0.0/8 — chacune est appliquée avant que le paquet ne vous coûte quoi que ce soit,
et capture.filter reste la seule clé capable d'exprimer des contraintes d'hôte, de réseau ou de
sens. Les trois clés-listes sont le raccourci lisible pour les cas protocole et port ; elles
aboutissent au même endroit.
Ce qui est réellement inerte ici, ce sont les options de journalisation
--log-level et --log-format ne font rienCette page désignait autrefois les clés de filtrage comme ce qui s'analyse sans avoir d'effet. Les réglages qui se comportent réellement ainsi sont les options de journalisation.
--log-level et --log-format sont déclarées sur la commande racine et apparaissent dans
--help avec les valeurs par défaut info et json, mais aucun code ne lit ni l'une ni
l'autre. Le journaliseur est un journaliseur zap de production figé, construit au démarrage
— JSON, niveau info — et aucune des deux options ne peut le changer. Passer --log-level debug
ne vous donne aucun détail supplémentaire ; passer --log-format console vous donne toujours du
JSON.
Les autres options de capture se comportent de la même façon. --interfaces, --filter,
--snaplen, --promiscuous, --buffer-size, --workers, --queue-size et --stats-interval
sont liées dans Viper sous leur nom d'option alors que la configuration est lue depuis des clés
imbriquées (capture.filter, capture.snaplen, performance.workers, …) : elles sont donc
analysées puis ignorées. --enable-grpc et --enable-http sont pires qu'ignorées : elles valent
true par défaut dans --help et décrivent des serveurs que cet agent
ne construit jamais — il n'y a aucun écouteur gRPC ou HTTP à
activer.
--config est la seule option qui change ce que fait l'agent. Mettez tout le reste dans le
fichier YAML.
Lire les paquets
| Clé | Défaut | Ce qu'elle fait |
|---|---|---|
capture.snaplen | 65535 | Octets capturés par paquet (validé de 0 à 65535) |
capture.promiscuous | true | Mode promiscuité |
capture.buffer_size | 104857600 | Tampon de capture du noyau, en octets |
capture.timeout | 100ms | Délai d'attente de lecture d'un paquet |
Snaplen est le levier qu'il vaut le plus la peine de baisser. bitmapper construit une carte des connexions — qui parle à qui, par quoi, en quelle quantité — et tout cela se trouve entièrement dans les en-têtes des paquets. Capturer la charge utile complète de 65535 octets copie dans la mémoire de l'agent des données applicatives que rien ici ne lit. Un snaplen de quelques centaines d'octets conserve tous les en-têtes dont le suivi a besoin et empêche purement et simplement la copie de la charge utile, ce qui est à la fois moins coûteux et une exposition bien moindre si l'hôte est compromis.
Le mode promiscuité fait accepter à la carte réseau des trames qui ne lui sont pas adressées. Sur un réseau commuté, cela ne rapporte guère que du broadcast et du multicast ; sur un port miroir/SPAN, c'est ce qui rend la capture utile tout court. Il exige aussi des privilèges élevés, et il vaut la peine de le désactiver lorsque vous ne voulez que les conversations propres à cet hôte.
Attribution de processus
capture:
enable_process_mapping: true
process_mapping_interval: 5s
Tout ce qui suit — l'attribution par flux, le rattrapage, l'inférence à partir des sockets en
écoute et le champ attribution — n'est pas publié. Cela ne figure pas dans 0.1.0-ga
(commit 64ebc64), qui reste le seul binaire publié. Lancez bitmapper version et comparez
avant de bâtir quoi que ce soit sur cette page.
Ce que fait le binaire que vous pouvez télécharger aujourd'hui. Lu dans le code au commit
64ebc64 :
- L'attribution est tentée une seule fois, à la création de la connexion, à partir d'un
instantané des tables de sockets qui peut avoir jusqu'à
process_mapping_intervald'ancienneté. Il n'y a aucune reprise, d'aucune sorte. - Il n'existe aucune inférence à partir des sockets en écoute, d'aucune sorte. Le code qui la
réalise n'existe pas à ce commit.
0.1.0-gane peut jamais émettrelistening_socket, ni jamais nommer un processus qu'il n'a pas trouvé sur la socket propre au flux. - La réponse est toujours enregistrée sur l'extrémité source.
destination_processn'est affecté nulle part dans cette version, il ne peut donc jamais apparaître dans un enregistrement exporté. - L'objet processus exporté porte
pid,name,executableetuser— et aucun champattribution.
La socket d'une connexion sortante ne peut pas figurer dans un instantané pris avant que cette
connexion n'existe : les flux de 0.1.0-ga ne portent donc souvent aucun processus. Mesuré sur
l'hôte de développement : 0 flux attribué sur 12. Attendez-vous à cela de la part de cette
version plutôt que d'y voir une erreur de configuration.
Ce que fait la prochaine version. La tentative est réessayée sur les paquets suivants du
flux, puis une dernière fois sur le chemin d'export ; les deux extrémités sont attribuées ; et
chaque objet processus porte un champ attribution indiquant si l'identité vient de la socket
propre au flux ou d'une socket en écoute. Cette inférence est encadrée par trois conditions :
l'extrémité doit être une adresse de cet hôte, un seul processus exactement doit être prouvé
détenteur de la socket en écoute, et le flux doit être en TCP.
C'est ce qui distingue une capture d'un simple vidage de paquets : une connexion suivie est rattachée aux PID, nom de processus, chemin de l'exécutable et utilisateur propriétaires de la socket, en lisant les tables de sockets de l'hôte.
L'attribution se fait par flux, et non par paquet, et elle est enregistrée du côté du flux
qui possède la socket — un enregistrement de flux peut donc porter source_process,
destination_process, ou aucun des deux. Sur un hôte qui est l'une des extrémités de la
conversation, l'autre extrémité est un pair distant dont le processus n'est pas sur cette
machine et ne le sera jamais ; une seule extrémité est censée être renseignée.
Elle est complétée après coup, pas résolue une seule fois
La première tentative d'attribution d'un flux a lieu à la création de la connexion, et elle échoue très souvent : la socket d'une connexion sortante ne peut pas figurer dans un instantané des tables de sockets pris avant que la connexion n'existe. La tentative est donc répétée :
- Sur les paquets suivants du flux, avec un backoff qui démarre à 100 ms et double jusqu'à un plafond de 30 s. Un flux qui n'a réellement aucune socket locale — du trafic que l'hôte ne fait que router — se stabilise ainsi à quelques recherches par minute plutôt qu'une par paquet.
- Sur le chemin d'export, avant la construction d'un enregistrement pour ce flux. Pour un flux déjà terminé, c'est sa seule chance restante : un aller-retour local peut durer bien moins d'une milliseconde, si bien que sa socket a disparu quelques microsecondes après son unique tentative sur le chemin des paquets.
process_mapping_interval n'est pas le réglage des flux non attribuésCette page décrivait auparavant un compromis dans lequel un intervalle court attribue plus
souvent les connexions éphémères et un intervalle long les perd. Ce n'est plus ainsi que
fonctionne l'attribution, et cela contredit désormais la configuration que l'agent livre —
configs/bitmapper.yaml affirme le contraire dans un commentaire sur cette même clé.
process_mapping_interval fixe le rafraîchissement planifié des tables de sockets. Ce n'est
plus la seule chose dont dépend l'attribution : une recherche qui manque l'instantané déclenche
une relecture à la demande des tables de sockets du noyau pour ce seul flux, et la tentative est
réessayée comme décrit ci-dessus. Baisser l'intervalle n'est pas le remède aux flux qui
arrivent non attribués, et l'augmenter ne vous coûte plus les flux courts d'autrefois.
Les connexions qui ne peuvent pas être attribuées sont tout de même suivies et exportées ; elles ne portent simplement aucune identité de processus. C'est une réponse correcte, pas une lacune — voir ci-dessous pourquoi elle est préférable à l'alternative.
Comment l'attribution a été faite : socket vs listening_socket
Chaque objet processus d'un enregistrement de flux exporté porte un champ attribution qui
indique comment cette identité a été déterminée. C'est un signal de confiance, et les deux
valeurs ne sont pas interchangeables :
"source_process": {
"pid": 41207,
"name": "curl",
"executable": "/usr/bin/curl",
"user": "deploy",
"attribution": "socket"
}
| Valeur | Comment elle a été déterminée | Jusqu'où lui faire confiance |
|---|---|---|
socket | Correspondance avec la socket propre à ce flux dans les tables de sockets de l'hôte, sur le quadruplet complet | Un fait. Ce processus détenait cette socket. |
listening_socket | Aucune socket n'a été trouvée pour ce flux. L'identité a été prise sur le processus en écoute sur cette adresse et ce port — et uniquement lorsque cette adresse est sur cet hôte, qu'un seul processus exactement est prouvé détenteur de la socket, et que le flux est en TCP | Une inférence, étiquetée comme telle. Encadrée, mais elle reste une affirmation plus faible que socket : voir la règle du propriétaire unique et TCP uniquement. |
La valeur la plus faible existe parce que l'alternative est de n'avoir rien du tout : un flux qui
vit quelques centaines de microsecondes est fermé bien avant qu'une lecture de /proc ne puisse
voir sa socket, et la socket en écoute est la seule chose qui lui survit. Elle mérite d'être
rapportée — mais elle ne doit pas se lire comme la même affirmation que socket.
Un consommateur qui traite les deux à l'identique tire une conclusion que l'agent n'a pas faite. Si vous construisez des alertes, des cartes de dépendances ou des politiques à partir des enregistrements de flux, branchez-vous sur ce champ.
Une version antérieure de cette page portait un bloc « danger » intitulé
« listening_socket est une inférence, et elle est aujourd'hui sur-appliquée ». Il avançait deux
affirmations précises — que l'inférence « n'est pas vérifiée contre l'hôte local », et qu'elle
« n'identifie pas quel processus en écoute » — et vous conseillait d'écarter purement et
simplement listening_socket pour toute extrémité qui n'est pas une adresse de l'hôte déclarant.
Ces deux affirmations sont fausses pour toutes les versions de bitmapper que vous pouvez vous procurer. Elles décrivaient un état interne corrigé avant toute publication :
- La version publiée
0.1.0-gan'a rien à sur-appliquer. Elle ne contient aucune inférence à partir des sockets en écoute et ne peut pas émettrelistening_socket. - La prochaine version vérifie ces deux points avant d'inférer. L'extrémité doit être une adresse de cet hôte — c'est ce qui empêche d'attribuer un flux sortant vers un pair distant à un processus local en écoute sur l'adresse joker — et un seul processus exactement doit être prouvé détenteur de cette socket en écoute, ce qui empêche de nommer l'un des frères d'un serveur qui pré-forke. Mesuré après le correctif, sur le même hôte et le même trafic que ceux qui avaient produit les fabrications : aucune attribution inventée, et chaque attribution effectivement produite par l'agent était juste.
Le conseil qui découlait de ces affirmations était un raisonnement juste appliqué à du code
qu'aucun client ne possède. listening_socket reste la plus faible des deux valeurs et mérite
toujours qu'on s'y branche — c'est une inférence, et elle est étiquetée comme telle — mais c'est
une inférence encadrée et non une inférence sans contrôle, et « l'écarter pour une extrémité
non locale » décrit désormais une règle que l'agent applique lui-même, avant que
l'enregistrement ne soit construit.
L'inférence est réservée à TCP : un flux UDP ne la porte donc jamais
listening_socket ne peut apparaître que sur un flux TCP. UDP n'a pas d'état LISTEN : une
socket UDP liée est indiscernable de celle d'un serveur, il n'y a donc rien à partir de quoi
inférer. L'inférence ne renvoie rien pour tout protocole autre que TCP, avant même d'examiner
quoi que ce soit d'autre.
Ce n'est pas une limite en attente d'être levée : c'est ce qui empêche une erreur précise. Un flux UDP peut très bien arriver sur un port sur lequel un serveur TCP écoute ; 53 et 853 sont le cas ordinaire. Sans cette vérification de protocole, le processus TCP en écoute d'un serveur DNS serait désigné comme propriétaire d'un trafic UDP sans rapport sur le même port.
Un flux UDP dont la socket propre n'a pas pu être trouvée est donc exporté sans processus, et
c'est le cas ordinaire pour UDP, non un cas rare : une requête DNS est terminée en bien moins
d'une milliseconde, sa socket a disparu avant qu'une lecture de /proc ne puisse l'atteindre, et
il n'existe aucune réponse plus faible sur laquelle se replier. Lisez un champ processus vide
sur un flux UDP comme la seule réponse honnête disponible pour ce protocole, et non comme un
défaut.
L'attribution directe n'est pas affectée par cette vérification de protocole. Les sockets UDP
sont lues dans les mêmes tables de sockets : un flux UDP dont la socket propre y figure avec un
quadruplet correspondant est attribué exactement comme un flux TCP, avec
"attribution": "socket". La nuance est qu'une socket UDP qui n'a jamais fait l'objet d'un
connect() n'a aucune adresse distante à déclarer : il n'y a donc aucun quadruplet à faire
correspondre — c'est l'autre raison pour laquelle l'attribution est plus clairsemée en UDP qu'en
TCP.
Une inférence exige une socket dont un seul processus est propriétaire
bitmapper ne prend une identité sur une socket en écoute que s'il peut prouver qu'un seul processus détient cette socket. Faute de cette preuve, le flux est exporté sans aucun processus plutôt qu'avec l'un des candidats.
Une socket en écoute détenue par plusieurs processus est le cas ordinaire, pas un cas exotique.
Mesuré sur l'hôte de développement : une socket nginx en écoute sur 0.0.0.0:443 — un seul
inode de socket — était détenue par 17 processus, ce à quoi ressemble tout serveur qui
pré-forke ses processus ouvriers. Une socket, dix-sept noms qui pourraient être inscrits dans
l'enregistrement. Les flux entrants vers une telle socket sont laissés sans attribution,
délibérément. Nommer l'un des dix-sept mettrait une supposition dans le même champ, et sous la
même forme, qu'une mesure.
Seul le rafraîchissement périodique complet de /proc peut produire cette preuve. Il
parcourt tous les processus : il peut donc établir qu'un inode de socket apparaît dans les
descripteurs d'un processus et dans ceux d'aucun autre. Le parcours à la demande, moins coûteux —
celui qu'une recherche manquée déclenche pour un seul flux — s'arrête au premier processus
détenant l'inode qu'il cherche : il peut prouver qu'un processus détient une socket, jamais qu'il
est le seul.
Un processus qui vient tout juste de se mettre en écoute ne sert donc pas de base à une inférence tant que le prochain rafraîchissement complet ne l'a pas couvert. Pendant un court moment après le démarrage d'un service, le trafic éphémère qui lui parvient peut apparaître sans aucune attribution de processus. Deux propriétés bornent cela, et toutes deux comptent au moment de juger si vous avez affaire à un défaut :
- Cela coûte de l'attribution, jamais de l'exactitude. Aucun processus erroné n'est produit pendant cette fenêtre ; le champ est vide, pas trompeur.
- Une socket en écoute survit largement à l'intervalle de rafraîchissement : c'est donc un effet de fenêtre de démarrage, pas un régime permanent. Une fois qu'un rafraîchissement complet a couvert un processus en écoute, il reste couvert aussi longtemps qu'il écoute.
La durée de cette fenêtre dépend de process_mapping_interval et de l'hôte : il n'y a pas de
chiffre unique à annoncer. La boucle de rafraîchissement est limitée en cycle de service —
parcourir /proc ne doit pas devenir à soi seul la charge d'une machine occupée — si bien qu'un
hôte à la table de processus volumineuse met plus de temps à terminer un rafraîchissement, et que
la fenêtre y est d'autant plus longue.
Rien de tout cela n'empêche un flux d'être capturé, suivi, compté ni exporté. Si vous avez sous
les yeux des enregistrements aux champs source_process et destination_process vides, lisez
les statistiques périodiques que journalise l'agent avant de conclure qu'il est en panne : des
compteurs de paquets et de connexions qui continuent d'avancer vous disent que la capture
fonctionne, et que ce que vous voyez est une attribution retenue.
Une mauvaise attribution est pire que pas d'attribution du tout : un flux non attribué est visiblement incomplet, tandis qu'un flux nommant le mauvais processus est une affirmation fausse et assurée qu'aucun consommateur ne peut détecter. C'est pourquoi un flux non attribué est laissé non attribué plutôt que deviné, et pourquoi l'inférence est étiquetée plutôt que silencieusement mélangée aux faits.
Le pipeline de workers
| Clé | Défaut | Contrainte |
|---|---|---|
performance.workers | 4 | ≥ 1 |
performance.queue_size | 100000 | ≥ 100 |
Les paquets sont remis à un pool de workers via une file bornée. Lorsque la file est pleine, le paquet est abandonné et le compteur d'abandons est incrémenté — l'agent ne bloque pas le chemin de capture pour suivre le rythme, parce que bloquer à cet endroit ferait déborder le tampon du noyau lui-même à la place.
Le compteur d'abandons est le chiffre à surveiller. Il apparaît dans les statistiques
périodiques, et un nombre d'abandons qui monte continuellement signifie que l'hôte voit passer
plus de trafic que cette configuration ne peut en traiter. Par ordre d'effet, les corrections
sont : resserrer le filtre noyau — au choix capture.filter, capture.protocols,
capture.ports ou capture.exclude_ports, puisque les quatre aboutissent dans la même
expression — puis baisser capture.snaplen, puis augmenter performance.workers.
Suivi des connexions
| Clé | Défaut | Contrainte |
|---|---|---|
performance.connection_table_size | 1000000 | ≥ 1000 — nombre maximal de connexions suivies avant éviction |
performance.connection_timeout | 5m | ≥ 1s — durée d'inactivité avant qu'une connexion ne soit ramassée |
performance.gc_interval | 1m | ≥ 1s — fréquence d'exécution du ramassage |
Le suivi apparie les deux sens d'une conversation en une seule connexion, exécute une machine
à états TCP (SYN_SENT → ESTABLISHED → … → CLOSED), et compte les paquets et les octets
par connexion.
Deux bornes le maintiennent fini, et ce sont deux mécanismes différents :
connection_table_sizeest un plafond strict. Au-delà, les entrées sont évincées — un hôte sous un déluge de connexions perd ses anciennes entrées plutôt que de grossir jusqu'à ce que le processus soit tué.connection_timeout+gc_intervalramassent les connexions devenues simplement inactives, que la table soit proche ou non de son plafond.
Un hôte qui établit beaucoup de connexions sortantes éphémères — un robot d'indexation web très actif, un exécuteur de CI — fera énormément tourner cette table. C'est le comportement voulu : une table bornée qui oublie vaut mieux qu'une table non bornée qui met fin au processus.
Statistiques
performance:
stats_interval: 10s # 0 disables the reporter entirely
Les compteurs de paquets, d'octets, d'abandons et de connexions sont écrits en JSON structuré via le journaliseur de l'agent selon cet intervalle. Ils constituent la preuve locale que la capture elle-même fonctionne, indépendamment du fait que l'export atteigne ou non la plateforme :
bitmapper capture --config /etc/bitmapper/config.yaml
La sortie est du JSON au niveau info et aucune option ne change cela — voir
les options de journalisation. Passez-la dans jq si vous la voulez lisible.
Surveillez le compteur d'abandons sur plusieurs intervalles. Zéro abandon et un nombre de connexions qui augmente signifient que le pipeline suit le rythme. Si le compteur de paquets reste à zéro sur un hôte que vous savez actif, vérifiez le filtre compilé que l'agent a journalisé au démarrage avant de soupçonner le chemin de capture : le défaut de protocole exclut plus de choses que la plupart des gens ne l'imaginent.
Ce qui quitte l'hôte, et ce qui n'en sort pas
Le trafic lui-même reste ici. Ce qui part est un enregistrement de flux — le résumé d'une connexion, pas son contenu. Pour être exact :
| Donnée | Où elle va |
|---|---|
En-têtes de paquets et charge utile jusqu'à snaplen | La mémoire de l'agent uniquement, le temps du traitement du paquet |
| Octets de charge utile des paquets | Nulle part. Jamais exportés, jamais écrits sur disque |
| Enregistrements de connexions, avec attribution de processus | La table des connexions en mémoire — et, sous forme d'enregistrements de flux, vers la plateforme en https |
Comment chaque attribution a été faite (socket / listening_socket) | Porté dans l'enregistrement de flux à côté du processus à partir de la prochaine version — voir confiance de l'attribution |
| La ligne de commande du processus | Nulle part. Délibérément exclue : les lignes de commande transportent couramment des identifiants en arguments |
| Compteurs de paquets/octets/abandons/connexions | La sortie de journal de l'agent lui-même |
| Enregistrement de l'agent et battement de cœur | Le plan de contrôle, en https |
Un enregistrement de flux porte les extrémités, les ports, le protocole, l'état de la connexion,
les compteurs d'octets et de paquets et — pour l'extrémité du flux qui possède la socket — le
PID du processus attribué, son nom, le chemin de son exécutable, son utilisateur et — à partir
de la prochaine version — le marqueur attribution indiquant comment cette identité a été
déterminée. C'est tout. Si vous devez en tenir un sous-réseau à l'écart,
output.filter.exclude_cidrs abandonne le flux à l'entrée — avant qu'un enregistrement ne soit
construit — et il porte sur l'une ou l'autre extrémité. Voir
la présentation.
Il n'existe aucune implémentation de storage.* ni aucun export vers fichier : rien n'est donc
persisté par l'agent. Quand le processus s'arrête, la table des connexions disparaît avec
lui.
Étapes suivantes
- Présentation de bitmapper — version, plateformes, privilèges, et la liste complète des clés qui sont validées mais ne font rien.
- bitscanner — la découverte tournée vers l'extérieur.
- Qu'est-ce que bits ? — comment les agents s'articulent.
Cette page vous a-t-elle été utile ?