Schlagwort: Netzwerk

Traceroute per C# 👍 👎

In früheren Beiträgen hatte ich bereits erläutert, wie man per C# auf eine Konsolenausgabe zugreifen und programmatisch einen Ping durchführen kann. Dieser Beitrag soll nun ein einfaches Tracerouting per C# nachbilden. Dazu implementieren wir im Folgenden eine einfache (und wie üblich auf das Wesentliche reduzierte) Klasse, welche die Funktionalität durch sukzessive Erhöhung des TTL-Wertes für schlichte Ping-Pakete umsetzt.
Klasse implementieren
01020304050607080910111213141516171819202122232425
public class Traceroute : IDisposable {    private static readonly byte[] buffer = new byte[] {        0x01, 0x03, 0x03, 0x07    };  // Daten zur Übertragung
private readonly Ping ping = new Ping();

public IEnumerable<PingReply> Send(string hostNameOrAddress, int timeout = 3000) { // Paket mit TTL=1 initialisieren PingOptions pingOptions = new PingOptions(1, false);
PingReply pingReply = null;
do { pingReply = this.ping.Send(hostNameOrAddress, timeout, Traceroute.buffer, pingOptions);
// TTL für nächsten Schritt inkrementieren pingOptions.Ttl++;
yield return pingReply; } while(pingReply.Status != IPStatus.Success); }
public void Dispose() => this.ping.Dispose();}
Die Verwendung gestaltet sich nun sehr einfach:
Klasse verwenden (exkl. Namensauflösung)
0102030405
using(Traceroute traceroute = new Traceroute()) {    foreach(PingReply pingReply in traceroute.Send("coders-online.net")) {        Console.WriteLine(pingReply.Address);    }}
Um die entsprechenden Hostnamen zu den jeweiligen IP-Adressen zu ermitteln, kann beispielsweise die Methode Dns.GetHostEntry(…) dienen:
Klasse verwenden (inkl. Namensauflösung)
0102030405060708091011
using(Traceroute traceroute = new Traceroute()) {    foreach(string hostNameOrAddress in traceroute.Send("coders-online.net").Select(pR => {        try {            return Dns.GetHostEntry(pR.Address).HostName;        } catch {            return pR.Address.ToString();        }    })) {        Console.WriteLine(hostNameOrAddress);    }}

Syslog-Nachrichten mit C# versenden 👍 👎

Syslog beschreibt einen Protokollierungsstandard. Dieser Beitrag soll die beispielhafte Implementierung eines C#-Clients aufzeigen. Dazu werden UDP-basierte Nachrichten im (älteren) BSD-Format nach RFC 3164 erzeugt.

In einem früheren Beitrag hatte ich bereits mein NAS von Synology erwähnt. Sofern ihr ebenfalls ein solches besitzt, könnt ihr dieses sehr einfach als Server einrichten und somit direkt für die Beispiele (und mehr) nutzen.
Syslog-Klasse implementieren
010203040506070809101112131415161718192021222324252627282930313233343536
public class Syslog : IDisposable {    private const int Facility = 1;  // user-level messages    private const int FacilityFactor = 8;
private readonly UdpClient udpClient;

public Syslog(string hostname = "localhost", int port = 514) { this.udpClient = new UdpClient(hostname, port); }
public void Send(Severity severity, string message, [CallerMemberName] string caller = null) { byte[] data = Encoding.UTF8.GetBytes(String.Format("<{0}>{1} {2} {3}", ((Syslog.Facility * Syslog.FacilityFactor) + (int) severity), DateTime.Now.ToString("MMM dd HH:mm:ss"), Dns.GetHostName(), ((!String.IsNullOrWhiteSpace(caller)) ? (caller + " ") : (String.Empty)) + message ));
this.udpClient.Send(data, data.Length); }
public void Dispose() => this.udpClient?.Dispose();

public enum Severity { Emergency, // [0] system is unusable Alert, // [1] action must be taken immediately Critical, // [2] critical conditions Error, // [3] error conditions Warning, // [4] warning conditions Notice, // [5] normal but significant condition Informational, // [6] informational messages Debug, // [7] debug-level messages } // https://tools.ietf.org/html/rfc3164}
Es handelt sich hierbei – wie üblich – um eine minimale Implementierung ohne Fehlerbehandlung, welche außerdem keine Konfiguration des Facility-Wertes ermöglicht. Die Verwendung gestaltet sich nun jedoch sehr einfach:
Syslog-Klasse verwenden
01020304
using(Syslog syslog = new Syslog("syslog.example.net")) {    syslog.Send(Severity.Notice, "Dies ist eine weniger interessante Meldung.");    syslog.Send(Severity.Warning, "Dies ist eine sehr interessante Meldung.", "MyApp");}

PHP-Funktionen in C# (noch nicht) als Programmbibliothek 👍 👎

Meine beispielhaften PHP-Funktionen in C# erfreuen sich gewisser Beliebtheit, sodass mich mittlerweile schon ein paar mal die Frage erreicht hat, ob ich diese nicht als Programmbibliothek zur Verfügung stellen möchte.

Aus technischer Sicht wäre das tatsächlich kein Problem und grundsätzlich sogar mit überschaubarem Aufwand automatisierbar. Ich habe daher auch selbst schon einmal mit dem Gedanken der Veröffentlichung als Paket gespielt, dennoch möchte ich erst einmal Abstand davon nehmen und zwar vor allem aus folgenden Gründen:
  • Design

