/* * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions.
*/
/* * A dummy DNS server. * * Loads a sequence of DNS messages from a capture file into its cache. * It listens for DNS UDP requests, finds match request in cache and sends the * corresponding DNS responses. * * The capture file contains an DNS protocol exchange in the hexadecimal * dump format emitted by HexDumpEncoder: * * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................ * * Typically, DNS protocol exchange is generated by DNSTracer who captures * communication messages between DNS application program and real DNS server
*/ publicclass DNSServer extendsThreadimplements Server {
publicclass Pair<F, S> { private F first; private S second;
public Pair(F first, S second) { this.first = first; this.second = second;
}
System.out.println( "DNSServer: Done for all cached messages playback");
System.out.println( "DNSServer: Still listening for possible retry query"); while (true) {
DatagramPacket reqPacket = receiveQuery();
// here we only handle the retry query for last one if (!verifyRequestMsg(reqPacket, playbackIndex - 1)) { thrownew RuntimeException( "DNSServer: Error: Failed to verify DNS request. "
+ "Not identical request message : \n"
+ encoder.encodeBuffer(
Arrays.copyOf(reqPacket.getData(),
reqPacket.getLength())));
}
/* * Load a capture file containing an DNS protocol exchange in the * hexadecimal dump format emitted by sun.misc.HexDumpEncoder: * * xxxx: 00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff ................
*/ privatevoid loadCaptureFile(String filename) throws IOException {
StringBuilder hexString = new StringBuilder();
String pattern = "(....): (..) (..) (..) (..) (..) (..) (..) (..) "
+ "(..) (..) (..) (..) (..) (..) (..) (..).*";
try (Scanner fileScanner = new Scanner(Paths.get(filename))) { while (fileScanner.hasNextLine()) {
try (Scanner lineScanner = new Scanner(
fileScanner.nextLine())) { if (lineScanner.findInLine(pattern) == null) { continue;
}
MatchResult result = lineScanner.match(); for (int i = 1; i <= result.groupCount(); i++) {
String digits = result.group(i); if (digits.length() == 4) { if (digits.equals("0000")) { // start-of-message if (hexString.length() > 0) {
addToCache(hexString.toString());
hexString.delete(0, hexString.length());
}
} continue;
} elseif (digits.equals(" ")) { // short message continue;
}
hexString.append(digits);
}
}
}
}
addToCache(hexString.toString());
}
/* * Add an DNS encoding to the cache (by request message key).
*/ privatevoid addToCache(String hexString) { byte[] encoding = parseHexBinary(hexString); if (encoding.length < DNS_HEADER_SIZE) { thrownew RuntimeException("Invalid DNS message : " + hexString);
}
if (getQR(encoding) == 0) { // a query message, create entry in cache
cache.add(new Pair<>(encoding, null));
System.out.println( " adding DNS query message with ID " + getID(encoding)
+ " to the cache");
} else { // a response message, attach it to the query entry if (!cache.isEmpty() && (getID(getLatestCacheEntry().getFirst())
== getID(encoding))) {
getLatestCacheEntry().setSecond(encoding);
System.out.println( " adding DNS response message associated to ID "
+ getID(encoding) + " in the cache");
} else { thrownew RuntimeException( "Invalid DNS message : " + hexString);
}
}
}
/* * ID: A 16 bit identifier assigned by the program that generates any * kind of query. This identifier is copied the corresponding reply and * can be used by the requester to match up replies to outstanding queries.
*/ privatestaticint getID(byte[] encoding) { return ByteBuffer.wrap(encoding, 0, 2).getShort();
}
/* * QR: A one bit field that specifies whether this message is * a query (0), or a response (1) after ID
*/ privatestaticint getQR(byte[] encoding) { return encoding[2] & (0x01 << 7);
}
// replace the ID with same with real request
payload[0] = packet.getData()[0];
payload[1] = packet.getData()[1];
return payload;
}
publicstaticbyte[] parseHexBinary(String s) {
finalint len = s.length();
// "111" is not a valid hex encoding. if (len % 2 != 0) { thrownew IllegalArgumentException( "hexBinary needs to be even-length: " + s);
}
byte[] out = newbyte[len / 2];
for (int i = 0; i < len; i += 2) { int h = hexToBin(s.charAt(i)); int l = hexToBin(s.charAt(i + 1)); if (h == -1 || l == -1) { thrownew IllegalArgumentException( "contains illegal character for hexBinary: " + s);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.