IIS: App_Offline.htm – .NET Webapplikation offline nehmen

Will man eine .NET Webapplikation mit einer neueren Version ersetzen, sollte man diese offline nehmen. Ansonsten werden die HTTP-Anfragen munter weiter bedient und dies führt dann oft zu unschönen Fehlermeldungen.

Eine elegante Methode ist die Datei „App_Offline.htm“. Wird ins Root-Verzeichnis der .NET Webapplikation eine Datei mit dem Namen „App_Offline.htm“ kopiert, werden sämtliche neuen HTTP-Anfragen mit dem Inhalt dieser Datei beantwortet und zugleich wird die Webapplikation sowie deren „Application Domain“ beendet.

Nach den Wartungsarbeiten oder dem Updaten wird die Datei „App_Offline.htm“ einfach wieder gelöscht. Ist die Datei nicht mehr vorhanden, werden sämtliche Anfragen wieder wie gewohnt beantwortet.

Schritte um eine .NET Webapplikation zu aktualisieren:

  1. App_Offline.htm ins Root-Verzeichnis kopieren
  2. ein Backup der Dateien erstellen
  3. Webapplikation updaten
  4. App_Offline.htm aus dem Root-Verzeichnis löschen

Nützliche Links

Vipin Agarwal: App_Offline.htm, taking site down for maintenance
ScottGu’s Blog: App_Offline.htm
stackoverflow.com: explain the differences, in IIS, between application pools, worker processes and app domains

OWASP: Rangliste der zehn grössten Risiken für Webanwendungen

Das Open Web Application Security Project (OWASP) ist eine Non-Profit-Organisation mit dem Ziel, die Sicherheit von Anwendungen und Diensten im World Wide Web zu verbessern. [1]

Dazu veröffentlicht OWASP eine Rangliste mit den zehn schwerwiegendsten Sicherheitsschwachstellen von Webanwendungen. Auf Platz 1 ist „Injection“, das Einschleusen von fremdem Code.

Passend zum Thema Injection musste ich erst kürzlich feststellen, dass es immer noch Webanwendungen gibt bei denen SQL-Injection ohne grosse mühe funktioniert.

SQL-Injection

Das erste Mal aufmerksam auf das Thema SQL-Injection wurde ich im Jahr 2000. In dieser Zeit waren sehr viele Webanwendungen davon betroffen. Auch bekannte online Shops waren vor dieser Problematik nicht gefeit. Dies war auch die Zeit des „Quick-Login“, oft genügte die Eingabe des Prozentzeichens (%) bei Passwort und Benutzername und man wurde mit dem erst besten Login angemeldet.

Inzwischen sollte eigentlich jeder Programmierer, der mit Datenbanken arbeitet, wissen was SQL-Injection ist und was es für geeigneten Gegenmassnahmen gibt. Sei dies die Verwendung von Stored Procedures, Prepared Statements oder dem Maskieren von Metazeichen. Auch sollte die Webanwendung Benutzereingaben genau prüfen und nur korrekte Werte akzeptieren. Hat man keinen Einfluss auf die Webanwendung, kann auch ein WAF (Web Application Firewall) eingesetzt werden.

Aber leider musste ich schon des Öfteren feststellen, dass es auch im 2013 Programmierer gibt, die sich nicht mit diesem Thema beschäftigen. Im Glauben ein Projekt schneller fertigzustellen wird dies einfach ignoriert. Auch Begründungen wie: „Diese Anwendung ist nur für den internen Gebrauch…“ oder „Unsere Daten sind doch nicht interessant für einen Hacker…“.

Und was passiert bei einem „DROP TABLE;“ oder „WAITFOR DELAY ‚0:30:00‘–“ usw.?

Ich glaube diese Programmierer haben noch nicht bemerkt, das Programmieren viel mehr Spass macht, wenn man versucht „sicheren“ und „sauberen“ Code zu schreiben.

Nützliche Links:

