test/jdk/com/sun/jndi/dns/lib/DNSServer.java
changeset 51192 499b873761d8
parent 49127 73385a708426
equal deleted inserted replaced
51191:96fae3a62612 51192:499b873761d8
    24 import sun.security.util.HexDumpEncoder;
    24 import sun.security.util.HexDumpEncoder;
    25 
    25 
    26 import java.io.IOException;
    26 import java.io.IOException;
    27 import java.net.DatagramPacket;
    27 import java.net.DatagramPacket;
    28 import java.net.DatagramSocket;
    28 import java.net.DatagramSocket;
       
    29 import java.net.InetAddress;
       
    30 import java.net.SocketException;
    29 import java.nio.ByteBuffer;
    31 import java.nio.ByteBuffer;
    30 import java.nio.file.Paths;
    32 import java.nio.file.Paths;
    31 import java.util.ArrayList;
    33 import java.util.ArrayList;
    32 import java.util.Arrays;
    34 import java.util.Arrays;
    33 import java.util.List;
    35 import java.util.List;
    47  * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
    49  * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
    48  *
    50  *
    49  * Typically, DNS protocol exchange is generated by DNSTracer who captures
    51  * Typically, DNS protocol exchange is generated by DNSTracer who captures
    50  * communication messages between DNS application program and real DNS server
    52  * communication messages between DNS application program and real DNS server
    51  */
    53  */
    52 public class DNSServer implements Runnable {
    54 public class DNSServer extends Thread implements Server {
    53 
    55 
    54     public class Pair<F, S> {
    56     public class Pair<F, S> {
    55         private F first;
    57         private F first;
    56         private S second;
    58         private S second;
    57 
    59 
    85     private DatagramSocket socket;
    87     private DatagramSocket socket;
    86     private String filename;
    88     private String filename;
    87     private boolean loop;
    89     private boolean loop;
    88     private final List<Pair<byte[], byte[]>> cache = new ArrayList<>();
    90     private final List<Pair<byte[], byte[]>> cache = new ArrayList<>();
    89     private ByteBuffer reqBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
    91     private ByteBuffer reqBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
    90 
    92     private volatile boolean isRunning;
    91     public DNSServer(DatagramSocket socket, String filename) {
    93 
    92         this(socket, filename, false);
    94     public DNSServer(String filename) throws SocketException {
    93     }
    95         this(filename, false);
    94 
    96     }
    95     public DNSServer(DatagramSocket socket, String filename, boolean loop) {
    97 
    96         this.socket = socket;
    98     public DNSServer(String filename, boolean loop) throws SocketException {
       
    99         this.socket = new DatagramSocket(0, InetAddress.getLoopbackAddress());
    97         this.filename = filename;
   100         this.filename = filename;
    98         this.loop = loop;
   101         this.loop = loop;
    99     }
   102     }
   100 
   103 
   101     public void run() {
   104     public void run() {
   102         try {
   105         try {
       
   106             isRunning = true;
   103             System.out.println(
   107             System.out.println(
   104                     "DNSServer: Loading DNS cache data from : " + filename);
   108                     "DNSServer: Loading DNS cache data from : " + filename);
   105             loadCaptureFile(filename);
   109             loadCaptureFile(filename);
   106 
   110 
   107             System.out.println(
   111             System.out.println(
   110             System.out.println("DNSServer: loop playback: " + loop);
   114             System.out.println("DNSServer: loop playback: " + loop);
   111 
   115 
   112             int playbackIndex = 0;
   116             int playbackIndex = 0;
   113 
   117 
   114             while (playbackIndex < cache.size()) {
   118             while (playbackIndex < cache.size()) {
   115                 DatagramPacket reqPacket = new DatagramPacket(reqBuffer.array(),
   119                 DatagramPacket reqPacket = receiveQuery();
   116                         reqBuffer.array().length);
       
   117                 socket.receive(reqPacket);
       
   118 
       
   119                 System.out.println(
       
   120                         "DNSServer: received query message from " + reqPacket
       
   121                                 .getSocketAddress());
       
   122 
   120 
   123                 if (!verifyRequestMsg(reqPacket, playbackIndex)) {
   121                 if (!verifyRequestMsg(reqPacket, playbackIndex)) {
       
   122                     if (playbackIndex > 0 && verifyRequestMsg(reqPacket,
       
   123                             playbackIndex - 1)) {
       
   124                         System.out.println(
       
   125                                 "DNSServer: received retry query, resend");
       
   126                         playbackIndex--;
       
   127                     } else {
       
   128                         throw new RuntimeException(
       
   129                                 "DNSServer: Error: Failed to verify DNS request. "
       
   130                                         + "Not identical request message : \n"
       
   131                                         + encoder.encodeBuffer(
       
   132                                         Arrays.copyOf(reqPacket.getData(),
       
   133                                                 reqPacket.getLength())));
       
   134                     }
       
   135                 }
       
   136 
       
   137                 sendResponse(reqPacket, playbackIndex);
       
   138 
       
   139                 playbackIndex++;
       
   140                 if (loop && playbackIndex >= cache.size()) {
       
   141                     playbackIndex = 0;
       
   142                 }
       
   143             }
       
   144 
       
   145             System.out.println(
       
   146                     "DNSServer: Done for all cached messages playback");
       
   147 
       
   148             System.out.println(
       
   149                     "DNSServer: Still listening for possible retry query");
       
   150             while (true) {
       
   151                 DatagramPacket reqPacket = receiveQuery();
       
   152 
       
   153                 // here we only handle the retry query for last one
       
   154                 if (!verifyRequestMsg(reqPacket, playbackIndex - 1)) {
   124                     throw new RuntimeException(
   155                     throw new RuntimeException(
   125                             "DNSServer: Error: Failed to verify DNS request. "
   156                             "DNSServer: Error: Failed to verify DNS request. "
   126                                     + "Not identical request message : \n"
   157                                     + "Not identical request message : \n"
   127                                     + encoder.encodeBuffer(
   158                                     + encoder.encodeBuffer(
   128                                     Arrays.copyOf(reqPacket.getData(),
   159                                     Arrays.copyOf(reqPacket.getData(),
   129                                             reqPacket.getLength())));
   160                                             reqPacket.getLength())));
   130                 }
   161                 }
   131 
   162 
   132                 byte[] payload = generateResponsePayload(reqPacket,
   163                 sendResponse(reqPacket, playbackIndex - 1);
   133                         playbackIndex);
   164             }
   134                 socket.send(new DatagramPacket(payload, payload.length,
       
   135                         reqPacket.getSocketAddress()));
       
   136                 System.out.println(
       
   137                         "DNSServer: send response message to " + reqPacket
       
   138                                 .getSocketAddress());
       
   139 
       
   140                 playbackIndex++;
       
   141                 if (loop && playbackIndex >= cache.size()) {
       
   142                     playbackIndex = 0;
       
   143                 }
       
   144             }
       
   145 
       
   146             System.out.println(
       
   147                     "DNSServer: Done for all cached messages playback");
       
   148         } catch (Exception e) {
   165         } catch (Exception e) {
   149             System.err.println("DNSServer: Error: " + e);
   166             if (isRunning) {
   150         }
   167                 System.err.println("DNSServer: Error: " + e);
       
   168                 e.printStackTrace();
       
   169             } else {
       
   170                 System.out.println("DNSServer: Exit");
       
   171             }
       
   172         }
       
   173     }
       
   174 
       
   175     private DatagramPacket receiveQuery() throws IOException {
       
   176         DatagramPacket reqPacket = new DatagramPacket(reqBuffer.array(),
       
   177                 reqBuffer.array().length);
       
   178         socket.receive(reqPacket);
       
   179 
       
   180         System.out.println("DNSServer: received query message from " + reqPacket
       
   181                 .getSocketAddress());
       
   182 
       
   183         return reqPacket;
       
   184     }
       
   185 
       
   186     private void sendResponse(DatagramPacket reqPacket, int playbackIndex)
       
   187             throws IOException {
       
   188         byte[] payload = generateResponsePayload(reqPacket, playbackIndex);
       
   189         socket.send(new DatagramPacket(payload, payload.length,
       
   190                 reqPacket.getSocketAddress()));
       
   191         System.out.println("DNSServer: send response message to " + reqPacket
       
   192                 .getSocketAddress());
   151     }
   193     }
   152 
   194 
   153     /*
   195     /*
   154      * Load a capture file containing an DNS protocol exchange in the
   196      * Load a capture file containing an DNS protocol exchange in the
   155      * hexadecimal dump format emitted by sun.misc.HexDumpEncoder:
   197      * hexadecimal dump format emitted by sun.misc.HexDumpEncoder:
   297         if ('a' <= ch && ch <= 'f') {
   339         if ('a' <= ch && ch <= 'f') {
   298             return ch - 'a' + 10;
   340             return ch - 'a' + 10;
   299         }
   341         }
   300         return -1;
   342         return -1;
   301     }
   343     }
       
   344 
       
   345     @Override public void stopServer() {
       
   346         isRunning = false;
       
   347         if (socket != null) {
       
   348             try {
       
   349                 socket.close();
       
   350             } catch (Exception e) {
       
   351                 // ignore
       
   352             }
       
   353         }
       
   354     }
       
   355 
       
   356     @Override public int getPort() {
       
   357         if (socket != null) {
       
   358             return socket.getLocalPort();
       
   359         } else {
       
   360             return -1;
       
   361         }
       
   362     }
   302 }
   363 }