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 :
DOTNET_DiagnosticPorts=my_diag_port1
: (Windows) Le runtime se connecte au canal nommé\\.\pipe\my_diag_port1
.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
.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.DOTNET_DiagnosticPorts=/foo/tool1.socket,nosuspend
: (Linux et macOS) Cet exemple contient le modificateurnosuspend
. 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 avecnosuspend
, 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’environnementDOTNET_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.