Wikipedia: OWASP [1]
Wikipedia: WAF
Anfälligkeit von Webapplikationen durch SQL-Injection prüfen, mit Hilfe von sqlmap
Clean Code Developer
The OWASP Cheat Sheet Series – web application security

C# .NET: Erstellen einer COM-Komponente

COM-Komponenten können sowohl in Form von Laufzeitmodulen (DLL’s) als auch als ausführbare Programme implementiert werden. Damit die Funktionen der Komponente für den COM-Client sichtbar sind, müssen folgende Punkte befolgt werden:

  • Die Klasse muss „public“ sein
  • Properties, Methoden und Events müssen „public“ sein
  • Properties und Methoden müssen im Klassen-Interface definiert sein
  • Events müssen im Event-Interface definiert sein

Erstellen:

Projekteinstellungen
Projekteinstellungen
  1. Zuerst muss das COM-Interface definiert werden (Definition der Schnittstelle)
  2. Als zweiter Schritt muss die Klasse implementiert werden. Die Klasse muss den Namespace „InteropServices“ importieren (using System.Runtime.InteropServices;)
  3. In den Projekteinstellungen unter „Erstellen“ muss die Option „Für COM-Interop registrieren“ sowie unter „Anwendung->Assemblyinformationen“ die Option „Assembly COM-sichtbar machen“ aktiviert werden
  4. Am Schluss muss das Assembly noch signiert werden. Dies kann in den Einstellungen unter „Signierung“ gemacht werden. Dazu wird eine neue Schlüsseldatei erstellt

3. „Für COM-Interop registrieren“ Komponente lokal installieren
3. „Für COM-Interop registrieren“ Komponente lokal installieren
3. „Assembly COM-sichtbar machen“
3. „Assembly COM-sichtbar machen“
4. Assembly signieren
4. Assembly signieren


COM-Komponente registrieren:

Um die COM-Komponente auf einem anderen Gerät zu verwenden muss diese zuerst registriert werden. Dazu wird das Programm „RegAsm.exe“ verwendet.


RegAsm.exe sCOMDemo.dll /codebase /tlb:sCOMDemo.tlb

COM-Komponente deregistrieren:

Bevor eine neue Version installiert wird, sollte die alte Version unregistriert werden.


RegAsm.exe sCOMDemo.dll /unregister

Beispiel Code:

Klassendiagramm
Klassendiagramm

Das Interface:



namespace sCOMDemo
{
    public interface IsCom
    {
        string helloWorld();
    }
}

Die Klasse:


using System.Runtime.InteropServices;

namespace sCOMDemo
{
    public class sCom:IsCom
    {
        public string helloWorld()
        {
            return "hello world!";
        }
    }
}

Verwendung der COM-Komponente unter VBScript:


Dim objDemo: set objDemo = createObject("sCOMDemo.sCom")
wscript.echo objDemo.HelloWorld()

wscript - Ausgabe
Nützliche Links:

Component Object Model (COM)
COM Interop Part 1: C# Client Tutorial
System.Runtime.InteropServices Namespace
How to: Create COM Wrappers
How to: Raise Events Handled by a COM Sink
Creating a COM Visible C# Component
Assembly Registration-Tool (Regasm.exe)
Wikipedia: COM

Windows: Alternative Datenströme (ADS)

Mit Hilfe von sogenannten alternativen Datenströme (ADS), können im Dateisystem NTFS, zusätzliche Informationen / Daten zu den Hauptdaten gespeichert werden. Da Windows die alternativen Datenströme nicht standardmässig anzeigt, werden diese auch verwendet um Malware oder Daten zu verstecken.

Erstellen eines ADS

Ein ADS wird mit einem Doppelpunkt an eine Datei angehängt: „Dateiname:AD-Streamname“

Anhängen eines Textes:


echo "Ich bin nicht sofort Sichtbar" > normaler.txt:unsichtbar.txt

