package org.exobel.routerkeygen.utils.dns; /* * Java Network Programming, Second Edition * Merlin Hughes, Michael Shoffner, Derek Hamner * Manning Publications Company; ISBN 188477749X * * http://nitric.com/jnp/ * * Copyright (c) 1997-1999 Merlin Hughes, Michael Shoffner, Derek Hamner; * all rights reserved; see license.txt for details. */ import java.io.*; import java.util.*; public class DNSQuery { private String queryHost; private int queryType, queryClass, queryID; private static int globalID; public DNSQuery(String host, int type, int clas) { StringTokenizer labels = new StringTokenizer(host, "."); while (labels.hasMoreTokens()) if (labels.nextToken().length() > 63) throw new IllegalArgumentException("Invalid hostname: " + host); queryHost = host; queryType = type; queryClass = clas; synchronized (getClass()) { queryID = (++globalID) % 65536; } } public String getQueryHost() { return queryHost; } public int getQueryType() { return queryType; } public int getQueryClass() { return queryClass; } public int getQueryID() { return queryID; } public byte[] extractQuery() { ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); DataOutputStream dataOut = new DataOutputStream(byteArrayOut); try { dataOut.writeShort(queryID); dataOut.writeShort((1 << DNS.SHIFT_RECURSE_PLEASE)); dataOut.writeShort(1); // # queries dataOut.writeShort(0); // # answers dataOut.writeShort(0); // # authorities dataOut.writeShort(0); // # additional StringTokenizer labels = new StringTokenizer(queryHost, "."); while (labels.hasMoreTokens()) { String label = labels.nextToken(); dataOut.writeByte(label.length()); dataOut.writeBytes(label); } dataOut.writeByte(0); dataOut.writeShort(queryType); dataOut.writeShort(queryClass); } catch (IOException ignored) { } return byteArrayOut.toByteArray(); } private final Vector<DNSRR> answers = new Vector<>(); private final Vector<DNSRR> authorities = new Vector<>(); private final Vector<DNSRR> additional = new Vector<>(); public void receiveResponse(byte[] data, int length) throws IOException { DNSInputStream dnsIn = new DNSInputStream(data, 0, length); int id = dnsIn.readShort(); if (id != queryID) throw new IOException("ID does not match request"); int flags = dnsIn.readShort(); decodeFlags(flags); int numQueries = dnsIn.readShort(); int numAnswers = dnsIn.readShort(); int numAuthorities = dnsIn.readShort(); int numAdditional = dnsIn.readShort(); while (numQueries-- > 0) { // discard questions dnsIn.readDomainName(); dnsIn.readShort(); dnsIn.readShort(); } try { while (numAnswers-- > 0) { answers.addElement(dnsIn.readRR()); } while (numAuthorities-- > 0) authorities.addElement(dnsIn.readRR()); while (numAdditional-- > 0) additional.addElement(dnsIn.readRR()); } catch (EOFException ex) { if (!truncated) throw ex; } } private boolean authoritative, truncated, recursive; private void decodeFlags(int flags) throws IOException { boolean isResponse = ((flags >> DNS.SHIFT_QUERY) & 1) != 0; if (!isResponse) throw new IOException("Response flag not set"); // could check opcode authoritative = ((flags >> DNS.SHIFT_AUTHORITATIVE) & 1) != 0; truncated = ((flags >> DNS.SHIFT_TRUNCATED) & 1) != 0; // could check recurse request recursive = ((flags >> DNS.SHIFT_RECURSE_AVAILABLE) & 1) != 0; int code = (flags) & 15; if (code != 0) throw new IOException(DNS.codeName(code) + " (" + code + ")"); } public boolean isAuthoritative() { return authoritative; } public boolean isTruncated() { return truncated; } public boolean isRecursive() { return recursive; } public Enumeration<DNSRR> getAnswers() { return answers.elements(); } public Enumeration<DNSRR> getAuthorities() { return authorities.elements(); } public Enumeration<DNSRR> getAdditional() { return additional.elements(); } }