Partager via


Ports de diagnostic

Cet article s’applique à : ✔️ .NET Core 3.1 et versions ultérieures

Le runtime .NET expose un point de terminaison de service qui permet à d’autres processus d’envoyer des commandes de diagnostic et de recevoir des réponses sur un canal IPC. Ce point de terminaison est appelé port de diagnostic. Les commandes peuvent être envoyées au port de diagnostic vers :

  • Capturez une image mémoire.
  • Démarrez une trace EventPipe.
  • Demandez la ligne de commande utilisée pour lancer l’application.

Le port de diagnostic prend en charge différents transports en fonction de la plateforme. Actuellement, les implémentations du runtime CoreCLR et Mono utilisent des canaux nommés sur des sockets de domaine Windows et Unix sur Linux et macOS. L’implémentation du runtime Mono sur Android, iOS et tvOS utilise TCP/IP. Le canal utilise un protocole binaire personnalisé. La plupart des développeurs n’interagissent jamais directement avec le canal et le protocole sous-jacents, ils utilisent plutôt des outils d’interface utilisateur graphique ou de ligne de commande qui communiquent pour lui. Par exemple, les outils dotnet-dump et dotnet-trace suppriment les commandes de protocole d’envoi pour capturer des images mémoire et démarrer des traces. Pour les développeurs qui souhaitent écrire des outils personnalisés, le package NuGet Microsoft.Diagnostics.NETCore.Client fournit une abstraction d’API .NET du transport et du protocole sous-jacents.

Considérations relatives à la sécurité

Le port de diagnostic expose des informations sensibles sur une application en cours d’exécution. Si un utilisateur non approuvé accède à ce canal, il peut observer l’état détaillé du programme, y compris les secrets en mémoire, et modifier arbitrairement l’exécution du programme. Sur le runtime CoreCLR, le port de diagnostic par défaut est configuré pour être accessible uniquement par le compte d’utilisateur qui a lancé l’application ou par un compte disposant d’autorisations super utilisateur. Si votre modèle de sécurité n’approuve pas d’autres processus avec les mêmes informations d’identification de compte d’utilisateur, vous pouvez désactiver tous les ports de diagnostic en configurant la variable d’environnement DOTNET_EnableDiagnostics=0. Ce paramètre vous empêchera d’utiliser des outils externes tels que le débogage .NET ou l’un des outils de diagnostic dotnet-*.

Remarque

.NET 6 se normalise sur le préfixe DOTNET_ au lieu de COMPlus_ pour les variables d’environnement qui configurent le comportement au moment de l’exécution de .NET. Toutefois, le préfixe COMPlus_ continuera à fonctionner. Si vous utilisez une version précédente du runtime .NET, vous devez tout de même utiliser le préfixe COMPlus_.

Port de diagnostic par défaut

Sur Windows, Linux et macOS, le runtime dispose d’un port de diagnostic ouvert par défaut sur un point de terminaison connu. Il s’agit du port auquel les outils de diagnostic dotnet-* se connectent automatiquement lorsqu’ils n’ont pas été configurés explicitement pour utiliser un autre port. Le point de terminaison est le suivant :

  • Windows : canal nommé \\.\pipe\dotnet-diagnostic-{pid}
  • Linux et macOS : socket de domaine Unix {temp}/dotnet-diagnostic-{pid}-{disambiguation_key}-socket

{pid} est l’ID de processus écrit en décimal, {temp} est la variable d’environnement TMPDIR ou la valeur /tmp si TMPDIR n’est pas défini/vide, et {disambiguation_key} est l’heure de début du processus écrite en décimal. Sur macOS et NetBSD, l’heure de démarrage du processus est le nombre de secondes depuis l’époque UNIX. Sur toutes les autres plateformes, il s’agit du nombre de jiffies depuis l’heure de démarrage de la machine.

Interrompre le runtime au démarrage

Par défaut, le runtime exécute du code managé dès son démarrage, que des outils de diagnostic se soient connectés ou non au port de diagnostic. Parfois, il est utile que le runtime attende la connexion d’un outil de diagnostic avant d’exécuter du code managé pour observer le comportement initial du programme. Lorsque la variable d’environnement DOTNET_DefaultDiagnosticPortSuspend=1 est définie, le runtime attend la connexion d’un outil au port par défaut. Si aucun outil n’est attaché au bout de plusieurs secondes, le runtime imprime un message d’avertissement dans la console indiquant qu’aucun outil n’est attaché.

Configurer des ports de diagnostic supplémentaires

Remarque

Cela fonctionne uniquement pour les applications exécutant .NET 5 ou version ultérieure.