Schauen wir mit dem Windows-Explorer das Verzeichnis an, in dem die Datei liegt, können wir nur die Datei „normaler.txt“ sehen. Diese Datei scheint jedoch keine Daten zu enthalten, da sie 0 KB gross ist.

normaler.txt
normaler.txt

Anhängen einer Datei:

Es können beliebige Binär- Asciidateien gespeichert werden. In diesem Beispiel wird die „netcat.exe“ angehängt.


type nc.exe > normaler.txt:security.exe

Ausführen einer Datei im ADS

In den meisten Beispielen, im Internet, wird die angehängte Exe-Datei direkt mit dem Befehl start ausgeführt:


start c:\tmp\ads\normaler.txt:security.exe

Leider funktioniert dies bei mir unter Windows 7 nicht. Wird aber ein Systemlink auf diesen ADS gemacht, kann Netcat ausgeführt werden. Daher erstelle ich zuerst ein Systemlink auf diesen ADS:


mklink happy.exe c:\tmp\ads\normaler.txt:security.exe

Jetzt kann mit dem Befehl start Netcat ausgeführt werden:


start c:\tmp\ads\happy.exe

Anzeigen von AD-Streams

Windows 7 / Windows Vista:

Ab Windows Vista wurde der Befehl dir mit dem Parameter „/R“ erweitert. Dieser listet alle dazugehörigen AD-Streams einer Datei auf.

dir /R
AD-Stream
Auflisten von AD-Streams

Windows XP / Windows 2000:

Bei den früheren Windows Versionen musste ein zusätzliches Tool verwendet werden um die AD-Streams anzuzeigen. Dabei kann das Command-Line Tool Streams 1.56 verwendet werden.

Auflisten von AD-Streams mit dem Command-Line Tool Streams
Auflisten von AD-Streams mit dem Command-Line Tool Streams

Als alternative kann auch die GUI-Basierte Anwendung AlternateStreamView v1.35 verwendet werden.

AlternateStreamView v1.35
AlternateStreamView v1.35

Nützliche Links

ADS Wikipedia
Dissecting NTFS Hidden Streams
Alternate Data Streams als Versteck für Schädlinge

Command-Line
mklink Dokumentation
type Dokumentation
start Dokumentation
echo Dokumentation
dir Dokumentation

Tools
AlternateStreamView v1.35
Streams 1.56

Ubuntu: Server Edition Installation upgraden

Eine Ubuntu Server Installation kann mit dem „do-release-upgrade utility“ auf die nächsthöhere Version aktualisiert werden. Die Verwendung dieses Utility wird in der Ubuntu Dokumentation als die empfohlene Methode beschrieben.

Bevor man die Aktualisierung auf einen neueren Release beginnt, sollte man sicherstellen, dass das System auf dem neusten Stand ist.

Dazu holt man zuerst die neusten Paketinformationen:

>sudo apt-get update

Als Nächstes werden die Pakete aktualisiert:
>sudo apt-get dist-upgrade

Nun kann mit dem Release-Upgrade begonnen werden:

>do-release-upgrade

Jetzt folgt man nur noch den Anweisungen auf dem Bildschirm. Werden Konfigurationdateien geändert sollte man die Änderungen gut prüfen oder eben die eigenen behalten.

Nützliche Links

apt-get Dokumentation
Upgrading ubuntu
Upgrade Lucid auf Precise

pfSense: Konfigurieren eines transparenten Squid Web Proxy mit Multi-WAN Links

Wichtiger Hinweis zur pfSense Version 2.1:

04.02.2014: Es scheint das Load Balancing mit aktiviertem Squid bei vielen gar nicht mehr funktioniert. Die Failover-Konfiguration funktioniert jedoch ohne Probleme mit dem Squid Proxy. Siehe pfSense Forum

