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; |
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: |