Les runtimes Mono et CoreCLR peuvent utiliser des ports de diagnostic configurés et personnalisés dans le rôle connect. Mono prend également en charge les ports TCP/IP personnalisés dans le rôle listen, quand il est utilisé avec dotnet-dsrouter sur Android ou iOS. Ces ports personnalisés s’ajoutent au port par défaut qui reste disponible. Voici des raisons courantes pour lesquelles les ports personnalisés sont utiles :

  • Sur Android, iOS et tvOS, il n’y a pas de port par défaut. La configuration d’un port est donc nécessaire pour utiliser les outils de diagnostic.
  • Dans les environnements avec des conteneurs ou des pare-feu, vous pouvez configurer une adresse de point de terminaison prévisible qui ne varie pas en fonction de l’ID de processus comme le fait le port par défaut. Ensuite, le port personnalisé peut être explicitement ajouté à une liste verte ou traitée par proxy sur une limite de sécurité.
  • Pour les outils de supervision, il est utile de faire écouter l’outil sur un point de terminaison, et le runtime tente activement de s’y connecter. Cela évite d’avoir besoin de l’outil de supervision pour interroger en continu les nouvelles applications qui démarrent. Dans les environnements où le port de diagnostic par défaut n’est pas accessible, cela permet également de ne pas avoir à configurer le moniteur avec un point de terminaison personnalisé pour chaque application supervisée.

Dans chaque canal de communication entre un outil de diagnostic et le runtime .NET, un côté doit être l’écouteur et attendre que l’autre côté se connecte. Le runtime peut être configuré pour jouer le rôle connect pour n’importe quel port. (Le runtime Mono peut aussi être configuré pour agir dans le rôle listen pour n’importe quel port.) Les ports peuvent également être configurés indépendamment pour s’interrompre au démarrage, en attendant qu’un outil de diagnostic émette une commande de reprise. Les ports configurés pour se connecter répètent indéfiniment leurs tentatives de connexion si le point de terminaison distant n’écoute pas ou si la connexion est perdue. Toutefois, l’application ne suspend pas automatiquement le code managé en attendant d’établir cette connexion. Si vous souhaitez que l’application attende qu’une connexion soit établie, utilisez l’option Interrompre au démarrage.

Les ports personnalisés sont configurés à l’aide de la variable d’environnement DOTNET_DiagnosticPorts. Cette variable doit être définie sur une liste de descriptions de port délimitée par des points-virgules. Chaque description de port est composée d’une adresse de point de terminaison et de modificateurs facultatifs qui contrôlent le rôle connect ou listen du runtime, et décident s’il faut interrompre le runtime au démarrage. Sur Windows, l’adresse du point de terminaison est le nom d’un canal nommé sans le préfixe \\.\pipe\. Sur Linux et macOS, il s’agit du chemin complet d’un socket de domaine Unix. Sur Android, iOS et tvOS, l’adresse est une adresse IP et un port. Par exemple :

  1. DOTNET_DiagnosticPorts=my_diag_port1 : (Windows) Le runtime se connecte au canal nommé \\.\pipe\my_diag_port1.
  2. DOTNET_DiagnosticPorts=/foo/tool1.socket;foo/tool2.socket : (Linux et macOS) Le runtime se connecte aux sockets de domaine Unix /foo/tool1.socket et /foo/tool2.socket.
  3. DOTNET_DiagnosticPorts=127.0.0.1:9000 : (Android, iOS et tvOS) Le runtime se connecte à l’adresse IP 127.0.0.1 sur le port 9000.
  4. DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend : (Linux et macOS) Cet exemple contient le modificateur nosuspend. Le runtime tente de se connecter au socket de domaine Unix /foo/tool1.socket qu’un outil externe crée. D’autres ports de diagnostic entraînent normalement l’interruption du runtime au démarrage lorsqu’une commande de reprise est attendue, mais avec nosuspend, le runtime n’attend pas.

La syntaxe complète d’un port est address[,(listen|connect)][,(suspend|nosuspend)]. connect est la valeur par défaut si ni connect ni listen ne sont spécifiés (et listen est pris en charge seulement par le runtime Mono sur Android ou iOS). suspend est la valeur par défaut si suspend et nosuspend ne sont pas spécifiés.

Utilisation dans les outils de diagnostic dotnet

Les outils tels que dotnet-dump, dotnet-counters et dotnet-trace prennent tous en charge les verbes collect ou monitor qui communiquent avec une application .NET via le port de diagnostic.

  • Lorsque ces outils utilisent l’argument --processId, l’outil calcule automatiquement l’adresse de port de diagnostic par défaut et s’y connecte.
  • Lorsque vous spécifiez l’argument --diagnostic-port, l’outil écoute à l’adresse donnée et vous devez utiliser la variable d’environnement DOTNET_DiagnosticPorts pour configurer la connexion de votre application. Pour obtenir un exemple complet avec dotnet-counters, consultez Utilisation du port de diagnostic.

Utiliser ds-router pour proxyser le port de diagnostic

Tous les outils de diagnostic dotnet-* doivent se connecter à un port de diagnostic qui est un canal nommé local ou un socket de domaine Unix. Mono s’exécute souvent sur du matériel isolé ou dans des émulateurs qui ont besoin d’un proxy sur TCP pour devenir accessibles. L’outil dotnet-dsrouter peut proxyser un canal nommé local ou un socket de domaine Unix vers TCP afin de pouvoir utiliser les outils dans ces environnements. Pour plus d’informations, consultez dotnet-dsrouter.