Um einen Standort mit redundanter Internetanbindung auszurüsten, eignet sich die Firewall-Distribution pfSense 2.x perfekt. Die Distribution unterstützt standardmässig Load Balancing und Failover mit mehreren WAN-Anschlüssen. Mehr dazu findet man im pfSense Wiki unter Multi-WAN.

Wird der Web Proxy Squid nicht auf dem gleichen Host betrieben, sondern hinter der Firewall, bietet auch diese Konfiguration keine grossen Probleme. Den das LoadBalancing und Failover funktioniert gut.

In diesem Beitrag werde ich auf die Konfiguration eingehen, bei der Squid auf dem selben Host läuft. Im Web findet man sehr viele Beiträge zu diesem Thema. Es scheint für diese Lösung keine Standardkonfiguration zu geben. Je nachdem ob man zusätzliche Pakete installiert hat, kann die Konfiguration abweichen. Was bei einer Installation läuft, muss nicht zwangsläufig bei einer anderen funktionieren. Ich werde hier einfach meine Erfahrungen und Ergänzungen vorstellen, die ich beim Sichten der verschiedenen Anleitungen gemacht habe, bis ich eine funktionierende Konfiguration hatte. Dieser Beitrag soll kein vollständiges „Howto“ sein, sondern nur die wichtigen Punkte hervorheben, die mir geholfen haben.

Schritt 1: Multi-WAN

Als erster Schritt muss die Multi-WAN Konfiguration, wie in der Anleitung beschrieben, erstellt und ohne Proxy getestet werden. Dabei sollten zusätzlich folgende wichtige Punkte beachtet werden:

Gateways Einstellungen

Anmerkung zur pfSense Version 2.0.3:

Unter „System->Routing->Gateways“ sollte kein Gateway als „Default-Gateway“ markiert sein. Es scheint als verwendet pfSense standardmässig den Gateway des WAN-Interfaces als „Default-Gateway“. (Beim Versuch das WAN2-Interface als „Default-Gateway“ zu definieren funktionierte die Abfrage über Squid nicht mehr.)

Gateways Einstellungen
Gateways Einstellungen

Anmerkung zur pfSense Version 2.1:

Mit der Version 2.1 scheint das Definieren eines „Default-Gateway“ auch bei mir wieder zu Funktionieren. Daher sollte unter „System->Routing->Gateways“ ein Gateway als „Default-Gateway“ markiert werden.

Unter „Diagnostics->Routes“ kann die Routingtabelle eingesehen werden und dort findet man auch den Eintrag des „Default-Gateway“.

Routingtabelle
Routingtabelle

Ein weiterer wichtiger Punkt ist die Einstellung „Allow default gateway switching“ welche aktiviert werden sollte. So wird beim Ausfall des WAN-Interfaces automatisch ein anderes Interface als „Default-Gateway“ eingesetzt. Dies kann unter „System->Advanced->Miscellaneous“ geändert werden.

Load Balancing Einstellungen
Load Balancing Einstellungen

DNS-Server Einstellungen

Bei den DNS-Server Einstellungen sollten pro Gateway mindestens ein DNS-Server eingetragen werden. Was auch nicht schaden kann, ist ein öffentlicher DNS-Server der über alle Interfaces erreichbar ist. Hier in diesem Beispiel wurde zusätzlich ein DNS-Server von Google angegeben. Eintragen kann man diese unter „System->General Setup“.

DNS-Server Einstellungen
DNS-Server Einstellungen

Firewall Rules

Zusätzlich zu den Firewall-Regeln die den Datenverkehr über den gewünschten Gateway oder die Gatewaygruppe leiten, muss noch eine eigene Regel für den DNS-Traffic des Squid Proxy erstellt werden.

DNS-Floating Rule
DNS-Floating Rule

Details der Floating-Rule:

  • Interfaces: Wan & Wan2
  • Direction: out
  • Protocol: TCP/UDP
  • Source: any
  • Destination: any
  • Destination Port: 53 (DNS)
  • Gateway: Wan1BalanceWan2 (Definierte Gatewaygruppe)