    Die Umsetzung der Methoden (Bezeichner, Datentypen, Parameter) ist stark an PHP angelehnt, sprich ist soweit möglich identisch zu den gleichnamigen PHP-Funktionen. Diese Umsetzung widerspricht jedoch in nahezu allen Fällen in vielerlei Hinsicht den .NET-Guidelines für Programmbibliotheken und auch die Datentypen entsprechen oftmals nicht den bei C# für den jeweiligen Einsatzzweck üblichen.

  • Qualität

    Die Umsetzungen sollen einen Ansatz bzw. Tipps liefern, entsprechen jedoch in einigen Fällen nicht einer Qualität, die einen sofortigen und ungeprüften Einsatz in Produktionsumgebungen ermöglicht. Dies wäre für eine tatsächliche Veröffentlichung jedoch zwingend erforderlich. Darüber hinaus wären an einigen Stellen Optimierungen für den effizienten Einsatz in echten Projekten durchaus sinnvoll.

Dennoch stimme ich natürlich grundsätzlich zu, dass die Implementierungen einige praktische Funktionen anbieten, die in PHP durchaus üblich sind, in C# standardmäßig jedoch nicht ohne Weiteres zur Verfügung stehen. Daher werde ich an einer entsprechenden Programmbibliothek arbeiten, die ausschließlich solche Funktionalität in stabiler Qualität zur Verfügung stellt. Einen konkreten Zeitplan kann und möchte ich derzeit jedoch noch nicht nennen.

Zertifikat einer Adresse mit C# ermitteln 👍 👎

Manchmal möchte man gerne Zertifikate von Webseiten automatisiert abrufen. Im Rahmen eines Monitorings bietet es sich beispielsweise an, die Gültigkeitsdauer zu überwachen. Dazu eine beispielhafte Implementierung:
Zertifikat einer Webseite ermitteln
010203040506070809
public static X509Certificate2 GetCertificate(string hostName, int port = 443) {    using(TcpClient client = new TcpClient(hostName, port)) {        using(SslStream stream = new SslStream(client.GetStream())) {            stream.AuthenticateAsClient(hostName);
return new X509Certificate2(stream.RemoteCertificate); } }}
Die Implementierung ist dabei – wie üblich – auf das Wesentliche beschränkt; es findet keine umfassende Problembehandlung statt. Sofern die Methode in größerem Kontext zum Einsatz kommen soll, empfiehlt sich auf jeden Fall ein Blick auf die beteiligten Klassen TcpClient, SslStream und X509Certificate2 im MSDN.

Nun stehen uns diverse Informationen zur Verfügung; einige Beispiele zur Ausgabe auf der Konsole:
Methode verwenden und Informationen ausgeben
010203040506
X509Certificate2 certificate = GetCertificate("coders-online.net");
Console.WriteLine(certificate.Subject); // "CN=coders-online.net"
Console.WriteLine(certificate.NotBefore); // 30.04.2017 08:01:00Console.WriteLine(certificate.NotAfter); // 29.07.2017 08:01:00
Im Besonderen sei abschließend noch auf RemoteCertificateValidationCallback hingewiesen, mit welchem sich das Verhalten bei Zertifizierungsfehlern beeinflussen lässt.

HTTP-Statuscode einer Webseite mit C# ermitteln 👍 👎

Hin und wieder kann es – beispielsweise im Rahmen eines Monitorings - erforderlich sein, den HTTP-Statuscode einer Webseite zu ermitteln. Das lässt sich mit C# grundsätzlich bereits mit wenigen Zeilen lösen:
Hilfsmethode
01020304050607
public static HttpStatusCode GetHttpStatusCode(Uri uri) {    HttpWebRequest httpWebRequest = WebRequest.CreateHttp(uri);
using(HttpWebResponse webResponse = (HttpWebResponse) httpWebRequest.GetResponse()) { return webResponse.StatusCode; }}
In der Praxis möchte man vermutlich zumindest noch das Weiterleitungs- und Zwischenspeicherverhalten konfigurieren, daher bietet es sich an, unsere Methode entsprechend zu erweitern:
Hilfsmethode (erweitert)
010203040506070809101112131415
public static HttpStatusCode GetHttpStatusCode(    Uri uri,    bool allowAutoRedirect = false,    RequestCacheLevel requestCacheLevel = RequestCacheLevel.NoCacheNoStore) {    HttpWebRequest httpWebRequest = WebRequest.CreateHttp(uri);    {        httpWebRequest.AllowAutoRedirect = allowAutoRedirect;        httpWebRequest.CachePolicy = new RequestCachePolicy(requestCacheLevel);    }
using(HttpWebResponse webResponse = (HttpWebResponse) httpWebRequest.GetResponse()) { return webResponse.StatusCode; }}
Die Verwendung gestaltet sich nun sehr intuitiv:
Hilfsmethode verwenden
01020304
Uri uri = new Uri("https://ccc.coders-online.net/");
HttpStatusCode statusCode = GetHttpStatusCode(uri); // Found (302)statusCode = GetHttpStatusCode(uri, true); // OK (200)
Wenn ihr den Wert der HttpStatusCode-Aufzählung zu int konvertiert erhaltet ihr im Übrigen den entsprechenden numerischen Wert nach Definition des HTTP-Protokolls.

Projektverweise

Kategorien / Archiv  |  Übersicht RSS-Feed

Schlagworte

Suche