8195976: Add JNDI test com/sun/jndi/dns/AttributeTests/GetAny.java
Reviewed-by: vtewari, rriggs, alanb, jjiang, xiaofeya
This commit is contained in:
parent
0e1817736c
commit
a0382a29e5
test/jdk/com/sun/jndi/dns
110
test/jdk/com/sun/jndi/dns/AttributeTests/GetAny.dns
Normal file
110
test/jdk/com/sun/jndi/dns/AttributeTests/GetAny.dns
Normal file
@ -0,0 +1,110 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
################################################################################
|
||||
# Capture file for GetAny.java
|
||||
#
|
||||
# NOTE: This hexadecimal dump of DNS protocol messages was generated by
|
||||
# running the GetAny application program against a real DNS
|
||||
# server along with DNSTracer
|
||||
#
|
||||
################################################################################
|
||||
|
||||
# DNS Request
|
||||
|
||||
0000: 32 72 01 00 00 01 00 00 00 00 00 00 05 68 6F 73 2r...........hos
|
||||
0010: 74 31 07 64 6F 6D 61 69 6E 31 03 63 6F 6D 00 00 t1.domain1.com..
|
||||
0020: FF 00 01 ...
|
||||
|
||||
|
||||
# DNS Response
|
||||
|
||||
0000: 32 72 85 80 00 01 00 06 00 01 00 01 05 68 6F 73 2r...........hos
|
||||
0010: 74 31 07 64 6F 6D 61 69 6E 31 03 63 6F 6D 00 00 t1.domain1.com..
|
||||
0020: FF 00 01 C0 0C 00 10 00 01 00 00 8C A0 00 15 14 ................
|
||||
0030: 41 20 76 65 72 79 20 70 6F 70 75 6C 61 72 20 68 A very popular h
|
||||
0040: 6F 73 74 2E C0 0C 00 1D 00 01 00 00 8C A0 00 10 ost.............
|
||||
0050: 00 12 16 13 88 97 1A 35 69 68 41 38 00 9B 16 58 .......5ihA8...X
|
||||
0060: C0 0C 00 0D 00 01 00 00 8C A0 00 13 0C 54 68 65 .............The
|
||||
0070: 20 4F 72 69 67 69 6E 61 6C 05 53 75 6E 6E 79 C0 Original.Sunny.
|
||||
0080: 0C 00 0F 00 01 00 00 8C A0 00 11 00 0A 05 72 65 ..............re
|
||||
0090: 6C 61 79 04 6F 68 69 6F 02 75 73 00 C0 0C 00 0F lay.ohio.us.....
|
||||
00A0: 00 01 00 00 8C A0 00 10 00 14 05 72 65 6C 61 79 ...........relay
|
||||
00B0: 05 74 65 78 61 73 C0 98 C0 0C 00 01 00 01 00 01 .texas..........
|
||||
00C0: 51 80 00 04 01 02 04 01 C0 12 00 02 00 01 00 00 Q...............
|
||||
00D0: 8C A0 00 05 02 6E 73 C0 12 C0 D4 00 01 00 01 00 .....ns.........
|
||||
00E0: 00 8C A0 00 04 7F 00 00 01 .........
|
||||
|
||||
|
||||
# DNS Request
|
||||
|
||||
0000: 41 80 01 00 00 01 00 00 00 00 00 00 05 68 6F 73 A............hos
|
||||
0010: 74 31 07 64 6F 6D 61 69 6E 31 03 63 6F 6D 00 00 t1.domain1.com..
|
||||
0020: FF 00 FF ...
|
||||
|
||||
|
||||
# DNS Response
|
||||
|
||||
0000: 41 80 85 80 00 01 00 06 00 01 00 01 05 68 6F 73 A............hos
|
||||
0010: 74 31 07 64 6F 6D 61 69 6E 31 03 63 6F 6D 00 00 t1.domain1.com..
|
||||
0020: FF 00 FF C0 0C 00 10 00 01 00 00 8C A0 00 15 14 ................
|
||||
0030: 41 20 76 65 72 79 20 70 6F 70 75 6C 61 72 20 68 A very popular h
|
||||
0040: 6F 73 74 2E C0 0C 00 1D 00 01 00 00 8C A0 00 10 ost.............
|
||||
0050: 00 12 16 13 88 97 1A 35 69 68 41 38 00 9B 16 58 .......5ihA8...X
|
||||
0060: C0 0C 00 0D 00 01 00 00 8C A0 00 13 0C 54 68 65 .............The
|
||||
0070: 20 4F 72 69 67 69 6E 61 6C 05 53 75 6E 6E 79 C0 Original.Sunny.
|
||||
0080: 0C 00 0F 00 01 00 00 8C A0 00 12 00 14 05 72 65 ..............re
|
||||
0090: 6C 61 79 05 74 65 78 61 73 02 75 73 00 C0 0C 00 lay.texas.us....
|
||||
00A0: 0F 00 01 00 00 8C A0 00 0F 00 0A 05 72 65 6C 61 ............rela
|
||||
00B0: 79 04 6F 68 69 6F C0 99 C0 0C 00 01 00 01 00 01 y.ohio..........
|
||||
00C0: 51 80 00 04 01 02 04 01 C0 12 00 02 00 01 00 00 Q...............
|
||||
00D0: 8C A0 00 05 02 6E 73 C0 12 C0 D4 00 01 00 01 00 .....ns.........
|
||||
00E0: 00 8C A0 00 04 7F 00 00 01 .........
|
||||
|
||||
|
||||
# DNS Request
|
||||
|
||||
0000: 65 2E 01 00 00 01 00 00 00 00 00 00 05 68 6F 73 e............hos
|
||||
0010: 74 31 07 64 6F 6D 61 69 6E 31 03 63 6F 6D 00 00 t1.domain1.com..
|
||||
0020: FF 00 01 ...
|
||||
|
||||
|
||||
# DNS Response
|
||||
|
||||
0000: 65 2E 85 80 00 01 00 06 00 01 00 01 05 68 6F 73 e............hos
|
||||
0010: 74 31 07 64 6F 6D 61 69 6E 31 03 63 6F 6D 00 00 t1.domain1.com..
|
||||
0020: FF 00 01 C0 0C 00 10 00 01 00 00 8C A0 00 15 14 ................
|
||||
0030: 41 20 76 65 72 79 20 70 6F 70 75 6C 61 72 20 68 A very popular h
|
||||
0040: 6F 73 74 2E C0 0C 00 1D 00 01 00 00 8C A0 00 10 ost.............
|
||||
0050: 00 12 16 13 88 97 1A 35 69 68 41 38 00 9B 16 58 .......5ihA8...X
|
||||
0060: C0 0C 00 0D 00 01 00 00 8C A0 00 13 0C 54 68 65 .............The
|
||||
0070: 20 4F 72 69 67 69 6E 61 6C 05 53 75 6E 6E 79 C0 Original.Sunny.
|
||||
0080: 0C 00 0F 00 01 00 00 8C A0 00 11 00 0A 05 72 65 ..............re
|
||||
0090: 6C 61 79 04 6F 68 69 6F 02 75 73 00 C0 0C 00 0F lay.ohio.us.....
|
||||
00A0: 00 01 00 00 8C A0 00 10 00 14 05 72 65 6C 61 79 ...........relay
|
||||
00B0: 05 74 65 78 61 73 C0 98 C0 0C 00 01 00 01 00 01 .texas..........
|
||||
00C0: 51 80 00 04 01 02 04 01 C0 12 00 02 00 01 00 00 Q...............
|
||||
00D0: 8C A0 00 05 02 6E 73 C0 12 C0 D4 00 01 00 01 00 .....ns.........
|
||||
00E0: 00 8C A0 00 04 7F 00 00 01 .........
|
||||
|
||||
|
82
test/jdk/com/sun/jndi/dns/AttributeTests/GetAny.java
Normal file
82
test/jdk/com/sun/jndi/dns/AttributeTests/GetAny.java
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8195976
|
||||
* @summary Tests that we can get the attributes of a DNS entry using special
|
||||
* qualifiers.
|
||||
* @modules java.xml.bind
|
||||
* java.base/sun.security.util
|
||||
* @library ../lib/
|
||||
* @build DNSTestUtils DNSServer DNSTracer
|
||||
* @run main GetAny
|
||||
*/
|
||||
|
||||
import javax.naming.directory.Attributes;
|
||||
import javax.naming.directory.DirContext;
|
||||
import javax.naming.directory.InitialDirContext;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetAddress;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class GetAny {
|
||||
private static final String KEY = "host1";
|
||||
|
||||
private static final String[] MANDATORY = { "A", "MX", "HINFO", "TXT", "29"
|
||||
// "LOC"
|
||||
};
|
||||
|
||||
private static final String[] OPTIONAL = {};
|
||||
|
||||
public static void main(String argv[]) throws Exception {
|
||||
// Create socket on localhost only to avoid possible noise packet
|
||||
DatagramSocket socket = new DatagramSocket(0,
|
||||
InetAddress.getLoopbackAddress());
|
||||
|
||||
// initialize test
|
||||
Hashtable<Object, Object> env;
|
||||
|
||||
env = DNSTestUtils.initEnv(socket, GetAny.class.getName(), argv);
|
||||
|
||||
DirContext ctx = null;
|
||||
|
||||
try {
|
||||
// connect to server
|
||||
ctx = new InitialDirContext(env);
|
||||
|
||||
// Any type from IN class
|
||||
Attributes retAttrs = ctx.getAttributes(KEY, new String[] { "*" });
|
||||
DNSTestUtils.verifySchema(retAttrs, MANDATORY, OPTIONAL);
|
||||
|
||||
retAttrs = ctx.getAttributes(KEY, new String[] { "* *" });
|
||||
DNSTestUtils.verifySchema(retAttrs, MANDATORY, OPTIONAL);
|
||||
|
||||
retAttrs = ctx.getAttributes(KEY, new String[] { "IN *" });
|
||||
DNSTestUtils.verifySchema(retAttrs, MANDATORY, OPTIONAL);
|
||||
|
||||
} finally {
|
||||
DNSTestUtils.cleanup(ctx);
|
||||
}
|
||||
}
|
||||
}
|
264
test/jdk/com/sun/jndi/dns/lib/DNSServer.java
Normal file
264
test/jdk/com/sun/jndi/dns/lib/DNSServer.java
Normal file
@ -0,0 +1,264 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import sun.security.util.HexDumpEncoder;
|
||||
|
||||
import javax.xml.bind.DatatypeConverter;
|
||||
import java.io.IOException;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.regex.MatchResult;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
public class DNSServer implements Runnable {
|
||||
|
||||
public class Pair<F, S> {
|
||||
private F first;
|
||||
private S second;
|
||||
|
||||
public Pair(F first, S second) {
|
||||
this.first = first;
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public void setFirst(F first) {
|
||||
this.first = first;
|
||||
}
|
||||
|
||||
public void setSecond(S second) {
|
||||
this.second = second;
|
||||
}
|
||||
|
||||
public F getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public S getSecond() {
|
||||
return second;
|
||||
}
|
||||
}
|
||||
|
||||
public static final int DNS_HEADER_SIZE = 12;
|
||||
public static final int DNS_PACKET_SIZE = 512;
|
||||
|
||||
static HexDumpEncoder encoder = new HexDumpEncoder();
|
||||
|
||||
private DatagramSocket socket;
|
||||
private String filename;
|
||||
private boolean loop;
|
||||
private final List<Pair<byte[], byte[]>> cache = new ArrayList<>();
|
||||
private ByteBuffer reqBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
|
||||
|
||||
public DNSServer(DatagramSocket socket, String filename) {
|
||||
this(socket, filename, false);
|
||||
}
|
||||
|
||||
public DNSServer(DatagramSocket socket, String filename, boolean loop) {
|
||||
this.socket = socket;
|
||||
this.filename = filename;
|
||||
this.loop = loop;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
System.out.println(
|
||||
"DNSServer: Loading DNS cache data from : " + filename);
|
||||
loadCaptureFile(filename);
|
||||
|
||||
System.out.println(
|
||||
"DNSServer: listening on port " + socket.getLocalPort());
|
||||
|
||||
System.out.println("DNSServer: loop playback: " + loop);
|
||||
|
||||
int playbackIndex = 0;
|
||||
|
||||
while (playbackIndex < cache.size()) {
|
||||
DatagramPacket reqPacket = new DatagramPacket(reqBuffer.array(),
|
||||
reqBuffer.array().length);
|
||||
socket.receive(reqPacket);
|
||||
|
||||
System.out.println(
|
||||
"DNSServer: received query message from " + reqPacket
|
||||
.getSocketAddress());
|
||||
|
||||
if (!verifyRequestMsg(reqPacket, playbackIndex)) {
|
||||
throw new RuntimeException(
|
||||
"DNSServer: Error: Failed to verify DNS request. "
|
||||
+ "Not identical request message : \n"
|
||||
+ encoder.encodeBuffer(
|
||||
Arrays.copyOf(reqPacket.getData(),
|
||||
reqPacket.getLength())));
|
||||
}
|
||||
|
||||
byte[] payload = generateResponsePayload(reqPacket,
|
||||
playbackIndex);
|
||||
socket.send(new DatagramPacket(payload, payload.length,
|
||||
reqPacket.getSocketAddress()));
|
||||
System.out.println(
|
||||
"DNSServer: send response message to " + reqPacket
|
||||
.getSocketAddress());
|
||||
|
||||
playbackIndex++;
|
||||
if (loop && playbackIndex >= cache.size()) {
|
||||
playbackIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
System.out.println(
|
||||
"DNSServer: Done for all cached messages playback");
|
||||
} catch (Exception e) {
|
||||
System.err.println("DNSServer: Error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 ................
|
||||
*/
|
||||
private void 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;
|
||||
} else if (digits.equals(" ")) { // short message
|
||||
continue;
|
||||
}
|
||||
hexString.append(digits);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
addToCache(hexString.toString());
|
||||
}
|
||||
|
||||
/*
|
||||
* Add an DNS encoding to the cache (by request message key).
|
||||
*/
|
||||
private void addToCache(String hexString) {
|
||||
byte[] encoding = DatatypeConverter.parseHexBinary(hexString);
|
||||
if (encoding.length < DNS_HEADER_SIZE) {
|
||||
throw new 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 {
|
||||
throw new 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.
|
||||
*/
|
||||
private static int 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
|
||||
*/
|
||||
private static int getQR(byte[] encoding) {
|
||||
return encoding[2] & (0x01 << 7);
|
||||
}
|
||||
|
||||
private Pair<byte[], byte[]> getLatestCacheEntry() {
|
||||
return cache.get(cache.size() - 1);
|
||||
}
|
||||
|
||||
private boolean verifyRequestMsg(DatagramPacket packet, int playbackIndex) {
|
||||
byte[] cachedRequest = cache.get(playbackIndex).getFirst();
|
||||
return Arrays.equals(Arrays
|
||||
.copyOfRange(packet.getData(), 2, packet.getLength()),
|
||||
Arrays.copyOfRange(cachedRequest, 2, cachedRequest.length));
|
||||
}
|
||||
|
||||
private byte[] generateResponsePayload(DatagramPacket packet,
|
||||
int playbackIndex) {
|
||||
byte[] resMsg = cache.get(playbackIndex).getSecond();
|
||||
byte[] payload = Arrays.copyOf(resMsg, resMsg.length);
|
||||
|
||||
// replace the ID with same with real request
|
||||
payload[0] = packet.getData()[0];
|
||||
payload[1] = packet.getData()[1];
|
||||
|
||||
return payload;
|
||||
}
|
||||
}
|
246
test/jdk/com/sun/jndi/dns/lib/DNSTestUtils.java
Normal file
246
test/jdk/com/sun/jndi/dns/lib/DNSTestUtils.java
Normal file
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import javax.naming.Context;
|
||||
import javax.naming.NamingException;
|
||||
import javax.naming.directory.Attributes;
|
||||
import java.io.PrintStream;
|
||||
import java.net.DatagramSocket;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Hashtable;
|
||||
|
||||
public class DNSTestUtils {
|
||||
public static final String TEST_DNS_SERVER_THREAD = "test.dns.server.thread";
|
||||
public static final String TEST_DNS_ROOT_URL = "test.dns.root.url";
|
||||
public static final int HOSTS_LOOKUP_MAX_DEPTH = 3;
|
||||
|
||||
protected static boolean debug = true;
|
||||
|
||||
/*
|
||||
* Check that attrs contains the mandatory attributes and the right
|
||||
* objectclass attribute
|
||||
*/
|
||||
public static boolean checkSchema(Attributes attrs, String[] mandatory,
|
||||
String[] optional) {
|
||||
// Check mandatory attributes
|
||||
for (String mandatoryAttr : mandatory) {
|
||||
if (attrs.get(mandatoryAttr) == null) {
|
||||
debug("missing mandatory attribute: " + mandatoryAttr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check optional attributes
|
||||
int optMissing = 0;
|
||||
for (String optionalAttr : optional) {
|
||||
if (attrs.get(optionalAttr) == null) {
|
||||
debug("warning: missing optional attribute: " + optionalAttr);
|
||||
++optMissing;
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs.size() > (mandatory.length + (optional.length
|
||||
- optMissing))) {
|
||||
debug("too many attributes: " + attrs);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Process command line arguments and init env
|
||||
*/
|
||||
public static Hashtable<Object, Object> initEnv(DatagramSocket socket,
|
||||
String testname, String[] args) {
|
||||
|
||||
Hashtable<Object, Object> env = new Hashtable<>();
|
||||
|
||||
// set some default parameters if no additional specified
|
||||
env.put("DNS_DOMAIN", "domain1.com.");
|
||||
env.put("FOREIGN_DOMAIN", "Central.Sun.COM.");
|
||||
env.put("FOREIGN_LEAF", "sunweb");
|
||||
|
||||
// set defaults for some JNDI properties
|
||||
env.put(Context.INITIAL_CONTEXT_FACTORY,
|
||||
"com.sun.jndi.dns.DnsContextFactory");
|
||||
|
||||
boolean traceEnable = false;
|
||||
boolean loopPlayback = false;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
if ((args[i].equals("-D")) && (args.length > i + 1)) {
|
||||
extractProperty(args[++i], env);
|
||||
} else if (args[i].startsWith("-D")) {
|
||||
extractProperty(args[i].substring(2), env);
|
||||
} else if (args[i].equalsIgnoreCase("-trace")) {
|
||||
traceEnable = true;
|
||||
} else if (args[i].equalsIgnoreCase("-loop")) {
|
||||
loopPlayback = true;
|
||||
}
|
||||
}
|
||||
|
||||
debug = Boolean.valueOf(System.getProperty("debug", "true"));
|
||||
|
||||
if (env.get("DNS_SERVER") != null) {
|
||||
String port = (String) env.get("DNS_PORT");
|
||||
String portSuffix = (port == null) ? "" : ":" + port;
|
||||
String url = "dns://" + env.get("DNS_SERVER") + portSuffix;
|
||||
env.put(Context.PROVIDER_URL, url);
|
||||
env.put(Context.PROVIDER_URL, url + "/" + env.get("DNS_DOMAIN"));
|
||||
}
|
||||
|
||||
Runnable inst = null;
|
||||
if (traceEnable) {
|
||||
inst = createDNSTracer(socket, testname, env);
|
||||
} else {
|
||||
if (socket != null) {
|
||||
inst = createDNSServer(socket, testname, loopPlayback);
|
||||
} else {
|
||||
// for tests which run against remote server
|
||||
// or no server required
|
||||
debug("Skip local DNS Server creation "
|
||||
+ "since DatagramSocket is null");
|
||||
}
|
||||
}
|
||||
|
||||
if (inst != null) {
|
||||
env.put(TEST_DNS_SERVER_THREAD, startServer(inst));
|
||||
String url = "dns://localhost:" + socket.getLocalPort();
|
||||
|
||||
env.put(TEST_DNS_ROOT_URL, url);
|
||||
env.put(Context.PROVIDER_URL, url + "/" + env.get("DNS_DOMAIN"));
|
||||
}
|
||||
|
||||
return env;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean-up the directory context.
|
||||
*/
|
||||
public static void cleanup(Context ctx) {
|
||||
if (ctx != null) {
|
||||
try {
|
||||
ctx.close();
|
||||
} catch (NamingException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void extractProperty(String propString,
|
||||
Hashtable<Object, Object> env) {
|
||||
int index;
|
||||
|
||||
if ((index = propString.indexOf('=')) > 0) {
|
||||
env.put(propString.substring(0, index),
|
||||
propString.substring(index + 1));
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Failed to extract test args property from " + propString);
|
||||
}
|
||||
}
|
||||
|
||||
public static DNSTracer createDNSTracer(DatagramSocket socket,
|
||||
String testname, Hashtable<Object, Object> env) {
|
||||
if (socket == null) {
|
||||
throw new RuntimeException("Error: failed to create DNSTracer "
|
||||
+ "since DatagramSocket is null");
|
||||
}
|
||||
|
||||
try {
|
||||
PrintStream outStream = new PrintStream(getCaptureFile(testname));
|
||||
return new DNSTracer(socket, outStream,
|
||||
(String) env.get("DNS_SERVER"),
|
||||
Integer.parseInt((String) env.get("DNS_PORT")));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(
|
||||
"Error: failed to create DNSTracer : " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public static DNSServer createDNSServer(DatagramSocket socket,
|
||||
String testname, boolean loop) {
|
||||
if (socket == null) {
|
||||
throw new RuntimeException("Error: failed to create DNSServer "
|
||||
+ "since DatagramSocket is null");
|
||||
}
|
||||
|
||||
String path = getCaptureFile(testname);
|
||||
if (Files.exists(Paths.get(path))) {
|
||||
return new DNSServer(socket, path, loop);
|
||||
} else {
|
||||
throw new RuntimeException(
|
||||
"Error: failed to create DNSServer, not found dns "
|
||||
+ "cache file " + path);
|
||||
}
|
||||
}
|
||||
|
||||
public static Thread startServer(Runnable runnable) {
|
||||
Thread thread = new Thread(runnable);
|
||||
thread.start();
|
||||
return thread;
|
||||
}
|
||||
|
||||
public static String getCaptureFile(String testname) {
|
||||
return Paths.get(System.getProperty("test.src"))
|
||||
.resolve(testname + ".dns").toString();
|
||||
}
|
||||
|
||||
public static void enableHostsFile(String hostsFile) {
|
||||
System.out.println("Enable jdk.net.hosts.file = " + hostsFile);
|
||||
System.setProperty("jdk.net.hosts.file", hostsFile);
|
||||
}
|
||||
|
||||
public static void enableHostsFile(int depth) {
|
||||
Path path = Paths.get(System.getProperty("test.src", "."))
|
||||
.toAbsolutePath();
|
||||
for (int i = depth; i >= 0; i--) {
|
||||
Path filePath = path.resolve("hosts");
|
||||
if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
|
||||
enableHostsFile(filePath.toString());
|
||||
break;
|
||||
}
|
||||
|
||||
path = path.getParent();
|
||||
if (path == null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void debug(Object object) {
|
||||
if (debug) {
|
||||
System.out.println(object);
|
||||
}
|
||||
}
|
||||
|
||||
public static void verifySchema(Attributes attrs, String[] mandatory,
|
||||
String[] optional) {
|
||||
debug(attrs);
|
||||
if (!checkSchema(attrs, mandatory, optional)) {
|
||||
throw new RuntimeException("Check schema failed.");
|
||||
}
|
||||
}
|
||||
}
|
130
test/jdk/com/sun/jndi/dns/lib/DNSTracer.java
Normal file
130
test/jdk/com/sun/jndi/dns/lib/DNSTracer.java
Normal file
@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
import sun.security.util.HexDumpEncoder;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.net.DatagramPacket;
|
||||
import java.net.DatagramSocket;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
/*
|
||||
* A DNS UDP message tracer.
|
||||
*
|
||||
* It listens for DNS UDP requests, forward request to real DNS server, receives
|
||||
* response message and sends back to requester, at same time dump all messages
|
||||
* into capture file
|
||||
*
|
||||
* 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, the capture file data will be used by DNSServer for playback
|
||||
*/
|
||||
public class DNSTracer implements Runnable {
|
||||
public static final int DNS_DEFAULT_PORT = 53;
|
||||
public static final int DNS_PACKET_SIZE = 512;
|
||||
static HexDumpEncoder encoder = new HexDumpEncoder();
|
||||
|
||||
private DatagramSocket inSocket;
|
||||
private SocketAddress dnsServerAddress;
|
||||
private ByteBuffer reqBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
|
||||
private ByteBuffer resBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
|
||||
private PrintStream out = null;
|
||||
|
||||
public DNSTracer(DatagramSocket socket, String dnsHostname) {
|
||||
this(socket, dnsHostname, DNS_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
public DNSTracer(DatagramSocket socket, PrintStream outStream,
|
||||
String dnsHostname) {
|
||||
this(socket, outStream, dnsHostname, DNS_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
public DNSTracer(DatagramSocket socket, String dnsHostname, int dnsPort) {
|
||||
this(socket, System.out, dnsHostname, dnsPort);
|
||||
}
|
||||
|
||||
public DNSTracer(DatagramSocket socket, PrintStream outStream,
|
||||
String dnsHostname, int dnsPort) {
|
||||
inSocket = socket;
|
||||
out = outStream;
|
||||
dnsServerAddress = new InetSocketAddress(dnsHostname, dnsPort);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
System.out.println(
|
||||
"DNSTracer: listening on port " + inSocket.getLocalPort());
|
||||
|
||||
System.out.println("DNSTracer: will forward request to server "
|
||||
+ dnsServerAddress);
|
||||
|
||||
try (DatagramSocket outSocket = new DatagramSocket()) {
|
||||
while (true) {
|
||||
DatagramPacket reqPacket = new DatagramPacket(reqBuffer.array(),
|
||||
reqBuffer.array().length);
|
||||
inSocket.receive(reqPacket);
|
||||
|
||||
out.println("-> " + reqPacket.getSocketAddress());
|
||||
out.println();
|
||||
// dump dns request data
|
||||
out.println(encoder.encodeBuffer(
|
||||
Arrays.copyOf(reqPacket.getData(),
|
||||
reqPacket.getLength())));
|
||||
out.println();
|
||||
|
||||
outSocket.send(new DatagramPacket(reqPacket.getData(),
|
||||
reqPacket.getLength(), dnsServerAddress));
|
||||
DatagramPacket resPacket = new DatagramPacket(resBuffer.array(),
|
||||
resBuffer.array().length);
|
||||
outSocket.receive(resPacket);
|
||||
|
||||
out.println("<- " + resPacket.getSocketAddress());
|
||||
out.println();
|
||||
// dump dns response data
|
||||
out.println(encoder.encodeBuffer(
|
||||
Arrays.copyOf(resPacket.getData(),
|
||||
resPacket.getLength())));
|
||||
out.println();
|
||||
|
||||
inSocket.send(new DatagramPacket(resPacket.getData(),
|
||||
resPacket.getLength(), reqPacket.getSocketAddress()));
|
||||
}
|
||||
} catch (SocketException se) {
|
||||
if (inSocket.isClosed()) {
|
||||
out.flush();
|
||||
System.out.println("DNSTracer: Exit");
|
||||
} else {
|
||||
se.printStackTrace();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user