Schritt 2: Squid Konfiguration

Wurde die Multi-WAN Konfiguration erfolgreich getestet (Unterbruch simulieren der verschiedenen WAN’s, surfen funktioniert noch), kann mit der Konfiguration des Proxy-Server’s angefangen werden.

Dazu werden unter „Services->Proxy Server“ die Interfaces ausgewählt bei denen die HTTP-Abfrage über den Proxy Server laufen sollen. Anmerkung: In manchen Anleitungen steht, man soll das „Loopback“ Interface auch auswählen. Dies wird jedoch in dieser Konfiguration nicht verwendet, sondern führt nur zu Fehler bei den Proxy abfragen.

Squid Einstellungen Interfaces
Squid Einstellungen Interfaces

Als letzte Einstellung muss unter „Custom Options“ die Zeile „tcp_outgoing_address 127.0.0.1;“ eingetragen werden. Mit diesem Befehl schickt Squid sämtliche TCP-Anfragen wieder zurück an pfSense, wo dann die Pakete an den richtigen Gateway verschickt werden.

Squid Einstellung Custom Options
Squid Einstellung Custom Options

Zum Schluss

Nach diesen Einstellungen sollten nun alle HTTP-Anfragen die über den Squid Web Proxy gehen, auch vom Load Balancing und Failover Mechanismus von pfSense profitieren. Diese Konfiguration habe ich nun seit einiger Zeit im Einsatz und es scheint gut zu funktionieren.

Bei Webapplikationen welche die Anmeldeinformationen an eine IP knüpfen, kann das Load Balancing zu Probleme führen. Nach dem Anmelden wird man kurze Zeit später wieder abgemeldet. Das ist immer dann der Fall, wenn die Verbindung neu über einen anderen Gateway geht. Um diese Problematik zu minimieren, kann man eigene Floating-Rules definieren oder man verwendet die Option „Use sticky connections“. Diese Option sorgt dafür, dass eine bestehende Verbindung immer über denselben Gateway geleitet wird. Aktivieren kann man sie unter „System->Advanced->Miscellaneous“. (Siehe Screenshot „Load Balancing Einstellungen“)

Nützliche Links

pfSense: Erweitern mit Zusatzpaketen (Erweiterungen)
pfSense doc: Multi-WAN
Google Public DNS
pfSense 2.0.2 Multiwan will filter ssl (squid+squidGuard+Lightsquid)
PDF: Set-up transparent Squid Web Proxy with failover on multi-WAN links
default gateway switching concern
New HOWTO: pfSense Squid Web Proxy with multi-WAN links
pfSense Multi-WAN – How to really make it work
Öffentliche Nameserver in der Schweiz

Windows 7: Arbeitsspeicher prüfen (RAM-Check)

Startmenü Arbeitsspeicher prüfen
Startmenü Arbeitsspeicher prüfen
Hat man den Verdacht das etwas mit dem Arbeitsspeicher nicht mehr in Ordnung ist, da der PC plötzlich langsamer ist oder verschiedene Programme einfach nicht mehr ohne Probleme laufen, bietet Windows 7 ein kleines Tool, um den Arbeitsspeicher zu testen.

Am einfachsten kann dieses Tool über die Suchmaske im Startmenü ausgeführt werden. Dazu sucht man nach „arbeitsspeich“.

Wurde das Tool gestartet, legt man fest, wann die Arbeitsspeicher überprüfung ausgeführt werden soll, sofort oder erst beim nächsten Starten des Computers. Wählt man sofort, wird der Computer für die Ausführung neu gestartet.

Programmfenster Computer auf Speicherprobleme prüfen
Programmfenster Computer auf Speicherprobleme prüfen

Alternative Memtest86+

