|
|
 |
|
|
 |
|
|
 |
|
|
 |
|
|
 |
5 Weitere Informationensquellen
|
|
|
|
 |
|
|
|
 |
| 4. Anwendungsbeispiel |
In diesem Kapitel wird eine Beispielimplementation gezeigt.
Implementiert wird die Enthüllung der NAT-Umgebung. Die interne Funktionsweise der Bibliothek wird nicht gesprochen.
Auf die Demonstration einer Anmeldung mittels Shared Secret muss verzichtet werden, da jstun dies nicht implementiert.
Betrachtet wird dei Clientseite.
Eine Enthüllung gliedert sich in drei Abschnitte: Request senden, Response empfangen, Response auswerten.
Siehe hierzu auch Kapitel 2 Abschnitt 'Protokolldetails' sowie die Abb. des Flussdiagrammes in 'Funktionsweise' ebenda.
Der nachfolgende Code implementiert "Test I" sowie dessen Auswertung. Andere Operationen sollten daraus leicht abzuleiten sein.
Hier nun das Senden der Anfrage:
• Erzeugen der STUN-Anfrage:
MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
sendMH.generateTransactionID();
ChangeRequest changeRequest = new ChangeRequest();
sendMH.addMessageAttribute(changeRequest);
|
Es wird eine Message erzeugt mit dem Typ 'BindingRequest'.
Diese erhält eine Transaction ID.
Dieser Anfrage wird nun ein Attribut hinzugefügt.
• Erzeugen des UDP-Packetes:
byte[] data = sendMH.getBytes();
DatagramPacket send = new DatagramPacket(data,
data.length,
InetAddress.getByName(stunServer),
port);
|
Hier wird einfach nur ein UDP-Packet erzeugt mit den Daten der eben generierten STUN-Anfrage als Inhalt.
• Versenden des UDP-Packetes:
socketTest1 = new DatagramSocket();
socketTest1.setReuseAddress(true);
socketTest1.connect(InetAddress.getByName(stunServer), port);
socketTest1.setSoTimeout(timeout);
socketTest1.send(send);
|
Ein UDP-Socket wird erzeugt und das UDP-Packet mit den STUN-Request als inhalt darüber versendet.
Damit ist eine komplette STUN-Anfrage getätigt.
Der zweite Schritt ist nun das Empfangen der Antwort des Servers:
• Emfangen der Antwort:
MessageHeader receiveMH = new MessageHeader();
DatagramPacket receive = new DatagramPacket(new byte[200], 200);
socketTest1.receive(receive);
receiveMH = MessageHeader.parseHeader(receive.getData());
|
Von den früher erzeugten UDP-Socket wird ein Packet emfangen und per parseHeader() an ein neues STUN-Packet übergeben.
Das Auswerten der Antwort ist ebenso einfach:
• Auswerten:
// Attribute aus Antwort lesen
ma = (MappedAddress) receiveMH.getMessageAttribute(
MessageAttribute.MessageAttributeType.MappedAddress);
ca = (ChangedAddress) receiveMH.getMessageAttribute(
MessageAttribute.MessageAttributeType.ChangedAddress);
ErrorCode ec = (ErrorCode) receiveMH.getMessageAttribute(
MessageAttribute.MessageAttributeType.ErrorCode);
// Auf Fehlermeldung des Servers prüfen:
if (ec != null) {
di.setError(ec.getResponseCode(), ec.getReason());
logger.config('Message header contains errorcode message attribute.');
return false;
}
// Auf fehlerhaftes Packet prüfen:
if ((ma == null) || (ca == null)) {
logger.config('Mapped address or changed address attribute missing.');
return false;
}
// Packet auswerten
if (
(ma.getPort() == socketTest1.getLocalPort()) &&
(ma.getAddress().getInetAddress().equals(socketTest1.getLocalAddress()))
)
logger.fine("Node is not natted.");
else logger.fine("Node is natted.");
|
Zuerst werden aus dem emfangenen STUN-Packet die Attribute MappedAddress, ChangedAddress und ErrorCode extrahiert. Damit läßt sich etwas handlicher arbeiten.
Weiter wird überprüft, ob der Server einen Fehler meldet oder das empfangene Packet ungültig ist.
Jetzt folgt die eigentliche Auswertung: Stimmen IP und Port des lokalen UDP-Socket mit dem vom Server gelieferten Attribut MAPPEDADDRESS überein, so ist der Client nicht hinter einem NAT.
Diese Codefragmente zeigen den Ablauf eines Anfrage-Antwort-Zykluses.
Eine Emthüllung wie z.B. im Flussdiagrammes im Kapitel 2 Abschnitt 'Funktionsweise' ist nun sehr einfach zu vervollständigen: Es müssen nur 4 weitere Anfragen gesendet und ausgewertet werden.
|
|
, Dresden am 20.01.2006
|
|