I’m stuck on Stage #HD8.
Here are my logs:
And here’s a snippet of my code
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
public class Main {
public static void main(String args) {
System.out.println(“Logs from your program will appear here!”);
try (DatagramSocket serverSocket = new DatagramSocket(2053)) {
while (true) {
final byte[] buf = new byte[512];
final DatagramPacket packet = new DatagramPacket(buf, buf.length);
serverSocket.receive(packet);
System.out.println("Received data");
ByteBuffer requestBuffer = ByteBuffer.wrap(buf);
requestBuffer.order(ByteOrder.BIG_ENDIAN);
// Parse DNS header
short transactionID = requestBuffer.getShort();
short flags = requestBuffer.getShort();
short qdCount = requestBuffer.getShort();
short anCount = requestBuffer.getShort();
short nsCount = requestBuffer.getShort();
short arCount = requestBuffer.getShort();
System.out.println("Transaction ID: " + transactionID);
// Extract the RecursionDesired (RD) flag
boolean recursionDesired = (flags & 0x0100) != 0;
// Extract the Opcode from the flags (bits 1–4)
int opcode = (flags >> 11) & 0xF;
// Parse DNS question section
String domainName = parseDomainName(requestBuffer);
short qType = requestBuffer.getShort();
short qClass = requestBuffer.getShort();
System.out.println("Parsed domain name: " + domainName);
System.out.println("Query Type: " + qType);
System.out.println("Query Class: " + qClass);
// Build the response
ByteBuffer responseBuffer = ByteBuffer.allocate(512);
responseBuffer.order(ByteOrder.BIG_ENDIAN);
// Header section
responseBuffer.putShort(transactionID); // Transaction ID
// Set the Flags: QR=1 (response), Opcode=opcode, AA=0, TC=0, RD=recursionDesired, RA=1, Z=000, RCODE=0
short responseFlags = (short) (0x8000 | (opcode << 11) | (recursionDesired ? 0x0100 : 0) | 0x0080); // QR=1, RD=recursionDesired, RA=1
responseBuffer.putShort(responseFlags);
responseBuffer.putShort(qdCount); // QDCOUNT
responseBuffer.putShort((short) 1); // ANCOUNT (1 Answer Record)
responseBuffer.putShort((short) 0); // NSCOUNT
responseBuffer.putShort((short) 0); // ARCOUNT
// Question section (echo the received question section)
responseBuffer.put(domainNameToByteArray(domainName)); // Name
responseBuffer.putShort(qType); // Type
responseBuffer.putShort(qClass); // Class
// Answer section
responseBuffer.put(domainNameToByteArray(domainName)); // Name
responseBuffer.putShort((short) 1); // Type (A record)
responseBuffer.putShort((short) 1); // Class (IN)
responseBuffer.putInt(60); // TTL (Time-To-Live)
responseBuffer.putShort((short) 4); // Length of RDATA (4 bytes for IPv4 address)
responseBuffer.put(new byte[]{(byte) 8, (byte) 8, (byte) 8, (byte) 8}); // RDATA (example IP address 8.8.8.8)
final byte[] responseData = responseBuffer.array();
DatagramPacket responsePacket = new DatagramPacket(responseData, responseData.length, packet.getSocketAddress());
serverSocket.send(responsePacket);
System.out.println("Response sent");
}
} catch (IOException e) {
System.out.println("IOException: " + e.getMessage());
}
}
private static String parseDomainName(ByteBuffer buffer) {
StringBuilder domainName = new StringBuilder();
int length;
while ((length = buffer.get() & 0xFF) != 0) {
if (domainName.length() > 0) {
domainName.append('.');
}
byte[] label = new byte[length];
buffer.get(label);
domainName.append(new String(label));
}
return domainName.toString();
}
private static byte[] domainNameToByteArray(String domainName) {
String[] labels = domainName.split("\\.");
ByteBuffer buffer = ByteBuffer.allocate(domainName.length() + 2);
for (String label : labels) {
buffer.put((byte) label.length());
buffer.put(label.getBytes());
}
buffer.put((byte) 0); // Null byte to terminate domain name
return buffer.array();
}
}