Möchte man etwas ausführlichere Tests machen, kann dafür das gratis Programm Memtest86+ verwendet werden. Memtest86+ ist ein Fork des schon länger existierenden Memtest86. Auf der Downloadseite von Memtest86+ findet man vorgefertigte ISO-Images für Boot CD’s und ein Auto-Installer für USB-Sticks.

Memtest86+
Memtest86+

Beide Programme (Memtest86+ und Memtest86) und viele weitere nützliche Tools findet man auch auf der „Ultimate Boot CD“.

Ultimate Boot CD
Ultimate Boot CD

Nützliche Links

Wikipedia: Arbeitsspeicher (RAM)
Memtest86+ (Advanced Memory Diagnostic Tool)
Memtest86
Ultimate Boot CD

C#: XML-Serialisierung mit dem XmlSerializer Teil 3

In den vorhergehenden Beiträgen Teil 1 & Teil 2 haben wir eine Adressklasse erstellt um B2B- und B2C-Adressen zu speichern. Nun werden wir diese Adressklasse erweitern, damit auch Kommunikationsdetails (Telefon, Email, usw.) gespeichert werden können.

Als Erstes erstellen wir die Klasse „CommunicationDetail“ um damit die Kommunikationsdetails zu speichern:


namespace XML_Serialisierung
{
    public class CommunicationDetail
    {
        public enum CommunicationDetailType
        {
            PRIVATE_MOBILE,
            BUSINESS_MOBILE,
            PRIVATE_PHONE,
            BUSINESS_PHONE,
            PRIVATE_FAX,
            BUSINESS_FAX,
            PRIVATE_EMAIL,
            BUSINESS_EMAIL,
            SKYPE_MESSANGER
        }

        [XmlAttribute("Typ")]
        public CommunicationDetailType DetailType { get; set; }

        [XmlElement("Wert")]
        public string Value { get; set; }

        public CommunicationDetail()
        {
        }
        public CommunicationDetail(CommunicationDetailType detailType, string value)
        {
            this.Value = value;
            this.DetailType = detailType;
        }
    }
}

Nun werden wir die Address-Klasse mit einer Liste vom Typ „CommunicationDetail“ erweitern. Damit beim Serialisieren der Liste, die einzelnen Details auch richtig im XML-Abgebildet werden, verwenden wir das Attribut [XmlArray(„“)] um den Namen des Hauptelementes festzulegen und [XmlArrayItem(„“)] um damit den Namen der Unterknoten zu bestimmen.


namespace XML_Serialisierung
{
    public class Address
    {
        [XmlAttribute("Adressenummer")]
        public int AddressNumber { get; set; }
        
        [XmlElement("Strasse")]
        public string Street { get; set; }

        [XmlElement("Hausnumer")]
        public string HouseNumber { get; set; }

        [XmlElement("Land")]
        public string Country { get; set; }

        [XmlElement("Postleitzahl")]
        public string ZIP { get; set; }

        [XmlElement("Stadt")]
        public string City { get; set; }

        [XmlArray("Kommunikation")]
        [XmlArrayItem("Kommunikationsdetail")]
        public List CommunicationNumbers;


        public Address()
        {
            this.CommunicationNumbers = new List();
        }
    }
}

Klasse mit dem XmlSerializer serialisieren

Nun haben wir die Möglichkeit die Adresse mit Kommunikationsdetails zu erweitern:


/*b2c addresse*/
AddressB2C addressB2C_2 = new AddressB2C();
addressB2C_2.AddressNumber = 123456789;
addressB2C_2.Firstname = "Max";
addressB2C_2.Lastname = "Mustermann";
addressB2C_2.Street = "Musterstrasse";
addressB2C_2.HouseNumber = "77a";
addressB2C_2.City = "Musterhausen";
addressB2C_2.ZIP = "1234";
addressB2C_2.Country = "In einem fernen Land";

CommunicationDetail mobile = new CommunicationDetail(CommunicationDetail.CommunicationDetailType.PRIVATE_MOBILE, "079 123 45 67");
addressB2C_2.CommunicationNumbers.Add(mobile);

CommunicationDetail email = new CommunicationDetail(CommunicationDetail.CommunicationDetailType.PRIVATE_EMAIL, "meine@email.ch");
addressB2C_2.CommunicationNumbers.Add(email);

XmlSerializer xmls3 = new XmlSerializer(typeof(AddressB2C));
StreamWriter mwriter3 = new StreamWriter("b2cAddressWithNumbers.xml");
xmls3.Serialize(mwriter3, addressB2C_2);
mwriter3.Close();

Und als Ergebniss erhalten wir folgendes XML:




  
    
      079 123 45 67
    
    
      meine@email.ch
    
  
  Musterstrasse
  77a
  In einem fernen Land
  1234
  Musterhausen
  Max
  Mustermann

Nützliche Links:

C#: XML-Serialisierung mit dem XmlSerializer Teil 1
C#: XML-Serialisierung mit dem XmlSerializer Teil 2
msdn: xml.serialization
msdn: List

pfSense: NTP-Server aktivieren / konfigurieren

Um bei allen Rechnern in einem Netzwerk die Zeit synchron zu halten, benötigt man einen Zeitserver. Bei der Firewall-Distribution pfSense ist standardmässig OpenNTPD installiert. OpenNTPD ist eine einfache Implementierung des „Network Time Protocol“, welche den einfachen Betrieb eines NTP-Client und NTP-Server ermöglicht.
In diesem Beitrag wird der OpenNTPD von pfSense als Netzwerkzeitserver verwendet. Die Firewall bezieht die Zeit bei einem offiziellen Zeitserver und beantwortet NTP-Anfragen von den verschiedenen lokalen Netzwerken. Diese Konfiguration vereinfacht die Verwaltung und minimiert die NTP-Abfragen gegen Aussen.

Netzwerk konfiguration
Netzwerk konfiguration

1. Konfigurieren des pfSense NTP-Client

Damit auf der Firewall die aktuelle Zeit eines offiziellen Zeitservers verwendet wird, muss dieser im Menü „System -> General Setup“ konfiguriert werden. Hier in diesem Beispiel wird der offizielle Zeitserver für die Schweiz „ntp.metas.ch“ verwendet.
Wichtig: Die richtige Zeitzone muss eingestellt sein!

Eintragen der NTP-Server
Eintragen der NTP-Server

2. Konfigurieren des pfSense NTP-Server

Damit NTP-Anfragen auch beantwortet werden, muss der OpenNTP-Deamon unter „Services -> OpenNTPD“ aktiviert werden. Als Nächstes wird noch angegeben an welchen Interfaces (Netzwerke) eine NTP-Abfrage erlaubt wird.

OpenNTP Einstellungen
OpenNTP Einstellungen

Im oberen Beispiel sind NTP-Anfragen aus den Netzwerken LAN, DMZ und Gray1 erlaubt. NTP-Anfragen aus dem WAN-Interface werden ignoriert.

3. Konfigurieren der Server und Clients

Zum Schluss müssen die verschiedenen Server und Clients so konfiguriert werden, damit die Firewall als Zeitserver verwendet wird.

Nützliche Links:

pfSense
OpenNTPD
ntp.metas.ch
Informationen zum NTP – ntp.org

C#: XML-Serialisierung mit dem XmlSerializer Teil 2

Im vorhergehenden Beitrag haben wir aus einer einfachen Adressklasse eine XML-Datei generiert. In diesem Beitrag werden wir eine Kundenklasse erstellen, die entweder eine B2B- oder B2C-Adresse enthält und dann in eine XML-Datei geschrieben wird. Dazu erstellen wir zuerst eine Kundenklasse:


using System.Xml.Serialization;

namespace XML_Serialisierung
{
    [XmlRoot("Kunde")]
    public class Customer
    {
        [XmlAttribute("Kundennummer")]
        public int CustomerID { get; set; }

        [XmlElement("Adresse")]
        public Address CustomerAddress { get; set; }
        
        public Customer(bool b2c)
        {
            if (b2c == true)
            {
                this.CustomerAddress = new AddressB2C();
            }
            else
            {
                this.CustomerAddress = new AddressB2B();
            }
        }
        /*default constructor*/
        public Customer() {
            this.CustomerAddress = new AddressB2C();
        }
    }
}

Wird jetzt versucht diese Klasse zu serialiseren wird eine Exception geworfen:


System.InvalidOperationException wurde nicht behandelt.
  Message="Beim Generieren des XML-Dokuments ist ein Fehler aufgetreten."
  Source="System.Xml"
  StackTrace:
       bei System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
       bei System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o)
       bei XML_Serialisierung.Program.Main(String[] args) in D:\data\Projects\intern\blog\src\XML-Serialisierung\Program.cs:Zeile 59.
       bei System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args)
       bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       bei System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.InvalidOperationException
       Message="Der Typ XML_Serialisierung.AddressB2B wurde nicht erwartet. Verwenden Sie das XmlInclude- oder das SoapInclude-Attribut, um Typen anzugeben, die nicht statisch sind."
       Source="uwky4mcz"
       StackTrace:
            bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer.Write2_Address(String n, String ns, Address o, Boolean isNullable, Boolean needType)
            bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer.Write3_Customer(String n, String ns, Customer o, Boolean isNullable, Boolean needType)
            bei Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterCustomer.Write4_Kunde(Object o)

Da das Property „CustomerAddress“ vom Typ Address ist, beim serialisieren jedoch als Typ AddressB2B oder AddressB2C erscheint, weiss der XmlSerializer nicht, wie er diesen Datentyp verarbeiten soll. Damit der XmlSerializer damit korrekt umgehen kann, müssen wir ihn mit den möglichen Datentypen bekannt machen. Dazu wird das Attribut [XmlInclude(„“)] verwendet.


using System.Xml.Serialization;

namespace XML_Serialisierung
{
    [XmlInclude(typeof(AddressB2C))]
    [XmlInclude(typeof(AddressB2B))]

    [XmlRoot("Kunde")]
    public class Customer
    {
        [XmlAttribute("Kundennummer")]
        public int CustomerID { get; set; }

        [XmlElement("Adresse")]
        public Address CustomerAddress { get; set; }
        
        public Customer(bool b2c)
        {
            if (b2c == true)
            {
                this.CustomerAddress = new AddressB2C();
            }
            else
            {
                this.CustomerAddress = new AddressB2B();
            }
        }
        /*default constructor*/
        public Customer() {
            this.CustomerAddress = new AddressB2B();
        }
    }
}

Klasse mit dem XmlSerializer serialisieren

Starten wir nun nochmals einen Versuch, wird das Serialsieren funktionieren.


/*create a customer object*/
Customer customer = new Customer(false);
customer.CustomerID = 175;

AddressB2B b2bAddress = ((AddressB2B)(customer.CustomerAddress));
b2bAddress.AddressNumber = 123456789;
b2bAddress.CompanyName = "Muster AG";
b2bAddress.Division = "Musterkreation";
b2bAddress.Street  = "Musterstrasse";
b2bAddress.HouseNumber = "77a";

b2bAddress.City = "Musterhausen";
b2bAddress.ZIP = "1234";
b2bAddress.Country = "In einem Land";


XmlSerializer xmls2 = new XmlSerializer(typeof(Customer));
StreamWriter mwriter2 = new StreamWriter("CustomerWithb2bAddress.xml");
xmls2.Serialize(mwriter2, customer);
mwriter.Close();

Und als Ergebnis erhalten wir:




Musterstrasse
77a
In einem Land
1234
Musterhausen
Muster AG
Musterkreation




Nützliche Links:

C#: XML-Serialisierung mit dem XmlSerializer Teil 1
msdn: xml.serialization