Added xbill derrived DNS - WIP
This commit is contained in:
parent
b17dfce221
commit
2a66a70a4f
85
src/dorkbox/network/dns/Compression.java
Normal file
85
src/dorkbox/network/dns/Compression.java
Normal file
|
@ -0,0 +1,85 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns;
|
||||
|
||||
import dorkbox.network.dns.records.DnsMessage;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
|
||||
/**
|
||||
* DNS Name Compression object.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see DnsMessage
|
||||
* @see Name
|
||||
*/
|
||||
|
||||
public
|
||||
class Compression {
|
||||
|
||||
private static final int TABLE_SIZE = 17;
|
||||
private static final int MAX_POINTER = 0x3FFF;
|
||||
private Entry[] table;
|
||||
private boolean verbose = Options.check("verbosecompression");
|
||||
|
||||
|
||||
private static
|
||||
class Entry {
|
||||
Name name;
|
||||
int pos;
|
||||
Entry next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Compression object.
|
||||
*/
|
||||
public
|
||||
Compression() {
|
||||
table = new Entry[TABLE_SIZE];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a compression entry mapping a name to a position in a message.
|
||||
*
|
||||
* @param pos The position at which the name is added.
|
||||
* @param name The name being added to the message.
|
||||
*/
|
||||
public
|
||||
void add(int pos, Name name) {
|
||||
if (pos > MAX_POINTER) {
|
||||
return;
|
||||
}
|
||||
int row = (name.hashCode() & 0x7FFFFFFF) % TABLE_SIZE;
|
||||
Entry entry = new Entry();
|
||||
entry.name = name;
|
||||
entry.pos = pos;
|
||||
entry.next = table[row];
|
||||
table[row] = entry;
|
||||
if (verbose) {
|
||||
System.err.println("Adding " + name + " at " + pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the position of the given name, if it has been previously
|
||||
* included in the message.
|
||||
*
|
||||
* @param name The name to find in the compression table.
|
||||
*
|
||||
* @return The position of the name, or -1 if not found.
|
||||
*/
|
||||
public
|
||||
int get(Name name) {
|
||||
int row = (name.hashCode() & 0x7FFFFFFF) % TABLE_SIZE;
|
||||
int pos = -1;
|
||||
for (Entry entry = table[row]; entry != null; entry = entry.next) {
|
||||
if (entry.name.equals(name)) {
|
||||
pos = entry.pos;
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
System.err.println("Looking for " + name + ", found " + pos);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
237
src/dorkbox/network/dns/DnsInput.java
Normal file
237
src/dorkbox/network/dns/DnsInput.java
Normal file
|
@ -0,0 +1,237 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns;
|
||||
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
/**
|
||||
* An class for parsing DNS messages.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class DnsInput {
|
||||
|
||||
private ByteBuf byteBuf;
|
||||
private int savedActiveIndex = -1;
|
||||
private boolean marked = false;
|
||||
|
||||
/**
|
||||
* Creates a new DnsInput
|
||||
*
|
||||
* @param input The byte array to read from
|
||||
*/
|
||||
public
|
||||
DnsInput(byte[] input) {
|
||||
byteBuf = Unpooled.wrappedBuffer(input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DnsInput from the given {@link ByteBuf}
|
||||
*
|
||||
* @param byteBuf The ByteBuf
|
||||
*/
|
||||
public
|
||||
DnsInput(ByteBuf byteBuf) {
|
||||
this.byteBuf = byteBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position, for reading only
|
||||
*/
|
||||
public
|
||||
int readIndex() {
|
||||
return byteBuf.readerIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* NOTE: "Active" restricts operations to a specific part of the buffer, defined by the current position + length. Operations that
|
||||
* extend BEYOND this section are denied by virtue that we set the max readable length in the underlying ByteBuf.
|
||||
*
|
||||
* Marks the following bytes in the stream as active, and saves it's state (so it can be restored later)
|
||||
*
|
||||
* @param len The number of bytes in the active region.
|
||||
*
|
||||
* @throws IllegalArgumentException The number of bytes in the active region
|
||||
* is longer than the remainder of the input.
|
||||
*/
|
||||
public
|
||||
void setActive(int len) {
|
||||
savedActiveIndex = byteBuf.writerIndex();
|
||||
|
||||
if (len > byteBuf.readableBytes()) {
|
||||
throw new IllegalArgumentException("cannot set active " + "region past end of input");
|
||||
}
|
||||
|
||||
byteBuf.writerIndex(byteBuf.readerIndex() + len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the previously set active region.
|
||||
*/
|
||||
public
|
||||
void restoreActive() {
|
||||
if (savedActiveIndex > -1) {
|
||||
byteBuf.writerIndex(savedActiveIndex);
|
||||
savedActiveIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current position of the input stream to the specified index,
|
||||
* and clears the active region.
|
||||
*
|
||||
* @param index The position to continue parsing at.
|
||||
*
|
||||
* @throws IllegalArgumentException The index is not within the input.
|
||||
*/
|
||||
public
|
||||
void jump(int index) {
|
||||
if (index >= byteBuf.capacity()) {
|
||||
throw new IllegalArgumentException("cannot jump past " + "end of input");
|
||||
}
|
||||
byteBuf.readerIndex(index);
|
||||
|
||||
restoreActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current state of the input stream. Both the current position and
|
||||
* the end of the active region are saved.
|
||||
*
|
||||
* @throws IllegalArgumentException The index is not within the input.
|
||||
*/
|
||||
public
|
||||
void save() {
|
||||
marked = true;
|
||||
byteBuf.markReaderIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the input stream to its state before the call to {@link #save}.
|
||||
*/
|
||||
public
|
||||
void restore() {
|
||||
if (!marked) {
|
||||
throw new IllegalStateException("Not marked first");
|
||||
}
|
||||
byteBuf.resetReaderIndex();
|
||||
}
|
||||
|
||||
private
|
||||
void require(int n) throws WireParseException {
|
||||
if (n > remaining()) {
|
||||
throw new WireParseException("end of input");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bytes that can be read from this stream before
|
||||
* reaching the end.
|
||||
*/
|
||||
public
|
||||
int remaining() {
|
||||
return byteBuf.readableBytes();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned 8 bit value from the stream, as an int.
|
||||
*
|
||||
* @return An unsigned 8 bit value.
|
||||
*
|
||||
* @throws WireParseException The end of the stream was reached.
|
||||
*/
|
||||
public
|
||||
int readU8() throws WireParseException {
|
||||
require(1);
|
||||
return byteBuf.readUnsignedByte();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned 16 bit value from the stream, as an int.
|
||||
*
|
||||
* @return An unsigned 16 bit value.
|
||||
*
|
||||
* @throws WireParseException The end of the stream was reached.
|
||||
*/
|
||||
public
|
||||
int readU16() throws WireParseException {
|
||||
require(2);
|
||||
return byteBuf.readUnsignedShort();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads an unsigned 32 bit value from the stream, as a long.
|
||||
*
|
||||
* @return An unsigned 32 bit value.
|
||||
*
|
||||
* @throws WireParseException The end of the stream was reached.
|
||||
*/
|
||||
public
|
||||
long readU32() throws WireParseException {
|
||||
require(4);
|
||||
return byteBuf.readUnsignedInt();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte array of a specified length from the stream into an existing
|
||||
* array.
|
||||
*
|
||||
* @param b The array to read into.
|
||||
* @param off The offset of the array to start copying data into.
|
||||
* @param len The number of bytes to copy.
|
||||
*
|
||||
* @throws WireParseException The end of the stream was reached.
|
||||
*/
|
||||
public
|
||||
void readByteArray(byte[] b, int off, int len) throws WireParseException {
|
||||
require(len);
|
||||
byteBuf.readBytes(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte array of a specified length from the stream.
|
||||
*
|
||||
* @return The byte array.
|
||||
*
|
||||
* @throws WireParseException The end of the stream was reached.
|
||||
*/
|
||||
public
|
||||
byte[] readByteArray(int len) throws WireParseException {
|
||||
require(len);
|
||||
byte[] out = new byte[len];
|
||||
byteBuf.readBytes(out, 0, len);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a byte array consisting of the remainder of the stream (or the
|
||||
* active region, if one is set.
|
||||
*
|
||||
* @return The byte array.
|
||||
*/
|
||||
public
|
||||
byte[] readByteArray() {
|
||||
int len = remaining();
|
||||
byte[] out = new byte[len];
|
||||
byteBuf.readBytes(out, 0, len);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a counted string from the stream. A counted string is a one byte
|
||||
* value indicating string length, followed by bytes of data.
|
||||
*
|
||||
* @return A byte array containing the string.
|
||||
*
|
||||
* @throws WireParseException The end of the stream was reached.
|
||||
*/
|
||||
public
|
||||
byte[] readCountedString() throws WireParseException {
|
||||
int len = readU8();
|
||||
return readByteArray(len);
|
||||
}
|
||||
}
|
221
src/dorkbox/network/dns/DnsOutput.java
Normal file
221
src/dorkbox/network/dns/DnsOutput.java
Normal file
|
@ -0,0 +1,221 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
|
||||
/**
|
||||
* A class for rendering DNS messages.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
|
||||
public
|
||||
class DnsOutput {
|
||||
|
||||
private ByteBuf byteBuf;
|
||||
private boolean marked = false;
|
||||
|
||||
/**
|
||||
* Create a new DnsOutput
|
||||
*/
|
||||
public
|
||||
DnsOutput() {
|
||||
this(32);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DnsOutput with a specified size.
|
||||
*
|
||||
* @param size The initial size
|
||||
*/
|
||||
public
|
||||
DnsOutput(int size) {
|
||||
this(Unpooled.buffer(size));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new DnsOutput with a specified ByteBuf.
|
||||
*
|
||||
* @param byteBuf The ByteBuf to use
|
||||
*/
|
||||
public
|
||||
DnsOutput(ByteBuf byteBuf) {
|
||||
this.byteBuf = byteBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current position.
|
||||
*/
|
||||
public
|
||||
int current() {
|
||||
return byteBuf.writerIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the current position of the output stream to the specified index.
|
||||
*
|
||||
* @param index The new current position.
|
||||
*
|
||||
* @throws IllegalArgumentException The index is not within the output.
|
||||
*/
|
||||
public
|
||||
void jump(int index) {
|
||||
if (index >= byteBuf.writerIndex()) {
|
||||
// we haven't written data to this point yet, and the contract for jump() is that it can only jump to a PREVIOUSLY written spot
|
||||
throw new IllegalArgumentException("Unable to jump to invalid position " + index + ". Max is " + byteBuf.writerIndex());
|
||||
}
|
||||
|
||||
byteBuf.writerIndex(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the current state of the output stream.
|
||||
*
|
||||
* @throws IllegalArgumentException The index is not within the output.
|
||||
*/
|
||||
public
|
||||
void save() {
|
||||
marked = true;
|
||||
byteBuf.markWriterIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the input stream to its state before the call to {@link #save}.
|
||||
*/
|
||||
public
|
||||
void restore() {
|
||||
if (!marked) {
|
||||
throw new IllegalStateException("Not marked first");
|
||||
}
|
||||
byteBuf.resetWriterIndex();
|
||||
marked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an unsigned 8 bit value to the stream.
|
||||
*
|
||||
* @param val The value to be written
|
||||
*/
|
||||
public
|
||||
void writeU8(int val) {
|
||||
check(val, 8);
|
||||
|
||||
byteBuf.ensureWritable(1);
|
||||
byteBuf.writeByte(val);
|
||||
}
|
||||
|
||||
private
|
||||
void check(long val, int bits) {
|
||||
long max = 1;
|
||||
max <<= bits;
|
||||
if (val < 0 || val > max) {
|
||||
throw new IllegalArgumentException(val + " out of range for " + bits + " bit value");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an unsigned 16 bit value to the stream.
|
||||
*
|
||||
* @param val The value to be written
|
||||
*/
|
||||
public
|
||||
void writeU16(int val) {
|
||||
check(val, 16);
|
||||
|
||||
byteBuf.ensureWritable(2);
|
||||
byteBuf.writeShort(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an unsigned 16 bit value to the specified position in the stream.
|
||||
*
|
||||
* @param val The value to be written
|
||||
* @param where The position to write the value.
|
||||
*/
|
||||
public
|
||||
void writeU16At(int val, int where) {
|
||||
check(val, 16);
|
||||
|
||||
// save and set both the read/write index, otherwise if the read index is > write index, errors happen.
|
||||
int saved = byteBuf.writerIndex();
|
||||
int readSaved = byteBuf.readerIndex();
|
||||
|
||||
byteBuf.setIndex(where, where);
|
||||
byteBuf.ensureWritable(2);
|
||||
byteBuf.writeShort(val);
|
||||
|
||||
byteBuf.writerIndex(saved);
|
||||
byteBuf.readerIndex(readSaved);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes an unsigned 32 bit value to the stream.
|
||||
*
|
||||
* @param val The value to be written
|
||||
*/
|
||||
public
|
||||
void writeU32(long val) {
|
||||
check(val, 32);
|
||||
|
||||
byteBuf.ensureWritable(4);
|
||||
byteBuf.writeInt((int) val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array to the stream.
|
||||
*
|
||||
* @param b The array to write.
|
||||
*/
|
||||
public
|
||||
void writeByteArray(byte[] b) {
|
||||
writeByteArray(b, 0, b.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a byte array to the stream.
|
||||
*
|
||||
* @param b The array to write.
|
||||
* @param off The offset of the array to start copying data from.
|
||||
* @param len The number of bytes to write.
|
||||
*/
|
||||
public
|
||||
void writeByteArray(byte[] b, int off, int len) {
|
||||
byteBuf.ensureWritable(len);
|
||||
byteBuf.writeBytes(b, off, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a counted string from the stream. A counted string is a one byte
|
||||
* value indicating string length, followed by bytes of data.
|
||||
*
|
||||
* @param s The string to write.
|
||||
*/
|
||||
public
|
||||
void writeCountedString(byte[] s) {
|
||||
if (s.length > 0xFF) {
|
||||
throw new IllegalArgumentException("Invalid counted string");
|
||||
}
|
||||
|
||||
byteBuf.ensureWritable(1 + s.length);
|
||||
byteBuf.writeByte(s.length);
|
||||
byteBuf.writeBytes(s, 0, s.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a byte array containing the current contents of the stream.
|
||||
*/
|
||||
public
|
||||
byte[] toByteArray() {
|
||||
byte[] out = new byte[byteBuf.writerIndex()];
|
||||
byteBuf.readBytes(out, 0, out.length);
|
||||
return out;
|
||||
}
|
||||
|
||||
public
|
||||
ByteBuf getByteBuf() {
|
||||
return byteBuf;
|
||||
}
|
||||
}
|
222
src/dorkbox/network/dns/Mnemonic.java
Normal file
222
src/dorkbox/network/dns/Mnemonic.java
Normal file
|
@ -0,0 +1,222 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* A utility class for converting between numeric codes and mnemonics
|
||||
* for those codes. Mnemonics are case insensitive.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
public
|
||||
class Mnemonic {
|
||||
|
||||
private static Integer cachedInts[] = new Integer[64];
|
||||
/* Strings are case-sensitive. */
|
||||
public static final int CASE_SENSITIVE = 1;
|
||||
/* Strings will be stored/searched for in uppercase. */
|
||||
public static final int CASE_UPPER = 2;
|
||||
/* Strings will be stored/searched for in lowercase. */
|
||||
public static final int CASE_LOWER = 3;
|
||||
|
||||
|
||||
private HashMap<String, Integer> strings;
|
||||
private HashMap<Integer, String> values;
|
||||
private String description;
|
||||
private int wordcase;
|
||||
private String prefix;
|
||||
private int max;
|
||||
private boolean numericok;
|
||||
|
||||
static {
|
||||
for (int i = 0; i < cachedInts.length; i++) {
|
||||
cachedInts[i] = new Integer(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Mnemonic table.
|
||||
*
|
||||
* @param description A short description of the mnemonic to use when
|
||||
* @param wordcase Whether to convert strings into uppercase, lowercase,
|
||||
* or leave them unchanged.
|
||||
* throwing exceptions.
|
||||
*/
|
||||
public
|
||||
Mnemonic(String description, int wordcase) {
|
||||
this.description = description;
|
||||
this.wordcase = wordcase;
|
||||
strings = new HashMap();
|
||||
values = new HashMap();
|
||||
max = Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum numeric value
|
||||
*/
|
||||
public
|
||||
void setMaximum(int max) {
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prefix to use when converting to and from values that don't
|
||||
* have mnemonics.
|
||||
*/
|
||||
public
|
||||
void setPrefix(String prefix) {
|
||||
this.prefix = sanitize(prefix);
|
||||
}
|
||||
|
||||
/* Converts a String to the correct case. */
|
||||
private
|
||||
String sanitize(String str) {
|
||||
if (wordcase == CASE_UPPER) {
|
||||
return str.toUpperCase();
|
||||
}
|
||||
else if (wordcase == CASE_LOWER) {
|
||||
return str.toLowerCase();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether numeric values stored in strings are acceptable.
|
||||
*/
|
||||
public
|
||||
void setNumericAllowed(boolean numeric) {
|
||||
this.numericok = numeric;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the text representation of a numeric value.
|
||||
*
|
||||
* @param val The numeric value
|
||||
* @param string The text string
|
||||
*/
|
||||
public
|
||||
void add(int val, String string) {
|
||||
check(val);
|
||||
Integer value = toInteger(val);
|
||||
string = sanitize(string);
|
||||
strings.put(string, value);
|
||||
values.put(value, string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an int into a possibly cached Integer.
|
||||
*/
|
||||
public static
|
||||
Integer toInteger(int val) {
|
||||
if (val >= 0 && val < cachedInts.length) {
|
||||
return (cachedInts[val]);
|
||||
}
|
||||
return new Integer(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a numeric value is within the range [0..max]
|
||||
*/
|
||||
public
|
||||
void check(int val) {
|
||||
if (val < 0 || val > max) {
|
||||
throw new IllegalArgumentException(description + " " + val + "is out of range");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines an additional text representation of a numeric value. This will
|
||||
* be used by getValue(), but not getText().
|
||||
*
|
||||
* @param val The numeric value
|
||||
* @param string The text string
|
||||
*/
|
||||
public
|
||||
void addAlias(int val, String string) {
|
||||
check(val);
|
||||
Integer value = toInteger(val);
|
||||
string = sanitize(string);
|
||||
strings.put(string, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all mnemonics from one table into another.
|
||||
*
|
||||
* @param source The Mnemonic source to add from
|
||||
*
|
||||
* @throws IllegalArgumentException The wordcases of the Mnemonics do not
|
||||
* match.
|
||||
*/
|
||||
public
|
||||
void addAll(Mnemonic source) {
|
||||
if (wordcase != source.wordcase) {
|
||||
throw new IllegalArgumentException(source.description + ": wordcases do not match");
|
||||
}
|
||||
strings.putAll(source.strings);
|
||||
values.putAll(source.values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text mnemonic corresponding to a numeric value.
|
||||
*
|
||||
* @param val The numeric value
|
||||
*
|
||||
* @return The corresponding text mnemonic.
|
||||
*/
|
||||
public
|
||||
String getText(int val) {
|
||||
check(val);
|
||||
String str = (String) values.get(toInteger(val));
|
||||
if (str != null) {
|
||||
return str;
|
||||
}
|
||||
str = Integer.toString(val);
|
||||
if (prefix != null) {
|
||||
return prefix + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the numeric value corresponding to a text mnemonic.
|
||||
*
|
||||
* @param str The text mnemonic
|
||||
*
|
||||
* @return The corresponding numeric value, or -1 if there is none
|
||||
*/
|
||||
public
|
||||
int getValue(String str) {
|
||||
str = sanitize(str);
|
||||
Integer value = (Integer) strings.get(str);
|
||||
if (value != null) {
|
||||
return value.intValue();
|
||||
}
|
||||
if (prefix != null) {
|
||||
if (str.startsWith(prefix)) {
|
||||
int val = parseNumeric(str.substring(prefix.length()));
|
||||
if (val >= 0) {
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (numericok) {
|
||||
return parseNumeric(str);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private
|
||||
int parseNumeric(String s) {
|
||||
try {
|
||||
int val = Integer.parseInt(s);
|
||||
if (val >= 0 && val <= max) {
|
||||
return val;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
989
src/dorkbox/network/dns/Name.java
Normal file
989
src/dorkbox/network/dns/Name.java
Normal file
|
@ -0,0 +1,989 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import dorkbox.network.dns.exceptions.NameTooLongException;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.records.DNAMERecord;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
|
||||
/**
|
||||
* A representation of a domain name. It may either be absolute (fully
|
||||
* qualified) or relative.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class Name implements Comparable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7257019940971525644L;
|
||||
|
||||
private static final int LABEL_NORMAL = 0;
|
||||
private static final int LABEL_COMPRESSION = 0xC0;
|
||||
private static final int LABEL_MASK = 0xC0;
|
||||
|
||||
/* The name data */
|
||||
private byte[] name;
|
||||
|
||||
/*
|
||||
* Effectively an 8 byte array, where the low order byte stores the number
|
||||
* of labels and the 7 higher order bytes store per-label offsets.
|
||||
*/
|
||||
private long offsets;
|
||||
|
||||
/* Precomputed hashcode. */
|
||||
private int hashcode;
|
||||
|
||||
private static final byte[] emptyLabel = new byte[] {(byte) 0};
|
||||
private static final byte[] wildLabel = new byte[] {(byte) 1, (byte) '*'};
|
||||
|
||||
/**
|
||||
* The root name
|
||||
*/
|
||||
public static final Name root;
|
||||
|
||||
/**
|
||||
* The root name
|
||||
*/
|
||||
public static final Name empty;
|
||||
|
||||
/**
|
||||
* The maximum length of a Name
|
||||
*/
|
||||
private static final int MAXNAME = 255;
|
||||
|
||||
/**
|
||||
* The maximum length of a label a Name
|
||||
*/
|
||||
private static final int MAXLABEL = 63;
|
||||
|
||||
/**
|
||||
* The maximum number of labels in a Name
|
||||
*/
|
||||
private static final int MAXLABELS = 128;
|
||||
|
||||
/**
|
||||
* The maximum number of cached offsets
|
||||
*/
|
||||
private static final int MAXOFFSETS = 7;
|
||||
|
||||
/* Used for printing non-printable characters */
|
||||
private static final DecimalFormat byteFormat = new DecimalFormat();
|
||||
|
||||
/* Used to efficiently convert bytes to lowercase */
|
||||
private static final byte lowercase[] = new byte[256];
|
||||
|
||||
/* Used in wildcard names. */
|
||||
private static final Name wild;
|
||||
|
||||
static {
|
||||
byteFormat.setMinimumIntegerDigits(3);
|
||||
for (int i = 0; i < lowercase.length; i++) {
|
||||
if (i < 'A' || i > 'Z') {
|
||||
lowercase[i] = (byte) i;
|
||||
}
|
||||
else {
|
||||
lowercase[i] = (byte) (i - 'A' + 'a');
|
||||
}
|
||||
}
|
||||
root = new Name();
|
||||
root.appendSafe(emptyLabel, 0, 1);
|
||||
empty = new Name();
|
||||
empty.name = new byte[0];
|
||||
wild = new Name();
|
||||
wild.appendSafe(wildLabel, 0, 1);
|
||||
}
|
||||
|
||||
private
|
||||
Name() {
|
||||
}
|
||||
|
||||
private
|
||||
void setoffset(int n, int offset) {
|
||||
if (n >= MAXOFFSETS) {
|
||||
return;
|
||||
}
|
||||
int shift = 8 * (7 - n);
|
||||
offsets &= (~(0xFFL << shift));
|
||||
offsets |= ((long) offset << shift);
|
||||
}
|
||||
|
||||
private
|
||||
int offset(int n) {
|
||||
if (n == 0 && getlabels() == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (n < 0 || n >= getlabels()) {
|
||||
throw new IllegalArgumentException("label out of range");
|
||||
}
|
||||
if (n < MAXOFFSETS) {
|
||||
int shift = 8 * (7 - n);
|
||||
return ((int) (offsets >>> shift) & 0xFF);
|
||||
}
|
||||
else {
|
||||
int pos = offset(MAXOFFSETS - 1);
|
||||
for (int i = MAXOFFSETS - 1; i < n; i++) {
|
||||
pos += (name[pos] + 1);
|
||||
}
|
||||
return (pos);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
void setlabels(int labels) {
|
||||
offsets &= ~(0xFF);
|
||||
offsets |= labels;
|
||||
}
|
||||
|
||||
private static
|
||||
void copy(Name src, Name dst) {
|
||||
if (src.offset(0) == 0) {
|
||||
dst.name = src.name;
|
||||
dst.offsets = src.offsets;
|
||||
}
|
||||
else {
|
||||
int offset0 = src.offset(0);
|
||||
int namelen = src.name.length - offset0;
|
||||
int labels = src.labels();
|
||||
dst.name = new byte[namelen];
|
||||
System.arraycopy(src.name, offset0, dst.name, 0, namelen);
|
||||
for (int i = 0; i < labels && i < MAXOFFSETS; i++) {
|
||||
dst.setoffset(i, src.offset(i) - offset0);
|
||||
}
|
||||
dst.setlabels(labels);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
void append(byte[] array, int start, int n) throws NameTooLongException {
|
||||
int length = (name == null ? 0 : (name.length - offset(0)));
|
||||
int alength = 0;
|
||||
for (int i = 0, pos = start; i < n; i++) {
|
||||
int len = array[pos];
|
||||
if (len > MAXLABEL) {
|
||||
throw new IllegalStateException("invalid label");
|
||||
}
|
||||
len++;
|
||||
pos += len;
|
||||
alength += len;
|
||||
}
|
||||
int newlength = length + alength;
|
||||
if (newlength > MAXNAME) {
|
||||
throw new NameTooLongException();
|
||||
}
|
||||
int labels = getlabels();
|
||||
int newlabels = labels + n;
|
||||
if (newlabels > MAXLABELS) {
|
||||
throw new IllegalStateException("too many labels");
|
||||
}
|
||||
byte[] newname = new byte[newlength];
|
||||
if (length != 0) {
|
||||
System.arraycopy(name, offset(0), newname, 0, length);
|
||||
}
|
||||
System.arraycopy(array, start, newname, length, alength);
|
||||
name = newname;
|
||||
for (int i = 0, pos = length; i < n; i++) {
|
||||
setoffset(labels + i, pos);
|
||||
pos += (newname[pos] + 1);
|
||||
}
|
||||
setlabels(newlabels);
|
||||
}
|
||||
|
||||
private static
|
||||
TextParseException parseException(String str, String message) {
|
||||
return new TextParseException("'" + str + "': " + message);
|
||||
}
|
||||
|
||||
private
|
||||
void appendFromString(String fullName, byte[] array, int start, int n) throws TextParseException {
|
||||
try {
|
||||
append(array, start, n);
|
||||
} catch (NameTooLongException e) {
|
||||
throw parseException(fullName, "Name too long");
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
void appendSafe(byte[] array, int start, int n) {
|
||||
try {
|
||||
append(array, start, n);
|
||||
} catch (NameTooLongException e) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from a string and an origin. This does not automatically
|
||||
* make the name absolute; it will be absolute if it has a trailing dot or an
|
||||
* absolute origin is appended.
|
||||
*
|
||||
* @param s The string to be converted
|
||||
* @param origin If the name is not absolute, the origin to be appended.
|
||||
*
|
||||
* @throws TextParseException The name is invalid.
|
||||
*/
|
||||
public
|
||||
Name(String s, Name origin) throws TextParseException {
|
||||
if (s.equals("")) {
|
||||
throw parseException(s, "empty name");
|
||||
}
|
||||
else if (s.equals("@")) {
|
||||
if (origin == null) {
|
||||
copy(empty, this);
|
||||
}
|
||||
else {
|
||||
copy(origin, this);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (s.equals(".")) {
|
||||
copy(root, this);
|
||||
return;
|
||||
}
|
||||
int labelstart = -1;
|
||||
int pos = 1;
|
||||
byte[] label = new byte[MAXLABEL + 1];
|
||||
boolean escaped = false;
|
||||
int digits = 0;
|
||||
int intval = 0;
|
||||
boolean absolute = false;
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
byte b = (byte) s.charAt(i);
|
||||
if (escaped) {
|
||||
if (b >= '0' && b <= '9' && digits < 3) {
|
||||
digits++;
|
||||
intval *= 10;
|
||||
intval += (b - '0');
|
||||
if (intval > 255) {
|
||||
throw parseException(s, "bad escape");
|
||||
}
|
||||
if (digits < 3) {
|
||||
continue;
|
||||
}
|
||||
b = (byte) intval;
|
||||
}
|
||||
else if (digits > 0 && digits < 3) {
|
||||
throw parseException(s, "bad escape");
|
||||
}
|
||||
if (pos > MAXLABEL) {
|
||||
throw parseException(s, "label too long");
|
||||
}
|
||||
labelstart = pos;
|
||||
label[pos++] = b;
|
||||
escaped = false;
|
||||
}
|
||||
else if (b == '\\') {
|
||||
escaped = true;
|
||||
digits = 0;
|
||||
intval = 0;
|
||||
}
|
||||
else if (b == '.') {
|
||||
if (labelstart == -1) {
|
||||
throw parseException(s, "invalid empty label");
|
||||
}
|
||||
label[0] = (byte) (pos - 1);
|
||||
appendFromString(s, label, 0, 1);
|
||||
labelstart = -1;
|
||||
pos = 1;
|
||||
}
|
||||
else {
|
||||
if (labelstart == -1) {
|
||||
labelstart = i;
|
||||
}
|
||||
if (pos > MAXLABEL) {
|
||||
throw parseException(s, "label too long");
|
||||
}
|
||||
label[pos++] = b;
|
||||
}
|
||||
}
|
||||
if (digits > 0 && digits < 3) {
|
||||
throw parseException(s, "bad escape");
|
||||
}
|
||||
if (escaped) {
|
||||
throw parseException(s, "bad escape");
|
||||
}
|
||||
if (labelstart == -1) {
|
||||
appendFromString(s, emptyLabel, 0, 1);
|
||||
absolute = true;
|
||||
}
|
||||
else {
|
||||
label[0] = (byte) (pos - 1);
|
||||
appendFromString(s, label, 0, 1);
|
||||
}
|
||||
if (origin != null && !absolute) {
|
||||
appendFromString(s, origin.name, origin.offset(0), origin.getlabels());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from a string. This does not automatically make the name
|
||||
* absolute; it will be absolute if it has a trailing dot.
|
||||
*
|
||||
* @param s The string to be converted
|
||||
*
|
||||
* @throws TextParseException The name is invalid.
|
||||
*/
|
||||
public
|
||||
Name(String s) throws TextParseException {
|
||||
this(s, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from a string. This does not automatically make the name
|
||||
* absolute; it will be absolute if it has a trailing dot. This is identical
|
||||
* to the constructor, except that it will avoid creating new objects in some
|
||||
* cases.
|
||||
*
|
||||
* @param s The string to be converted
|
||||
*
|
||||
* @throws TextParseException The name is invalid.
|
||||
*/
|
||||
public static
|
||||
Name fromString(String s) throws TextParseException {
|
||||
return fromString(s, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from a string and an origin. This does not automatically
|
||||
* make the name absolute; it will be absolute if it has a trailing dot or an
|
||||
* absolute origin is appended. This is identical to the constructor, except
|
||||
* that it will avoid creating new objects in some cases.
|
||||
*
|
||||
* @param s The string to be converted
|
||||
* @param origin If the name is not absolute, the origin to be appended.
|
||||
*
|
||||
* @throws TextParseException The name is invalid.
|
||||
*/
|
||||
public static
|
||||
Name fromString(String s, Name origin) throws TextParseException {
|
||||
if (s.equals("@") && origin != null) {
|
||||
return origin;
|
||||
}
|
||||
else if (s.equals(".")) {
|
||||
return (root);
|
||||
}
|
||||
|
||||
return new Name(s, origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from a constant string. This should only be used when
|
||||
* the name is known to be good - that is, when it is constant.
|
||||
*
|
||||
* @param s The string to be converted
|
||||
*
|
||||
* @throws IllegalArgumentException The name is invalid.
|
||||
*/
|
||||
public static
|
||||
Name fromConstantString(String s) {
|
||||
try {
|
||||
return fromString(s, null);
|
||||
} catch (TextParseException e) {
|
||||
throw new IllegalArgumentException("Invalid name '" + s + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from DNS a wire format message
|
||||
*
|
||||
* @param in A stream containing the DNS message which is currently
|
||||
* positioned at the start of the name to be read.
|
||||
*/
|
||||
public
|
||||
Name(DnsInput in) throws WireParseException {
|
||||
int len, pos;
|
||||
boolean done = false;
|
||||
byte[] label = new byte[MAXLABEL + 1];
|
||||
boolean savedState = false;
|
||||
|
||||
while (!done) {
|
||||
len = in.readU8();
|
||||
switch (len & LABEL_MASK) {
|
||||
case LABEL_NORMAL:
|
||||
if (getlabels() >= MAXLABELS) {
|
||||
throw new WireParseException("too many labels");
|
||||
}
|
||||
if (len == 0) {
|
||||
append(emptyLabel, 0, 1);
|
||||
done = true;
|
||||
}
|
||||
else {
|
||||
label[0] = (byte) len;
|
||||
in.readByteArray(label, 1, len);
|
||||
append(label, 0, 1);
|
||||
}
|
||||
break;
|
||||
case LABEL_COMPRESSION:
|
||||
pos = in.readU8();
|
||||
pos += ((len & ~LABEL_MASK) << 8);
|
||||
if (Options.check("verbosecompression")) {
|
||||
System.err.println("currently " + in.readIndex() + ", pointer to " + pos);
|
||||
}
|
||||
|
||||
if (pos >= in.readIndex() - 2) {
|
||||
throw new WireParseException("bad compression");
|
||||
}
|
||||
if (!savedState) {
|
||||
in.save();
|
||||
savedState = true;
|
||||
}
|
||||
in.jump(pos);
|
||||
if (Options.check("verbosecompression")) {
|
||||
System.err.println("current name '" + this + "', seeking to " + pos);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new WireParseException("bad label type");
|
||||
}
|
||||
}
|
||||
if (savedState) {
|
||||
in.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name from DNS wire format
|
||||
*
|
||||
* @param b A byte array containing the wire format of the name.
|
||||
*/
|
||||
public
|
||||
Name(byte[] b) throws IOException {
|
||||
this(new DnsInput(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new name by removing labels from the beginning of an existing Name
|
||||
*
|
||||
* @param src An existing Name
|
||||
* @param n The number of labels to remove from the beginning in the copy
|
||||
*/
|
||||
public
|
||||
Name(Name src, int n) {
|
||||
int slabels = src.labels();
|
||||
if (n > slabels) {
|
||||
throw new IllegalArgumentException("attempted to remove too " + "many labels");
|
||||
}
|
||||
name = src.name;
|
||||
setlabels(slabels - n);
|
||||
for (int i = 0; i < MAXOFFSETS && i < slabels - n; i++) {
|
||||
setoffset(i, src.offset(i + n));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new name by concatenating two existing names.
|
||||
*
|
||||
* @param prefix The prefix name.
|
||||
* @param suffix The suffix name.
|
||||
*
|
||||
* @return The concatenated name.
|
||||
*
|
||||
* @throws NameTooLongException The name is too long.
|
||||
*/
|
||||
public static
|
||||
Name concatenate(Name prefix, Name suffix) throws NameTooLongException {
|
||||
if (prefix.isAbsolute()) {
|
||||
return (prefix);
|
||||
}
|
||||
Name newname = new Name();
|
||||
copy(prefix, newname);
|
||||
newname.append(suffix.name, suffix.offset(0), suffix.getlabels());
|
||||
return newname;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this name is a subdomain of origin, return a new name relative to
|
||||
* origin with the same value. Otherwise, return the existing name.
|
||||
*
|
||||
* @param origin The origin to remove.
|
||||
*
|
||||
* @return The possibly relativized name.
|
||||
*/
|
||||
public
|
||||
Name relativize(Name origin) {
|
||||
if (origin == null || !subdomain(origin)) {
|
||||
return this;
|
||||
}
|
||||
Name newname = new Name();
|
||||
copy(this, newname);
|
||||
int length = length() - origin.length();
|
||||
int labels = newname.labels() - origin.labels();
|
||||
newname.setlabels(labels);
|
||||
newname.name = new byte[length];
|
||||
System.arraycopy(name, offset(0), newname.name, 0, length);
|
||||
return newname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Name with the first n labels replaced by a wildcard
|
||||
*
|
||||
* @return The wildcard name
|
||||
*/
|
||||
public
|
||||
Name wild(int n) {
|
||||
if (n < 1) {
|
||||
throw new IllegalArgumentException("must replace 1 or more " + "labels");
|
||||
}
|
||||
try {
|
||||
Name newname = new Name();
|
||||
copy(wild, newname);
|
||||
newname.append(name, offset(n), getlabels() - n);
|
||||
return newname;
|
||||
} catch (NameTooLongException e) {
|
||||
throw new IllegalStateException("Name.wild: concatenate failed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a canonicalized version of the Name (all lowercase). This may be
|
||||
* the same name, if the input Name is already canonical.
|
||||
*/
|
||||
public
|
||||
Name canonicalize() {
|
||||
boolean canonical = true;
|
||||
for (int i = 0; i < name.length; i++) {
|
||||
if (lowercase[name[i] & 0xFF] != name[i]) {
|
||||
canonical = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (canonical) {
|
||||
return this;
|
||||
}
|
||||
|
||||
Name newname = new Name();
|
||||
newname.appendSafe(name, offset(0), getlabels());
|
||||
for (int i = 0; i < newname.name.length; i++) {
|
||||
newname.name[i] = lowercase[newname.name[i] & 0xFF];
|
||||
}
|
||||
|
||||
return newname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new Name to be used when following a DNAME.
|
||||
*
|
||||
* @param dname The DNAME record to follow.
|
||||
*
|
||||
* @return The constructed name.
|
||||
*
|
||||
* @throws NameTooLongException The resulting name is too long.
|
||||
*/
|
||||
public
|
||||
Name fromDNAME(DNAMERecord dname) throws NameTooLongException {
|
||||
Name dnameowner = dname.getName();
|
||||
Name dnametarget = dname.getTarget();
|
||||
if (!subdomain(dnameowner)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
int plabels = labels() - dnameowner.labels();
|
||||
int plength = length() - dnameowner.length();
|
||||
int pstart = offset(0);
|
||||
|
||||
int dlabels = dnametarget.labels();
|
||||
int dlength = dnametarget.length();
|
||||
|
||||
if (plength + dlength > MAXNAME) {
|
||||
throw new NameTooLongException();
|
||||
}
|
||||
|
||||
Name newname = new Name();
|
||||
newname.setlabels(plabels + dlabels);
|
||||
newname.name = new byte[plength + dlength];
|
||||
System.arraycopy(name, pstart, newname.name, 0, plength);
|
||||
System.arraycopy(dnametarget.name, 0, newname.name, plength, dlength);
|
||||
|
||||
for (int i = 0, pos = 0; i < MAXOFFSETS && i < plabels + dlabels; i++) {
|
||||
newname.setoffset(i, pos);
|
||||
pos += (newname.name[pos] + 1);
|
||||
}
|
||||
return newname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this name a wildcard?
|
||||
*/
|
||||
public
|
||||
boolean isWild() {
|
||||
if (labels() == 0) {
|
||||
return false;
|
||||
}
|
||||
return (name[0] == (byte) 1 && name[1] == (byte) '*');
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of labels in the name.
|
||||
*/
|
||||
public
|
||||
int labels() {
|
||||
return getlabels();
|
||||
}
|
||||
|
||||
private
|
||||
int getlabels() {
|
||||
return (int) (offsets & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this name absolute?
|
||||
*/
|
||||
public
|
||||
boolean isAbsolute() {
|
||||
int nlabels = labels();
|
||||
if (nlabels == 0) {
|
||||
return false;
|
||||
}
|
||||
return name[offset(nlabels - 1)] == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The length of the name.
|
||||
*/
|
||||
public
|
||||
short length() {
|
||||
if (getlabels() == 0) {
|
||||
return 0;
|
||||
}
|
||||
return (short) (name.length - offset(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the current Name a subdomain of the specified name?
|
||||
*/
|
||||
public
|
||||
boolean subdomain(Name domain) {
|
||||
int labels = labels();
|
||||
int dlabels = domain.labels();
|
||||
if (dlabels > labels) {
|
||||
return false;
|
||||
}
|
||||
if (dlabels == labels) {
|
||||
return equals(domain);
|
||||
}
|
||||
return domain.equals(name, offset(labels - dlabels));
|
||||
}
|
||||
|
||||
private
|
||||
String byteString(byte[] array, int pos) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int len = array[pos++];
|
||||
|
||||
for (int i = pos; i < pos + len; i++) {
|
||||
int b = array[i] & 0xFF;
|
||||
if (b <= 0x20 || b >= 0x7f) {
|
||||
sb.append('\\');
|
||||
sb.append(byteFormat.format(b));
|
||||
}
|
||||
else if (b == '"' || b == '(' || b == ')' || b == '.' || b == ';' || b == '\\' || b == '@' || b == '$') {
|
||||
sb.append('\\');
|
||||
sb.append((char) b);
|
||||
}
|
||||
else {
|
||||
sb.append((char) b);
|
||||
}
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Name to a String
|
||||
*
|
||||
* @param omitFinalDot If true, and the name is absolute, omit the final dot.
|
||||
*
|
||||
* @return The representation of this name as a (printable) String.
|
||||
*/
|
||||
public
|
||||
String toString(boolean omitFinalDot) {
|
||||
int labels = labels();
|
||||
if (labels == 0) {
|
||||
return "@";
|
||||
}
|
||||
else if (labels == 1 && name[offset(0)] == 0) {
|
||||
return ".";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0, pos = offset(0); i < labels; i++) {
|
||||
int len = name[pos];
|
||||
if (len > MAXLABEL) {
|
||||
throw new IllegalStateException("invalid label");
|
||||
}
|
||||
if (len == 0) {
|
||||
if (!omitFinalDot) {
|
||||
sb.append('.');
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (i > 0) {
|
||||
sb.append('.');
|
||||
}
|
||||
sb.append(byteString(name, pos));
|
||||
pos += (1 + len);
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the nth label of a Name. This makes a copy of the label; changing
|
||||
* this does not change the Name.
|
||||
*
|
||||
* @param n The label to be retrieved. The first label is 0.
|
||||
*/
|
||||
public
|
||||
byte[] getLabel(int n) {
|
||||
int pos = offset(n);
|
||||
byte len = (byte) (name[pos] + 1);
|
||||
byte[] label = new byte[len];
|
||||
System.arraycopy(name, pos, label, 0, len);
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the nth label in a Name to a String
|
||||
*
|
||||
* @param n The label to be converted to a (printable) String. The first
|
||||
* label is 0.
|
||||
*/
|
||||
public
|
||||
String getLabelString(int n) {
|
||||
int pos = offset(n);
|
||||
return byteString(name, pos);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a Name in DNS wire format
|
||||
*
|
||||
* @param out The output stream containing the DNS message.
|
||||
* @param c The compression context, or null of no compression is desired.
|
||||
*
|
||||
* @throws IllegalArgumentException The name is not absolute.
|
||||
*/
|
||||
public
|
||||
void toWire(DnsOutput out, Compression c) {
|
||||
if (!isAbsolute()) {
|
||||
throw new IllegalArgumentException("toWire() called on " + "non-absolute name");
|
||||
}
|
||||
|
||||
int labels = labels();
|
||||
for (int i = 0; i < labels - 1; i++) {
|
||||
Name tname;
|
||||
if (i == 0) {
|
||||
tname = this;
|
||||
}
|
||||
else {
|
||||
tname = new Name(this, i);
|
||||
}
|
||||
int pos = -1;
|
||||
if (c != null) {
|
||||
pos = c.get(tname);
|
||||
}
|
||||
if (pos >= 0) {
|
||||
pos |= (LABEL_MASK << 8);
|
||||
out.writeU16(pos);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if (c != null) {
|
||||
c.add(out.current(), tname);
|
||||
}
|
||||
int off = offset(i);
|
||||
out.writeByteArray(name, off, name[off] + 1);
|
||||
}
|
||||
}
|
||||
out.writeU8(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a Name in DNS wire format
|
||||
*
|
||||
* @throws IllegalArgumentException The name is not absolute.
|
||||
*/
|
||||
public
|
||||
byte[] toWire() {
|
||||
DnsOutput out = new DnsOutput();
|
||||
toWire(out, null);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a Name in canonical DNS wire format (all lowercase)
|
||||
*
|
||||
* @param out The output stream to which the message is written.
|
||||
*/
|
||||
public
|
||||
void toWireCanonical(DnsOutput out) {
|
||||
byte[] b = toWireCanonical();
|
||||
out.writeByteArray(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a Name in canonical DNS wire format (all lowercase)
|
||||
*
|
||||
* @return The canonical form of the name.
|
||||
*/
|
||||
public
|
||||
byte[] toWireCanonical() {
|
||||
int labels = labels();
|
||||
if (labels == 0) {
|
||||
return (new byte[0]);
|
||||
}
|
||||
byte[] b = new byte[name.length - offset(0)];
|
||||
for (int i = 0, spos = offset(0), dpos = 0; i < labels; i++) {
|
||||
int len = name[spos];
|
||||
if (len > MAXLABEL) {
|
||||
throw new IllegalStateException("invalid label");
|
||||
}
|
||||
b[dpos++] = name[spos++];
|
||||
for (int j = 0; j < len; j++) {
|
||||
b[dpos++] = lowercase[(name[spos++] & 0xFF)];
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Emit a Name in DNS wire format
|
||||
*
|
||||
* @param out The output stream containing the DNS message.
|
||||
* @param c The compression context, or null of no compression is desired.
|
||||
* @param canonical If true, emit the name in canonicalized form
|
||||
* (all lowercase).
|
||||
*
|
||||
* @throws IllegalArgumentException The name is not absolute.
|
||||
*/
|
||||
public
|
||||
void toWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
if (canonical) {
|
||||
toWireCanonical(out);
|
||||
}
|
||||
else {
|
||||
toWire(out, c);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
boolean equals(byte[] b, int bpos) {
|
||||
int labels = labels();
|
||||
for (int i = 0, pos = offset(0); i < labels; i++) {
|
||||
if (name[pos] != b[bpos]) {
|
||||
return false;
|
||||
}
|
||||
int len = name[pos++];
|
||||
bpos++;
|
||||
if (len > MAXLABEL) {
|
||||
throw new IllegalStateException("invalid label");
|
||||
}
|
||||
for (int j = 0; j < len; j++) {
|
||||
if (lowercase[(name[pos++] & 0xFF)] != lowercase[(b[bpos++] & 0xFF)]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes a hashcode based on the value
|
||||
*/
|
||||
public
|
||||
int hashCode() {
|
||||
if (hashcode != 0) {
|
||||
return (hashcode);
|
||||
}
|
||||
int code = 0;
|
||||
for (int i = offset(0); i < name.length; i++) {
|
||||
code += ((code << 3) + lowercase[(name[i] & 0xFF)]);
|
||||
}
|
||||
hashcode = code;
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are these two Names equivalent?
|
||||
*/
|
||||
public
|
||||
boolean equals(Object arg) {
|
||||
if (arg == this) {
|
||||
return true;
|
||||
}
|
||||
if (arg == null || !(arg instanceof Name)) {
|
||||
return false;
|
||||
}
|
||||
Name d = (Name) arg;
|
||||
if (d.hashcode == 0) {
|
||||
d.hashCode();
|
||||
}
|
||||
if (hashcode == 0) {
|
||||
hashCode();
|
||||
}
|
||||
if (d.hashcode != hashcode) {
|
||||
return false;
|
||||
}
|
||||
if (d.labels() != labels()) {
|
||||
return false;
|
||||
}
|
||||
return equals(d.name, d.offset(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Name to a String
|
||||
*
|
||||
* @return The representation of this name as a (printable) String.
|
||||
*/
|
||||
public
|
||||
String toString() {
|
||||
return toString(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this Name to another Object.
|
||||
*
|
||||
* @param o The Object to be compared.
|
||||
*
|
||||
* @return The value 0 if the argument is a name equivalent to this name;
|
||||
* a value less than 0 if the argument is less than this name in the canonical
|
||||
* ordering, and a value greater than 0 if the argument is greater than this
|
||||
* name in the canonical ordering.
|
||||
*
|
||||
* @throws ClassCastException if the argument is not a Name.
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
int compareTo(Object o) {
|
||||
Name arg = (Name) o;
|
||||
|
||||
if (this == arg) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
int labels = labels();
|
||||
int alabels = arg.labels();
|
||||
int compares = labels > alabels ? alabels : labels;
|
||||
|
||||
for (int i = 1; i <= compares; i++) {
|
||||
int start = offset(labels - i);
|
||||
int astart = arg.offset(alabels - i);
|
||||
int length = name[start];
|
||||
int alength = arg.name[astart];
|
||||
for (int j = 0; j < length && j < alength; j++) {
|
||||
int n = lowercase[(name[j + start + 1]) & 0xFF] - lowercase[(arg.name[j + astart + 1]) & 0xFF];
|
||||
if (n != 0) {
|
||||
return (n);
|
||||
}
|
||||
}
|
||||
if (length != alength) {
|
||||
return (length - alength);
|
||||
}
|
||||
}
|
||||
return (labels - alabels);
|
||||
}
|
||||
|
||||
}
|
132
src/dorkbox/network/dns/constants/DnsClass.java
Normal file
132
src/dorkbox/network/dns/constants/DnsClass.java
Normal file
|
@ -0,0 +1,132 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.exceptions.InvalidDClassException;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to DNS classes. This is called DnsClass to avoid confusion with Class.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
public final
|
||||
class DnsClass {
|
||||
|
||||
/**
|
||||
* Internet DNS resource record class: {@code IN}
|
||||
*/
|
||||
public static final int IN = 1;
|
||||
|
||||
/**
|
||||
* Computer Science Network network DNS resource record class: {@code CSNET}. It was never installed as a top-level domain
|
||||
* in the Domain Name System, but parsed in the message routing logic of mail transport agents (MTA). It was introduced in 1985.
|
||||
*/
|
||||
public static final int CS = 2;
|
||||
|
||||
/**
|
||||
* Computer Science Network network DNS resource record class: {@code CSNET}. It was never installed as a top-level domain
|
||||
* in the Domain Name System, but parsed in the message routing logic of mail transport agents (MTA). It was introduced in 1985.
|
||||
*/
|
||||
public static final int CSNET = 2;
|
||||
|
||||
/**
|
||||
* Chaos network DNS resource record class: {@code CH} (MIT)
|
||||
*/
|
||||
public static final int CH = 3;
|
||||
|
||||
/**
|
||||
* Chaos network DNS resource record class: {@code CHAOS} (MIT, alternate name)
|
||||
*/
|
||||
public static final int CHAOS = 3;
|
||||
|
||||
/**
|
||||
* Hesiod DNS resource record class: {@code HS} (MIT)
|
||||
*/
|
||||
public static final int HS = 4;
|
||||
|
||||
/**
|
||||
* Hesiod DNS resource record class: {@code HESIOD} (MIT, alternate name)
|
||||
*/
|
||||
public static final int HESIOD = 4;
|
||||
|
||||
/**
|
||||
* Special value used in dynamic update messages
|
||||
*/
|
||||
public static final int NONE = 254;
|
||||
|
||||
/**
|
||||
* Matches any class
|
||||
*/
|
||||
public static final int ANY = 255;
|
||||
|
||||
|
||||
|
||||
private static Mnemonic classes = new DClassMnemonic();
|
||||
|
||||
|
||||
private static
|
||||
class DClassMnemonic extends Mnemonic {
|
||||
DClassMnemonic() {
|
||||
super("DnsClass", CASE_UPPER);
|
||||
setPrefix("CLASS");
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void check(int val) {
|
||||
DnsClass.check(val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static {
|
||||
classes.add(IN, "IN");
|
||||
classes.add(CS, "CS");
|
||||
classes.addAlias(CSNET, "CSNET");
|
||||
classes.add(CH, "CH");
|
||||
classes.addAlias(CH, "CHAOS");
|
||||
classes.add(HS, "HS");
|
||||
classes.addAlias(HS, "HESIOD");
|
||||
classes.add(NONE, "NONE");
|
||||
classes.add(ANY, "ANY");
|
||||
}
|
||||
|
||||
private
|
||||
DnsClass() {}
|
||||
|
||||
/**
|
||||
* Checks that a numeric DnsClass is valid.
|
||||
*
|
||||
* @throws InvalidDClassException The class is out of range.
|
||||
*/
|
||||
public static
|
||||
void check(int i) {
|
||||
if (i < 0 || i > 0xFFFF) {
|
||||
throw new InvalidDClassException(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsClass into a String
|
||||
*
|
||||
* @return The canonical string representation of the class
|
||||
*
|
||||
* @throws InvalidDClassException The class is out of range.
|
||||
*/
|
||||
public static
|
||||
String string(int i) {
|
||||
return classes.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of a DnsClass into its numeric value
|
||||
*
|
||||
* @return The class code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return classes.getValue(s);
|
||||
}
|
||||
|
||||
}
|
73
src/dorkbox/network/dns/constants/DnsOpCode.java
Normal file
73
src/dorkbox/network/dns/constants/DnsOpCode.java
Normal file
|
@ -0,0 +1,73 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to DNS opcodes
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public final
|
||||
class DnsOpCode {
|
||||
|
||||
/**
|
||||
* A standard query
|
||||
*/
|
||||
public static final int QUERY = 0;
|
||||
|
||||
/**
|
||||
* An inverse query (deprecated)
|
||||
*/
|
||||
public static final int IQUERY = 1;
|
||||
|
||||
/**
|
||||
* A server status request (not used)
|
||||
*/
|
||||
public static final int STATUS = 2;
|
||||
|
||||
/**
|
||||
* A message from a primary to a secondary server to initiate a zone transfer
|
||||
*/
|
||||
public static final int NOTIFY = 4;
|
||||
|
||||
/**
|
||||
* A dynamic update message
|
||||
*/
|
||||
public static final int UPDATE = 5;
|
||||
|
||||
private static Mnemonic opcodes = new Mnemonic("DNS DnsOpCode", Mnemonic.CASE_UPPER);
|
||||
|
||||
static {
|
||||
opcodes.setMaximum(0xF);
|
||||
opcodes.setPrefix("RESERVED");
|
||||
opcodes.setNumericAllowed(true);
|
||||
|
||||
opcodes.add(QUERY, "QUERY");
|
||||
opcodes.add(IQUERY, "IQUERY");
|
||||
opcodes.add(STATUS, "STATUS");
|
||||
opcodes.add(NOTIFY, "NOTIFY");
|
||||
opcodes.add(UPDATE, "UPDATE");
|
||||
}
|
||||
|
||||
private
|
||||
DnsOpCode() {}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsOpCode into a String
|
||||
*/
|
||||
public static
|
||||
String string(int i) {
|
||||
return opcodes.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of an DnsOpCode into its numeric value
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return opcodes.getValue(s);
|
||||
}
|
||||
}
|
565
src/dorkbox/network/dns/constants/DnsRecordType.java
Normal file
565
src/dorkbox/network/dns/constants/DnsRecordType.java
Normal file
|
@ -0,0 +1,565 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.exceptions.InvalidTypeException;
|
||||
import dorkbox.network.dns.records.DnsRecord;
|
||||
import dorkbox.network.dns.records.DnsTypeProtoAssignment;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to DNS Types
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public final
|
||||
class DnsRecordType {
|
||||
|
||||
/**
|
||||
* Address record RFC 1035 Returns a 32-bit IPv4 address, most commonly used
|
||||
* to map hostnames to an IP address of the host, but also used for DNSBLs,
|
||||
* storing subnet masks in RFC 1101, etc.
|
||||
*/
|
||||
public static final int A = 1;
|
||||
|
||||
/**
|
||||
* Name server record RFC 1035 Delegates a DNS zone to use the given
|
||||
* authoritative name servers
|
||||
*/
|
||||
public static final int NS = 2;
|
||||
|
||||
/**
|
||||
* Mail destination. MD specifies the final destination to which a message addressed to a given domain name should be delivered
|
||||
* (Obsolete, as it's behavior has been replaced by MX)
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int MD = 3;
|
||||
|
||||
/**
|
||||
* Mail forwarder. MF specifies a host that would forward mail on to the eventual destination, should that destination be unreachable.
|
||||
* (Obsolete, as it's behavior has been replaced by MX)
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int MF = 4;
|
||||
|
||||
/**
|
||||
* Canonical name (alias) record RFC 1035 Alias of one name to another: the DNS
|
||||
* lookup will continue by retrying the lookup with the new name.
|
||||
*/
|
||||
public static final int CNAME = 5;
|
||||
|
||||
/**
|
||||
* Start of [a zone of] authority record RFC 1035 and RFC 2308 Specifies
|
||||
* authoritative information about a DNS zone, including the primary name
|
||||
* server, the email of the domain administrator, the domain serial number,
|
||||
* and several timers relating to refreshing the zone.
|
||||
*/
|
||||
public static final int SOA = 6;
|
||||
|
||||
/**
|
||||
* Mailbox domain name RFC 1035. EXPERIMENTAL. A <domain-name> which specifies a host which has the
|
||||
* specified mailbox.
|
||||
*/
|
||||
public static final int MB = 7;
|
||||
|
||||
/**
|
||||
* Mail group member RFC 1035. EXPERIMENTAL. A <domain-name> which specifies a mailbox which is a
|
||||
* member of the mail group specified by the domain name. MG records cause no additional section processing.
|
||||
*/
|
||||
public static final int MG = 8;
|
||||
|
||||
/**
|
||||
* Mail rename name RFC 1035. EXPERIMENTAL. A <domain-name> which specifies a mailbox which is the
|
||||
* proper rename of the specified mailbox.
|
||||
*/
|
||||
public static final int MR = 9;
|
||||
|
||||
/**
|
||||
* Null record RFC 1035. EXPERIMENTAL. Anything at all may be in the RDATA field so long as it is 65535 octets
|
||||
* or less
|
||||
*/
|
||||
public static final int NULL = 10;
|
||||
|
||||
/**
|
||||
* The WKS record RFC 1035 is used to describe the well known services supported by
|
||||
* a particular protocol on a particular internet address.
|
||||
*/
|
||||
public static final int WKS = 11;
|
||||
|
||||
/**
|
||||
* Pointer record RFC 1035 Pointer to a canonical name. Unlike a CNAME, DNS
|
||||
* processing does NOT proceed, just the name is returned. The most common
|
||||
* use is for implementing reverse DNS lookups, but other uses include such
|
||||
* things as DNS-SD.
|
||||
*/
|
||||
public static final int PTR = 12;
|
||||
|
||||
/**
|
||||
* Host information HINFO RFC 1035. records are used to acquire general information about a host. The
|
||||
* main use is for protocols such as FTP that can use special procedures when talking between machines
|
||||
* or operating systems of the same type.
|
||||
*/
|
||||
public static final int HINFO = 13;
|
||||
|
||||
/**
|
||||
* Mailbox or mail list information RFC 1035. EXPERIMENTAL. MINFO records cause no additional section processing. Although these
|
||||
* records can be associated with a simple mailbox, they are usually used with a mailing list.
|
||||
*/
|
||||
public static final int MINFO = 14;
|
||||
|
||||
/**
|
||||
* Mail exchange (routing) record RFC 1035 Maps a domain name to a list of message transfer agents for that domain.
|
||||
*/
|
||||
public static final int MX = 15;
|
||||
|
||||
/**
|
||||
* Text record RFC 1035 Originally for arbitrary human-readable text in a
|
||||
* DNS record. Since the early 1990s, however, this record more often
|
||||
* carries machine-readable data, such as specified by RFC 1464,
|
||||
* opportunistic encryption, Sender Policy Framework, DKIM, DMARC DNS-SD,
|
||||
* etc.
|
||||
*/
|
||||
public static final int TXT = 16;
|
||||
|
||||
/**
|
||||
* Responsible person record RFC 1183 Information about the responsible
|
||||
* person(s) for the domain. Usually an email address with the @ replaced by
|
||||
* a .
|
||||
*/
|
||||
public static final int RP = 17;
|
||||
|
||||
/**
|
||||
* AFS cell database record RFC 1183 Location of database servers of an AFS cell.
|
||||
* This record is commonly used by AFS clients to contact AFS cells outside
|
||||
* their local domain. A subtype of this record is used by the obsolete
|
||||
* DCE/DFS file system.
|
||||
*/
|
||||
public static final int AFSDB = 18;
|
||||
|
||||
/**
|
||||
* X.25 calling address
|
||||
*/
|
||||
public static final int X25 = 19;
|
||||
|
||||
/**
|
||||
* ISDN calling address
|
||||
*/
|
||||
public static final int ISDN = 20;
|
||||
|
||||
/**
|
||||
* Router
|
||||
*/
|
||||
public static final int RT = 21;
|
||||
|
||||
/**
|
||||
* NSAP address
|
||||
*/
|
||||
public static final int NSAP = 22;
|
||||
|
||||
/**
|
||||
* Reverse NSAP address (deprecated)
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int NSAP_PTR = 23;
|
||||
|
||||
/**
|
||||
* Signature record RFC 2535 Signature record used in SIG(0) (RFC 2931) and
|
||||
* TKEY (RFC 2930). RFC 3755 designated RRSIG as the replacement for SIG for
|
||||
* use within DNSSEC.
|
||||
*/
|
||||
public static final int SIG = 24;
|
||||
|
||||
/**
|
||||
* key record RFC 2535 and RFC 2930 Used only for SIG(0) (RFC 2931) and TKEY
|
||||
* (RFC 2930). RFC 3445 eliminated their use for application keys and
|
||||
* limited their use to DNSSEC. RFC 3755 designates DNSKEY as the
|
||||
* replacement within DNSSEC. RFC 4025 designates IPSECKEY as the
|
||||
* replacement for use with IPsec.
|
||||
*/
|
||||
public static final int KEY = 25;
|
||||
|
||||
/**
|
||||
* X.400 mail mapping
|
||||
*/
|
||||
public static final int PX = 26;
|
||||
|
||||
/**
|
||||
* Geographical position (withdrawn)
|
||||
*/
|
||||
@Deprecated
|
||||
public static final int GPOS = 27;
|
||||
|
||||
/**
|
||||
* IPv6 address record RFC 3596 Returns a 128-bit IPv6 address, most
|
||||
* commonly used to map hostnames to an IP address of the host.
|
||||
*/
|
||||
public static final int AAAA = 28;
|
||||
|
||||
/**
|
||||
* Location record RFC 1876 Specifies a geographical location associated
|
||||
* with a domain name.
|
||||
*/
|
||||
public static final int LOC = 29;
|
||||
|
||||
/**
|
||||
* Next valid name in zone
|
||||
*/
|
||||
public static final int NXT = 30;
|
||||
|
||||
/**
|
||||
* Endpoint identifier
|
||||
*/
|
||||
public static final int EID = 31;
|
||||
|
||||
/**
|
||||
* Nimrod locator
|
||||
*/
|
||||
public static final int NIMLOC = 32;
|
||||
|
||||
/**
|
||||
* Service selection locator RFC 2782 Generalized service location record, used for
|
||||
* newer protocols instead of creating protocol-specific records such as MX.
|
||||
*/
|
||||
public static final int SRV = 33;
|
||||
|
||||
/**
|
||||
* ATM address
|
||||
*/
|
||||
public static final int ATMA = 34;
|
||||
|
||||
/**
|
||||
* Naming Authority Pointer record RFC 3403 Allows regular expression based
|
||||
* rewriting of domain names which can then be used as URIs, further domain
|
||||
* names to lookups, etc.
|
||||
*/
|
||||
public static final int NAPTR = 35;
|
||||
|
||||
/**
|
||||
* Key eXchanger record RFC 2230 Used with some cryptographic systems (not
|
||||
* including DNSSEC) to identify a key management agent for the associated
|
||||
* domain-name. Note that this has nothing to do with DNS Security. It is
|
||||
* Informational status, rather than being on the IETF standards-track. It
|
||||
* has always had limited deployment, but is still in use.
|
||||
*/
|
||||
public static final int KX = 36;
|
||||
|
||||
/**
|
||||
* Certificate record RFC 4398 Stores PKIX, SPKI, PGP, etc.
|
||||
*/
|
||||
public static final int CERT = 37;
|
||||
|
||||
/**
|
||||
* IPv6 address (experimental)
|
||||
*/
|
||||
public static final int A6 = 38;
|
||||
|
||||
/**
|
||||
* Delegation name record RFC 2672 DNAME creates an alias for a name and all
|
||||
* its subnames, unlike CNAME, which aliases only the exact name in its
|
||||
* label. Like the CNAME record, the DNS lookup will continue by retrying
|
||||
* the lookup with the new name. This is also known as Non-terminal name redirection
|
||||
*/
|
||||
public static final int DNAME = 39;
|
||||
|
||||
/**
|
||||
* Options - contains EDNS metadata. Option record RFC 2671 This is a pseudo DNS
|
||||
* record type needed to support EDNS.
|
||||
*/
|
||||
public static final int OPT = 41;
|
||||
|
||||
/**
|
||||
* Address Prefix List record RFC 3123 Specify lists of address ranges, e.g.
|
||||
* in CIDR format, for various address families. Experimental.
|
||||
*/
|
||||
public static final int APL = 42;
|
||||
|
||||
/**
|
||||
* Delegation signer record RFC 4034 The record used to identify the DNSSEC
|
||||
* signing key of a delegated zone.
|
||||
*/
|
||||
public static final int DS = 43;
|
||||
|
||||
/**
|
||||
* SSH Public Key Fingerprint record RFC 4255 Resource record for publishing
|
||||
* SSH public host key fingerprints in the DNS System, in order to aid in
|
||||
* verifying the authenticity of the host. RFC 6594 defines ECC SSH keys and
|
||||
* SHA-256 hashes. See the IANA SSHFP RR parameters registry for details.
|
||||
*/
|
||||
public static final int SSHFP = 44;
|
||||
|
||||
/**
|
||||
* IPsec Key record RFC 4025 Key record that can be used with IPsec.
|
||||
*/
|
||||
public static final int IPSECKEY = 45;
|
||||
|
||||
/**
|
||||
* Resource Record Signature. DNSSEC signature record RFC 4034 Signature for a DNSSEC-secured record
|
||||
* set. Uses the same format as the SIG record.
|
||||
*/
|
||||
public static final int RRSIG = 46;
|
||||
|
||||
/**
|
||||
* Next Secure Name. Next-Secure record RFC 4034 Part of DNSSEC, used to prove a name does not
|
||||
* exist. Uses the same format as the (obsolete) NXT record.
|
||||
*/
|
||||
public static final int NSEC = 47;
|
||||
|
||||
/**
|
||||
* DNSSEC Key record RFC 4034 The key record used in DNSSEC. Uses the same
|
||||
* format as the KEY record.
|
||||
*/
|
||||
public static final int DNSKEY = 48;
|
||||
|
||||
/**
|
||||
* Dynamic Host Configuration Protocol (DHCP) ID. DHCP identifier record RFC 4701
|
||||
* Used in conjunction with the FQDN option to DHCP.
|
||||
*/
|
||||
public static final int DHCID = 49;
|
||||
|
||||
/**
|
||||
* Next SECure, 3rd edition, RFC 5155. An extension to DNSSEC that allows proof
|
||||
* of nonexistence for a name without permitting zonewalking.
|
||||
*/
|
||||
public static final int NSEC3 = 50;
|
||||
|
||||
/**
|
||||
* NSEC3 parameters record RFC 5155 Parameter record for use with NSEC3.
|
||||
*/
|
||||
public static final int NSEC3PARAM = 51;
|
||||
|
||||
/**
|
||||
* Transport Layer Security Authentication, draft-ietf-dane-protocol-23.
|
||||
* TLSA certificate association record RFC 6698 A record for DNS-based
|
||||
* Authentication of Named Entities (DANE). RFC 6698 defines The TLSA DNS
|
||||
* resource record is used to associate a TLS server certificate or public
|
||||
* key with the domain name where the record is found, thus forming a 'TLSA
|
||||
* certificate association'.
|
||||
*/
|
||||
public static final int TLSA = 52;
|
||||
|
||||
/**
|
||||
* S/MIME cert association, draft-ietf-dane-smime
|
||||
*/
|
||||
public static final int SMIMEA = 53;
|
||||
|
||||
|
||||
/**
|
||||
* Host Identity Protocol record RFC 5205 Method of separating the end-point
|
||||
* identifier and locator roles of IP addresses.
|
||||
*/
|
||||
public static final int HIP = 55;
|
||||
|
||||
/**
|
||||
* OpenPGP Key, RFC 7929
|
||||
*/
|
||||
public static final int OPENPGPKEY = 61;
|
||||
|
||||
/**
|
||||
* Sender Policy Framework (experimental) record RFC 4408 Specified as part of the SPF
|
||||
* protocol as an alternative to of storing SPF data in TXT records. Uses
|
||||
* the same format as the earlier TXT record.
|
||||
*/
|
||||
public static final int SPF = 99;
|
||||
|
||||
/**
|
||||
* Transaction key - used to compute a shared secret or exchange a key.
|
||||
* Secret key record RFC 2930 A method of providing keying material to be
|
||||
* used with TSIG that is encrypted under the public key in an accompanying
|
||||
* KEY RR..
|
||||
*/
|
||||
public static final int TKEY = 249;
|
||||
|
||||
/**
|
||||
* Transaction Signature record RFC 2845 Can be used to authenticate dynamic
|
||||
* updates as coming from an approved client, or to authenticate responses
|
||||
* as coming from an approved recursive name server similar to DNSSEC.
|
||||
*/
|
||||
public static final int TSIG = 250;
|
||||
|
||||
/**
|
||||
* Incremental Zone Transfer record RFC 1996 Requests a zone transfer of the
|
||||
* given zone but only differences from a previous serial number. This
|
||||
* request may be ignored and a full (AXFR) sent in response if the
|
||||
* authoritative server is unable to fulfill the request due to
|
||||
* configuration or lack of required deltas.
|
||||
*/
|
||||
public static final int IXFR = 251;
|
||||
|
||||
/**
|
||||
* Authoritative Zone Transfer record RFC 1035 Transfer entire zone file
|
||||
* from the master name server to secondary name servers.
|
||||
*/
|
||||
public static final int AXFR = 252;
|
||||
|
||||
/**
|
||||
* Transfer mailbox records
|
||||
*/
|
||||
public static final int MAILB = 253;
|
||||
|
||||
/**
|
||||
* Transfer mail agent records
|
||||
*/
|
||||
public static final int MAILA = 254;
|
||||
|
||||
/**
|
||||
* Matches any type
|
||||
*
|
||||
* All cached records RFC 1035 Returns all records of all types known to the
|
||||
* name server. If the name server does not have any information on the
|
||||
* name, the request will be forwarded on. The records returned may not be
|
||||
* complete. For example, if there is both an A and an MX for a name, but
|
||||
* the name server has only the A record cached, only the A record will be
|
||||
* returned. Sometimes referred to as ANY, for example in Windows nslookup
|
||||
* and Wireshark.
|
||||
*/
|
||||
public static final int ANY = 255;
|
||||
|
||||
/**
|
||||
* URI
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/draft-faltstrom-uri-14">draft-faltstrom-uri-14</a>
|
||||
*/
|
||||
public static final int URI = 256;
|
||||
|
||||
/**
|
||||
* Certification Authority Authorization, RFC 6844. CA pinning,
|
||||
* constraining acceptable CAs for a host/domain.
|
||||
*/
|
||||
public static final int CAA = 257;
|
||||
|
||||
/**
|
||||
* DNSSEC Trust Authorities record N/A Part of a deployment proposal for
|
||||
* DNSSEC without a signed DNS root. See the IANA database and Weiler Spec
|
||||
* for details. Uses the same format as the DS record.
|
||||
*/
|
||||
public static final int TA = 32768;
|
||||
|
||||
/**
|
||||
* DNSSEC Lookaside Validation, RFC 4431. For publishing DNSSEC trust
|
||||
* anchors outside of the DNS delegation chain. Uses the same format as the
|
||||
* DS record. RFC 5074 describes a way of using these records.
|
||||
*/
|
||||
public static final int DLV = 32769;
|
||||
private static TypeMnemonic types = new TypeMnemonic();
|
||||
|
||||
|
||||
public static
|
||||
class TypeMnemonic extends Mnemonic {
|
||||
private HashMap objects;
|
||||
|
||||
public
|
||||
TypeMnemonic() {
|
||||
super("DnsRecordType", CASE_UPPER);
|
||||
setPrefix("TYPE");
|
||||
objects = new HashMap();
|
||||
}
|
||||
|
||||
public
|
||||
void add(int val, String str, DnsRecord proto) {
|
||||
super.add(val, str);
|
||||
objects.put(Mnemonic.toInteger(val), proto);
|
||||
}
|
||||
|
||||
public
|
||||
<T extends DnsRecord> T getProto(int val) {
|
||||
check(val);
|
||||
return (T) objects.get(toInteger(val));
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void check(int val) {
|
||||
DnsRecordType.check(val);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
// this is so we don't have to make each type constructor public
|
||||
DnsTypeProtoAssignment.assign(types);
|
||||
}
|
||||
|
||||
private
|
||||
DnsRecordType() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a numeric DnsRecordType is valid.
|
||||
*
|
||||
* @throws InvalidTypeException The type is out of range.
|
||||
*/
|
||||
public static
|
||||
void check(int val) {
|
||||
if (val < 0 || val > 0xFFFF) {
|
||||
throw new InvalidTypeException(val);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsRecordType into a String
|
||||
*
|
||||
* @param val The type value.
|
||||
*
|
||||
* @return The canonical string representation of the type
|
||||
*
|
||||
* @throws InvalidTypeException The type is out of range.
|
||||
*/
|
||||
public static
|
||||
String string(int val) {
|
||||
return types.getText(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of an DnsRecordType into its numeric value
|
||||
*
|
||||
* @return The type code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return value(s, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of an DnsRecordType into its numeric value.
|
||||
*
|
||||
* @param s The string representation of the type
|
||||
* @param numberok Whether a number will be accepted or not.
|
||||
*
|
||||
* @return The type code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s, boolean numberok) {
|
||||
int val = types.getValue(s);
|
||||
if (val == -1 && numberok) {
|
||||
val = types.getValue("TYPE" + s);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
public static
|
||||
<T extends DnsRecord> T getProto(int val) {
|
||||
return types.getProto(val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this type valid for a record (a non-meta type)?
|
||||
*/
|
||||
public static
|
||||
boolean isRR(int type) {
|
||||
switch (type) {
|
||||
case OPT:
|
||||
case TKEY:
|
||||
case TSIG:
|
||||
case IXFR:
|
||||
case AXFR:
|
||||
case MAILB:
|
||||
case MAILA:
|
||||
case ANY:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
180
src/dorkbox/network/dns/constants/DnsResponseCode.java
Normal file
180
src/dorkbox/network/dns/constants/DnsResponseCode.java
Normal file
|
@ -0,0 +1,180 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to DNS rcodes (error values)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public final
|
||||
class DnsResponseCode {
|
||||
|
||||
private static Mnemonic rcodes = new Mnemonic("DNS DnsResponseCode", Mnemonic.CASE_UPPER);
|
||||
|
||||
private static Mnemonic tsigrcodes = new Mnemonic("TSIG rcode", Mnemonic.CASE_UPPER);
|
||||
|
||||
/**
|
||||
* No error
|
||||
*/
|
||||
public static final int NOERROR = 0;
|
||||
|
||||
/**
|
||||
* Format error
|
||||
*/
|
||||
public static final int FORMERR = 1;
|
||||
|
||||
/**
|
||||
* Server failure
|
||||
*/
|
||||
public static final int SERVFAIL = 2;
|
||||
|
||||
/**
|
||||
* The name does not exist
|
||||
*/
|
||||
public static final int NXDOMAIN = 3;
|
||||
|
||||
/**
|
||||
* The operation requested is not implemented
|
||||
*/
|
||||
public static final int NOTIMP = 4;
|
||||
|
||||
/**
|
||||
* Deprecated synonym for NOTIMP.
|
||||
*/
|
||||
public static final int NOTIMPL = 4;
|
||||
|
||||
/**
|
||||
* The operation was refused by the server
|
||||
*/
|
||||
public static final int REFUSED = 5;
|
||||
|
||||
/**
|
||||
* The name exists
|
||||
*/
|
||||
public static final int YXDOMAIN = 6;
|
||||
|
||||
/**
|
||||
* The RRset (name, type) exists
|
||||
*/
|
||||
public static final int YXRRSET = 7;
|
||||
|
||||
/**
|
||||
* The RRset (name, type) does not exist
|
||||
*/
|
||||
public static final int NXRRSET = 8;
|
||||
|
||||
/**
|
||||
* The requestor is not authorized to perform this operation
|
||||
*/
|
||||
public static final int NOTAUTH = 9;
|
||||
|
||||
/**
|
||||
* The zone specified is not a zone
|
||||
*/
|
||||
public static final int NOTZONE = 10;
|
||||
|
||||
|
||||
|
||||
/* EDNS extended rcodes */
|
||||
/**
|
||||
* Unsupported EDNS level
|
||||
*/
|
||||
public static final int BADVERS = 16;
|
||||
|
||||
|
||||
|
||||
/* TSIG/TKEY only rcodes */
|
||||
/**
|
||||
* The signature is invalid (TSIG/TKEY extended error)
|
||||
*/
|
||||
public static final int BADSIG = 16;
|
||||
|
||||
/**
|
||||
* The key is invalid (TSIG/TKEY extended error)
|
||||
*/
|
||||
public static final int BADKEY = 17;
|
||||
|
||||
/**
|
||||
* The time is out of range (TSIG/TKEY extended error)
|
||||
*/
|
||||
public static final int BADTIME = 18;
|
||||
|
||||
/**
|
||||
* The mode is invalid (TKEY extended error)
|
||||
*/
|
||||
public static final int BADMODE = 19;
|
||||
|
||||
/**
|
||||
* The 'BADNAME' DNS RCODE (20), as defined in <a href="https://tools.ietf.org/html/rfc2930">RFC2930</a>.
|
||||
*/
|
||||
public static final int BADNAME = 20;
|
||||
|
||||
/**
|
||||
* The 'BADALG' DNS RCODE (21), as defined in <a href="https://tools.ietf.org/html/rfc2930">RFC2930</a>.
|
||||
*/
|
||||
public static final int BADALG = 21;
|
||||
|
||||
static {
|
||||
rcodes.setMaximum(0xFFF);
|
||||
rcodes.setPrefix("RESERVED");
|
||||
rcodes.setNumericAllowed(true);
|
||||
|
||||
rcodes.add(NOERROR, "NOERROR");
|
||||
rcodes.add(FORMERR, "FORMERR");
|
||||
rcodes.add(SERVFAIL, "SERVFAIL");
|
||||
rcodes.add(NXDOMAIN, "NXDOMAIN");
|
||||
rcodes.add(NOTIMP, "NOTIMP");
|
||||
rcodes.addAlias(NOTIMP, "NOTIMPL");
|
||||
rcodes.add(REFUSED, "REFUSED");
|
||||
rcodes.add(YXDOMAIN, "YXDOMAIN");
|
||||
rcodes.add(YXRRSET, "YXRRSET");
|
||||
rcodes.add(NXRRSET, "NXRRSET");
|
||||
rcodes.add(NOTAUTH, "NOTAUTH");
|
||||
rcodes.add(NOTZONE, "NOTZONE");
|
||||
rcodes.add(BADVERS, "BADVERS");
|
||||
|
||||
tsigrcodes.setMaximum(0xFFFF);
|
||||
tsigrcodes.setPrefix("RESERVED");
|
||||
tsigrcodes.setNumericAllowed(true);
|
||||
tsigrcodes.addAll(rcodes);
|
||||
|
||||
tsigrcodes.add(BADSIG, "BADSIG");
|
||||
tsigrcodes.add(BADKEY, "BADKEY");
|
||||
tsigrcodes.add(BADTIME, "BADTIME");
|
||||
tsigrcodes.add(BADMODE, "BADMODE");
|
||||
tsigrcodes.add(BADNAME, "BADNAME");
|
||||
tsigrcodes.add(BADALG, "BADALG");
|
||||
}
|
||||
|
||||
private
|
||||
DnsResponseCode() {}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsResponseCode into a String
|
||||
*/
|
||||
public static
|
||||
String string(int i) {
|
||||
return rcodes.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a numeric TSIG extended DnsResponseCode into a String
|
||||
*/
|
||||
public static
|
||||
String TSIGstring(int i) {
|
||||
return tsigrcodes.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of an DnsResponseCode into its numeric value
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return rcodes.getValue(s);
|
||||
}
|
||||
|
||||
}
|
115
src/dorkbox/network/dns/constants/DnsSection.java
Normal file
115
src/dorkbox/network/dns/constants/DnsSection.java
Normal file
|
@ -0,0 +1,115 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to DNS message sections
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public final
|
||||
class DnsSection {
|
||||
public static final int TOTAL_SECTION_COUNT = 4;
|
||||
|
||||
/**
|
||||
* The question (first) section
|
||||
*/
|
||||
public static final int QUESTION = 0;
|
||||
|
||||
/**
|
||||
* The answer (second) section
|
||||
*/
|
||||
public static final int ANSWER = 1;
|
||||
|
||||
/**
|
||||
* The authority (third) section
|
||||
*/
|
||||
public static final int AUTHORITY = 2;
|
||||
|
||||
/**
|
||||
* The additional (fourth) section
|
||||
*/
|
||||
public static final int ADDITIONAL = 3;
|
||||
|
||||
/* Aliases for dynamic update */
|
||||
/**
|
||||
* The zone (first) section of a dynamic update message
|
||||
*/
|
||||
public static final int ZONE = 0;
|
||||
|
||||
/**
|
||||
* The prerequisite (second) section of a dynamic update message
|
||||
*/
|
||||
public static final int PREREQ = 1;
|
||||
|
||||
/**
|
||||
* The update (third) section of a dynamic update message
|
||||
*/
|
||||
public static final int UPDATE = 2;
|
||||
|
||||
private static Mnemonic sections = new Mnemonic("DnsMessage DnsSection", Mnemonic.CASE_LOWER);
|
||||
private static String[] longSections = new String[4];
|
||||
private static String[] updateSections = new String[4];
|
||||
|
||||
static {
|
||||
sections.setMaximum(3);
|
||||
sections.setNumericAllowed(true);
|
||||
|
||||
sections.add(QUESTION, "qd");
|
||||
sections.add(ANSWER, "an");
|
||||
sections.add(AUTHORITY, "au");
|
||||
sections.add(ADDITIONAL, "ad");
|
||||
|
||||
longSections[QUESTION] = "QUESTIONS";
|
||||
longSections[ANSWER] = "ANSWERS";
|
||||
longSections[AUTHORITY] = "AUTHORITY RECORDS";
|
||||
longSections[ADDITIONAL] = "ADDITIONAL RECORDS";
|
||||
|
||||
updateSections[ZONE] = "ZONE";
|
||||
updateSections[PREREQ] = "PREREQUISITES";
|
||||
updateSections[UPDATE] = "UPDATE RECORDS";
|
||||
updateSections[ADDITIONAL] = "ADDITIONAL RECORDS";
|
||||
}
|
||||
|
||||
private
|
||||
DnsSection() {}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsSection into an abbreviation String
|
||||
*/
|
||||
public static
|
||||
String string(int i) {
|
||||
return sections.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsSection into a full description String
|
||||
*/
|
||||
public static
|
||||
String longString(int i) {
|
||||
sections.check(i);
|
||||
return longSections[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a numeric DnsSection into a full description String for an update
|
||||
* DnsMessage.
|
||||
*/
|
||||
public static
|
||||
String updString(int i) {
|
||||
sections.check(i);
|
||||
return updateSections[i];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of a DnsSection into its numeric value
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return sections.getValue(s);
|
||||
}
|
||||
|
||||
}
|
105
src/dorkbox/network/dns/constants/Flags.java
Normal file
105
src/dorkbox/network/dns/constants/Flags.java
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.constants;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.records.ExtendedFlags;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to flags in the DNS header.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public final
|
||||
class Flags {
|
||||
|
||||
private static Mnemonic flags = new Mnemonic("DNS Header Flag", Mnemonic.CASE_LOWER);
|
||||
|
||||
/**
|
||||
* query/response
|
||||
*/
|
||||
public static final byte QR = 0;
|
||||
|
||||
/**
|
||||
* authoritative answer
|
||||
*/
|
||||
public static final byte AA = 5;
|
||||
|
||||
/**
|
||||
* truncated
|
||||
*/
|
||||
public static final byte TC = 6;
|
||||
|
||||
/**
|
||||
* recursion desired
|
||||
*/
|
||||
public static final byte RD = 7;
|
||||
|
||||
/**
|
||||
* recursion available
|
||||
*/
|
||||
public static final byte RA = 8;
|
||||
|
||||
/**
|
||||
* authenticated data
|
||||
*/
|
||||
public static final byte AD = 10;
|
||||
|
||||
/**
|
||||
* (security) checking disabled
|
||||
*/
|
||||
public static final byte CD = 11;
|
||||
|
||||
/**
|
||||
* dnssec ok (extended)
|
||||
*/
|
||||
public static final int DO = ExtendedFlags.DO;
|
||||
|
||||
static {
|
||||
flags.setMaximum(0xF);
|
||||
flags.setPrefix("FLAG");
|
||||
flags.setNumericAllowed(true);
|
||||
|
||||
flags.add(QR, "qr");
|
||||
flags.add(AA, "aa");
|
||||
flags.add(TC, "tc");
|
||||
flags.add(RD, "rd");
|
||||
flags.add(RA, "ra");
|
||||
flags.add(AD, "ad");
|
||||
flags.add(CD, "cd");
|
||||
}
|
||||
|
||||
private
|
||||
Flags() {}
|
||||
|
||||
/**
|
||||
* Converts a numeric Flag into a String
|
||||
*/
|
||||
public static
|
||||
String string(int i) {
|
||||
return flags.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a String representation of an Flag into its numeric value
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return flags.getValue(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if a bit in the flags field is a flag or not. If it's part of
|
||||
* the rcode or opcode, it's not.
|
||||
*/
|
||||
public static
|
||||
boolean isFlag(int index) {
|
||||
flags.check(index);
|
||||
if ((index >= 1 && index <= 4) || (index >= 12)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.decoder;
|
||||
|
||||
import dorkbox.network.dns.record.MailExchangerRecord;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.dns.DnsRecord;
|
||||
import io.netty.resolver.dns.DnsNameResolverAccess;
|
||||
|
||||
public
|
||||
class MailExchangerDecoder implements RecordDecoder<MailExchangerRecord> {
|
||||
|
||||
@Override
|
||||
public
|
||||
MailExchangerRecord decode(final DnsRecord record, final ByteBuf response) {
|
||||
int priority = response.readUnsignedShort();
|
||||
|
||||
String name = DnsNameResolverAccess.decodeDomainName(response);
|
||||
return new MailExchangerRecord(priority, name);
|
||||
}
|
||||
}
|
|
@ -1,26 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.decoder;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.DecoderException;
|
||||
import io.netty.handler.codec.dns.DnsRecord;
|
||||
|
||||
public
|
||||
interface RecordDecoder<T> {
|
||||
|
||||
T decode(final DnsRecord record, final ByteBuf response) throws DecoderException;
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.decoder;
|
||||
|
||||
import dorkbox.network.dns.record.ServiceRecord;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.dns.DnsRecord;
|
||||
import io.netty.resolver.dns.DnsNameResolverAccess;
|
||||
|
||||
public
|
||||
class ServiceDecoder implements RecordDecoder<ServiceRecord> {
|
||||
|
||||
@Override
|
||||
public
|
||||
ServiceRecord decode(final DnsRecord record, final ByteBuf response) {
|
||||
int priority = response.readShort();
|
||||
int weight = response.readShort();
|
||||
int port = response.readUnsignedShort();
|
||||
String target = DnsNameResolverAccess.decodeDomainName(response);
|
||||
|
||||
return new ServiceRecord(record.name(), priority, weight, port, target);
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.decoder;
|
||||
|
||||
import dorkbox.network.dns.record.StartOfAuthorityRecord;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.dns.DnsRecord;
|
||||
import io.netty.resolver.dns.DnsNameResolverAccess;
|
||||
|
||||
public
|
||||
class StartOfAuthorityDecoder implements RecordDecoder<StartOfAuthorityRecord> {
|
||||
|
||||
@Override
|
||||
public
|
||||
StartOfAuthorityRecord decode(final DnsRecord record, final ByteBuf response) {
|
||||
String primaryName = DnsNameResolverAccess.decodeDomainName(response);
|
||||
String personName = DnsNameResolverAccess.decodeDomainName(response);
|
||||
|
||||
long serial = response.readUnsignedInt();
|
||||
int refresh = response.readInt();
|
||||
int retry = response.readInt();
|
||||
int expire = response.readInt();
|
||||
long minimum = response.readUnsignedInt();
|
||||
|
||||
return new StartOfAuthorityRecord(primaryName, personName, serial, refresh, retry, expire, minimum);
|
||||
}
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.decoder;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.dns.DnsRecord;
|
||||
import io.netty.util.CharsetUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public
|
||||
class TextDecoder implements RecordDecoder<List<String>> {
|
||||
|
||||
@Override
|
||||
public
|
||||
List<String> decode(final DnsRecord record, final ByteBuf response) {
|
||||
List<String> list = new ArrayList<String>();
|
||||
|
||||
int index = response.readerIndex();
|
||||
while (index < response.writerIndex()) {
|
||||
int len = response.getUnsignedByte(index++);
|
||||
list.add(response.toString(index, len, CharsetUtil.UTF_8));
|
||||
index += len;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
/**
|
||||
* An exception thrown when an invalid dclass code is specified.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class InvalidDClassException extends IllegalArgumentException {
|
||||
|
||||
public
|
||||
InvalidDClassException(int dclass) {
|
||||
super("Invalid DNS class: " + dclass);
|
||||
}
|
||||
|
||||
}
|
19
src/dorkbox/network/dns/exceptions/InvalidTTLException.java
Normal file
19
src/dorkbox/network/dns/exceptions/InvalidTTLException.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
/**
|
||||
* An exception thrown when an invalid TTL is specified.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class InvalidTTLException extends IllegalArgumentException {
|
||||
|
||||
public
|
||||
InvalidTTLException(long ttl) {
|
||||
super("Invalid DNS TTL: " + ttl);
|
||||
}
|
||||
|
||||
}
|
19
src/dorkbox/network/dns/exceptions/InvalidTypeException.java
Normal file
19
src/dorkbox/network/dns/exceptions/InvalidTypeException.java
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
/**
|
||||
* An exception thrown when an invalid type code is specified.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class InvalidTypeException extends IllegalArgumentException {
|
||||
|
||||
public
|
||||
InvalidTypeException(int type) {
|
||||
super("Invalid DNS type: " + type);
|
||||
}
|
||||
|
||||
}
|
25
src/dorkbox/network/dns/exceptions/NameTooLongException.java
Normal file
25
src/dorkbox/network/dns/exceptions/NameTooLongException.java
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
/**
|
||||
* An exception thrown when a name is longer than the maximum length of a DNS
|
||||
* name.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class NameTooLongException extends WireParseException {
|
||||
|
||||
public
|
||||
NameTooLongException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public
|
||||
NameTooLongException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
|
||||
/**
|
||||
* An exception thrown when a relative name is passed as an argument to
|
||||
* a method requiring an absolute name.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class RelativeNameException extends IllegalArgumentException {
|
||||
|
||||
public
|
||||
RelativeNameException(Name name) {
|
||||
super("'" + name + "' is not an absolute name");
|
||||
}
|
||||
|
||||
public
|
||||
RelativeNameException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
26
src/dorkbox/network/dns/exceptions/TextParseException.java
Normal file
26
src/dorkbox/network/dns/exceptions/TextParseException.java
Normal file
|
@ -0,0 +1,26 @@
|
|||
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception thrown when unable to parse text.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class TextParseException extends IOException {
|
||||
|
||||
public
|
||||
TextParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public
|
||||
TextParseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
32
src/dorkbox/network/dns/exceptions/WireParseException.java
Normal file
32
src/dorkbox/network/dns/exceptions/WireParseException.java
Normal file
|
@ -0,0 +1,32 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* An exception thrown when a DNS message is invalid.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class WireParseException extends IOException {
|
||||
|
||||
public
|
||||
WireParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public
|
||||
WireParseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
public
|
||||
WireParseException(String s, Throwable cause) {
|
||||
super(s);
|
||||
initCause(cause);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) 2003-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.exceptions;
|
||||
|
||||
/**
|
||||
* An exception thrown when a zone transfer fails.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class ZoneTransferException extends Exception {
|
||||
|
||||
public
|
||||
ZoneTransferException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public
|
||||
ZoneTransferException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
}
|
17
src/dorkbox/network/dns/handlers/DnsHandler.java
Normal file
17
src/dorkbox/network/dns/handlers/DnsHandler.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package dorkbox.network.dns.handlers;
|
||||
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
import io.netty.channel.socket.DatagramChannel;
|
||||
|
||||
public
|
||||
class DnsHandler extends ChannelInitializer<DatagramChannel> {
|
||||
@Override
|
||||
protected
|
||||
void initChannel(DatagramChannel ch) throws Exception {
|
||||
ChannelPipeline pipeline = ch.pipeline();
|
||||
pipeline.addLast(new DnsMessageEncoder());
|
||||
pipeline.addLast(new DnsMessageDecoder());
|
||||
// pipeline.addLast(new DNSMessageDecoder());
|
||||
}
|
||||
}
|
46
src/dorkbox/network/dns/handlers/DnsMessageDecoder.java
Normal file
46
src/dorkbox/network/dns/handlers/DnsMessageDecoder.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
package dorkbox.network.dns.handlers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.handwerkszeug.dns.DNSMessage;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.socket.DatagramPacket;
|
||||
import io.netty.handler.codec.MessageToMessageDecoder;
|
||||
|
||||
|
||||
public
|
||||
class DnsMessageDecoder extends MessageToMessageDecoder<DatagramPacket> {
|
||||
@Override
|
||||
public
|
||||
void exceptionCaught(ChannelHandlerContext context, Throwable cause) throws Exception {
|
||||
// Channel channel = context.channel();
|
||||
|
||||
System.err.println("POW! ");
|
||||
cause.printStackTrace();
|
||||
// this.logger.error("Unexpected exception while trying to send/receive data on Client remote (network) channel. ({})" +
|
||||
// System.getProperty("line.separator"), channel.remoteAddress(), cause);
|
||||
// if (channel.isOpen()) {
|
||||
// channel.close();
|
||||
// }
|
||||
}
|
||||
|
||||
@Override
|
||||
protected
|
||||
void decode(ChannelHandlerContext ctx, DatagramPacket packet, List<Object> out) throws Exception {
|
||||
System.err.println("READING MESSAGE");
|
||||
final ByteBuf buf = packet.content();
|
||||
|
||||
boolean success = false;
|
||||
try {
|
||||
DNSMessage dnsMessage = new DNSMessage(buf);
|
||||
out.add(dnsMessage);
|
||||
success = true;
|
||||
} finally {
|
||||
if (!success) {
|
||||
buf.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
76
src/dorkbox/network/dns/handlers/DnsMessageEncoder.java
Normal file
76
src/dorkbox/network/dns/handlers/DnsMessageEncoder.java
Normal file
|
@ -0,0 +1,76 @@
|
|||
package dorkbox.network.dns.handlers;
|
||||
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.records.DnsMessage;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelHandler;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.MessageToByteEncoder;
|
||||
|
||||
/**
|
||||
* An encoder which serializes a Java object into a {@link ByteBuf}.
|
||||
* <p>
|
||||
* Please note that the serialized form this encoder produces is not
|
||||
* compatible with the standard {@link ObjectInputStream}. Please use
|
||||
* {@link ObjectDecoder} or {@link ObjectDecoderInputStream} to ensure the
|
||||
* interoperability with this encoder.
|
||||
*/
|
||||
|
||||
|
||||
@ChannelHandler.Sharable
|
||||
public
|
||||
class DnsMessageEncoder extends MessageToByteEncoder<DnsMessage> {
|
||||
|
||||
|
||||
// public
|
||||
// class ObjectEncoder extends MessageToByteEncoder<Serializable> {
|
||||
// private static final byte[] LENGTH_PLACEHOLDER = new byte[4];
|
||||
|
||||
// @Override
|
||||
// protected
|
||||
// void encode(ChannelHandlerContext ctx, Serializable msg, ByteBuf out) throws Exception {
|
||||
// int startIdx = out.writerIndex();
|
||||
//
|
||||
// ByteBufOutputStream bout = new ByteBufOutputStream(out);
|
||||
// ObjectOutputStream oout = null;
|
||||
// try {
|
||||
// bout.write(LENGTH_PLACEHOLDER);
|
||||
// oout = new CompactObjectOutputStream(bout);
|
||||
// oout.writeObject(msg);
|
||||
// oout.flush();
|
||||
// } finally {
|
||||
// if (oout != null) {
|
||||
// oout.close();
|
||||
// }
|
||||
// else {
|
||||
// bout.close();
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// int endIdx = out.writerIndex();
|
||||
//
|
||||
// out.setInt(startIdx, endIdx - startIdx - 4);
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected
|
||||
void encode(final ChannelHandlerContext ctx, final DnsMessage msg, final ByteBuf out) throws Exception {
|
||||
System.err.println("WRITING MESSAGE");
|
||||
final DnsOutput outd = new DnsOutput(out);
|
||||
msg.toWire(outd);
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
void exceptionCaught(ChannelHandlerContext context, Throwable cause) throws Exception {
|
||||
// Channel channel = context.channel();
|
||||
|
||||
System.err.println("POW! ");
|
||||
cause.printStackTrace();
|
||||
// this.logger.error("Unexpected exception while trying to send/receive data on Client remote (network) channel. ({})" +
|
||||
// System.getProperty("line.separator"), channel.remoteAddress(), cause);
|
||||
// if (channel.isOpen()) {
|
||||
// channel.close();
|
||||
// }
|
||||
}
|
||||
}
|
56
src/dorkbox/network/dns/handlers/DnsServerHandler.java
Normal file
56
src/dorkbox/network/dns/handlers/DnsServerHandler.java
Normal file
|
@ -0,0 +1,56 @@
|
|||
package dorkbox.network.dns.handlers;
|
||||
|
||||
import org.handwerkszeug.dns.server.DNSMessageDecoder;
|
||||
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelPipeline;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public
|
||||
class DnsServerHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
protected DNSMessageDecoder decoder = new DNSMessageDecoder();
|
||||
|
||||
public
|
||||
DnsServerHandler(final String threadName) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public final
|
||||
void channelRegistered(final ChannelHandlerContext context) throws Exception {
|
||||
boolean success = false;
|
||||
try {
|
||||
initChannel(context.channel());
|
||||
context.fireChannelRegistered();
|
||||
success = true;
|
||||
} catch (Throwable t) {
|
||||
// this.logger.error("Failed to initialize a channel. Closing: {}", context.channel(), t);
|
||||
} finally {
|
||||
if (!success) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* STEP 1: Channel is first created
|
||||
*/
|
||||
protected
|
||||
void initChannel(final Channel channel) {
|
||||
ChannelPipeline pipeline = channel.pipeline();
|
||||
|
||||
///////////////////////
|
||||
// DECODE (or upstream)
|
||||
///////////////////////
|
||||
pipeline.addLast("decoder", this.decoder);
|
||||
|
||||
// ENCODE (or downstream)
|
||||
/////////////////////////
|
||||
pipeline.addLast("fowarder", new ForwardingHandler());
|
||||
// pipeline.addLast("fowarder", new ForwardingHandler(this.config, this.clientChannelFactory));
|
||||
}
|
||||
}
|
156
src/dorkbox/network/dns/handlers/ForwardingHandler.java
Normal file
156
src/dorkbox/network/dns/handlers/ForwardingHandler.java
Normal file
|
@ -0,0 +1,156 @@
|
|||
package dorkbox.network.dns.handlers;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.channel.ChannelOutboundHandlerAdapter;
|
||||
|
||||
public class ForwardingHandler extends ChannelOutboundHandlerAdapter {
|
||||
|
||||
static final Logger LOG = LoggerFactory.getLogger(ForwardingHandler.class);
|
||||
|
||||
// protected ServerConfiguration config;
|
||||
// protected ChannelFactory clientChannelFactory;
|
||||
|
||||
// public
|
||||
// ForwardingHandler(ServerConfiguration config,
|
||||
// ChannelFactory clientChannelFactory) {
|
||||
// this.config = config;
|
||||
// this.clientChannelFactory = clientChannelFactory;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public
|
||||
void read(final ChannelHandlerContext ctx) throws Exception {
|
||||
super.read(ctx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// @Override
|
||||
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e)
|
||||
// throws Exception {
|
||||
// final DNSMessage original = DNSMessage.class.cast(e.getMessage());
|
||||
//
|
||||
// ClientBootstrap cb = new ClientBootstrap(this.clientChannelFactory);
|
||||
// cb.setOption("broadcast", "false");
|
||||
// cb.setPipelineFactory(new ChannelPipelineFactory() {
|
||||
// @Override
|
||||
// public ChannelPipeline getPipeline() throws Exception {
|
||||
// return Channels.pipeline(new ClientHanler(original, e
|
||||
// .getChannel(), e.getRemoteAddress()));
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// List<SocketAddress> newlist = new ArrayList<SocketAddress>(
|
||||
// this.config.getForwarders());
|
||||
// sendRequest(e, original, cb, newlist);
|
||||
// }
|
||||
//
|
||||
// protected void sendRequest(final MessageEvent e, final DNSMessage original, final ClientBootstrap bootstrap, final List<SocketAddress> forwarders) {
|
||||
// if (0 < forwarders.size()) {
|
||||
// SocketAddress sa = forwarders.remove(0);
|
||||
// LOG.debug("send to {}", sa);
|
||||
//
|
||||
// ChannelFuture f = bootstrap.connect(sa);
|
||||
// ChannelBuffer newone = ChannelBuffers.buffer(512);
|
||||
// DNSMessage msg = new DNSMessage(original);
|
||||
// msg.write(newone);
|
||||
// newone.resetReaderIndex();
|
||||
// final Channel c = f.getChannel();
|
||||
//
|
||||
// if (LOG.isDebugEnabled()) {
|
||||
// LOG.debug(
|
||||
// "STATUS : [isOpen/isConnected/isWritable {}] {} {}",
|
||||
// new Object[] {
|
||||
// new boolean[] { c.isOpen(), c.isConnected(),
|
||||
// c.isWritable() }, c.getRemoteAddress(),
|
||||
// c.getClass() });
|
||||
// }
|
||||
//
|
||||
// c.write(newone, sa).addListener(new ChannelFutureListener() {
|
||||
// @Override
|
||||
// public void operationComplete(ChannelFuture future)
|
||||
// throws Exception {
|
||||
// LOG.debug("request complete isSuccess : {}",
|
||||
// future.isSuccess());
|
||||
// if (future.isSuccess() == false) {
|
||||
// if (0 < forwarders.size()) {
|
||||
// sendRequest(e, original, bootstrap, forwarders);
|
||||
// } else {
|
||||
// original.header().rcode(RCode.ServFail);
|
||||
// ChannelBuffer buffer = ChannelBuffers.buffer(512);
|
||||
// original.write(buffer);
|
||||
// // close inbound channel
|
||||
// e.getChannel().write(buffer)
|
||||
// .addListener(ChannelFutureListener.CLOSE);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// // f.awaitUninterruptibly(30, TimeUnit.SECONDS);
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
public
|
||||
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
LOG.error("ForwardingHandler#exceptionCaught");
|
||||
LOG.error(cause.getMessage(), cause);
|
||||
}
|
||||
|
||||
|
||||
protected class ClientHanler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
// protected DNSMessage original;
|
||||
//
|
||||
// protected Channel originalChannel;
|
||||
//
|
||||
// protected SocketAddress originalAddress;
|
||||
//
|
||||
// public ClientHanler(DNSMessage msg, Channel c, SocketAddress sa) {
|
||||
// this.original = msg;
|
||||
// this.originalChannel = c;
|
||||
// this.originalAddress = sa;
|
||||
// }
|
||||
//
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// @Override
|
||||
// public void messageReceived(ChannelHandlerContext ctx, final MessageEvent e) throws Exception {
|
||||
// LOG.debug("ClientHanler#messageReceived");
|
||||
// ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
|
||||
// DNSMessage msg = new DNSMessage(buffer);
|
||||
// msg.header().id(this.original.header().id());
|
||||
// ChannelBuffer newone = ChannelBuffers.buffer(buffer.capacity());
|
||||
// msg.write(newone);
|
||||
// newone.resetReaderIndex();
|
||||
// this.originalChannel.write(newone, this.originalAddress)
|
||||
// .addListener(new ChannelFutureListener() {
|
||||
// @Override
|
||||
// public void operationComplete(ChannelFuture future)
|
||||
// throws Exception {
|
||||
// e.getChannel().close();
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
//
|
||||
|
||||
@Override
|
||||
public
|
||||
void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause) throws Exception {
|
||||
LOG.error("ClientHanler#exceptionCaught");
|
||||
LOG.error(cause.getMessage(), cause);
|
||||
// e.getFuture()
|
||||
// .setFailure(t);
|
||||
ctx.channel().close();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.record;
|
||||
|
||||
/**
|
||||
* Represents an MX record.
|
||||
*/
|
||||
public
|
||||
class MailExchangerRecord {
|
||||
|
||||
private final int priority;
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* @param priority lower is more preferred
|
||||
* @param name e-mail address in the format admin.example.com, which
|
||||
* represents admin@example.com
|
||||
*/
|
||||
public
|
||||
MailExchangerRecord(int priority, String name) {
|
||||
this.priority = priority;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public
|
||||
int priority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MX (an e-mail address) in the format
|
||||
* admin.example.com, which represents admin@example.com.
|
||||
*/
|
||||
public
|
||||
String name() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.record;
|
||||
|
||||
/**
|
||||
* Represents an SRV record.
|
||||
* <p/>
|
||||
* This is the location (or hostname and port), of servers for specified services. For example, a service "http"
|
||||
* may be running on the server "example.com" on port 80.
|
||||
*/
|
||||
public
|
||||
class ServiceRecord {
|
||||
|
||||
private final int priority;
|
||||
private final int weight;
|
||||
private final int port;
|
||||
private final String name;
|
||||
private final String protocol;
|
||||
private final String service;
|
||||
private final String target;
|
||||
|
||||
/**
|
||||
* @param fullPath the name first read in the SRV record which contains the
|
||||
* service, the protocol, and the name of the server being
|
||||
* queried. The format is {@code _service._protocol.hostname}, or
|
||||
* for example {@code _http._tcp.example.com}
|
||||
* @param priority relative priority of this service, range 0-65535 (lower is
|
||||
* higher priority)
|
||||
* @param weight determines how often multiple services will be used in the
|
||||
* event they have the same priority (greater weight means
|
||||
* service is used more often)
|
||||
* @param port the port for the service
|
||||
* @param target the name of the host for the service
|
||||
*/
|
||||
public
|
||||
ServiceRecord(String fullPath, int priority, int weight, int port, String target) {
|
||||
String[] parts = fullPath.split("\\.", 3);
|
||||
this.service = parts[0];
|
||||
this.protocol = parts[1];
|
||||
this.name = parts[2];
|
||||
this.priority = priority;
|
||||
this.weight = weight;
|
||||
this.port = port;
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public
|
||||
int priority() {
|
||||
return this.priority;
|
||||
}
|
||||
|
||||
public
|
||||
int weight() {
|
||||
return this.weight;
|
||||
}
|
||||
|
||||
public
|
||||
int port() {
|
||||
return this.port;
|
||||
}
|
||||
|
||||
public
|
||||
String name() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public
|
||||
String protocol() {
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the service's name (i.e. "_http").
|
||||
*/
|
||||
public
|
||||
String service() {
|
||||
return this.service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return he name of the host for the service.
|
||||
*/
|
||||
public
|
||||
String target() {
|
||||
return this.target;
|
||||
}
|
||||
}
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Copyright 2013 The Netty Project
|
||||
*
|
||||
* The Netty Project licenses this file to you under the Apache License,
|
||||
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at:
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package dorkbox.network.dns.record;
|
||||
|
||||
/**
|
||||
* Represents an SOA record.
|
||||
* <p/>
|
||||
* There can only be one SOA record per zone.
|
||||
*/
|
||||
public
|
||||
class StartOfAuthorityRecord {
|
||||
|
||||
private final String primaryNameServer;
|
||||
private final String responsiblePerson;
|
||||
private final long serial;
|
||||
private final int refreshTime;
|
||||
private final int retryTime;
|
||||
private final int expireTime;
|
||||
private final long minimumTtl;
|
||||
|
||||
/**
|
||||
* @param primaryNameServer any name server that will respond authoritatively for the domain
|
||||
* @param responsiblePerson e-mail address of person responsible for this zone
|
||||
* @param serial a serial number that must be incremented when changes are
|
||||
* made. Recommended format is YYYYMMDDnn. For example, if the
|
||||
* primary name server is changed on June 19, 2013, then the
|
||||
* serial would be 2013061901. If it is changed again on the same
|
||||
* day it would be 2013061902
|
||||
* @param refreshTime number of seconds a secondary name server waits, after getting
|
||||
* a copy of the zone, before it checks the zone again for
|
||||
* changes
|
||||
* @param retryTime number of seconds to wait after a failed refresh attempt
|
||||
* before another attempt to refresh is made
|
||||
* @param expireTime number of seconds secondary name server can hold information
|
||||
* before it is considered not authoritative
|
||||
* @param minimumTtl number of seconds that records in the zone are valid for (if a
|
||||
* record has a higher TTL, it overrides this value which is just
|
||||
* a minimum)
|
||||
*/
|
||||
public
|
||||
StartOfAuthorityRecord(String primaryNameServer,
|
||||
String responsiblePerson,
|
||||
long serial,
|
||||
int refreshTime,
|
||||
int retryTime,
|
||||
int expireTime,
|
||||
long minimumTtl) {
|
||||
|
||||
this.primaryNameServer = primaryNameServer;
|
||||
this.responsiblePerson = responsiblePerson;
|
||||
this.serial = serial;
|
||||
this.refreshTime = refreshTime;
|
||||
this.retryTime = retryTime;
|
||||
this.expireTime = expireTime;
|
||||
this.minimumTtl = minimumTtl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary name server.
|
||||
*/
|
||||
public
|
||||
String primaryNameServer() {
|
||||
return this.primaryNameServer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the responsible person's e-mail.
|
||||
*/
|
||||
public
|
||||
String responsiblePerson() {
|
||||
return this.responsiblePerson;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zone's serial number, usually in format YYYYMMDDnn.
|
||||
*/
|
||||
public
|
||||
long serial() {
|
||||
return this.serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time between refreshes for secondary name servers.
|
||||
*/
|
||||
public
|
||||
int refreshTime() {
|
||||
return this.refreshTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time between retries for failed refresh attempts.
|
||||
*/
|
||||
public
|
||||
int retryTime() {
|
||||
return this.retryTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns time before information stored in secondary name servers becomes
|
||||
* non authoritative.
|
||||
*/
|
||||
public
|
||||
int expireTime() {
|
||||
return this.expireTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum TTL for records in the zone (if the record has a
|
||||
* higher TTL, that value should be used as the TTL).
|
||||
*/
|
||||
public
|
||||
long minimumTtl() {
|
||||
return this.minimumTtl;
|
||||
}
|
||||
|
||||
}
|
147
src/dorkbox/network/dns/records/A6Record.java
Normal file
147
src/dorkbox/network/dns/records/A6Record.java
Normal file
|
@ -0,0 +1,147 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Address;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* A6 Record - maps a domain name to an IPv6 address (experimental)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class A6Record extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -8815026887337346789L;
|
||||
|
||||
private int prefixBits;
|
||||
private InetAddress suffix;
|
||||
private Name prefix;
|
||||
|
||||
A6Record() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new A6Record();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
prefixBits = in.readU8();
|
||||
int suffixbits = 128 - prefixBits;
|
||||
int suffixbytes = (suffixbits + 7) / 8;
|
||||
if (prefixBits < 128) {
|
||||
byte[] bytes = new byte[16];
|
||||
in.readByteArray(bytes, 16 - suffixbytes, suffixbytes);
|
||||
suffix = InetAddress.getByAddress(bytes);
|
||||
}
|
||||
if (prefixBits > 0) {
|
||||
prefix = new Name(in);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(prefixBits);
|
||||
if (suffix != null) {
|
||||
int suffixbits = 128 - prefixBits;
|
||||
int suffixbytes = (suffixbits + 7) / 8;
|
||||
byte[] data = suffix.getAddress();
|
||||
out.writeByteArray(data, 16 - suffixbytes, suffixbytes);
|
||||
}
|
||||
if (prefix != null) {
|
||||
prefix.toWire(out, null, canonical);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(prefixBits);
|
||||
if (suffix != null) {
|
||||
sb.append(" ");
|
||||
sb.append(suffix.getHostAddress());
|
||||
}
|
||||
if (prefix != null) {
|
||||
sb.append(" ");
|
||||
sb.append(prefix);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
prefixBits = st.getUInt8();
|
||||
if (prefixBits > 128) {
|
||||
throw st.exception("prefix bits must be [0..128]");
|
||||
}
|
||||
else if (prefixBits < 128) {
|
||||
String s = st.getString();
|
||||
try {
|
||||
suffix = Address.getByAddress(s, Address.IPv6);
|
||||
} catch (UnknownHostException e) {
|
||||
throw st.exception("invalid IPv6 address: " + s);
|
||||
}
|
||||
}
|
||||
if (prefixBits > 0) {
|
||||
prefix = st.getName(origin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an A6 Record from the given data
|
||||
*
|
||||
* @param prefixBits The number of bits in the address prefix
|
||||
* @param suffix The address suffix
|
||||
* @param prefix The name of the prefix
|
||||
*/
|
||||
public
|
||||
A6Record(Name name, int dclass, long ttl, int prefixBits, InetAddress suffix, Name prefix) {
|
||||
super(name, DnsRecordType.A6, dclass, ttl);
|
||||
this.prefixBits = checkU8("prefixBits", prefixBits);
|
||||
if (suffix != null && Address.familyOf(suffix) != Address.IPv6) {
|
||||
throw new IllegalArgumentException("invalid IPv6 address");
|
||||
}
|
||||
this.suffix = suffix;
|
||||
if (prefix != null) {
|
||||
this.prefix = checkName("prefix", prefix);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of bits in the prefix
|
||||
*/
|
||||
public
|
||||
int getPrefixBits() {
|
||||
return prefixBits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address suffix
|
||||
*/
|
||||
public
|
||||
InetAddress getSuffix() {
|
||||
return suffix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address prefix
|
||||
*/
|
||||
public
|
||||
Name getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
}
|
108
src/dorkbox/network/dns/records/AAAARecord.java
Normal file
108
src/dorkbox/network/dns/records/AAAARecord.java
Normal file
|
@ -0,0 +1,108 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Address;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* IPv6 Address Record - maps a domain name to an IPv6 address
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class AAAARecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -4588601512069748050L;
|
||||
|
||||
private byte[] address;
|
||||
|
||||
AAAARecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new AAAARecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
address = in.readByteArray(16);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeByteArray(address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
InetAddress addr;
|
||||
try {
|
||||
addr = InetAddress.getByAddress(null, address);
|
||||
} catch (UnknownHostException e) {
|
||||
return;
|
||||
}
|
||||
if (addr.getAddress().length == 4) {
|
||||
// Deal with Java's broken handling of mapped IPv4 addresses.
|
||||
sb.append("0:0:0:0:0:ffff:");
|
||||
int high = ((address[12] & 0xFF) << 8) + (address[13] & 0xFF);
|
||||
int low = ((address[14] & 0xFF) << 8) + (address[15] & 0xFF);
|
||||
sb.append(Integer.toHexString(high));
|
||||
sb.append(':');
|
||||
sb.append(Integer.toHexString(low));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
sb.append(addr.getHostAddress());
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
address = st.getAddressBytes(Address.IPv6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AAAA Record from the given data
|
||||
*
|
||||
* @param address The address suffix
|
||||
*/
|
||||
public
|
||||
AAAARecord(Name name, int dclass, long ttl, InetAddress address) {
|
||||
super(name, DnsRecordType.AAAA, dclass, ttl);
|
||||
if (Address.familyOf(address) != Address.IPv6) {
|
||||
throw new IllegalArgumentException("invalid IPv6 address");
|
||||
}
|
||||
this.address = address.getAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the address
|
||||
*/
|
||||
public
|
||||
InetAddress getAddress() {
|
||||
try {
|
||||
if (name == null) {
|
||||
return InetAddress.getByAddress(address);
|
||||
}
|
||||
else {
|
||||
return InetAddress.getByAddress(name.toString(true), address);
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
53
src/dorkbox/network/dns/records/AFSDBRecord.java
Normal file
53
src/dorkbox/network/dns/records/AFSDBRecord.java
Normal file
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* AFS Data Base Record - maps a domain name to the name of an AFS cell
|
||||
* database server.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class AFSDBRecord extends U16NameBase {
|
||||
|
||||
private static final long serialVersionUID = 3034379930729102437L;
|
||||
|
||||
AFSDBRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new AFSDBRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AFSDB Record from the given data.
|
||||
*
|
||||
* @param subtype Indicates the type of service provided by the host.
|
||||
* @param host The host providing the service.
|
||||
*/
|
||||
public
|
||||
AFSDBRecord(Name name, int dclass, long ttl, int subtype, Name host) {
|
||||
super(name, DnsRecordType.AFSDB, dclass, ttl, subtype, "subtype", host, "host");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the subtype indicating the service provided by the host.
|
||||
*/
|
||||
public
|
||||
int getSubtype() {
|
||||
return getU16Field();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the host providing service for the domain.
|
||||
*/
|
||||
public
|
||||
Name getHost() {
|
||||
return getNameField();
|
||||
}
|
||||
}
|
305
src/dorkbox/network/dns/records/APLRecord.java
Normal file
305
src/dorkbox/network/dns/records/APLRecord.java
Normal file
|
@ -0,0 +1,305 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Address;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* APL - Address Prefix List. See RFC 3123.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: this currently uses the same constants as the Address class;
|
||||
* this could change if more constants are defined for APL records.
|
||||
*/
|
||||
|
||||
public
|
||||
class APLRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -1348173791712935864L;
|
||||
private List elements;
|
||||
|
||||
|
||||
public static
|
||||
class Element {
|
||||
public final int family;
|
||||
public final boolean negative;
|
||||
public final int prefixLength;
|
||||
public final Object address;
|
||||
|
||||
/**
|
||||
* Creates an APL element corresponding to an IPv4 or IPv6 prefix.
|
||||
*
|
||||
* @param negative Indicates if this prefix is a negation.
|
||||
* @param address The IPv4 or IPv6 address.
|
||||
* @param prefixLength The length of this prefix, in bits.
|
||||
*
|
||||
* @throws IllegalArgumentException The prefix length is invalid.
|
||||
*/
|
||||
public
|
||||
Element(boolean negative, InetAddress address, int prefixLength) {
|
||||
this(Address.familyOf(address), negative, address, prefixLength);
|
||||
}
|
||||
|
||||
private
|
||||
Element(int family, boolean negative, Object address, int prefixLength) {
|
||||
this.family = family;
|
||||
this.negative = negative;
|
||||
this.address = address;
|
||||
this.prefixLength = prefixLength;
|
||||
if (!validatePrefixLength(family, prefixLength)) {
|
||||
throw new IllegalArgumentException("invalid prefix " + "length");
|
||||
}
|
||||
}
|
||||
|
||||
public
|
||||
int hashCode() {
|
||||
return address.hashCode() + prefixLength + (negative ? 1 : 0);
|
||||
}
|
||||
|
||||
public
|
||||
boolean equals(Object arg) {
|
||||
if (arg == null || !(arg instanceof Element)) {
|
||||
return false;
|
||||
}
|
||||
Element elt = (Element) arg;
|
||||
return (family == elt.family && negative == elt.negative && prefixLength == elt.prefixLength && address.equals(elt.address));
|
||||
}
|
||||
|
||||
public
|
||||
String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (negative) {
|
||||
sb.append("!");
|
||||
}
|
||||
sb.append(family);
|
||||
sb.append(":");
|
||||
if (family == Address.IPv4 || family == Address.IPv6) {
|
||||
sb.append(((InetAddress) address).getHostAddress());
|
||||
}
|
||||
else {
|
||||
sb.append(base16.toString((byte[]) address));
|
||||
}
|
||||
sb.append("/");
|
||||
sb.append(prefixLength);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
APLRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new APLRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
elements = new ArrayList(1);
|
||||
while (in.remaining() != 0) {
|
||||
int family = in.readU16();
|
||||
int prefix = in.readU8();
|
||||
int length = in.readU8();
|
||||
boolean negative = (length & 0x80) != 0;
|
||||
length &= ~0x80;
|
||||
|
||||
byte[] data = in.readByteArray(length);
|
||||
Element element;
|
||||
if (!validatePrefixLength(family, prefix)) {
|
||||
throw new WireParseException("invalid prefix length");
|
||||
}
|
||||
|
||||
if (family == Address.IPv4 || family == Address.IPv6) {
|
||||
data = parseAddress(data, Address.addressLength(family));
|
||||
InetAddress addr = InetAddress.getByAddress(data);
|
||||
element = new Element(negative, addr, prefix);
|
||||
}
|
||||
else {
|
||||
element = new Element(family, negative, data, prefix);
|
||||
}
|
||||
elements.add(element);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static
|
||||
boolean validatePrefixLength(int family, int prefixLength) {
|
||||
if (prefixLength < 0 || prefixLength >= 256) {
|
||||
return false;
|
||||
}
|
||||
if ((family == Address.IPv4 && prefixLength > 32) || (family == Address.IPv6 && prefixLength > 128)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static
|
||||
byte[] parseAddress(byte[] in, int length) throws WireParseException {
|
||||
if (in.length > length) {
|
||||
throw new WireParseException("invalid address length");
|
||||
}
|
||||
if (in.length == length) {
|
||||
return in;
|
||||
}
|
||||
byte[] out = new byte[length];
|
||||
System.arraycopy(in, 0, out, 0, in.length);
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
for (Iterator it = elements.iterator(); it.hasNext(); ) {
|
||||
Element element = (Element) it.next();
|
||||
int length = 0;
|
||||
byte[] data;
|
||||
if (element.family == Address.IPv4 || element.family == Address.IPv6) {
|
||||
InetAddress addr = (InetAddress) element.address;
|
||||
data = addr.getAddress();
|
||||
length = addressLength(data);
|
||||
}
|
||||
else {
|
||||
data = (byte[]) element.address;
|
||||
length = data.length;
|
||||
}
|
||||
int wlength = length;
|
||||
if (element.negative) {
|
||||
wlength |= 0x80;
|
||||
}
|
||||
out.writeU16(element.family);
|
||||
out.writeU8(element.prefixLength);
|
||||
out.writeU8(wlength);
|
||||
out.writeByteArray(data, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
for (Iterator it = elements.iterator(); it.hasNext(); ) {
|
||||
Element element = (Element) it.next();
|
||||
sb.append(element);
|
||||
if (it.hasNext()) {
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
elements = new ArrayList(1);
|
||||
while (true) {
|
||||
Tokenizer.Token t = st.get();
|
||||
if (!t.isString()) {
|
||||
break;
|
||||
}
|
||||
|
||||
boolean negative = false;
|
||||
int family = 0;
|
||||
int prefix = 0;
|
||||
|
||||
String s = t.value;
|
||||
int start = 0;
|
||||
if (s.startsWith("!")) {
|
||||
negative = true;
|
||||
start = 1;
|
||||
}
|
||||
int colon = s.indexOf(':', start);
|
||||
if (colon < 0) {
|
||||
throw st.exception("invalid address prefix element");
|
||||
}
|
||||
int slash = s.indexOf('/', colon);
|
||||
if (slash < 0) {
|
||||
throw st.exception("invalid address prefix element");
|
||||
}
|
||||
|
||||
String familyString = s.substring(start, colon);
|
||||
String addressString = s.substring(colon + 1, slash);
|
||||
String prefixString = s.substring(slash + 1);
|
||||
|
||||
try {
|
||||
family = Integer.parseInt(familyString);
|
||||
} catch (NumberFormatException e) {
|
||||
throw st.exception("invalid family");
|
||||
}
|
||||
if (family != Address.IPv4 && family != Address.IPv6) {
|
||||
throw st.exception("unknown family");
|
||||
}
|
||||
|
||||
try {
|
||||
prefix = Integer.parseInt(prefixString);
|
||||
} catch (NumberFormatException e) {
|
||||
throw st.exception("invalid prefix length");
|
||||
}
|
||||
|
||||
if (!validatePrefixLength(family, prefix)) {
|
||||
throw st.exception("invalid prefix length");
|
||||
}
|
||||
|
||||
byte[] bytes = Address.toByteArray(addressString, family);
|
||||
if (bytes == null) {
|
||||
throw st.exception("invalid IP address " + addressString);
|
||||
}
|
||||
|
||||
InetAddress address = InetAddress.getByAddress(bytes);
|
||||
elements.add(new Element(negative, address, prefix));
|
||||
}
|
||||
st.unget();
|
||||
}
|
||||
|
||||
private static
|
||||
int addressLength(byte[] addr) {
|
||||
for (int i = addr.length - 1; i >= 0; i--) {
|
||||
if (addr[i] != 0) {
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an APL Record from the given data.
|
||||
*
|
||||
* @param elements The list of APL elements.
|
||||
*/
|
||||
public
|
||||
APLRecord(Name name, int dclass, long ttl, List elements) {
|
||||
super(name, DnsRecordType.APL, dclass, ttl);
|
||||
this.elements = new ArrayList(elements.size());
|
||||
for (Iterator it = elements.iterator(); it.hasNext(); ) {
|
||||
Object o = it.next();
|
||||
if (!(o instanceof Element)) {
|
||||
throw new IllegalArgumentException("illegal element");
|
||||
}
|
||||
Element element = (Element) o;
|
||||
if (element.family != Address.IPv4 && element.family != Address.IPv6) {
|
||||
throw new IllegalArgumentException("unknown family");
|
||||
}
|
||||
this.elements.add(element);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of APL elements.
|
||||
*/
|
||||
public
|
||||
List getElements() {
|
||||
return elements;
|
||||
}
|
||||
|
||||
}
|
106
src/dorkbox/network/dns/records/ARecord.java
Normal file
106
src/dorkbox/network/dns/records/ARecord.java
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Address;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Address Record - maps a domain name to an Internet address
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class ARecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -2172609200849142323L;
|
||||
|
||||
private int addr;
|
||||
|
||||
ARecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new ARecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
addr = fromArray(in.readByteArray(4));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU32(((long) addr) & 0xFFFFFFFFL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(Address.toDottedQuad(toArray(addr)));
|
||||
}
|
||||
|
||||
private static
|
||||
byte[] toArray(int addr) {
|
||||
byte[] bytes = new byte[4];
|
||||
bytes[0] = (byte) ((addr >>> 24) & 0xFF);
|
||||
bytes[1] = (byte) ((addr >>> 16) & 0xFF);
|
||||
bytes[2] = (byte) ((addr >>> 8) & 0xFF);
|
||||
bytes[3] = (byte) (addr & 0xFF);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
addr = fromArray(st.getAddressBytes(Address.IPv4));
|
||||
}
|
||||
|
||||
private static
|
||||
int fromArray(byte[] array) {
|
||||
return (((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an A Record from the given data
|
||||
*
|
||||
* @param address The address that the name refers to
|
||||
*/
|
||||
public
|
||||
ARecord(Name name, int dclass, long ttl, InetAddress address) {
|
||||
super(name, DnsRecordType.A, dclass, ttl);
|
||||
if (Address.familyOf(address) != Address.IPv4) {
|
||||
throw new IllegalArgumentException("invalid IPv4 address");
|
||||
}
|
||||
addr = fromArray(address.getAddress());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Internet address
|
||||
*/
|
||||
public
|
||||
InetAddress getAddress() {
|
||||
try {
|
||||
if (name == null) {
|
||||
return InetAddress.getByAddress(toArray(addr));
|
||||
}
|
||||
else {
|
||||
return InetAddress.getByAddress(name.toString(true), toArray(addr));
|
||||
}
|
||||
} catch (UnknownHostException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
122
src/dorkbox/network/dns/records/CAARecord.java
Normal file
122
src/dorkbox/network/dns/records/CAARecord.java
Normal file
|
@ -0,0 +1,122 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Certification Authority Authorization
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class CAARecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 8544304287274216443L;
|
||||
private int flags;
|
||||
private byte[] tag;
|
||||
private byte[] value;
|
||||
|
||||
|
||||
public static
|
||||
class Flags {
|
||||
public static final int IssuerCritical = 128;
|
||||
|
||||
private
|
||||
Flags() {}
|
||||
}
|
||||
|
||||
CAARecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new CAARecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
flags = in.readU8();
|
||||
tag = in.readCountedString();
|
||||
value = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(flags);
|
||||
out.writeCountedString(tag);
|
||||
out.writeByteArray(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(flags);
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(tag, false));
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(value, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
flags = st.getUInt8();
|
||||
try {
|
||||
tag = byteArrayFromString(st.getString());
|
||||
value = byteArrayFromString(st.getString());
|
||||
} catch (TextParseException e) {
|
||||
throw st.exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an CAA Record from the given data.
|
||||
*
|
||||
* @param flags The flags.
|
||||
* @param tag The tag.
|
||||
* @param value The value.
|
||||
*/
|
||||
public
|
||||
CAARecord(Name name, int dclass, long ttl, int flags, String tag, String value) {
|
||||
super(name, DnsRecordType.CAA, dclass, ttl);
|
||||
this.flags = checkU8("flags", flags);
|
||||
try {
|
||||
this.tag = byteArrayFromString(tag);
|
||||
this.value = byteArrayFromString(value);
|
||||
} catch (TextParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags.
|
||||
*/
|
||||
public
|
||||
int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the tag.
|
||||
*/
|
||||
public
|
||||
String getTag() {
|
||||
return byteArrayToString(tag, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value
|
||||
*/
|
||||
public
|
||||
String getValue() {
|
||||
return byteArrayToString(value, false);
|
||||
}
|
||||
|
||||
}
|
257
src/dorkbox/network/dns/records/CERTRecord.java
Normal file
257
src/dorkbox/network/dns/records/CERTRecord.java
Normal file
|
@ -0,0 +1,257 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.OS;
|
||||
|
||||
/**
|
||||
* Certificate Record - Stores a certificate associated with a name. The
|
||||
* certificate might also be associated with a KEYRecord.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see KEYRecord
|
||||
*/
|
||||
|
||||
public
|
||||
class CERTRecord extends DnsRecord {
|
||||
|
||||
/**
|
||||
* PKIX (X.509v3)
|
||||
*/
|
||||
public static final int PKIX = CertificateType.PKIX;
|
||||
/**
|
||||
* Simple Public Key Infrastructure
|
||||
*/
|
||||
public static final int SPKI = CertificateType.SPKI;
|
||||
/**
|
||||
* Pretty Good Privacy
|
||||
*/
|
||||
public static final int PGP = CertificateType.PGP;
|
||||
/**
|
||||
* Certificate format defined by URI
|
||||
*/
|
||||
public static final int URI = CertificateType.URI;
|
||||
/**
|
||||
* Certificate format defined by IOD
|
||||
*/
|
||||
public static final int OID = CertificateType.OID;
|
||||
private static final long serialVersionUID = 4763014646517016835L;
|
||||
private int certType, keyTag;
|
||||
private int alg;
|
||||
private byte[] cert;
|
||||
|
||||
|
||||
public static
|
||||
class CertificateType {
|
||||
/**
|
||||
* PKIX (X.509v3)
|
||||
*/
|
||||
public static final int PKIX = 1;
|
||||
/**
|
||||
* Simple Public Key Infrastructure
|
||||
*/
|
||||
public static final int SPKI = 2;
|
||||
/**
|
||||
* Pretty Good Privacy
|
||||
*/
|
||||
public static final int PGP = 3;
|
||||
/**
|
||||
* URL of an X.509 data object
|
||||
*/
|
||||
public static final int IPKIX = 4;
|
||||
/**
|
||||
* URL of an SPKI certificate
|
||||
*/
|
||||
public static final int ISPKI = 5;
|
||||
/**
|
||||
* Fingerprint and URL of an OpenPGP packet
|
||||
*/
|
||||
public static final int IPGP = 6;
|
||||
/**
|
||||
* Attribute Certificate
|
||||
*/
|
||||
public static final int ACPKIX = 7;
|
||||
/**
|
||||
* URL of an Attribute Certificate
|
||||
*/
|
||||
public static final int IACPKIX = 8;
|
||||
/**
|
||||
* Certificate format defined by URI
|
||||
*/
|
||||
public static final int URI = 253;
|
||||
/**
|
||||
* Certificate format defined by OID
|
||||
*/
|
||||
public static final int OID = 254;
|
||||
private static Mnemonic types = new Mnemonic("Certificate type", Mnemonic.CASE_UPPER);
|
||||
|
||||
/**
|
||||
* Certificate type identifiers. See RFC 4398 for more detail.
|
||||
*/
|
||||
|
||||
private
|
||||
CertificateType() {}
|
||||
|
||||
static {
|
||||
types.setMaximum(0xFFFF);
|
||||
types.setNumericAllowed(true);
|
||||
|
||||
types.add(PKIX, "PKIX");
|
||||
types.add(SPKI, "SPKI");
|
||||
types.add(PGP, "PGP");
|
||||
types.add(PKIX, "IPKIX");
|
||||
types.add(SPKI, "ISPKI");
|
||||
types.add(PGP, "IPGP");
|
||||
types.add(PGP, "ACPKIX");
|
||||
types.add(PGP, "IACPKIX");
|
||||
types.add(URI, "URI");
|
||||
types.add(OID, "OID");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a certificate type into its textual representation
|
||||
*/
|
||||
public static
|
||||
String string(int type) {
|
||||
return types.getText(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a textual representation of an certificate type into its
|
||||
* numeric code. Integers in the range 0..65535 are also accepted.
|
||||
*
|
||||
* @param s The textual representation of the algorithm
|
||||
*
|
||||
* @return The algorithm code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return types.getValue(s);
|
||||
}
|
||||
}
|
||||
|
||||
CERTRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new CERTRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
certType = in.readU16();
|
||||
keyTag = in.readU16();
|
||||
alg = in.readU8();
|
||||
cert = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(certType);
|
||||
out.writeU16(keyTag);
|
||||
out.writeU8(alg);
|
||||
out.writeByteArray(cert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(certType);
|
||||
sb.append(" ");
|
||||
sb.append(keyTag);
|
||||
sb.append(" ");
|
||||
sb.append(alg);
|
||||
|
||||
if (cert != null) {
|
||||
if (Options.check("multiline")) {
|
||||
sb.append(" (");
|
||||
sb.append(OS.LINE_SEPARATOR);
|
||||
|
||||
sb.append(Base64Fast.formatString(Base64Fast.encode2(cert), 64, "\t", true));
|
||||
}
|
||||
else {
|
||||
sb.append(" ");
|
||||
sb.append(Base64Fast.encode2(cert));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
String certTypeString = st.getString();
|
||||
certType = CertificateType.value(certTypeString);
|
||||
if (certType < 0) {
|
||||
throw st.exception("Invalid certificate type: " + certTypeString);
|
||||
}
|
||||
keyTag = st.getUInt16();
|
||||
String algString = st.getString();
|
||||
alg = DNSSEC.Algorithm.value(algString);
|
||||
if (alg < 0) {
|
||||
throw st.exception("Invalid algorithm: " + algString);
|
||||
}
|
||||
cert = st.getBase64();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a CERT Record from the given data
|
||||
*
|
||||
* @param certType The type of certificate (see constants)
|
||||
* @param keyTag The ID of the associated KEYRecord, if present
|
||||
* @param alg The algorithm of the associated KEYRecord, if present
|
||||
* @param cert Binary data representing the certificate
|
||||
*/
|
||||
public
|
||||
CERTRecord(Name name, int dclass, long ttl, int certType, int keyTag, int alg, byte[] cert) {
|
||||
super(name, DnsRecordType.CERT, dclass, ttl);
|
||||
this.certType = checkU16("certType", certType);
|
||||
this.keyTag = checkU16("keyTag", keyTag);
|
||||
this.alg = checkU8("alg", alg);
|
||||
this.cert = cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of certificate
|
||||
*/
|
||||
public
|
||||
int getCertType() {
|
||||
return certType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ID of the associated KEYRecord, if present
|
||||
*/
|
||||
public
|
||||
int getKeyTag() {
|
||||
return keyTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the algorithm of the associated KEYRecord, if present
|
||||
*/
|
||||
public
|
||||
int getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary representation of the certificate
|
||||
*/
|
||||
public
|
||||
byte[] getCert() {
|
||||
return cert;
|
||||
}
|
||||
|
||||
}
|
52
src/dorkbox/network/dns/records/CNAMERecord.java
Normal file
52
src/dorkbox/network/dns/records/CNAMERecord.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* CNAME Record - maps an alias to its real name
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class CNAMERecord extends SingleCompressedNameBase {
|
||||
|
||||
private static final long serialVersionUID = -4020373886892538580L;
|
||||
|
||||
CNAMERecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new CNAMERecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CNAMERecord with the given data
|
||||
*
|
||||
* @param alias The name to which the CNAME alias points
|
||||
*/
|
||||
public
|
||||
CNAMERecord(Name name, int dclass, long ttl, Name alias) {
|
||||
super(name, DnsRecordType.CNAME, dclass, ttl, alias, "alias");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the CNAME Record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alias specified by the CNAME Record
|
||||
*/
|
||||
public
|
||||
Name getAlias() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
187
src/dorkbox/network/dns/records/ClientSubnetOption.java
Normal file
187
src/dorkbox/network/dns/records/ClientSubnetOption.java
Normal file
|
@ -0,0 +1,187 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Address;
|
||||
|
||||
/**
|
||||
* The Client Subnet EDNS Option, defined in
|
||||
* http://tools.ietf.org/html/draft-vandergaast-edns-client-subnet-00
|
||||
* ("Client subnet in DNS requests").
|
||||
* <p>
|
||||
* The option is used to convey information about the IP address of the
|
||||
* originating client, so that an authoritative server can make decisions
|
||||
* based on this address, rather than the address of the intermediate
|
||||
* caching name server.
|
||||
* <p>
|
||||
* The option is transmitted as part of an OPTRecord in the additional section
|
||||
* of a DNS message, as defined by RFC 2671 (EDNS0).
|
||||
* <p>
|
||||
* The wire format of the option contains a 2-byte length field (1 for IPv4, 2
|
||||
* for IPv6), a 1-byte source netmask, a 1-byte scope netmask, and an address
|
||||
* truncated to the source netmask length (where the final octet is padded with
|
||||
* bits set to 0)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @author Ming Zhou <mizhou@bnivideo.com>, Beaumaris Networks
|
||||
* @see OPTRecord
|
||||
*/
|
||||
public
|
||||
class ClientSubnetOption extends EDNSOption {
|
||||
|
||||
private static final long serialVersionUID = -3868158449890266347L;
|
||||
|
||||
private int family;
|
||||
private int sourceNetmask;
|
||||
private int scopeNetmask;
|
||||
private InetAddress address;
|
||||
|
||||
ClientSubnetOption() {
|
||||
super(EDNSOption.Code.CLIENT_SUBNET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Client Subnet option with scope netmask set to 0.
|
||||
*
|
||||
* @param sourceNetmask The length of the netmask pertaining to the query.
|
||||
* In replies, it mirrors the same value as in the requests.
|
||||
* @param address The address of the client.
|
||||
*
|
||||
* @see ClientSubnetOption
|
||||
*/
|
||||
public
|
||||
ClientSubnetOption(int sourceNetmask, InetAddress address) {
|
||||
this(sourceNetmask, 0, address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Client Subnet option. Note that the number of significant bits
|
||||
* in the address must not be greater than the supplied source netmask. There
|
||||
* may also be issues related to Java's handling of mapped addresses
|
||||
*
|
||||
* @param sourceNetmask The length of the netmask pertaining to the query.
|
||||
* In replies, it mirrors the same value as in the requests.
|
||||
* @param scopeNetmask The length of the netmask pertaining to the reply.
|
||||
* In requests, it MUST be set to 0. In responses, this may or may not match
|
||||
* the source netmask.
|
||||
* @param address The address of the client.
|
||||
*/
|
||||
public
|
||||
ClientSubnetOption(int sourceNetmask, int scopeNetmask, InetAddress address) {
|
||||
super(EDNSOption.Code.CLIENT_SUBNET);
|
||||
|
||||
this.family = Address.familyOf(address);
|
||||
this.sourceNetmask = checkMaskLength("source netmask", this.family, sourceNetmask);
|
||||
this.scopeNetmask = checkMaskLength("scope netmask", this.family, scopeNetmask);
|
||||
this.address = Address.truncate(address, sourceNetmask);
|
||||
|
||||
if (!address.equals(this.address)) {
|
||||
throw new IllegalArgumentException("source netmask is not " + "valid for address");
|
||||
}
|
||||
}
|
||||
|
||||
private static
|
||||
int checkMaskLength(String field, int family, int val) {
|
||||
int max = Address.addressLength(family) * 8;
|
||||
if (val < 0 || val > max) {
|
||||
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be in the range " + "[0.." + max + "]");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the family of the network address. This will be either IPv4 (1)
|
||||
* or IPv6 (2).
|
||||
*/
|
||||
public
|
||||
int getFamily() {
|
||||
return family;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the source netmask.
|
||||
*/
|
||||
public
|
||||
int getSourceNetmask() {
|
||||
return sourceNetmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the scope netmask.
|
||||
*/
|
||||
public
|
||||
int getScopeNetmask() {
|
||||
return scopeNetmask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the IP address of the client.
|
||||
*/
|
||||
public
|
||||
InetAddress getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
@Override
|
||||
void optionFromWire(DnsInput in) throws WireParseException {
|
||||
family = in.readU16();
|
||||
if (family != Address.IPv4 && family != Address.IPv6) {
|
||||
throw new WireParseException("unknown address family");
|
||||
}
|
||||
sourceNetmask = in.readU8();
|
||||
if (sourceNetmask > Address.addressLength(family) * 8) {
|
||||
throw new WireParseException("invalid source netmask");
|
||||
}
|
||||
scopeNetmask = in.readU8();
|
||||
if (scopeNetmask > Address.addressLength(family) * 8) {
|
||||
throw new WireParseException("invalid scope netmask");
|
||||
}
|
||||
|
||||
// Read the truncated address
|
||||
byte[] addr = in.readByteArray();
|
||||
if (addr.length != (sourceNetmask + 7) / 8) {
|
||||
throw new WireParseException("invalid address");
|
||||
}
|
||||
|
||||
// Convert it to a full length address.
|
||||
byte[] fulladdr = new byte[Address.addressLength(family)];
|
||||
System.arraycopy(addr, 0, fulladdr, 0, addr.length);
|
||||
|
||||
try {
|
||||
address = InetAddress.getByAddress(fulladdr);
|
||||
} catch (UnknownHostException e) {
|
||||
throw new WireParseException("invalid address", e);
|
||||
}
|
||||
|
||||
InetAddress tmp = Address.truncate(address, sourceNetmask);
|
||||
if (!tmp.equals(address)) {
|
||||
throw new WireParseException("invalid padding");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void optionToWire(DnsOutput out) {
|
||||
out.writeU16(family);
|
||||
out.writeU8(sourceNetmask);
|
||||
out.writeU8(scopeNetmask);
|
||||
out.writeByteArray(address.getAddress(), 0, (sourceNetmask + 7) / 8);
|
||||
}
|
||||
|
||||
@Override
|
||||
String optionToString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(address.getHostAddress());
|
||||
sb.append("/");
|
||||
sb.append(sourceNetmask);
|
||||
sb.append(", scope netmask ");
|
||||
sb.append(scopeNetmask);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
74
src/dorkbox/network/dns/records/DHCIDRecord.java
Normal file
74
src/dorkbox/network/dns/records/DHCIDRecord.java
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright (c) 2008 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.Base64Fast;
|
||||
|
||||
/**
|
||||
* DHCID - Dynamic Host Configuration Protocol (DHCP) ID (RFC 4701)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class DHCIDRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -8214820200808997707L;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
DHCIDRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new DHCIDRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
data = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeByteArray(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(Base64Fast.encode2(data));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
data = st.getBase64();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an DHCID Record from the given data
|
||||
*
|
||||
* @param data The binary data, which is opaque to DNS.
|
||||
*/
|
||||
public
|
||||
DHCIDRecord(Name name, int dclass, long ttl, byte[] data) {
|
||||
super(name, DnsRecordType.DHCID, dclass, ttl);
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary data.
|
||||
*/
|
||||
public
|
||||
byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
136
src/dorkbox/network/dns/records/DLVRecord.java
Normal file
136
src/dorkbox/network/dns/records/DLVRecord.java
Normal file
|
@ -0,0 +1,136 @@
|
|||
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* DLV - contains a Delegation Lookaside Validation record, which acts
|
||||
* as the equivalent of a DS record in a lookaside zone.
|
||||
*
|
||||
* @author David Blacka
|
||||
* @author Brian Wellington
|
||||
* @see DNSSEC
|
||||
* @see DSRecord
|
||||
*/
|
||||
|
||||
public
|
||||
class DLVRecord extends DnsRecord {
|
||||
|
||||
public static final int SHA1_DIGEST_ID = DSRecord.Digest.SHA1;
|
||||
public static final int SHA256_DIGEST_ID = DSRecord.Digest.SHA1;
|
||||
|
||||
private static final long serialVersionUID = 1960742375677534148L;
|
||||
|
||||
private int footprint;
|
||||
private int alg;
|
||||
private int digestid;
|
||||
private byte[] digest;
|
||||
|
||||
DLVRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new DLVRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
footprint = in.readU16();
|
||||
alg = in.readU8();
|
||||
digestid = in.readU8();
|
||||
digest = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(footprint);
|
||||
out.writeU8(alg);
|
||||
out.writeU8(digestid);
|
||||
if (digest != null) {
|
||||
out.writeByteArray(digest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(footprint);
|
||||
sb.append(" ");
|
||||
sb.append(alg);
|
||||
sb.append(" ");
|
||||
sb.append(digestid);
|
||||
if (digest != null) {
|
||||
sb.append(" ");
|
||||
sb.append(base16.toString(digest));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
footprint = st.getUInt16();
|
||||
alg = st.getUInt8();
|
||||
digestid = st.getUInt8();
|
||||
digest = st.getHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DLV Record from the given data
|
||||
*
|
||||
* @param footprint The original KEY record's footprint (keyid).
|
||||
* @param alg The original key algorithm.
|
||||
* @param digestid The digest id code.
|
||||
* @param digest A hash of the original key.
|
||||
*/
|
||||
public
|
||||
DLVRecord(Name name, int dclass, long ttl, int footprint, int alg, int digestid, byte[] digest) {
|
||||
super(name, DnsRecordType.DLV, dclass, ttl);
|
||||
this.footprint = checkU16("footprint", footprint);
|
||||
this.alg = checkU8("alg", alg);
|
||||
this.digestid = checkU8("digestid", digestid);
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's algorithm.
|
||||
*/
|
||||
public
|
||||
int getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's Digest ID.
|
||||
*/
|
||||
public
|
||||
int getDigestID() {
|
||||
return digestid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary hash of the key.
|
||||
*/
|
||||
public
|
||||
byte[] getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's footprint.
|
||||
*/
|
||||
public
|
||||
int getFootprint() {
|
||||
return footprint;
|
||||
}
|
||||
|
||||
}
|
52
src/dorkbox/network/dns/records/DNAMERecord.java
Normal file
52
src/dorkbox/network/dns/records/DNAMERecord.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* DNAME Record - maps a nonterminal alias (subtree) to a different domain
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class DNAMERecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = 2670767677200844154L;
|
||||
|
||||
DNAMERecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new DNAMERecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DNAMERecord with the given data
|
||||
*
|
||||
* @param alias The name to which the DNAME alias points
|
||||
*/
|
||||
public
|
||||
DNAMERecord(Name name, int dclass, long ttl, Name alias) {
|
||||
super(name, DnsRecordType.DNAME, dclass, ttl, alias, "alias");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the DNAME Record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the alias specified by the DNAME Record
|
||||
*/
|
||||
public
|
||||
Name getAlias() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
107
src/dorkbox/network/dns/records/DNSKEYRecord.java
Normal file
107
src/dorkbox/network/dns/records/DNSKEYRecord.java
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Key - contains a cryptographic public key for use by DNS.
|
||||
* The data can be converted to objects implementing
|
||||
* java.security.interfaces.PublicKey
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see DNSSEC
|
||||
*/
|
||||
|
||||
public
|
||||
class DNSKEYRecord extends KEYBase {
|
||||
|
||||
private static final long serialVersionUID = -8679800040426675002L;
|
||||
|
||||
|
||||
public static
|
||||
class Protocol {
|
||||
/**
|
||||
* Key will be used for DNSSEC
|
||||
*/
|
||||
public static final int DNSSEC = 3;
|
||||
|
||||
private
|
||||
Protocol() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Flags {
|
||||
/**
|
||||
* Key is a zone key
|
||||
*/
|
||||
public static final int ZONE_KEY = 0x100;
|
||||
/**
|
||||
* Key is a secure entry point key
|
||||
*/
|
||||
public static final int SEP_KEY = 0x1;
|
||||
/**
|
||||
* Key has been revoked
|
||||
*/
|
||||
public static final int REVOKE = 0x80;
|
||||
|
||||
private
|
||||
Flags() {}
|
||||
}
|
||||
|
||||
DNSKEYRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new DNSKEYRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
flags = st.getUInt16();
|
||||
proto = st.getUInt8();
|
||||
String algString = st.getString();
|
||||
alg = DNSSEC.Algorithm.value(algString);
|
||||
if (alg < 0) {
|
||||
throw st.exception("Invalid algorithm: " + algString);
|
||||
}
|
||||
key = st.getBase64();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DNSKEY Record from the given data
|
||||
*
|
||||
* @param flags Flags describing the key's properties
|
||||
* @param proto The protocol that the key was created for
|
||||
* @param alg The key's algorithm
|
||||
* @param key Binary representation of the key
|
||||
*/
|
||||
public
|
||||
DNSKEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, byte[] key) {
|
||||
super(name, DnsRecordType.DNSKEY, dclass, ttl, flags, proto, alg, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DNSKEY Record from the given data
|
||||
*
|
||||
* @param flags Flags describing the key's properties
|
||||
* @param proto The protocol that the key was created for
|
||||
* @param alg The key's algorithm
|
||||
* @param key The key as a PublicKey
|
||||
*
|
||||
* @throws DNSSEC.DNSSECException The PublicKey could not be converted into DNS
|
||||
* format.
|
||||
*/
|
||||
public
|
||||
DNSKEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, PublicKey key) throws DNSSEC.DNSSECException {
|
||||
super(name, DnsRecordType.DNSKEY, dclass, ttl, flags, proto, alg, DNSSEC.fromPublicKey(key, alg));
|
||||
publicKey = key;
|
||||
}
|
||||
|
||||
}
|
1278
src/dorkbox/network/dns/records/DNSSEC.java
Normal file
1278
src/dorkbox/network/dns/records/DNSSEC.java
Normal file
File diff suppressed because it is too large
Load Diff
170
src/dorkbox/network/dns/records/DSRecord.java
Normal file
170
src/dorkbox/network/dns/records/DSRecord.java
Normal file
|
@ -0,0 +1,170 @@
|
|||
// Copyright (c) 2002-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* DS - contains a Delegation Signer record, which acts as a
|
||||
* placeholder for KEY records in the parent zone.
|
||||
*
|
||||
* @author David Blacka
|
||||
* @author Brian Wellington
|
||||
* @see DNSSEC
|
||||
*/
|
||||
|
||||
public
|
||||
class DSRecord extends DnsRecord {
|
||||
|
||||
public static final int SHA1_DIGEST_ID = Digest.SHA1;
|
||||
public static final int SHA256_DIGEST_ID = Digest.SHA256;
|
||||
public static final int GOST3411_DIGEST_ID = Digest.GOST3411;
|
||||
public static final int SHA384_DIGEST_ID = Digest.SHA384;
|
||||
private static final long serialVersionUID = -9001819329700081493L;
|
||||
private int footprint;
|
||||
private int alg;
|
||||
private int digestid;
|
||||
private byte[] digest;
|
||||
|
||||
|
||||
public static
|
||||
class Digest {
|
||||
/**
|
||||
* SHA-1
|
||||
*/
|
||||
public static final int SHA1 = 1;
|
||||
/**
|
||||
* SHA-256
|
||||
*/
|
||||
public static final int SHA256 = 2;
|
||||
/**
|
||||
* GOST R 34.11-94
|
||||
*/
|
||||
public static final int GOST3411 = 3;
|
||||
/**
|
||||
* SHA-384
|
||||
*/
|
||||
public static final int SHA384 = 4;
|
||||
|
||||
private
|
||||
Digest() {}
|
||||
}
|
||||
|
||||
DSRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new DSRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
footprint = in.readU16();
|
||||
alg = in.readU8();
|
||||
digestid = in.readU8();
|
||||
digest = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(footprint);
|
||||
out.writeU8(alg);
|
||||
out.writeU8(digestid);
|
||||
if (digest != null) {
|
||||
out.writeByteArray(digest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(footprint);
|
||||
sb.append(" ");
|
||||
sb.append(alg);
|
||||
sb.append(" ");
|
||||
sb.append(digestid);
|
||||
if (digest != null) {
|
||||
sb.append(" ");
|
||||
sb.append(base16.toString(digest));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
footprint = st.getUInt16();
|
||||
alg = st.getUInt8();
|
||||
digestid = st.getUInt8();
|
||||
digest = st.getHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DS Record from the given data
|
||||
*
|
||||
* @param digestid The digest id code.
|
||||
* @param key The key to digest
|
||||
*/
|
||||
public
|
||||
DSRecord(Name name, int dclass, long ttl, int digestid, DNSKEYRecord key) {
|
||||
this(name, dclass, ttl, key.getFootprint(), key.getAlgorithm(), digestid, DNSSEC.generateDSDigest(key, digestid));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a DS Record from the given data
|
||||
*
|
||||
* @param footprint The original KEY record's footprint (keyid).
|
||||
* @param alg The original key algorithm.
|
||||
* @param digestid The digest id code.
|
||||
* @param digest A hash of the original key.
|
||||
*/
|
||||
public
|
||||
DSRecord(Name name, int dclass, long ttl, int footprint, int alg, int digestid, byte[] digest) {
|
||||
super(name, DnsRecordType.DS, dclass, ttl);
|
||||
this.footprint = checkU16("footprint", footprint);
|
||||
this.alg = checkU8("alg", alg);
|
||||
this.digestid = checkU8("digestid", digestid);
|
||||
this.digest = digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's algorithm.
|
||||
*/
|
||||
public
|
||||
int getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's Digest ID.
|
||||
*/
|
||||
public
|
||||
int getDigestID() {
|
||||
return digestid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary hash of the key.
|
||||
*/
|
||||
public
|
||||
byte[] getDigest() {
|
||||
return digest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's footprint.
|
||||
*/
|
||||
public
|
||||
int getFootprint() {
|
||||
return footprint;
|
||||
}
|
||||
|
||||
}
|
1025
src/dorkbox/network/dns/records/DnsMessage.java
Normal file
1025
src/dorkbox/network/dns/records/DnsMessage.java
Normal file
File diff suppressed because it is too large
Load Diff
823
src/dorkbox/network/dns/records/DnsRecord.java
Normal file
823
src/dorkbox/network/dns/records/DnsRecord.java
Normal file
|
@ -0,0 +1,823 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.Serializable;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.Arrays;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsClass;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.constants.DnsSection;
|
||||
import dorkbox.network.dns.exceptions.RelativeNameException;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* A generic DNS resource record. The specific record types extend this class.
|
||||
* A record contains a name, type, class, ttl, and rdata.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public abstract
|
||||
class DnsRecord implements Cloneable, Comparable, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2694906050116005466L;
|
||||
|
||||
protected Name name;
|
||||
protected int type, dclass;
|
||||
protected long ttl;
|
||||
|
||||
private static final DecimalFormat byteFormat = new DecimalFormat();
|
||||
|
||||
static {
|
||||
byteFormat.setMinimumIntegerDigits(3);
|
||||
}
|
||||
|
||||
protected
|
||||
DnsRecord() {}
|
||||
|
||||
DnsRecord(Name name, int type, int dclass, long ttl) {
|
||||
if (!name.isAbsolute()) {
|
||||
throw new RelativeNameException(name);
|
||||
}
|
||||
DnsRecordType.check(type);
|
||||
DnsClass.check(dclass);
|
||||
TTL.check(ttl);
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.dclass = dclass;
|
||||
this.ttl = ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new record, with the given parameters.
|
||||
*
|
||||
* @param name The owner name of the record.
|
||||
* @param type The record's type.
|
||||
* @param dclass The record's class.
|
||||
* @param ttl The record's time to live.
|
||||
* @param data The complete rdata of the record, in uncompressed DNS wire
|
||||
* format.
|
||||
*/
|
||||
public static
|
||||
DnsRecord newRecord(Name name, int type, int dclass, long ttl, byte[] data) {
|
||||
return newRecord(name, type, dclass, ttl, data.length, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new record, with the given parameters.
|
||||
*
|
||||
* @param name The owner name of the record.
|
||||
* @param type The record's type.
|
||||
* @param dclass The record's class.
|
||||
* @param ttl The record's time to live.
|
||||
* @param length The length of the record's data.
|
||||
* @param data The rdata of the record, in uncompressed DNS wire format. Only
|
||||
* the first length bytes are used.
|
||||
*/
|
||||
public static
|
||||
DnsRecord newRecord(Name name, int type, int dclass, long ttl, int length, byte[] data) {
|
||||
if (!name.isAbsolute()) {
|
||||
throw new RelativeNameException(name);
|
||||
}
|
||||
DnsRecordType.check(type);
|
||||
DnsClass.check(dclass);
|
||||
TTL.check(ttl);
|
||||
|
||||
DnsInput in;
|
||||
if (data != null) {
|
||||
in = new DnsInput(data);
|
||||
}
|
||||
else {
|
||||
in = null;
|
||||
}
|
||||
try {
|
||||
return newRecord(name, type, dclass, ttl, length, in);
|
||||
} catch (IOException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static
|
||||
DnsRecord newRecord(Name name, int type, int dclass, long ttl, int length, DnsInput in) throws IOException {
|
||||
DnsRecord rec;
|
||||
rec = getEmptyRecord(name, type, dclass, ttl, in != null);
|
||||
if (in != null) {
|
||||
if (in.remaining() < length) {
|
||||
throw new WireParseException("truncated record");
|
||||
}
|
||||
in.setActive(length);
|
||||
|
||||
rec.rrFromWire(in);
|
||||
|
||||
int remaining = in.remaining();
|
||||
in.restoreActive();
|
||||
|
||||
if (remaining > 0) {
|
||||
throw new WireParseException("invalid record length");
|
||||
}
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
private static
|
||||
DnsRecord getEmptyRecord(Name name, int type, int dclass, long ttl, boolean hasData) {
|
||||
DnsRecord proto, rec;
|
||||
|
||||
if (hasData) {
|
||||
proto = DnsRecordType.getProto(type);
|
||||
if (proto != null) {
|
||||
rec = proto.getObject();
|
||||
}
|
||||
else {
|
||||
rec = new UNKRecord();
|
||||
}
|
||||
}
|
||||
else {
|
||||
rec = new EmptyRecord();
|
||||
}
|
||||
rec.name = name;
|
||||
rec.type = type;
|
||||
rec.dclass = dclass;
|
||||
rec.ttl = ttl;
|
||||
return rec;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates an empty record of the correct type; must be overriden
|
||||
*/
|
||||
abstract
|
||||
DnsRecord getObject();
|
||||
|
||||
/**
|
||||
* Converts the type-specific RR to wire format - must be overriden
|
||||
*/
|
||||
abstract
|
||||
void rrFromWire(DnsInput in) throws IOException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new empty record, with the given parameters.
|
||||
*
|
||||
* @param name The owner name of the record.
|
||||
* @param type The record's type.
|
||||
* @param dclass The record's class.
|
||||
* @param ttl The record's time to live.
|
||||
*
|
||||
* @return An object of a subclass of Record
|
||||
*/
|
||||
public static
|
||||
DnsRecord newRecord(Name name, int type, int dclass, long ttl) {
|
||||
if (!name.isAbsolute()) {
|
||||
throw new RelativeNameException(name);
|
||||
}
|
||||
DnsRecordType.check(type);
|
||||
DnsClass.check(dclass);
|
||||
TTL.check(ttl);
|
||||
|
||||
return getEmptyRecord(name, type, dclass, ttl, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new empty record, with the given parameters. This method is
|
||||
* designed to create records that will be added to the QUERY section
|
||||
* of a message.
|
||||
*
|
||||
* @param name The owner name of the record.
|
||||
* @param type The record's type.
|
||||
* @param dclass The record's class.
|
||||
*
|
||||
* @return An object of a subclass of Record
|
||||
*/
|
||||
public static
|
||||
DnsRecord newRecord(Name name, int type, int dclass) {
|
||||
return newRecord(name, type, dclass, 0);
|
||||
}
|
||||
|
||||
static
|
||||
DnsRecord fromWire(DnsInput in, int section, boolean isUpdate) throws IOException {
|
||||
int type, dclass;
|
||||
long ttl;
|
||||
int length;
|
||||
Name name;
|
||||
DnsRecord rec;
|
||||
|
||||
name = new Name(in);
|
||||
type = in.readU16();
|
||||
dclass = in.readU16();
|
||||
|
||||
if (section == DnsSection.QUESTION) {
|
||||
return newRecord(name, type, dclass);
|
||||
}
|
||||
|
||||
ttl = in.readU32();
|
||||
length = in.readU16();
|
||||
if (length == 0 && isUpdate && (section == DnsSection.PREREQ || section == DnsSection.UPDATE)) {
|
||||
return newRecord(name, type, dclass, ttl);
|
||||
}
|
||||
rec = newRecord(name, type, dclass, ttl, length, in);
|
||||
return rec;
|
||||
}
|
||||
|
||||
static
|
||||
DnsRecord fromWire(DnsInput in, int section) throws IOException {
|
||||
return fromWire(in, section, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Record from DNS uncompressed wire format.
|
||||
*/
|
||||
public static
|
||||
DnsRecord fromWire(byte[] b, int section) throws IOException {
|
||||
return fromWire(new DnsInput(b), section, false);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Converts a Record into DNS uncompressed wire format.
|
||||
*/
|
||||
public
|
||||
byte[] toWire(int section) {
|
||||
DnsOutput out = new DnsOutput();
|
||||
toWire(out, section, null);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
void toWire(DnsOutput out, int section, Compression c) {
|
||||
name.toWire(out, c);
|
||||
out.writeU16(type);
|
||||
out.writeU16(dclass);
|
||||
if (section == DnsSection.QUESTION) {
|
||||
return;
|
||||
}
|
||||
out.writeU32(ttl);
|
||||
int lengthPosition = out.current();
|
||||
out.writeU16(0); /* until we know better */
|
||||
rrToWire(out, c, false);
|
||||
int rrlength = out.current() - lengthPosition - 2;
|
||||
out.writeU16At(rrlength, lengthPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the type-specific RR to wire format - must be overriden
|
||||
*/
|
||||
abstract
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical);
|
||||
|
||||
/**
|
||||
* Converts a Record into canonical DNS uncompressed wire format (all names are
|
||||
* converted to lowercase).
|
||||
*/
|
||||
public
|
||||
byte[] toWireCanonical() {
|
||||
return toWireCanonical(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Converts a Record into canonical DNS uncompressed wire format (all names are
|
||||
* converted to lowercase), optionally ignoring the TTL.
|
||||
*/
|
||||
private
|
||||
byte[] toWireCanonical(boolean noTTL) {
|
||||
DnsOutput out = new DnsOutput();
|
||||
toWireCanonical(out, noTTL);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
private
|
||||
void toWireCanonical(DnsOutput out, boolean noTTL) {
|
||||
name.toWireCanonical(out);
|
||||
out.writeU16(type);
|
||||
out.writeU16(dclass);
|
||||
if (noTTL) {
|
||||
out.writeU32(0);
|
||||
}
|
||||
else {
|
||||
out.writeU32(ttl);
|
||||
}
|
||||
int lengthPosition = out.current();
|
||||
out.writeU16(0); /* until we know better */
|
||||
rrToWire(out, null, true);
|
||||
int rrlength = out.current() - lengthPosition - 2;
|
||||
out.writeU16At(rrlength, lengthPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the rdata portion of a Record into a String representation
|
||||
*/
|
||||
public
|
||||
void rdataToString(StringBuilder sb) {
|
||||
rrToString(sb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the type-specific RR to text format - must be overriden
|
||||
*/
|
||||
abstract
|
||||
void rrToString(StringBuilder sb);
|
||||
|
||||
/**
|
||||
* Converts the text format of an RR to the internal format - must be overriden
|
||||
*/
|
||||
abstract
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException;
|
||||
|
||||
/**
|
||||
* Converts a String into a byte array.
|
||||
*/
|
||||
protected static
|
||||
byte[] byteArrayFromString(String s) throws TextParseException {
|
||||
byte[] array = s.getBytes();
|
||||
boolean escaped = false;
|
||||
boolean hasEscapes = false;
|
||||
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (array[i] == '\\') {
|
||||
hasEscapes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!hasEscapes) {
|
||||
if (array.length > 255) {
|
||||
throw new TextParseException("text string too long");
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
|
||||
int digits = 0;
|
||||
int intval = 0;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
byte b = array[i];
|
||||
if (escaped) {
|
||||
if (b >= '0' && b <= '9' && digits < 3) {
|
||||
digits++;
|
||||
intval *= 10;
|
||||
intval += (b - '0');
|
||||
if (intval > 255) {
|
||||
throw new TextParseException("bad escape");
|
||||
}
|
||||
if (digits < 3) {
|
||||
continue;
|
||||
}
|
||||
b = (byte) intval;
|
||||
}
|
||||
else if (digits > 0 && digits < 3) {
|
||||
throw new TextParseException("bad escape");
|
||||
}
|
||||
os.write(b);
|
||||
escaped = false;
|
||||
}
|
||||
else if (array[i] == '\\') {
|
||||
escaped = true;
|
||||
digits = 0;
|
||||
intval = 0;
|
||||
}
|
||||
else {
|
||||
os.write(array[i]);
|
||||
}
|
||||
}
|
||||
if (digits > 0 && digits < 3) {
|
||||
throw new TextParseException("bad escape");
|
||||
}
|
||||
array = os.toByteArray();
|
||||
if (array.length > 255) {
|
||||
throw new TextParseException("text string too long");
|
||||
}
|
||||
|
||||
return os.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array into a String.
|
||||
*/
|
||||
protected static
|
||||
String byteArrayToString(byte[] array, boolean quote) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (quote) {
|
||||
sb.append('"');
|
||||
}
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
int b = array[i] & 0xFF;
|
||||
if (b < 0x20 || b >= 0x7f) {
|
||||
sb.append('\\');
|
||||
sb.append(byteFormat.format(b));
|
||||
}
|
||||
else if (b == '"' || b == '\\') {
|
||||
sb.append('\\');
|
||||
sb.append((char) b);
|
||||
}
|
||||
else {
|
||||
sb.append((char) b);
|
||||
}
|
||||
}
|
||||
if (quote) {
|
||||
sb.append('"');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a byte array into the unknown RR format.
|
||||
*/
|
||||
protected static
|
||||
String unknownToString(byte[] data) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("\\# ");
|
||||
sb.append(data.length);
|
||||
sb.append(" ");
|
||||
sb.append(base16.toString(data));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new Record from its textual representation
|
||||
*
|
||||
* @param name The owner name of the record.
|
||||
* @param type The record's type.
|
||||
* @param dclass The record's class.
|
||||
* @param ttl The record's time to live.
|
||||
* @param st A tokenizer containing the textual representation of the rdata.
|
||||
* @param origin The default origin to be appended to relative domain names.
|
||||
*
|
||||
* @return The new record
|
||||
*
|
||||
* @throws IOException The text format was invalid.
|
||||
*/
|
||||
public static
|
||||
DnsRecord fromString(Name name, int type, int dclass, long ttl, Tokenizer st, Name origin) throws IOException {
|
||||
DnsRecord rec;
|
||||
|
||||
if (!name.isAbsolute()) {
|
||||
throw new RelativeNameException(name);
|
||||
}
|
||||
DnsRecordType.check(type);
|
||||
DnsClass.check(dclass);
|
||||
TTL.check(ttl);
|
||||
|
||||
Tokenizer.Token t = st.get();
|
||||
if (t.type == Tokenizer.IDENTIFIER && t.value.equals("\\#")) {
|
||||
int length = st.getUInt16();
|
||||
byte[] data = st.getHex();
|
||||
if (data == null) {
|
||||
data = new byte[0];
|
||||
}
|
||||
if (length != data.length) {
|
||||
throw st.exception("invalid unknown RR encoding: " + "length mismatch");
|
||||
}
|
||||
DnsInput in = new DnsInput(data);
|
||||
return newRecord(name, type, dclass, ttl, length, in);
|
||||
}
|
||||
st.unget();
|
||||
rec = getEmptyRecord(name, type, dclass, ttl, true);
|
||||
rec.rdataFromString(st, origin);
|
||||
t = st.get();
|
||||
if (t.type != Tokenizer.EOL && t.type != Tokenizer.EOF) {
|
||||
throw st.exception("unexpected tokens at end of record");
|
||||
}
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a new Record from its textual representation
|
||||
*
|
||||
* @param name The owner name of the record.
|
||||
* @param type The record's type.
|
||||
* @param dclass The record's class.
|
||||
* @param ttl The record's time to live.
|
||||
* @param s The textual representation of the rdata.
|
||||
* @param origin The default origin to be appended to relative domain names.
|
||||
*
|
||||
* @return The new record
|
||||
*
|
||||
* @throws IOException The text format was invalid.
|
||||
*/
|
||||
public static
|
||||
DnsRecord fromString(Name name, int type, int dclass, long ttl, String s, Name origin) throws IOException {
|
||||
return fromString(name, type, dclass, ttl, new Tokenizer(s), origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's name
|
||||
*
|
||||
* @see Name
|
||||
*/
|
||||
public
|
||||
Name getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's type
|
||||
*
|
||||
* @see DnsRecordType
|
||||
*/
|
||||
public
|
||||
int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's class
|
||||
*/
|
||||
public
|
||||
int getDClass() {
|
||||
return dclass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's TTL
|
||||
*/
|
||||
public
|
||||
long getTTL() {
|
||||
return ttl;
|
||||
}
|
||||
|
||||
/* Sets the TTL to the specified value. This is intentionally not public. EDIT: public now so we can change it if we want to */
|
||||
public
|
||||
void setTTL(long ttl) {
|
||||
this.ttl = ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two Records could be part of the same RRset.
|
||||
* This compares the name, type, and class of the Records; the ttl and
|
||||
* rdata are not compared.
|
||||
*/
|
||||
public
|
||||
boolean sameRRset(DnsRecord rec) {
|
||||
return (getRRsetType() == rec.getRRsetType() && dclass == rec.dclass && name.equals(rec.name));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of RRset that this record would belong to. For all types
|
||||
* except RRSIG, this is equivalent to getType().
|
||||
*
|
||||
* @return The type of record, if not RRSIG. If the type is RRSIG,
|
||||
* the type covered is returned.
|
||||
*
|
||||
* @see DnsRecordType
|
||||
* @see RRset
|
||||
* @see SIGRecord
|
||||
*/
|
||||
public
|
||||
int getRRsetType() {
|
||||
if (type == DnsRecordType.RRSIG) {
|
||||
RRSIGRecord sig = (RRSIGRecord) this;
|
||||
return sig.getTypeCovered();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a hash code based on the Record's data.
|
||||
*/
|
||||
public
|
||||
int hashCode() {
|
||||
byte[] array = toWireCanonical(true);
|
||||
int code = 0;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
code += ((code << 3) + (array[i] & 0xFF));
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two Records are identical. This compares the name, type,
|
||||
* class, and rdata (with names canonicalized). The TTLs are not compared.
|
||||
*
|
||||
* @param arg The record to compare to
|
||||
*
|
||||
* @return true if the records are equal, false otherwise.
|
||||
*/
|
||||
public
|
||||
boolean equals(Object arg) {
|
||||
if (arg == null || !(arg instanceof DnsRecord)) {
|
||||
return false;
|
||||
}
|
||||
DnsRecord r = (DnsRecord) arg;
|
||||
if (type != r.type || dclass != r.dclass || !name.equals(r.name)) {
|
||||
return false;
|
||||
}
|
||||
byte[] array1 = rdataToWireCanonical();
|
||||
byte[] array2 = r.rdataToWireCanonical();
|
||||
return Arrays.equals(array1, array2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the rdata in a Record into canonical DNS uncompressed wire format
|
||||
* (all names are converted to lowercase).
|
||||
*/
|
||||
public
|
||||
byte[] rdataToWireCanonical() {
|
||||
DnsOutput out = new DnsOutput();
|
||||
rrToWire(out, null, true);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Record into a String representation
|
||||
*/
|
||||
@Override
|
||||
public final
|
||||
String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toString(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a Record into a String representation in a StringBuilder
|
||||
*/
|
||||
public
|
||||
void toString(StringBuilder sb) {
|
||||
sb.append(name);
|
||||
if (sb.length() < 8) {
|
||||
sb.append("\t");
|
||||
}
|
||||
if (sb.length() < 16) {
|
||||
sb.append("\t");
|
||||
}
|
||||
sb.append("\t");
|
||||
if (Options.check("BINDTTL")) {
|
||||
sb.append(TTL.format(ttl));
|
||||
}
|
||||
else {
|
||||
sb.append(ttl);
|
||||
}
|
||||
sb.append("\t");
|
||||
if (dclass != DnsClass.IN || !Options.check("noPrintIN")) {
|
||||
sb.append(DnsClass.string(dclass));
|
||||
sb.append("\t");
|
||||
}
|
||||
sb.append(DnsRecordType.string(type));
|
||||
|
||||
sb.append("\t");
|
||||
int length = sb.length();
|
||||
rrToString(sb);
|
||||
|
||||
if (length == sb.length()) {
|
||||
// delete the /t since we had no record data
|
||||
sb.deleteCharAt(length-1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new record identical to the current record, but with a different
|
||||
* name. This is most useful for replacing the name of a wildcard record.
|
||||
*/
|
||||
public
|
||||
DnsRecord withName(Name name) {
|
||||
if (!name.isAbsolute()) {
|
||||
throw new RelativeNameException(name);
|
||||
}
|
||||
DnsRecord rec = cloneRecord();
|
||||
rec.name = name;
|
||||
return rec;
|
||||
}
|
||||
|
||||
DnsRecord cloneRecord() {
|
||||
try {
|
||||
return (DnsRecord) clone();
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new record identical to the current record, but with a different
|
||||
* class and ttl. This is most useful for dynamic update.
|
||||
*/
|
||||
DnsRecord withDClass(int dclass, long ttl) {
|
||||
DnsRecord rec = cloneRecord();
|
||||
rec.dclass = dclass;
|
||||
rec.ttl = ttl;
|
||||
return rec;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares this Record to another Object.
|
||||
*
|
||||
* @param o The Object to be compared.
|
||||
*
|
||||
* @return The value 0 if the argument is a record equivalent to this record;
|
||||
* a value less than 0 if the argument is less than this record in the
|
||||
* canonical ordering, and a value greater than 0 if the argument is greater
|
||||
* than this record in the canonical ordering. The canonical ordering
|
||||
* is defined to compare by name, class, type, and rdata.
|
||||
*
|
||||
* @throws ClassCastException if the argument is not a Record.
|
||||
*/
|
||||
@Override
|
||||
public
|
||||
int compareTo(Object o) {
|
||||
DnsRecord arg = (DnsRecord) o;
|
||||
|
||||
if (this == arg) {
|
||||
return (0);
|
||||
}
|
||||
|
||||
int n = name.compareTo(arg.name);
|
||||
if (n != 0) {
|
||||
return (n);
|
||||
}
|
||||
n = dclass - arg.dclass;
|
||||
if (n != 0) {
|
||||
return (n);
|
||||
}
|
||||
n = type - arg.type;
|
||||
if (n != 0) {
|
||||
return (n);
|
||||
}
|
||||
byte[] rdata1 = rdataToWireCanonical();
|
||||
byte[] rdata2 = arg.rdataToWireCanonical();
|
||||
for (int i = 0; i < rdata1.length && i < rdata2.length; i++) {
|
||||
n = (rdata1[i] & 0xFF) - (rdata2[i] & 0xFF);
|
||||
if (n != 0) {
|
||||
return (n);
|
||||
}
|
||||
}
|
||||
return (rdata1.length - rdata2.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name for which additional data processing should be done
|
||||
* for this record. This can be used both for building responses and
|
||||
* parsing responses.
|
||||
*
|
||||
* @return The name to used for additional data processing, or null if this
|
||||
* record type does not require additional data processing.
|
||||
*/
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Checks that an int contains an unsigned 8 bit value */
|
||||
static
|
||||
int checkU8(String field, int val) {
|
||||
if (val < 0 || val > 0xFF) {
|
||||
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be an unsigned 8 " + "bit value");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Checks that an int contains an unsigned 16 bit value */
|
||||
static
|
||||
int checkU16(String field, int val) {
|
||||
if (val < 0 || val > 0xFFFF) {
|
||||
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be an unsigned 16 " + "bit value");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Checks that a long contains an unsigned 32 bit value */
|
||||
static
|
||||
long checkU32(String field, long val) {
|
||||
if (val < 0 || val > 0xFFFFFFFFL) {
|
||||
throw new IllegalArgumentException("\"" + field + "\" " + val + " must be an unsigned 32 " + "bit value");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
/* Checks that a name is absolute */
|
||||
static
|
||||
Name checkName(String field, Name name) {
|
||||
if (!name.isAbsolute()) {
|
||||
throw new RelativeNameException(name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
static
|
||||
byte[] checkByteArrayLength(String field, byte[] array, int maxLength) {
|
||||
if (array.length > 0xFFFF) {
|
||||
throw new IllegalArgumentException("\"" + field + "\" array " + "must have no more than " + maxLength + " elements");
|
||||
}
|
||||
byte[] out = new byte[array.length];
|
||||
System.arraycopy(array, 0, out, 0, array.length);
|
||||
return out;
|
||||
}
|
||||
}
|
78
src/dorkbox/network/dns/records/DnsTypeProtoAssignment.java
Normal file
78
src/dorkbox/network/dns/records/DnsTypeProtoAssignment.java
Normal file
|
@ -0,0 +1,78 @@
|
|||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
public
|
||||
class DnsTypeProtoAssignment {
|
||||
|
||||
// this is so we don't have to make each type constructor public
|
||||
public static
|
||||
void assign(final DnsRecordType.TypeMnemonic types) {
|
||||
types.add(DnsRecordType.A, "A", new ARecord());
|
||||
types.add(DnsRecordType.NS, "NS", new NSRecord());
|
||||
types.add(DnsRecordType.MD, "MD", new MDRecord());
|
||||
types.add(DnsRecordType.MF, "MF", new MFRecord());
|
||||
types.add(DnsRecordType.CNAME, "CNAME", new CNAMERecord());
|
||||
types.add(DnsRecordType.SOA, "SOA", new SOARecord());
|
||||
types.add(DnsRecordType.MB, "MB", new MBRecord());
|
||||
types.add(DnsRecordType.MG, "MG", new MGRecord());
|
||||
types.add(DnsRecordType.MR, "MR", new MRRecord());
|
||||
types.add(DnsRecordType.NULL, "NULL", new NULLRecord());
|
||||
types.add(DnsRecordType.WKS, "WKS", new WKSRecord());
|
||||
types.add(DnsRecordType.PTR, "PTR", new PTRRecord());
|
||||
types.add(DnsRecordType.HINFO, "HINFO", new HINFORecord());
|
||||
types.add(DnsRecordType.MINFO, "MINFO", new MINFORecord());
|
||||
types.add(DnsRecordType.MX, "MX", new MXRecord());
|
||||
types.add(DnsRecordType.TXT, "TXT", new TXTRecord());
|
||||
types.add(DnsRecordType.RP, "RP", new RPRecord());
|
||||
types.add(DnsRecordType.AFSDB, "AFSDB", new AFSDBRecord());
|
||||
types.add(DnsRecordType.X25, "X25", new X25Record());
|
||||
types.add(DnsRecordType.ISDN, "ISDN", new ISDNRecord());
|
||||
types.add(DnsRecordType.RT, "RT", new RTRecord());
|
||||
types.add(DnsRecordType.NSAP, "NSAP", new NSAPRecord());
|
||||
types.add(DnsRecordType.NSAP_PTR, "NSAP-PTR", new NSAP_PTRRecord());
|
||||
types.add(DnsRecordType.SIG, "SIG", new SIGRecord());
|
||||
types.add(DnsRecordType.KEY, "KEY", new KEYRecord());
|
||||
types.add(DnsRecordType.PX, "PX", new PXRecord());
|
||||
types.add(DnsRecordType.GPOS, "GPOS", new GPOSRecord());
|
||||
types.add(DnsRecordType.AAAA, "AAAA", new AAAARecord());
|
||||
types.add(DnsRecordType.LOC, "LOC", new LOCRecord());
|
||||
types.add(DnsRecordType.NXT, "NXT", new NXTRecord());
|
||||
types.add(DnsRecordType.EID, "EID");
|
||||
types.add(DnsRecordType.NIMLOC, "NIMLOC");
|
||||
types.add(DnsRecordType.SRV, "SRV", new SRVRecord());
|
||||
types.add(DnsRecordType.ATMA, "ATMA");
|
||||
types.add(DnsRecordType.NAPTR, "NAPTR", new NAPTRRecord());
|
||||
types.add(DnsRecordType.KX, "KX", new KXRecord());
|
||||
types.add(DnsRecordType.CERT, "CERT", new CERTRecord());
|
||||
types.add(DnsRecordType.A6, "A6", new A6Record());
|
||||
types.add(DnsRecordType.DNAME, "DNAME", new DNAMERecord());
|
||||
types.add(DnsRecordType.OPT, "OPT", new OPTRecord());
|
||||
types.add(DnsRecordType.APL, "APL", new APLRecord());
|
||||
types.add(DnsRecordType.DS, "DS", new DSRecord());
|
||||
types.add(DnsRecordType.SSHFP, "SSHFP", new SSHFPRecord());
|
||||
types.add(DnsRecordType.IPSECKEY, "IPSECKEY", new IPSECKEYRecord());
|
||||
types.add(DnsRecordType.RRSIG, "RRSIG", new RRSIGRecord());
|
||||
types.add(DnsRecordType.NSEC, "NSEC", new NSECRecord());
|
||||
types.add(DnsRecordType.DNSKEY, "DNSKEY", new DNSKEYRecord());
|
||||
types.add(DnsRecordType.DHCID, "DHCID", new DHCIDRecord());
|
||||
types.add(DnsRecordType.NSEC3, "NSEC3", new NSEC3Record());
|
||||
types.add(DnsRecordType.NSEC3PARAM, "NSEC3PARAM", new NSEC3PARAMRecord());
|
||||
types.add(DnsRecordType.TLSA, "TLSA", new TLSARecord());
|
||||
types.add(DnsRecordType.SMIMEA, "SMIMEA", new SMIMEARecord());
|
||||
types.add(DnsRecordType.SMIMEA, "HIP");
|
||||
types.add(DnsRecordType.OPENPGPKEY, "OPENPGPKEY", new OPENPGPKEYRecord());
|
||||
types.add(DnsRecordType.SPF, "SPF", new SPFRecord());
|
||||
types.add(DnsRecordType.TKEY, "TKEY", new TKEYRecord());
|
||||
types.add(DnsRecordType.TSIG, "TSIG", new TSIGRecord());
|
||||
types.add(DnsRecordType.IXFR, "IXFR");
|
||||
types.add(DnsRecordType.AXFR, "AXFR");
|
||||
types.add(DnsRecordType.MAILB, "MAILB");
|
||||
types.add(DnsRecordType.MAILA, "MAILA");
|
||||
types.add(DnsRecordType.ANY, "ANY");
|
||||
types.add(DnsRecordType.URI, "URI", new URIRecord());
|
||||
types.add(DnsRecordType.CAA, "CAA", new CAARecord());
|
||||
types.add(DnsRecordType.TA, "TA");
|
||||
types.add(DnsRecordType.DLV, "DLV", new DLVRecord());
|
||||
}
|
||||
}
|
236
src/dorkbox/network/dns/records/EDNSOption.java
Normal file
236
src/dorkbox/network/dns/records/EDNSOption.java
Normal file
|
@ -0,0 +1,236 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
|
||||
/**
|
||||
* DNS extension options, as described in RFC 2671. The rdata of an OPT record
|
||||
* is defined as a list of options; this represents a single option.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @author Ming Zhou <mizhou@bnivideo.com>, Beaumaris Networks
|
||||
*/
|
||||
public abstract
|
||||
class EDNSOption {
|
||||
|
||||
private final int code;
|
||||
|
||||
|
||||
public static
|
||||
class Code {
|
||||
/**
|
||||
* Name Server Identifier, RFC 5001
|
||||
*/
|
||||
public final static int NSID = 3;
|
||||
/**
|
||||
* Client Subnet, defined in draft-vandergaast-edns-client-subnet-02
|
||||
*/
|
||||
public final static int CLIENT_SUBNET = 8;
|
||||
private static Mnemonic codes = new Mnemonic("EDNS Option Codes", Mnemonic.CASE_UPPER);
|
||||
|
||||
private
|
||||
Code() {}
|
||||
|
||||
static {
|
||||
codes.setMaximum(0xFFFF);
|
||||
codes.setPrefix("CODE");
|
||||
codes.setNumericAllowed(true);
|
||||
|
||||
codes.add(NSID, "NSID");
|
||||
codes.add(CLIENT_SUBNET, "CLIENT_SUBNET");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an EDNS Option Code into its textual representation
|
||||
*/
|
||||
public static
|
||||
String string(int code) {
|
||||
return codes.getText(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a textual representation of an EDNS Option Code into its
|
||||
* numeric value.
|
||||
*
|
||||
* @param s The textual representation of the option code
|
||||
*
|
||||
* @return The option code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return codes.getValue(s);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an option with the given option code and data.
|
||||
*/
|
||||
public
|
||||
EDNSOption(int code) {
|
||||
this.code = DnsRecord.checkU16("code", code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the EDNS Option's code.
|
||||
*
|
||||
* @return the option code
|
||||
*/
|
||||
public
|
||||
int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the wire format of an EDNS Option (including code and length) into
|
||||
* the type-specific format.
|
||||
*
|
||||
* @return The option, in wire format.
|
||||
*/
|
||||
public static
|
||||
EDNSOption fromWire(byte[] b) throws IOException {
|
||||
return fromWire(new DnsInput(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the wire format of an EDNS Option (including code and length) into
|
||||
* the type-specific format.
|
||||
*
|
||||
* @param in The input stream.
|
||||
*/
|
||||
static
|
||||
EDNSOption fromWire(DnsInput in) throws IOException {
|
||||
int code, length;
|
||||
|
||||
code = in.readU16();
|
||||
length = in.readU16();
|
||||
if (in.remaining() < length) {
|
||||
throw new WireParseException("truncated option");
|
||||
}
|
||||
in.setActive(length);
|
||||
EDNSOption option;
|
||||
switch (code) {
|
||||
case Code.NSID:
|
||||
option = new NSIDOption();
|
||||
break;
|
||||
case Code.CLIENT_SUBNET:
|
||||
option = new ClientSubnetOption();
|
||||
break;
|
||||
default:
|
||||
option = new GenericEDNSOption(code);
|
||||
break;
|
||||
}
|
||||
option.optionFromWire(in);
|
||||
in.restoreActive();
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the wire format of an EDNS Option (the option data only) into the
|
||||
* type-specific format.
|
||||
*
|
||||
* @param in The input Stream.
|
||||
*/
|
||||
abstract
|
||||
void optionFromWire(DnsInput in) throws IOException;
|
||||
|
||||
/**
|
||||
* Converts an EDNS Option (including code and length) into wire format.
|
||||
*
|
||||
* @return The option, in wire format.
|
||||
*/
|
||||
public
|
||||
byte[] toWire() throws IOException {
|
||||
DnsOutput out = new DnsOutput();
|
||||
toWire(out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an EDNS Option (including code and length) into wire format.
|
||||
*
|
||||
* @param out The output stream.
|
||||
*/
|
||||
void toWire(DnsOutput out) {
|
||||
out.writeU16(code);
|
||||
int lengthPosition = out.current();
|
||||
out.writeU16(0); /* until we know better */
|
||||
optionToWire(out);
|
||||
int length = out.current() - lengthPosition - 2;
|
||||
out.writeU16At(length, lengthPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an EDNS Option (the type-specific option data only) into wire format.
|
||||
*
|
||||
* @param out The output stream.
|
||||
*/
|
||||
abstract
|
||||
void optionToWire(DnsOutput out);
|
||||
|
||||
/**
|
||||
* Generates a hash code based on the EDNS Option's data.
|
||||
*/
|
||||
public
|
||||
int hashCode() {
|
||||
byte[] array = getData();
|
||||
int hashval = 0;
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
hashval += ((hashval << 3) + (array[i] & 0xFF));
|
||||
}
|
||||
return hashval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two EDNS Options are identical.
|
||||
*
|
||||
* @param arg The option to compare to
|
||||
*
|
||||
* @return true if the options are equal, false otherwise.
|
||||
*/
|
||||
public
|
||||
boolean equals(Object arg) {
|
||||
if (arg == null || !(arg instanceof EDNSOption)) {
|
||||
return false;
|
||||
}
|
||||
EDNSOption opt = (EDNSOption) arg;
|
||||
if (code != opt.code) {
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(getData(), opt.getData());
|
||||
}
|
||||
|
||||
public
|
||||
String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("{");
|
||||
sb.append(EDNSOption.Code.string(code));
|
||||
sb.append(": ");
|
||||
sb.append(optionToString());
|
||||
sb.append("}");
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
abstract
|
||||
String optionToString();
|
||||
|
||||
/**
|
||||
* Returns the EDNS Option's data, as a byte array.
|
||||
*
|
||||
* @return the option data
|
||||
*/
|
||||
byte[] getData() {
|
||||
DnsOutput out = new DnsOutput();
|
||||
optionToWire(out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
}
|
47
src/dorkbox/network/dns/records/EmptyRecord.java
Normal file
47
src/dorkbox/network/dns/records/EmptyRecord.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* A class implementing Records with no data; that is, records used in
|
||||
* the question section of messages and meta-records in dynamic update.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
class EmptyRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 3601852050646429582L;
|
||||
|
||||
EmptyRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new EmptyRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
}
|
||||
|
||||
}
|
51
src/dorkbox/network/dns/records/ExtendedFlags.java
Normal file
51
src/dorkbox/network/dns/records/ExtendedFlags.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
|
||||
/**
|
||||
* Constants and functions relating to EDNS flags.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public final
|
||||
class ExtendedFlags {
|
||||
|
||||
private static Mnemonic extflags = new Mnemonic("EDNS Flag", Mnemonic.CASE_LOWER);
|
||||
|
||||
/**
|
||||
* dnssec ok
|
||||
*/
|
||||
public static final int DO = 0x8000;
|
||||
|
||||
static {
|
||||
extflags.setMaximum(0xFFFF);
|
||||
extflags.setPrefix("FLAG");
|
||||
extflags.setNumericAllowed(true);
|
||||
|
||||
extflags.add(DO, "do");
|
||||
}
|
||||
|
||||
private
|
||||
ExtendedFlags() {}
|
||||
|
||||
/**
|
||||
* Converts a numeric extended flag into a String
|
||||
*/
|
||||
public static
|
||||
String string(int i) {
|
||||
return extflags.getText(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a textual representation of an extended flag into its numeric
|
||||
* value
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return extflags.getValue(s);
|
||||
}
|
||||
|
||||
}
|
191
src/dorkbox/network/dns/records/GPOSRecord.java
Normal file
191
src/dorkbox/network/dns/records/GPOSRecord.java
Normal file
|
@ -0,0 +1,191 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Geographical Location - describes the physical location of a host.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class GPOSRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -6349714958085750705L;
|
||||
|
||||
private byte[] latitude, longitude, altitude;
|
||||
|
||||
GPOSRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new GPOSRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
longitude = in.readCountedString();
|
||||
latitude = in.readCountedString();
|
||||
altitude = in.readCountedString();
|
||||
try {
|
||||
validate(getLongitude(), getLatitude());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new WireParseException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeCountedString(longitude);
|
||||
out.writeCountedString(latitude);
|
||||
out.writeCountedString(altitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(byteArrayToString(longitude, true));
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(latitude, true));
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(altitude, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
try {
|
||||
longitude = byteArrayFromString(st.getString());
|
||||
latitude = byteArrayFromString(st.getString());
|
||||
altitude = byteArrayFromString(st.getString());
|
||||
} catch (TextParseException e) {
|
||||
throw st.exception(e.getMessage());
|
||||
}
|
||||
try {
|
||||
validate(getLongitude(), getLatitude());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new WireParseException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an GPOS Record from the given data
|
||||
*
|
||||
* @param longitude The longitude component of the location.
|
||||
* @param latitude The latitude component of the location.
|
||||
* @param altitude The altitude component of the location (in meters above sea
|
||||
* level).
|
||||
*/
|
||||
public
|
||||
GPOSRecord(Name name, int dclass, long ttl, double longitude, double latitude, double altitude) {
|
||||
super(name, DnsRecordType.GPOS, dclass, ttl);
|
||||
validate(longitude, latitude);
|
||||
this.longitude = Double.toString(longitude)
|
||||
.getBytes();
|
||||
this.latitude = Double.toString(latitude)
|
||||
.getBytes();
|
||||
this.altitude = Double.toString(altitude)
|
||||
.getBytes();
|
||||
}
|
||||
|
||||
private
|
||||
void validate(double longitude, double latitude) throws IllegalArgumentException {
|
||||
if (longitude < -90.0 || longitude > 90.0) {
|
||||
throw new IllegalArgumentException("illegal longitude " + longitude);
|
||||
}
|
||||
if (latitude < -180.0 || latitude > 180.0) {
|
||||
throw new IllegalArgumentException("illegal latitude " + latitude);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an GPOS Record from the given data
|
||||
*
|
||||
* @param longitude The longitude component of the location.
|
||||
* @param latitude The latitude component of the location.
|
||||
* @param altitude The altitude component of the location (in meters above sea
|
||||
* level).
|
||||
*/
|
||||
public
|
||||
GPOSRecord(Name name, int dclass, long ttl, String longitude, String latitude, String altitude) {
|
||||
super(name, DnsRecordType.GPOS, dclass, ttl);
|
||||
try {
|
||||
this.longitude = byteArrayFromString(longitude);
|
||||
this.latitude = byteArrayFromString(latitude);
|
||||
validate(getLongitude(), getLatitude());
|
||||
this.altitude = byteArrayFromString(altitude);
|
||||
} catch (TextParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the longitude as a double
|
||||
*
|
||||
* @throws NumberFormatException The string does not contain a valid numeric
|
||||
* value.
|
||||
*/
|
||||
public
|
||||
double getLongitude() {
|
||||
return Double.parseDouble(getLongitudeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the longitude as a string
|
||||
*/
|
||||
public
|
||||
String getLongitudeString() {
|
||||
return byteArrayToString(longitude, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude as a double
|
||||
*
|
||||
* @throws NumberFormatException The string does not contain a valid numeric
|
||||
* value.
|
||||
*/
|
||||
public
|
||||
double getLatitude() {
|
||||
return Double.parseDouble(getLatitudeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude as a string
|
||||
*/
|
||||
public
|
||||
String getLatitudeString() {
|
||||
return byteArrayToString(latitude, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the altitude as a double
|
||||
*
|
||||
* @throws NumberFormatException The string does not contain a valid numeric
|
||||
* value.
|
||||
*/
|
||||
public
|
||||
double getAltitude() {
|
||||
return Double.parseDouble(getAltitudeString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the altitude as a string
|
||||
*/
|
||||
public
|
||||
String getAltitudeString() {
|
||||
return byteArrayToString(altitude, false);
|
||||
}
|
||||
|
||||
}
|
51
src/dorkbox/network/dns/records/GenericEDNSOption.java
Normal file
51
src/dorkbox/network/dns/records/GenericEDNSOption.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* An EDNSOption with no internal structure.
|
||||
*
|
||||
* @author Ming Zhou <mizhou@bnivideo.com>, Beaumaris Networks
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
public
|
||||
class GenericEDNSOption extends EDNSOption {
|
||||
|
||||
private byte[] data;
|
||||
|
||||
GenericEDNSOption(int code) {
|
||||
super(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a generic EDNS option.
|
||||
*
|
||||
* @param data The contents of the option.
|
||||
*/
|
||||
public
|
||||
GenericEDNSOption(int code, byte[] data) {
|
||||
super(code);
|
||||
this.data = DnsRecord.checkByteArrayLength("option data", data, 0xFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
void optionFromWire(DnsInput in) throws IOException {
|
||||
data = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void optionToWire(DnsOutput out) {
|
||||
out.writeByteArray(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
String optionToString() {
|
||||
return "<" + base16.toString(data) + ">";
|
||||
}
|
||||
|
||||
}
|
102
src/dorkbox/network/dns/records/HINFORecord.java
Normal file
102
src/dorkbox/network/dns/records/HINFORecord.java
Normal file
|
@ -0,0 +1,102 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Host Information - describes the CPU and OS of a host
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class HINFORecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -4732870630947452112L;
|
||||
|
||||
private byte[] cpu, os;
|
||||
|
||||
HINFORecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new HINFORecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
cpu = in.readCountedString();
|
||||
os = in.readCountedString();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeCountedString(cpu);
|
||||
out.writeCountedString(os);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts to a string
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(byteArrayToString(cpu, true));
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(os, true));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
try {
|
||||
cpu = byteArrayFromString(st.getString());
|
||||
os = byteArrayFromString(st.getString());
|
||||
} catch (TextParseException e) {
|
||||
throw st.exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HINFO Record from the given data
|
||||
*
|
||||
* @param cpu A string describing the host's CPU
|
||||
* @param os A string describing the host's OS
|
||||
*
|
||||
* @throws IllegalArgumentException One of the strings has invalid escapes
|
||||
*/
|
||||
public
|
||||
HINFORecord(Name name, int dclass, long ttl, String cpu, String os) {
|
||||
super(name, DnsRecordType.HINFO, dclass, ttl);
|
||||
try {
|
||||
this.cpu = byteArrayFromString(cpu);
|
||||
this.os = byteArrayFromString(os);
|
||||
} catch (TextParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host's CPU
|
||||
*/
|
||||
public
|
||||
String getCPU() {
|
||||
return byteArrayToString(cpu, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host's OS
|
||||
*/
|
||||
public
|
||||
String getOS() {
|
||||
return byteArrayToString(os, false);
|
||||
}
|
||||
|
||||
}
|
343
src/dorkbox/network/dns/records/Header.java
Normal file
343
src/dorkbox/network/dns/records/Header.java
Normal file
|
@ -0,0 +1,343 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.constants.DnsOpCode;
|
||||
import dorkbox.network.dns.constants.DnsResponseCode;
|
||||
import dorkbox.network.dns.constants.DnsSection;
|
||||
import dorkbox.network.dns.constants.Flags;
|
||||
import dorkbox.util.FastThreadLocal;
|
||||
import dorkbox.util.MersenneTwisterFast;
|
||||
import dorkbox.util.OS;
|
||||
|
||||
/**
|
||||
* A DNS message header
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see DnsMessage
|
||||
*/
|
||||
|
||||
public
|
||||
class Header implements Cloneable {
|
||||
|
||||
private int id;
|
||||
private int flags;
|
||||
private int[] counts;
|
||||
|
||||
private static final
|
||||
FastThreadLocal<MersenneTwisterFast> random = new FastThreadLocal<MersenneTwisterFast>() {
|
||||
@Override
|
||||
public
|
||||
MersenneTwisterFast initialValue() {
|
||||
return new MersenneTwisterFast();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The length of a DNS Header in wire format.
|
||||
*/
|
||||
public static final int LENGTH = 12;
|
||||
|
||||
/**
|
||||
* Create a new empty header with a random message id
|
||||
*/
|
||||
public
|
||||
Header() {
|
||||
init();
|
||||
}
|
||||
|
||||
private
|
||||
void init() {
|
||||
counts = new int[4];
|
||||
flags = 0;
|
||||
id = -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Header from its DNS wire format representation
|
||||
*
|
||||
* @param b A byte array containing the DNS Header.
|
||||
*/
|
||||
public
|
||||
Header(byte[] b) throws IOException {
|
||||
this(new DnsInput(b));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a Header from a stream containing DNS wire format.
|
||||
*/
|
||||
Header(DnsInput in) throws IOException {
|
||||
this(in.readU16());
|
||||
flags = in.readU16();
|
||||
for (int i = 0; i < counts.length; i++) {
|
||||
counts[i] = in.readU16();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new empty header.
|
||||
*
|
||||
* @param id The message id
|
||||
*/
|
||||
public
|
||||
Header(int id) {
|
||||
init();
|
||||
setID(id);
|
||||
}
|
||||
|
||||
public
|
||||
byte[] toWire() {
|
||||
DnsOutput out = new DnsOutput();
|
||||
toWire(out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
void toWire(DnsOutput out) {
|
||||
out.writeU16(getID());
|
||||
out.writeU16(flags);
|
||||
for (int i = 0; i < counts.length; i++) {
|
||||
out.writeU16(counts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the message ID
|
||||
*/
|
||||
public
|
||||
int getID() {
|
||||
if (id >= 0) {
|
||||
return id;
|
||||
}
|
||||
synchronized (this) {
|
||||
if (id < 0) {
|
||||
id = random.get().nextInt(0xffff);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message ID
|
||||
*/
|
||||
public
|
||||
void setID(int id) {
|
||||
if (id < 0 || id > 0xffff) {
|
||||
throw new IllegalArgumentException("DNS message ID " + id + " is out of range");
|
||||
}
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to the supplied value
|
||||
*
|
||||
* @see Flags
|
||||
*/
|
||||
public
|
||||
void setFlag(int bit) {
|
||||
checkFlag(bit);
|
||||
flags = setFlag(flags, bit, true);
|
||||
}
|
||||
|
||||
static private
|
||||
void checkFlag(int bit) {
|
||||
if (!validFlag(bit)) {
|
||||
throw new IllegalArgumentException("invalid flag bit " + bit);
|
||||
}
|
||||
}
|
||||
|
||||
static private
|
||||
boolean validFlag(int bit) {
|
||||
return (bit >= 0 && bit <= 0xF && Flags.isFlag(bit));
|
||||
}
|
||||
|
||||
static
|
||||
int setFlag(int flags, int bit, boolean value) {
|
||||
checkFlag(bit);
|
||||
|
||||
// bits are indexed from left to right
|
||||
if (value) {
|
||||
return flags |= (1 << (15 - bit));
|
||||
}
|
||||
else {
|
||||
return flags &= ~(1 << (15 - bit));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a flag to the supplied value
|
||||
*
|
||||
* @see Flags
|
||||
*/
|
||||
public
|
||||
void unsetFlag(int bit) {
|
||||
checkFlag(bit);
|
||||
flags = setFlag(flags, bit, false);
|
||||
}
|
||||
|
||||
boolean[] getFlags() {
|
||||
boolean[] array = new boolean[16];
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (validFlag(i)) {
|
||||
array[i] = getFlag(i);
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a flag
|
||||
*
|
||||
* @see Flags
|
||||
*/
|
||||
public
|
||||
boolean getFlag(int bit) {
|
||||
checkFlag(bit);
|
||||
// bits are indexed from left to right
|
||||
return (flags & (1 << (15 - bit))) != 0;
|
||||
}
|
||||
|
||||
void setCount(int field, int value) {
|
||||
if (value < 0 || value > 0xFFFF) {
|
||||
throw new IllegalArgumentException("DNS section count " + value + " is out of range");
|
||||
}
|
||||
counts[field] = value;
|
||||
}
|
||||
|
||||
void incCount(int field) {
|
||||
if (counts[field] == 0xFFFF) {
|
||||
throw new IllegalStateException("DNS section count cannot " + "be incremented");
|
||||
}
|
||||
counts[field]++;
|
||||
}
|
||||
|
||||
void decCount(int field) {
|
||||
if (counts[field] == 0) {
|
||||
throw new IllegalStateException("DNS section count cannot " + "be decremented");
|
||||
}
|
||||
counts[field]--;
|
||||
}
|
||||
|
||||
int getFlagsByte() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/* Creates a new Header identical to the current one */
|
||||
@Override
|
||||
public
|
||||
Object clone() {
|
||||
Header h = new Header();
|
||||
h.id = id;
|
||||
h.flags = flags;
|
||||
System.arraycopy(counts, 0, h.counts, 0, counts.length);
|
||||
return h;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the header into a String
|
||||
*/
|
||||
public
|
||||
String toString() {
|
||||
return toStringWithRcode(getRcode());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the mesasge's rcode
|
||||
*
|
||||
* @see DnsResponseCode
|
||||
*/
|
||||
public
|
||||
int getRcode() {
|
||||
return flags & 0xF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message's rcode
|
||||
*
|
||||
* @see DnsResponseCode
|
||||
*/
|
||||
public
|
||||
void setRcode(int value) {
|
||||
if (value < 0 || value > 0xF) {
|
||||
throw new IllegalArgumentException("DNS DnsResponseCode " + value + " is out of range");
|
||||
}
|
||||
flags &= ~0xF;
|
||||
flags |= value;
|
||||
}
|
||||
|
||||
String toStringWithRcode(int newrcode) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append(";; ->>HEADER<<- ");
|
||||
sb.append("opcode: " + DnsOpCode.string(getOpcode()));
|
||||
sb.append(", status: " + DnsResponseCode.string(newrcode));
|
||||
sb.append(", id: " + getID());
|
||||
sb.append(OS.LINE_SEPARATOR);
|
||||
|
||||
sb.append(";; flags: ")
|
||||
.append(printFlags());
|
||||
sb.append("; ");
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sb.append(DnsSection.string(i))
|
||||
.append(": ")
|
||||
.append(getCount(i))
|
||||
.append(" ");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the mesasge's opcode
|
||||
*
|
||||
* @see DnsOpCode
|
||||
*/
|
||||
public
|
||||
int getOpcode() {
|
||||
return (flags >> 11) & 0xF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the message's opcode
|
||||
*
|
||||
* @see DnsOpCode
|
||||
*/
|
||||
public
|
||||
void setOpcode(int value) {
|
||||
if (value < 0 || value > 0xF) {
|
||||
throw new IllegalArgumentException("DNS DnsOpCode " + value + "is out of range");
|
||||
}
|
||||
flags &= 0x87FF;
|
||||
flags |= (value << 11);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the record count for the given section
|
||||
*
|
||||
* @see DnsSection
|
||||
*/
|
||||
public
|
||||
int getCount(int field) {
|
||||
return counts[field];
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the header's flags into a String
|
||||
*/
|
||||
public
|
||||
String printFlags() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (validFlag(i) && getFlag(i)) {
|
||||
sb.append(Flags.string(i));
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
253
src/dorkbox/network/dns/records/IPSECKEYRecord.java
Normal file
253
src/dorkbox/network/dns/records/IPSECKEYRecord.java
Normal file
|
@ -0,0 +1,253 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Address;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.Base64Fast;
|
||||
|
||||
/**
|
||||
* IPsec Keying Material (RFC 4025)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class IPSECKEYRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 3050449702765909687L;
|
||||
private int precedence;
|
||||
private int gatewayType;
|
||||
private int algorithmType;
|
||||
private Object gateway;
|
||||
private byte[] key;
|
||||
|
||||
|
||||
public static
|
||||
class Algorithm {
|
||||
public static final int DSA = 1;
|
||||
public static final int RSA = 2;
|
||||
private
|
||||
Algorithm() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Gateway {
|
||||
public static final int None = 0;
|
||||
public static final int IPv4 = 1;
|
||||
public static final int IPv6 = 2;
|
||||
public static final int Name = 3;
|
||||
private
|
||||
Gateway() {}
|
||||
}
|
||||
|
||||
IPSECKEYRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new IPSECKEYRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
precedence = in.readU8();
|
||||
gatewayType = in.readU8();
|
||||
algorithmType = in.readU8();
|
||||
switch (gatewayType) {
|
||||
case Gateway.None:
|
||||
gateway = null;
|
||||
break;
|
||||
case Gateway.IPv4:
|
||||
gateway = InetAddress.getByAddress(in.readByteArray(4));
|
||||
break;
|
||||
case Gateway.IPv6:
|
||||
gateway = InetAddress.getByAddress(in.readByteArray(16));
|
||||
break;
|
||||
case Gateway.Name:
|
||||
gateway = new Name(in);
|
||||
break;
|
||||
default:
|
||||
throw new WireParseException("invalid gateway type");
|
||||
}
|
||||
if (in.remaining() > 0) {
|
||||
key = in.readByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(precedence);
|
||||
out.writeU8(gatewayType);
|
||||
out.writeU8(algorithmType);
|
||||
switch (gatewayType) {
|
||||
case Gateway.None:
|
||||
break;
|
||||
case Gateway.IPv4:
|
||||
case Gateway.IPv6:
|
||||
InetAddress gatewayAddr = (InetAddress) gateway;
|
||||
out.writeByteArray(gatewayAddr.getAddress());
|
||||
break;
|
||||
case Gateway.Name:
|
||||
Name gatewayName = (Name) gateway;
|
||||
gatewayName.toWire(out, null, canonical);
|
||||
break;
|
||||
}
|
||||
if (key != null) {
|
||||
out.writeByteArray(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(precedence);
|
||||
sb.append(" ");
|
||||
sb.append(gatewayType);
|
||||
sb.append(" ");
|
||||
sb.append(algorithmType);
|
||||
sb.append(" ");
|
||||
|
||||
switch (gatewayType) {
|
||||
case Gateway.None:
|
||||
sb.append(".");
|
||||
break;
|
||||
case Gateway.IPv4:
|
||||
case Gateway.IPv6:
|
||||
InetAddress gatewayAddr = (InetAddress) gateway;
|
||||
sb.append(gatewayAddr.getHostAddress());
|
||||
break;
|
||||
case Gateway.Name:
|
||||
sb.append(gateway);
|
||||
break;
|
||||
}
|
||||
|
||||
if (key != null) {
|
||||
sb.append(" ");
|
||||
sb.append(Base64Fast.encode2(key));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
precedence = st.getUInt8();
|
||||
gatewayType = st.getUInt8();
|
||||
algorithmType = st.getUInt8();
|
||||
switch (gatewayType) {
|
||||
case Gateway.None:
|
||||
String s = st.getString();
|
||||
if (!s.equals(".")) {
|
||||
throw new TextParseException("invalid gateway format");
|
||||
}
|
||||
gateway = null;
|
||||
break;
|
||||
case Gateway.IPv4:
|
||||
gateway = st.getAddress(Address.IPv4);
|
||||
break;
|
||||
case Gateway.IPv6:
|
||||
gateway = st.getAddress(Address.IPv6);
|
||||
break;
|
||||
case Gateway.Name:
|
||||
gateway = st.getName(origin);
|
||||
break;
|
||||
default:
|
||||
throw new WireParseException("invalid gateway type");
|
||||
}
|
||||
key = st.getBase64(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an IPSECKEY Record from the given data.
|
||||
*
|
||||
* @param precedence The record's precedence.
|
||||
* @param gatewayType The record's gateway type.
|
||||
* @param algorithmType The record's algorithm type.
|
||||
* @param gateway The record's gateway.
|
||||
* @param key The record's public key.
|
||||
*/
|
||||
public
|
||||
IPSECKEYRecord(Name name, int dclass, long ttl, int precedence, int gatewayType, int algorithmType, Object gateway, byte[] key) {
|
||||
super(name, DnsRecordType.IPSECKEY, dclass, ttl);
|
||||
this.precedence = checkU8("precedence", precedence);
|
||||
this.gatewayType = checkU8("gatewayType", gatewayType);
|
||||
this.algorithmType = checkU8("algorithmType", algorithmType);
|
||||
switch (gatewayType) {
|
||||
case Gateway.None:
|
||||
this.gateway = null;
|
||||
break;
|
||||
case Gateway.IPv4:
|
||||
if (!(gateway instanceof InetAddress)) {
|
||||
throw new IllegalArgumentException("\"gateway\" " + "must be an IPv4 " + "address");
|
||||
}
|
||||
this.gateway = gateway;
|
||||
break;
|
||||
case Gateway.IPv6:
|
||||
if (!(gateway instanceof Inet6Address)) {
|
||||
throw new IllegalArgumentException("\"gateway\" " + "must be an IPv6 " + "address");
|
||||
}
|
||||
this.gateway = gateway;
|
||||
break;
|
||||
case Gateway.Name:
|
||||
if (!(gateway instanceof Name)) {
|
||||
throw new IllegalArgumentException("\"gateway\" " + "must be a DNS " + "name");
|
||||
}
|
||||
this.gateway = checkName("gateway", (Name) gateway);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("\"gatewayType\" " + "must be between 0 and 3");
|
||||
}
|
||||
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's precedence.
|
||||
*/
|
||||
public
|
||||
int getPrecedence() {
|
||||
return precedence;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's gateway type.
|
||||
*/
|
||||
public
|
||||
int getGatewayType() {
|
||||
return gatewayType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's algorithm type.
|
||||
*/
|
||||
public
|
||||
int getAlgorithmType() {
|
||||
return algorithmType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's gateway.
|
||||
*/
|
||||
public
|
||||
Object getGateway() {
|
||||
return gateway;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the record's public key
|
||||
*/
|
||||
public
|
||||
byte[] getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
}
|
118
src/dorkbox/network/dns/records/ISDNRecord.java
Normal file
118
src/dorkbox/network/dns/records/ISDNRecord.java
Normal file
|
@ -0,0 +1,118 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* ISDN - identifies the ISDN number and subaddress associated with a name.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class ISDNRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -8730801385178968798L;
|
||||
|
||||
private byte[] address;
|
||||
private byte[] subAddress;
|
||||
|
||||
ISDNRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new ISDNRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
address = in.readCountedString();
|
||||
if (in.remaining() > 0) {
|
||||
subAddress = in.readCountedString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeCountedString(address);
|
||||
if (subAddress != null) {
|
||||
out.writeCountedString(subAddress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(byteArrayToString(address, true));
|
||||
|
||||
if (subAddress != null) {
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(subAddress, true));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
try {
|
||||
address = byteArrayFromString(st.getString());
|
||||
Tokenizer.Token t = st.get();
|
||||
if (t.isString()) {
|
||||
subAddress = byteArrayFromString(t.value);
|
||||
}
|
||||
else {
|
||||
st.unget();
|
||||
}
|
||||
} catch (TextParseException e) {
|
||||
throw st.exception(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ISDN Record from the given data
|
||||
*
|
||||
* @param address The ISDN number associated with the domain.
|
||||
* @param subAddress The subaddress, if any.
|
||||
*
|
||||
* @throws IllegalArgumentException One of the strings is invalid.
|
||||
*/
|
||||
public
|
||||
ISDNRecord(Name name, int dclass, long ttl, String address, String subAddress) {
|
||||
super(name, DnsRecordType.ISDN, dclass, ttl);
|
||||
try {
|
||||
this.address = byteArrayFromString(address);
|
||||
if (subAddress != null) {
|
||||
this.subAddress = byteArrayFromString(subAddress);
|
||||
}
|
||||
} catch (TextParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ISDN number associated with the domain.
|
||||
*/
|
||||
public
|
||||
String getAddress() {
|
||||
return byteArrayToString(address, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ISDN subaddress, or null if there is none.
|
||||
*/
|
||||
public
|
||||
String getSubAddress() {
|
||||
if (subAddress == null) {
|
||||
return null;
|
||||
}
|
||||
return byteArrayToString(subAddress, false);
|
||||
}
|
||||
|
||||
}
|
175
src/dorkbox/network/dns/records/KEYBase.java
Normal file
175
src/dorkbox/network/dns/records/KEYBase.java
Normal file
|
@ -0,0 +1,175 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.OS;
|
||||
|
||||
/**
|
||||
* The base class for KEY/DNSKEY records, which have identical formats
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
abstract
|
||||
class KEYBase extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 3469321722693285454L;
|
||||
|
||||
protected int flags, proto, alg;
|
||||
protected byte[] key;
|
||||
protected int footprint = -1;
|
||||
protected PublicKey publicKey = null;
|
||||
|
||||
protected
|
||||
KEYBase() {}
|
||||
|
||||
public
|
||||
KEYBase(Name name, int type, int dclass, long ttl, int flags, int proto, int alg, byte[] key) {
|
||||
super(name, type, dclass, ttl);
|
||||
this.flags = checkU16("flags", flags);
|
||||
this.proto = checkU8("proto", proto);
|
||||
this.alg = checkU8("alg", alg);
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
flags = in.readU16();
|
||||
proto = in.readU8();
|
||||
alg = in.readU8();
|
||||
if (in.remaining() > 0) {
|
||||
key = in.readByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(flags);
|
||||
out.writeU8(proto);
|
||||
out.writeU8(alg);
|
||||
if (key != null) {
|
||||
out.writeByteArray(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the DNSKEY/KEY Record to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(flags);
|
||||
sb.append(" ");
|
||||
sb.append(proto);
|
||||
sb.append(" ");
|
||||
sb.append(alg);
|
||||
|
||||
if (key != null) {
|
||||
if (Options.check("multiline")) {
|
||||
sb.append(" (")
|
||||
.append(OS.LINE_SEPARATOR);
|
||||
|
||||
sb.append(Base64Fast.formatString(Base64Fast.encode2(key), 64, "\t", true));
|
||||
sb.append(" ; key_tag = ");
|
||||
sb.append(getFootprint());
|
||||
}
|
||||
else {
|
||||
sb.append(" ");
|
||||
sb.append(Base64Fast.encode2(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's footprint (after computing it)
|
||||
*/
|
||||
public
|
||||
int getFootprint() {
|
||||
if (footprint >= 0) {
|
||||
return footprint;
|
||||
}
|
||||
|
||||
int foot = 0;
|
||||
|
||||
DnsOutput out = new DnsOutput();
|
||||
rrToWire(out, null, false);
|
||||
byte[] rdata = out.toByteArray();
|
||||
|
||||
if (alg == DNSSEC.Algorithm.RSAMD5) {
|
||||
int d1 = rdata[rdata.length - 3] & 0xFF;
|
||||
int d2 = rdata[rdata.length - 2] & 0xFF;
|
||||
foot = (d1 << 8) + d2;
|
||||
}
|
||||
else {
|
||||
int i;
|
||||
for (i = 0; i < rdata.length - 1; i += 2) {
|
||||
int d1 = rdata[i] & 0xFF;
|
||||
int d2 = rdata[i + 1] & 0xFF;
|
||||
foot += ((d1 << 8) + d2);
|
||||
}
|
||||
if (i < rdata.length) {
|
||||
int d1 = rdata[i] & 0xFF;
|
||||
foot += (d1 << 8);
|
||||
}
|
||||
foot += ((foot >> 16) & 0xFFFF);
|
||||
}
|
||||
footprint = (foot & 0xFFFF);
|
||||
return footprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags describing the key's properties
|
||||
*/
|
||||
public
|
||||
int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol that the key was created for
|
||||
*/
|
||||
public
|
||||
int getProtocol() {
|
||||
return proto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key's algorithm
|
||||
*/
|
||||
public
|
||||
int getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary data representing the key
|
||||
*/
|
||||
public
|
||||
byte[] getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a PublicKey corresponding to the data in this key.
|
||||
*
|
||||
* @throws DNSSEC.DNSSECException The key could not be converted.
|
||||
*/
|
||||
public
|
||||
PublicKey getPublicKey() throws DNSSEC.DNSSECException {
|
||||
if (publicKey != null) {
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
publicKey = DNSSEC.toPublicKey(this);
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
}
|
421
src/dorkbox/network/dns/records/KEYRecord.java
Normal file
421
src/dorkbox/network/dns/records/KEYRecord.java
Normal file
|
@ -0,0 +1,421 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.PublicKey;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import dorkbox.network.dns.Mnemonic;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Key - contains a cryptographic public key. The data can be converted
|
||||
* to objects implementing java.security.interfaces.PublicKey
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see DNSSEC
|
||||
*/
|
||||
|
||||
public
|
||||
class KEYRecord extends KEYBase {
|
||||
|
||||
private static final long serialVersionUID = 6385613447571488906L;
|
||||
/**
|
||||
* This key cannot be used for confidentiality (encryption)
|
||||
*/
|
||||
public static final int FLAG_NOCONF = Flags.NOCONF;
|
||||
/**
|
||||
* This key cannot be used for authentication
|
||||
*/
|
||||
public static final int FLAG_NOAUTH = Flags.NOAUTH;
|
||||
|
||||
/* flags */
|
||||
/**
|
||||
* This key cannot be used for authentication or confidentiality
|
||||
*/
|
||||
public static final int FLAG_NOKEY = Flags.NOKEY;
|
||||
/**
|
||||
* A zone key
|
||||
*/
|
||||
public static final int OWNER_ZONE = Flags.ZONE;
|
||||
/**
|
||||
* A host/end entity key
|
||||
*/
|
||||
public static final int OWNER_HOST = Flags.HOST;
|
||||
/**
|
||||
* A user key
|
||||
*/
|
||||
public static final int OWNER_USER = Flags.USER;
|
||||
/**
|
||||
* Key was created for use with transaction level security
|
||||
*/
|
||||
public static final int PROTOCOL_TLS = Protocol.TLS;
|
||||
/**
|
||||
* Key was created for use with email
|
||||
*/
|
||||
public static final int PROTOCOL_EMAIL = Protocol.EMAIL;
|
||||
|
||||
/* protocols */
|
||||
/**
|
||||
* Key was created for use with DNSSEC
|
||||
*/
|
||||
public static final int PROTOCOL_DNSSEC = Protocol.DNSSEC;
|
||||
/**
|
||||
* Key was created for use with IPSEC
|
||||
*/
|
||||
public static final int PROTOCOL_IPSEC = Protocol.IPSEC;
|
||||
/**
|
||||
* Key was created for use with any protocol
|
||||
*/
|
||||
public static final int PROTOCOL_ANY = Protocol.ANY;
|
||||
|
||||
|
||||
public static
|
||||
class Protocol {
|
||||
/**
|
||||
* No defined protocol.
|
||||
*/
|
||||
public static final int NONE = 0;
|
||||
/**
|
||||
* Transaction Level Security
|
||||
*/
|
||||
public static final int TLS = 1;
|
||||
/**
|
||||
* Email
|
||||
*/
|
||||
public static final int EMAIL = 2;
|
||||
/**
|
||||
* DNSSEC
|
||||
*/
|
||||
public static final int DNSSEC = 3;
|
||||
/**
|
||||
* IPSEC Control
|
||||
*/
|
||||
public static final int IPSEC = 4;
|
||||
/**
|
||||
* Any protocol
|
||||
*/
|
||||
public static final int ANY = 255;
|
||||
private static Mnemonic protocols = new Mnemonic("KEY protocol", Mnemonic.CASE_UPPER);
|
||||
|
||||
/**
|
||||
* KEY protocol identifiers.
|
||||
*/
|
||||
|
||||
private
|
||||
Protocol() {}
|
||||
|
||||
static {
|
||||
protocols.setMaximum(0xFF);
|
||||
protocols.setNumericAllowed(true);
|
||||
|
||||
protocols.add(NONE, "NONE");
|
||||
protocols.add(TLS, "TLS");
|
||||
protocols.add(EMAIL, "EMAIL");
|
||||
protocols.add(DNSSEC, "DNSSEC");
|
||||
protocols.add(IPSEC, "IPSEC");
|
||||
protocols.add(ANY, "ANY");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an KEY protocol value into its textual representation
|
||||
*/
|
||||
public static
|
||||
String string(int type) {
|
||||
return protocols.getText(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a textual representation of a KEY protocol into its
|
||||
* numeric code. Integers in the range 0..255 are also accepted.
|
||||
*
|
||||
* @param s The textual representation of the protocol
|
||||
*
|
||||
* @return The protocol code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
return protocols.getValue(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Flags {
|
||||
/**
|
||||
* KEY cannot be used for confidentiality
|
||||
*/
|
||||
public static final int NOCONF = 0x4000;
|
||||
/**
|
||||
* KEY cannot be used for authentication
|
||||
*/
|
||||
public static final int NOAUTH = 0x8000;
|
||||
/**
|
||||
* No key present
|
||||
*/
|
||||
public static final int NOKEY = 0xC000;
|
||||
/**
|
||||
* Bitmask of the use fields
|
||||
*/
|
||||
public static final int USE_MASK = 0xC000;
|
||||
/**
|
||||
* Flag 2 (unused)
|
||||
*/
|
||||
public static final int FLAG2 = 0x2000;
|
||||
/**
|
||||
* Flags extension
|
||||
*/
|
||||
public static final int EXTEND = 0x1000;
|
||||
/**
|
||||
* Flag 4 (unused)
|
||||
*/
|
||||
public static final int FLAG4 = 0x0800;
|
||||
/**
|
||||
* Flag 5 (unused)
|
||||
*/
|
||||
public static final int FLAG5 = 0x0400;
|
||||
/**
|
||||
* Key is owned by a user.
|
||||
*/
|
||||
public static final int USER = 0x0000;
|
||||
/**
|
||||
* Key is owned by a zone.
|
||||
*/
|
||||
public static final int ZONE = 0x0100;
|
||||
/**
|
||||
* Key is owned by a host.
|
||||
*/
|
||||
public static final int HOST = 0x0200;
|
||||
/**
|
||||
* Key owner type 3 (reserved).
|
||||
*/
|
||||
public static final int NTYP3 = 0x0300;
|
||||
/**
|
||||
* Key owner bitmask.
|
||||
*/
|
||||
public static final int OWNER_MASK = 0x0300;
|
||||
/**
|
||||
* Flag 8 (unused)
|
||||
*/
|
||||
public static final int FLAG8 = 0x0080;
|
||||
/**
|
||||
* Flag 9 (unused)
|
||||
*/
|
||||
public static final int FLAG9 = 0x0040;
|
||||
/**
|
||||
* Flag 10 (unused)
|
||||
*/
|
||||
public static final int FLAG10 = 0x0020;
|
||||
/**
|
||||
* Flag 11 (unused)
|
||||
*/
|
||||
public static final int FLAG11 = 0x0010;
|
||||
/**
|
||||
* Signatory value 0
|
||||
*/
|
||||
public static final int SIG0 = 0;
|
||||
/**
|
||||
* Signatory value 1
|
||||
*/
|
||||
public static final int SIG1 = 1;
|
||||
/**
|
||||
* Signatory value 2
|
||||
*/
|
||||
public static final int SIG2 = 2;
|
||||
/**
|
||||
* Signatory value 3
|
||||
*/
|
||||
public static final int SIG3 = 3;
|
||||
/**
|
||||
* Signatory value 4
|
||||
*/
|
||||
public static final int SIG4 = 4;
|
||||
/**
|
||||
* Signatory value 5
|
||||
*/
|
||||
public static final int SIG5 = 5;
|
||||
/**
|
||||
* Signatory value 6
|
||||
*/
|
||||
public static final int SIG6 = 6;
|
||||
/**
|
||||
* Signatory value 7
|
||||
*/
|
||||
public static final int SIG7 = 7;
|
||||
/**
|
||||
* Signatory value 8
|
||||
*/
|
||||
public static final int SIG8 = 8;
|
||||
/**
|
||||
* Signatory value 9
|
||||
*/
|
||||
public static final int SIG9 = 9;
|
||||
/**
|
||||
* Signatory value 10
|
||||
*/
|
||||
public static final int SIG10 = 10;
|
||||
/**
|
||||
* Signatory value 11
|
||||
*/
|
||||
public static final int SIG11 = 11;
|
||||
/**
|
||||
* Signatory value 12
|
||||
*/
|
||||
public static final int SIG12 = 12;
|
||||
/**
|
||||
* Signatory value 13
|
||||
*/
|
||||
public static final int SIG13 = 13;
|
||||
/**
|
||||
* Signatory value 14
|
||||
*/
|
||||
public static final int SIG14 = 14;
|
||||
/**
|
||||
* Signatory value 15
|
||||
*/
|
||||
public static final int SIG15 = 15;
|
||||
private static Mnemonic flags = new Mnemonic("KEY flags", Mnemonic.CASE_UPPER);
|
||||
|
||||
/**
|
||||
* KEY flags identifiers.
|
||||
*/
|
||||
|
||||
private
|
||||
Flags() {}
|
||||
|
||||
static {
|
||||
flags.setMaximum(0xFFFF);
|
||||
flags.setNumericAllowed(false);
|
||||
|
||||
flags.add(NOCONF, "NOCONF");
|
||||
flags.add(NOAUTH, "NOAUTH");
|
||||
flags.add(NOKEY, "NOKEY");
|
||||
flags.add(FLAG2, "FLAG2");
|
||||
flags.add(EXTEND, "EXTEND");
|
||||
flags.add(FLAG4, "FLAG4");
|
||||
flags.add(FLAG5, "FLAG5");
|
||||
flags.add(USER, "USER");
|
||||
flags.add(ZONE, "ZONE");
|
||||
flags.add(HOST, "HOST");
|
||||
flags.add(NTYP3, "NTYP3");
|
||||
flags.add(FLAG8, "FLAG8");
|
||||
flags.add(FLAG9, "FLAG9");
|
||||
flags.add(FLAG10, "FLAG10");
|
||||
flags.add(FLAG11, "FLAG11");
|
||||
flags.add(SIG0, "SIG0");
|
||||
flags.add(SIG1, "SIG1");
|
||||
flags.add(SIG2, "SIG2");
|
||||
flags.add(SIG3, "SIG3");
|
||||
flags.add(SIG4, "SIG4");
|
||||
flags.add(SIG5, "SIG5");
|
||||
flags.add(SIG6, "SIG6");
|
||||
flags.add(SIG7, "SIG7");
|
||||
flags.add(SIG8, "SIG8");
|
||||
flags.add(SIG9, "SIG9");
|
||||
flags.add(SIG10, "SIG10");
|
||||
flags.add(SIG11, "SIG11");
|
||||
flags.add(SIG12, "SIG12");
|
||||
flags.add(SIG13, "SIG13");
|
||||
flags.add(SIG14, "SIG14");
|
||||
flags.add(SIG15, "SIG15");
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a textual representation of KEY flags into its
|
||||
* numeric code. Integers in the range 0..65535 are also accepted.
|
||||
*
|
||||
* @param s The textual representation of the protocol
|
||||
*
|
||||
* @return The protocol code, or -1 on error.
|
||||
*/
|
||||
public static
|
||||
int value(String s) {
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt(s);
|
||||
if (value >= 0 && value <= 0xFFFF) {
|
||||
return value;
|
||||
}
|
||||
return -1;
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
StringTokenizer st = new StringTokenizer(s, "|");
|
||||
value = 0;
|
||||
while (st.hasMoreTokens()) {
|
||||
int val = flags.getValue(st.nextToken());
|
||||
if (val < 0) {
|
||||
return -1;
|
||||
}
|
||||
value |= val;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
KEYRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new KEYRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
String flagString = st.getIdentifier();
|
||||
flags = Flags.value(flagString);
|
||||
if (flags < 0) {
|
||||
throw st.exception("Invalid flags: " + flagString);
|
||||
}
|
||||
String protoString = st.getIdentifier();
|
||||
proto = Protocol.value(protoString);
|
||||
if (proto < 0) {
|
||||
throw st.exception("Invalid protocol: " + protoString);
|
||||
}
|
||||
String algString = st.getIdentifier();
|
||||
alg = DNSSEC.Algorithm.value(algString);
|
||||
if (alg < 0) {
|
||||
throw st.exception("Invalid algorithm: " + algString);
|
||||
}
|
||||
/* If this is a null KEY, there's no key data */
|
||||
if ((flags & Flags.USE_MASK) == Flags.NOKEY) {
|
||||
key = null;
|
||||
}
|
||||
else {
|
||||
key = st.getBase64();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEY Record from the given data
|
||||
*
|
||||
* @param flags Flags describing the key's properties
|
||||
* @param proto The protocol that the key was created for
|
||||
* @param alg The key's algorithm
|
||||
* @param key Binary data representing the key
|
||||
*/
|
||||
public
|
||||
KEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, byte[] key) {
|
||||
super(name, DnsRecordType.KEY, dclass, ttl, flags, proto, alg, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KEY Record from the given data
|
||||
*
|
||||
* @param flags Flags describing the key's properties
|
||||
* @param proto The protocol that the key was created for
|
||||
* @param alg The key's algorithm
|
||||
* @param key The key as a PublicKey
|
||||
*
|
||||
* @throws DNSSEC.DNSSECException The PublicKey could not be converted into DNS
|
||||
* format.
|
||||
*/
|
||||
public
|
||||
KEYRecord(Name name, int dclass, long ttl, int flags, int proto, int alg, PublicKey key) throws DNSSEC.DNSSECException {
|
||||
super(name, DnsRecordType.KEY, dclass, ttl, flags, proto, alg, DNSSEC.fromPublicKey(key, alg));
|
||||
publicKey = key;
|
||||
}
|
||||
|
||||
}
|
60
src/dorkbox/network/dns/records/KXRecord.java
Normal file
60
src/dorkbox/network/dns/records/KXRecord.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Key Exchange - delegation of authority
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class KXRecord extends U16NameBase {
|
||||
|
||||
private static final long serialVersionUID = 7448568832769757809L;
|
||||
|
||||
KXRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new KXRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return getNameField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KX Record from the given data
|
||||
*
|
||||
* @param preference The preference of this KX. Records with lower priority
|
||||
* are preferred.
|
||||
* @param target The host that authority is delegated to
|
||||
*/
|
||||
public
|
||||
KXRecord(Name name, int dclass, long ttl, int preference, Name target) {
|
||||
super(name, DnsRecordType.KX, dclass, ttl, preference, "preference", target, "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target of the KX record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getNameField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preference of this KX record
|
||||
*/
|
||||
public
|
||||
int getPreference() {
|
||||
return getU16Field();
|
||||
}
|
||||
|
||||
}
|
349
src/dorkbox/network/dns/records/LOCRecord.java
Normal file
349
src/dorkbox/network/dns/records/LOCRecord.java
Normal file
|
@ -0,0 +1,349 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.WireParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Location - describes the physical location of hosts, networks, subnets.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class LOCRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 9058224788126750409L;
|
||||
|
||||
private static NumberFormat w2, w3;
|
||||
|
||||
private long size, hPrecision, vPrecision;
|
||||
private long latitude, longitude, altitude;
|
||||
|
||||
static {
|
||||
w2 = new DecimalFormat();
|
||||
w2.setMinimumIntegerDigits(2);
|
||||
|
||||
w3 = new DecimalFormat();
|
||||
w3.setMinimumIntegerDigits(3);
|
||||
}
|
||||
|
||||
LOCRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new LOCRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
int version;
|
||||
|
||||
version = in.readU8();
|
||||
if (version != 0) {
|
||||
throw new WireParseException("Invalid LOC version");
|
||||
}
|
||||
|
||||
size = parseLOCformat(in.readU8());
|
||||
hPrecision = parseLOCformat(in.readU8());
|
||||
vPrecision = parseLOCformat(in.readU8());
|
||||
latitude = in.readU32();
|
||||
longitude = in.readU32();
|
||||
altitude = in.readU32();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(0); /* version */
|
||||
out.writeU8(toLOCformat(size));
|
||||
out.writeU8(toLOCformat(hPrecision));
|
||||
out.writeU8(toLOCformat(vPrecision));
|
||||
out.writeU32(latitude);
|
||||
out.writeU32(longitude);
|
||||
out.writeU32(altitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
/* Latitude */
|
||||
sb.append(positionToString(latitude, 'N', 'S'));
|
||||
sb.append(" ");
|
||||
|
||||
/* Latitude */
|
||||
sb.append(positionToString(longitude, 'E', 'W'));
|
||||
sb.append(" ");
|
||||
|
||||
/* Altitude */
|
||||
renderFixedPoint(sb, w2, altitude - 10000000, 100);
|
||||
sb.append("m ");
|
||||
|
||||
/* Size */
|
||||
renderFixedPoint(sb, w2, size, 100);
|
||||
sb.append("m ");
|
||||
|
||||
/* Horizontal precision */
|
||||
renderFixedPoint(sb, w2, hPrecision, 100);
|
||||
sb.append("m ");
|
||||
|
||||
/* Vertical precision */
|
||||
renderFixedPoint(sb, w2, vPrecision, 100);
|
||||
sb.append("m");
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
latitude = parsePosition(st, "latitude");
|
||||
longitude = parsePosition(st, "longitude");
|
||||
altitude = parseDouble(st, "altitude", true, -10000000, 4284967295L, 0) + 10000000;
|
||||
size = parseDouble(st, "size", false, 0, 9000000000L, 100);
|
||||
hPrecision = parseDouble(st, "horizontal precision", false, 0, 9000000000L, 1000000);
|
||||
vPrecision = parseDouble(st, "vertical precision", false, 0, 9000000000L, 1000);
|
||||
}
|
||||
|
||||
private
|
||||
long parsePosition(Tokenizer st, String type) throws IOException {
|
||||
boolean isLatitude = type.equals("latitude");
|
||||
int deg = 0, min = 0;
|
||||
double sec = 0;
|
||||
long value;
|
||||
String s;
|
||||
|
||||
deg = st.getUInt16();
|
||||
if (deg > 180 || (deg > 90 && isLatitude)) {
|
||||
throw st.exception("Invalid LOC " + type + " degrees");
|
||||
}
|
||||
|
||||
s = st.getString();
|
||||
try {
|
||||
min = Integer.parseInt(s);
|
||||
if (min < 0 || min > 59) {
|
||||
throw st.exception("Invalid LOC " + type + " minutes");
|
||||
}
|
||||
s = st.getString();
|
||||
sec = parseFixedPoint(s);
|
||||
if (sec < 0 || sec >= 60) {
|
||||
throw st.exception("Invalid LOC " + type + " seconds");
|
||||
}
|
||||
s = st.getString();
|
||||
} catch (NumberFormatException e) {
|
||||
}
|
||||
|
||||
if (s.length() != 1) {
|
||||
throw st.exception("Invalid LOC " + type);
|
||||
}
|
||||
|
||||
value = (long) (1000 * (sec + 60L * (min + 60L * deg)));
|
||||
|
||||
char c = Character.toUpperCase(s.charAt(0));
|
||||
if ((isLatitude && c == 'S') || (!isLatitude && c == 'W')) {
|
||||
value = -value;
|
||||
}
|
||||
else if ((isLatitude && c != 'N') || (!isLatitude && c != 'E')) {
|
||||
throw st.exception("Invalid LOC " + type);
|
||||
}
|
||||
|
||||
value += (1L << 31);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private
|
||||
double parseFixedPoint(String s) {
|
||||
if (s.matches("^-?\\d+$")) {
|
||||
return Integer.parseInt(s);
|
||||
}
|
||||
else if (s.matches("^-?\\d+\\.\\d*$")) {
|
||||
String[] parts = s.split("\\.");
|
||||
double value = Integer.parseInt(parts[0]);
|
||||
double fraction = Integer.parseInt(parts[1]);
|
||||
if (value < 0) {
|
||||
fraction *= -1;
|
||||
}
|
||||
int digits = parts[1].length();
|
||||
return value + (fraction / Math.pow(10, digits));
|
||||
}
|
||||
else {
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
long parseDouble(Tokenizer st, String type, boolean required, long min, long max, long defaultValue) throws IOException {
|
||||
Tokenizer.Token token = st.get();
|
||||
if (token.isEOL()) {
|
||||
if (required) {
|
||||
throw st.exception("Invalid LOC " + type);
|
||||
}
|
||||
st.unget();
|
||||
return defaultValue;
|
||||
}
|
||||
String s = token.value;
|
||||
if (s.length() > 1 && s.charAt(s.length() - 1) == 'm') {
|
||||
s = s.substring(0, s.length() - 1);
|
||||
}
|
||||
try {
|
||||
long value = (long) (100 * parseFixedPoint(s));
|
||||
if (value < min || value > max) {
|
||||
throw st.exception("Invalid LOC " + type);
|
||||
}
|
||||
return value;
|
||||
} catch (NumberFormatException e) {
|
||||
throw st.exception("Invalid LOC " + type);
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
String positionToString(long value, char pos, char neg) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char direction;
|
||||
|
||||
long temp = value - (1L << 31);
|
||||
if (temp < 0) {
|
||||
temp = -temp;
|
||||
direction = neg;
|
||||
}
|
||||
else {
|
||||
direction = pos;
|
||||
}
|
||||
|
||||
sb.append(temp / (3600 * 1000)); /* degrees */
|
||||
temp = temp % (3600 * 1000);
|
||||
sb.append(" ");
|
||||
|
||||
sb.append(temp / (60 * 1000)); /* minutes */
|
||||
temp = temp % (60 * 1000);
|
||||
sb.append(" ");
|
||||
|
||||
renderFixedPoint(sb, w3, temp, 1000); /* seconds */
|
||||
sb.append(" ");
|
||||
|
||||
sb.append(direction);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private
|
||||
void renderFixedPoint(StringBuilder sb, NumberFormat formatter, long value, long divisor) {
|
||||
sb.append(value / divisor);
|
||||
value %= divisor;
|
||||
|
||||
if (value != 0) {
|
||||
sb.append(".");
|
||||
sb.append(formatter.format(value));
|
||||
}
|
||||
}
|
||||
|
||||
private
|
||||
int toLOCformat(long l) {
|
||||
byte exp = 0;
|
||||
while (l > 9) {
|
||||
exp++;
|
||||
l /= 10;
|
||||
}
|
||||
return (int) ((l << 4) + exp);
|
||||
}
|
||||
|
||||
private static
|
||||
long parseLOCformat(int b) throws WireParseException {
|
||||
long out = b >> 4;
|
||||
int exp = b & 0xF;
|
||||
if (out > 9 || exp > 9) {
|
||||
throw new WireParseException("Invalid LOC Encoding");
|
||||
}
|
||||
while (exp-- > 0) {
|
||||
out *= 10;
|
||||
}
|
||||
return (out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an LOC Record from the given data
|
||||
*
|
||||
* @param latitude The latitude of the center of the sphere
|
||||
* @param longitude The longitude of the center of the sphere
|
||||
* @param altitude The altitude of the center of the sphere, in m
|
||||
* @param size The diameter of a sphere enclosing the described entity, in m.
|
||||
* @param hPrecision The horizontal precision of the data, in m.
|
||||
* @param vPrecision The vertical precision of the data, in m.
|
||||
*/
|
||||
public
|
||||
LOCRecord(Name name,
|
||||
int dclass,
|
||||
long ttl,
|
||||
double latitude,
|
||||
double longitude,
|
||||
double altitude,
|
||||
double size,
|
||||
double hPrecision,
|
||||
double vPrecision) {
|
||||
super(name, DnsRecordType.LOC, dclass, ttl);
|
||||
this.latitude = (long) (latitude * 3600 * 1000 + (1L << 31));
|
||||
this.longitude = (long) (longitude * 3600 * 1000 + (1L << 31));
|
||||
this.altitude = (long) ((altitude + 100000) * 100);
|
||||
this.size = (long) (size * 100);
|
||||
this.hPrecision = (long) (hPrecision * 100);
|
||||
this.vPrecision = (long) (vPrecision * 100);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latitude
|
||||
*/
|
||||
public
|
||||
double getLatitude() {
|
||||
return ((double) (latitude - (1L << 31))) / (3600 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the longitude
|
||||
*/
|
||||
public
|
||||
double getLongitude() {
|
||||
return ((double) (longitude - (1L << 31))) / (3600 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the altitude
|
||||
*/
|
||||
public
|
||||
double getAltitude() {
|
||||
return ((double) (altitude - 10000000)) / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the diameter of the enclosing sphere
|
||||
*/
|
||||
public
|
||||
double getSize() {
|
||||
return ((double) size) / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal precision
|
||||
*/
|
||||
public
|
||||
double getHPrecision() {
|
||||
return ((double) hPrecision) / 100;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the horizontal precision
|
||||
*/
|
||||
public
|
||||
double getVPrecision() {
|
||||
return ((double) vPrecision) / 100;
|
||||
}
|
||||
|
||||
}
|
50
src/dorkbox/network/dns/records/MBRecord.java
Normal file
50
src/dorkbox/network/dns/records/MBRecord.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Mailbox Record - specifies a host containing a mailbox.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MBRecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = 532349543479150419L;
|
||||
|
||||
MBRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MBRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MB Record with the given data
|
||||
*
|
||||
* @param mailbox The host containing the mailbox for the domain.
|
||||
*/
|
||||
public
|
||||
MBRecord(Name name, int dclass, long ttl, Name mailbox) {
|
||||
super(name, DnsRecordType.MB, dclass, ttl, mailbox, "mailbox");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mailbox for the domain
|
||||
*/
|
||||
public
|
||||
Name getMailbox() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
51
src/dorkbox/network/dns/records/MDRecord.java
Normal file
51
src/dorkbox/network/dns/records/MDRecord.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Mail Destination Record - specifies a mail agent which delivers mail
|
||||
* for a domain (obsolete)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MDRecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = 5268878603762942202L;
|
||||
|
||||
MDRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MDRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MD Record with the given data
|
||||
*
|
||||
* @param mailAgent The mail agent that delivers mail for the domain.
|
||||
*/
|
||||
public
|
||||
MDRecord(Name name, int dclass, long ttl, Name mailAgent) {
|
||||
super(name, DnsRecordType.MD, dclass, ttl, mailAgent, "mail agent");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mail agent for the domain
|
||||
*/
|
||||
public
|
||||
Name getMailAgent() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
51
src/dorkbox/network/dns/records/MFRecord.java
Normal file
51
src/dorkbox/network/dns/records/MFRecord.java
Normal file
|
@ -0,0 +1,51 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Mail Forwarder Record - specifies a mail agent which forwards mail
|
||||
* for a domain (obsolete)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MFRecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = -6670449036843028169L;
|
||||
|
||||
MFRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MFRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MF Record with the given data
|
||||
*
|
||||
* @param mailAgent The mail agent that forwards mail for the domain.
|
||||
*/
|
||||
public
|
||||
MFRecord(Name name, int dclass, long ttl, Name mailAgent) {
|
||||
super(name, DnsRecordType.MF, dclass, ttl, mailAgent, "mail agent");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mail agent for the domain
|
||||
*/
|
||||
public
|
||||
Name getMailAgent() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
45
src/dorkbox/network/dns/records/MGRecord.java
Normal file
45
src/dorkbox/network/dns/records/MGRecord.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Mail Group Record - specifies a mailbox which is a member of a mail group.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MGRecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = -3980055550863644582L;
|
||||
|
||||
MGRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MGRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MG Record with the given data
|
||||
*
|
||||
* @param mailbox The mailbox that is a member of the group specified by the
|
||||
* domain.
|
||||
*/
|
||||
public
|
||||
MGRecord(Name name, int dclass, long ttl, Name mailbox) {
|
||||
super(name, DnsRecordType.MG, dclass, ttl, mailbox, "mailbox");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mailbox in the mail group specified by the domain
|
||||
*/
|
||||
public
|
||||
Name getMailbox() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
98
src/dorkbox/network/dns/records/MINFORecord.java
Normal file
98
src/dorkbox/network/dns/records/MINFORecord.java
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Mailbox information Record - lists the address responsible for a mailing
|
||||
* list/mailbox and the address to receive error messages relating to the
|
||||
* mailing list/mailbox.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MINFORecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -3962147172340353796L;
|
||||
|
||||
private Name responsibleAddress;
|
||||
private Name errorAddress;
|
||||
|
||||
MINFORecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MINFORecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
responsibleAddress = new Name(in);
|
||||
errorAddress = new Name(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
responsibleAddress.toWire(out, null, canonical);
|
||||
errorAddress.toWire(out, null, canonical);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the MINFO Record to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(responsibleAddress);
|
||||
sb.append(" ");
|
||||
sb.append(errorAddress);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
responsibleAddress = st.getName(origin);
|
||||
errorAddress = st.getName(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an MINFO Record from the given data
|
||||
*
|
||||
* @param responsibleAddress The address responsible for the
|
||||
* mailing list/mailbox.
|
||||
* @param errorAddress The address to receive error messages relating to the
|
||||
* mailing list/mailbox.
|
||||
*/
|
||||
public
|
||||
MINFORecord(Name name, int dclass, long ttl, Name responsibleAddress, Name errorAddress) {
|
||||
super(name, DnsRecordType.MINFO, dclass, ttl);
|
||||
|
||||
this.responsibleAddress = checkName("responsibleAddress", responsibleAddress);
|
||||
this.errorAddress = checkName("errorAddress", errorAddress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address responsible for the mailing list/mailbox.
|
||||
*/
|
||||
public
|
||||
Name getResponsibleAddress() {
|
||||
return responsibleAddress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the address to receive error messages relating to the mailing
|
||||
* list/mailbox.
|
||||
*/
|
||||
public
|
||||
Name getErrorAddress() {
|
||||
return errorAddress;
|
||||
}
|
||||
|
||||
}
|
45
src/dorkbox/network/dns/records/MRRecord.java
Normal file
45
src/dorkbox/network/dns/records/MRRecord.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Mailbox Rename Record - specifies a rename of a mailbox.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MRRecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = -5617939094209927533L;
|
||||
|
||||
MRRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MRRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new MR Record with the given data
|
||||
*
|
||||
* @param newName The new name of the mailbox specified by the domain.
|
||||
* domain.
|
||||
*/
|
||||
public
|
||||
MRRecord(Name name, int dclass, long ttl, Name newName) {
|
||||
super(name, DnsRecordType.MR, dclass, ttl, newName, "new name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the new name of the mailbox specified by the domain
|
||||
*/
|
||||
public
|
||||
Name getNewName() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
68
src/dorkbox/network/dns/records/MXRecord.java
Normal file
68
src/dorkbox/network/dns/records/MXRecord.java
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Mail Exchange - specifies where mail to a domain is sent
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class MXRecord extends U16NameBase {
|
||||
|
||||
private static final long serialVersionUID = 2914841027584208546L;
|
||||
|
||||
MXRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new MXRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return getNameField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an MX Record from the given data
|
||||
*
|
||||
* @param priority The priority of this MX. Records with lower priority
|
||||
* are preferred.
|
||||
* @param target The host that mail is sent to
|
||||
*/
|
||||
public
|
||||
MXRecord(Name name, int dclass, long ttl, int priority, Name target) {
|
||||
super(name, DnsRecordType.MX, dclass, ttl, priority, "priority", target, "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the target of the MX record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getNameField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority of this MX record
|
||||
*/
|
||||
public
|
||||
int getPriority() {
|
||||
return getU16Field();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(u16Field);
|
||||
nameField.toWire(out, c, canonical);
|
||||
}
|
||||
|
||||
}
|
174
src/dorkbox/network/dns/records/NAPTRRecord.java
Normal file
174
src/dorkbox/network/dns/records/NAPTRRecord.java
Normal file
|
@ -0,0 +1,174 @@
|
|||
// Copyright (c) 2000-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.exceptions.TextParseException;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Name Authority Pointer Record - specifies rewrite rule, that when applied
|
||||
* to an existing string will produce a new domain.
|
||||
*
|
||||
* @author Chuck Santos
|
||||
*/
|
||||
|
||||
public
|
||||
class NAPTRRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 5191232392044947002L;
|
||||
|
||||
private int order, preference;
|
||||
private byte[] flags, service, regexp;
|
||||
private Name replacement;
|
||||
|
||||
NAPTRRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NAPTRRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
order = in.readU16();
|
||||
preference = in.readU16();
|
||||
flags = in.readCountedString();
|
||||
service = in.readCountedString();
|
||||
regexp = in.readCountedString();
|
||||
replacement = new Name(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(order);
|
||||
out.writeU16(preference);
|
||||
out.writeCountedString(flags);
|
||||
out.writeCountedString(service);
|
||||
out.writeCountedString(regexp);
|
||||
replacement.toWire(out, null, canonical);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(order);
|
||||
sb.append(" ");
|
||||
sb.append(preference);
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(flags, true));
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(service, true));
|
||||
sb.append(" ");
|
||||
sb.append(byteArrayToString(regexp, true));
|
||||
sb.append(" ");
|
||||
sb.append(replacement);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
order = st.getUInt16();
|
||||
preference = st.getUInt16();
|
||||
try {
|
||||
flags = byteArrayFromString(st.getString());
|
||||
service = byteArrayFromString(st.getString());
|
||||
regexp = byteArrayFromString(st.getString());
|
||||
} catch (TextParseException e) {
|
||||
throw st.exception(e.getMessage());
|
||||
}
|
||||
replacement = st.getName(origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NAPTR Record from the given data
|
||||
*
|
||||
* @param order The order of this NAPTR. Records with lower order are
|
||||
* preferred.
|
||||
* @param preference The preference, used to select between records at the
|
||||
* same order.
|
||||
* @param flags The control aspects of the NAPTRRecord.
|
||||
* @param service The service or protocol available down the rewrite path.
|
||||
* @param regexp The regular/substitution expression.
|
||||
* @param replacement The domain-name to query for the next DNS resource
|
||||
* record, depending on the value of the flags field.
|
||||
*
|
||||
* @throws IllegalArgumentException One of the strings has invalid escapes
|
||||
*/
|
||||
public
|
||||
NAPTRRecord(Name name, int dclass, long ttl, int order, int preference, String flags, String service, String regexp, Name replacement) {
|
||||
super(name, DnsRecordType.NAPTR, dclass, ttl);
|
||||
this.order = checkU16("order", order);
|
||||
this.preference = checkU16("preference", preference);
|
||||
try {
|
||||
this.flags = byteArrayFromString(flags);
|
||||
this.service = byteArrayFromString(service);
|
||||
this.regexp = byteArrayFromString(regexp);
|
||||
} catch (TextParseException e) {
|
||||
throw new IllegalArgumentException(e.getMessage());
|
||||
}
|
||||
this.replacement = checkName("replacement", replacement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the order
|
||||
*/
|
||||
public
|
||||
int getOrder() {
|
||||
return order;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the preference
|
||||
*/
|
||||
public
|
||||
int getPreference() {
|
||||
return preference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns flags
|
||||
*/
|
||||
public
|
||||
String getFlags() {
|
||||
return byteArrayToString(flags, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns service
|
||||
*/
|
||||
public
|
||||
String getService() {
|
||||
return byteArrayToString(service, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns regexp
|
||||
*/
|
||||
public
|
||||
String getRegexp() {
|
||||
return byteArrayToString(regexp, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the replacement domain-name
|
||||
*/
|
||||
public
|
||||
Name getReplacement() {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
}
|
120
src/dorkbox/network/dns/records/NSAPRecord.java
Normal file
120
src/dorkbox/network/dns/records/NSAPRecord.java
Normal file
|
@ -0,0 +1,120 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* NSAP Address Record.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class NSAPRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -1037209403185658593L;
|
||||
|
||||
private byte[] address;
|
||||
|
||||
NSAPRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NSAPRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
address = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeByteArray(address);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append("0x")
|
||||
.append(base16.toString(address));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
String addr = st.getString();
|
||||
this.address = checkAndConvertAddress(addr);
|
||||
if (this.address == null) {
|
||||
throw st.exception("invalid NSAP address " + addr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NSAP Record from the given data
|
||||
*
|
||||
* @param address The NSAP address.
|
||||
*
|
||||
* @throws IllegalArgumentException The address is not a valid NSAP address.
|
||||
*/
|
||||
public
|
||||
NSAPRecord(Name name, int dclass, long ttl, String address) {
|
||||
super(name, DnsRecordType.NSAP, dclass, ttl);
|
||||
this.address = checkAndConvertAddress(address);
|
||||
if (this.address == null) {
|
||||
throw new IllegalArgumentException("invalid NSAP address " + address);
|
||||
}
|
||||
}
|
||||
|
||||
private static
|
||||
byte[] checkAndConvertAddress(String address) {
|
||||
if (!address.substring(0, 2)
|
||||
.equalsIgnoreCase("0x")) {
|
||||
return null;
|
||||
}
|
||||
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
|
||||
boolean partial = false;
|
||||
int current = 0;
|
||||
for (int i = 2; i < address.length(); i++) {
|
||||
char c = address.charAt(i);
|
||||
if (c == '.') {
|
||||
continue;
|
||||
}
|
||||
int value = Character.digit(c, 16);
|
||||
if (value == -1) {
|
||||
return null;
|
||||
}
|
||||
if (partial) {
|
||||
current += value;
|
||||
bytes.write(current);
|
||||
partial = false;
|
||||
}
|
||||
else {
|
||||
current = value << 4;
|
||||
partial = true;
|
||||
}
|
||||
|
||||
}
|
||||
if (partial) {
|
||||
return null;
|
||||
}
|
||||
return bytes.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the NSAP address.
|
||||
*/
|
||||
public
|
||||
String getAddress() {
|
||||
return byteArrayToString(address, false);
|
||||
}
|
||||
|
||||
}
|
45
src/dorkbox/network/dns/records/NSAP_PTRRecord.java
Normal file
45
src/dorkbox/network/dns/records/NSAP_PTRRecord.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* NSAP Pointer Record - maps a domain name representing an NSAP Address to
|
||||
* a hostname.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class NSAP_PTRRecord extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = 2386284746382064904L;
|
||||
|
||||
NSAP_PTRRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NSAP_PTRRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NSAP_PTR Record with the given data
|
||||
*
|
||||
* @param target The name of the host with this address
|
||||
*/
|
||||
public
|
||||
NSAP_PTRRecord(Name name, int dclass, long ttl, Name target) {
|
||||
super(name, DnsRecordType.NSAP_PTR, dclass, ttl, target, "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the NSAP_PTR Record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
188
src/dorkbox/network/dns/records/NSEC3PARAMRecord.java
Normal file
188
src/dorkbox/network/dns/records/NSEC3PARAMRecord.java
Normal file
|
@ -0,0 +1,188 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* Next SECure name 3 Parameters - this record contains the parameters (hash
|
||||
* algorithm, salt, iterations) used for a valid, complete NSEC3 chain present
|
||||
* in a zone. Zones signed using NSEC3 must include this record at the zone apex
|
||||
* to inform authoritative servers that NSEC3 is being used with the given
|
||||
* parameters.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @author David Blacka
|
||||
*/
|
||||
|
||||
public
|
||||
class NSEC3PARAMRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -8689038598776316533L;
|
||||
|
||||
private int hashAlg;
|
||||
private int flags;
|
||||
private int iterations;
|
||||
private byte salt[];
|
||||
|
||||
NSEC3PARAMRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NSEC3PARAMRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
hashAlg = in.readU8();
|
||||
flags = in.readU8();
|
||||
iterations = in.readU16();
|
||||
|
||||
int salt_length = in.readU8();
|
||||
if (salt_length > 0) {
|
||||
salt = in.readByteArray(salt_length);
|
||||
}
|
||||
else {
|
||||
salt = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(hashAlg);
|
||||
out.writeU8(flags);
|
||||
out.writeU16(iterations);
|
||||
|
||||
if (salt != null) {
|
||||
out.writeU8(salt.length);
|
||||
out.writeByteArray(salt);
|
||||
}
|
||||
else {
|
||||
out.writeU8(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(hashAlg);
|
||||
sb.append(' ');
|
||||
sb.append(flags);
|
||||
sb.append(' ');
|
||||
sb.append(iterations);
|
||||
sb.append(' ');
|
||||
|
||||
if (salt == null) {
|
||||
sb.append('-');
|
||||
}
|
||||
else {
|
||||
sb.append(base16.toString(salt));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
hashAlg = st.getUInt8();
|
||||
flags = st.getUInt8();
|
||||
iterations = st.getUInt16();
|
||||
|
||||
String s = st.getString();
|
||||
if (s.equals("-")) {
|
||||
salt = null;
|
||||
}
|
||||
else {
|
||||
st.unget();
|
||||
salt = st.getHexString();
|
||||
if (salt.length > 255) {
|
||||
throw st.exception("salt value too long");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NSEC3PARAM record from the given data.
|
||||
*
|
||||
* @param name The ownername of the NSEC3PARAM record (generally the zone name).
|
||||
* @param dclass The class.
|
||||
* @param ttl The TTL.
|
||||
* @param hashAlg The hash algorithm.
|
||||
* @param flags The value of the flags field.
|
||||
* @param iterations The number of hash iterations.
|
||||
* @param salt The salt to use (may be null).
|
||||
*/
|
||||
public
|
||||
NSEC3PARAMRecord(Name name, int dclass, long ttl, int hashAlg, int flags, int iterations, byte[] salt) {
|
||||
super(name, DnsRecordType.NSEC3PARAM, dclass, ttl);
|
||||
this.hashAlg = checkU8("hashAlg", hashAlg);
|
||||
this.flags = checkU8("flags", flags);
|
||||
this.iterations = checkU16("iterations", iterations);
|
||||
|
||||
if (salt != null) {
|
||||
if (salt.length > 255) {
|
||||
throw new IllegalArgumentException("Invalid salt " + "length");
|
||||
}
|
||||
if (salt.length > 0) {
|
||||
this.salt = new byte[salt.length];
|
||||
System.arraycopy(salt, 0, this.salt, 0, salt.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash algorithm
|
||||
*/
|
||||
public
|
||||
int getHashAlgorithm() {
|
||||
return hashAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags
|
||||
*/
|
||||
public
|
||||
int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of iterations
|
||||
*/
|
||||
public
|
||||
int getIterations() {
|
||||
return iterations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the salt
|
||||
*/
|
||||
public
|
||||
byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a name with the parameters of this NSEC3PARAM record.
|
||||
*
|
||||
* @param name The name to hash
|
||||
*
|
||||
* @return The hashed version of the name
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The hash algorithm is unknown.
|
||||
*/
|
||||
public
|
||||
byte[] hashName(Name name) throws NoSuchAlgorithmException {
|
||||
return NSEC3Record.hashName(name, hashAlg, iterations, salt);
|
||||
}
|
||||
|
||||
}
|
301
src/dorkbox/network/dns/records/NSEC3Record.java
Normal file
301
src/dorkbox/network/dns/records/NSEC3Record.java
Normal file
|
@ -0,0 +1,301 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
import dorkbox.network.dns.utils.base32;
|
||||
|
||||
/**
|
||||
* Next SECure name 3 - this record contains the next hashed name in an
|
||||
* ordered list of hashed names in the zone, and a set of types for which
|
||||
* records exist for this name. The presence of this record in a response
|
||||
* signifies a negative response from a DNSSEC-signed zone.
|
||||
* <p>
|
||||
* This replaces the NSEC and NXT records, when used.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @author David Blacka
|
||||
*/
|
||||
|
||||
public
|
||||
class NSEC3Record extends DnsRecord {
|
||||
|
||||
public static final int SHA1_DIGEST_ID = Digest.SHA1;
|
||||
private static final long serialVersionUID = -7123504635968932855L;
|
||||
private int hashAlg;
|
||||
private int flags;
|
||||
private int iterations;
|
||||
private byte[] salt;
|
||||
private byte[] next;
|
||||
private TypeBitmap types;
|
||||
private static final base32 b32 = new base32(base32.Alphabet.BASE32HEX, false, false);
|
||||
|
||||
|
||||
public static
|
||||
class Flags {
|
||||
/**
|
||||
* Unsigned delegation are not included in the NSEC3 chain.
|
||||
*/
|
||||
public static final int OPT_OUT = 0x01;
|
||||
|
||||
/**
|
||||
* NSEC3 flags identifiers.
|
||||
*/
|
||||
|
||||
private
|
||||
Flags() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Digest {
|
||||
/**
|
||||
* SHA-1
|
||||
*/
|
||||
public static final int SHA1 = 1;
|
||||
|
||||
private
|
||||
Digest() {}
|
||||
}
|
||||
|
||||
NSEC3Record() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NSEC3Record();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
hashAlg = in.readU8();
|
||||
flags = in.readU8();
|
||||
iterations = in.readU16();
|
||||
|
||||
int salt_length = in.readU8();
|
||||
if (salt_length > 0) {
|
||||
salt = in.readByteArray(salt_length);
|
||||
}
|
||||
else {
|
||||
salt = null;
|
||||
}
|
||||
|
||||
int next_length = in.readU8();
|
||||
next = in.readByteArray(next_length);
|
||||
types = new TypeBitmap(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(hashAlg);
|
||||
out.writeU8(flags);
|
||||
out.writeU16(iterations);
|
||||
|
||||
if (salt != null) {
|
||||
out.writeU8(salt.length);
|
||||
out.writeByteArray(salt);
|
||||
}
|
||||
else {
|
||||
out.writeU8(0);
|
||||
}
|
||||
|
||||
out.writeU8(next.length);
|
||||
out.writeByteArray(next);
|
||||
types.toWire(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(hashAlg);
|
||||
sb.append(' ');
|
||||
sb.append(flags);
|
||||
sb.append(' ');
|
||||
sb.append(iterations);
|
||||
sb.append(' ');
|
||||
|
||||
if (salt == null) {
|
||||
sb.append('-');
|
||||
}
|
||||
else {
|
||||
sb.append(base16.toString(salt));
|
||||
}
|
||||
|
||||
sb.append(' ');
|
||||
sb.append(b32.toString(next));
|
||||
|
||||
if (!types.empty()) {
|
||||
sb.append(' ');
|
||||
sb.append(types.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
hashAlg = st.getUInt8();
|
||||
flags = st.getUInt8();
|
||||
iterations = st.getUInt16();
|
||||
|
||||
String s = st.getString();
|
||||
if (s.equals("-")) {
|
||||
salt = null;
|
||||
}
|
||||
else {
|
||||
st.unget();
|
||||
salt = st.getHexString();
|
||||
if (salt.length > 255) {
|
||||
throw st.exception("salt value too long");
|
||||
}
|
||||
}
|
||||
|
||||
next = st.getBase32String(b32);
|
||||
types = new TypeBitmap(st);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NSEC3 record from the given data.
|
||||
*
|
||||
* @param name The ownername of the NSEC3 record (base32'd hash plus zonename).
|
||||
* @param dclass The class.
|
||||
* @param ttl The TTL.
|
||||
* @param hashAlg The hash algorithm.
|
||||
* @param flags The value of the flags field.
|
||||
* @param iterations The number of hash iterations.
|
||||
* @param salt The salt to use (may be null).
|
||||
* @param next The next hash (may not be null).
|
||||
* @param types The types present at the original ownername.
|
||||
*/
|
||||
public
|
||||
NSEC3Record(Name name, int dclass, long ttl, int hashAlg, int flags, int iterations, byte[] salt, byte[] next, int[] types) {
|
||||
super(name, DnsRecordType.NSEC3, dclass, ttl);
|
||||
this.hashAlg = checkU8("hashAlg", hashAlg);
|
||||
this.flags = checkU8("flags", flags);
|
||||
this.iterations = checkU16("iterations", iterations);
|
||||
|
||||
if (salt != null) {
|
||||
if (salt.length > 255) {
|
||||
throw new IllegalArgumentException("Invalid salt");
|
||||
}
|
||||
if (salt.length > 0) {
|
||||
this.salt = new byte[salt.length];
|
||||
System.arraycopy(salt, 0, this.salt, 0, salt.length);
|
||||
}
|
||||
}
|
||||
|
||||
if (next.length > 255) {
|
||||
throw new IllegalArgumentException("Invalid next hash");
|
||||
}
|
||||
this.next = new byte[next.length];
|
||||
System.arraycopy(next, 0, this.next, 0, next.length);
|
||||
this.types = new TypeBitmap(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the hash algorithm
|
||||
*/
|
||||
public
|
||||
int getHashAlgorithm() {
|
||||
return hashAlg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the flags
|
||||
*/
|
||||
public
|
||||
int getFlags() {
|
||||
return flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of iterations
|
||||
*/
|
||||
public
|
||||
int getIterations() {
|
||||
return iterations;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the salt
|
||||
*/
|
||||
public
|
||||
byte[] getSalt() {
|
||||
return salt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next hash
|
||||
*/
|
||||
public
|
||||
byte[] getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of types defined for this name
|
||||
*/
|
||||
public
|
||||
int[] getTypes() {
|
||||
return types.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a specific type is in the set of types.
|
||||
*/
|
||||
public
|
||||
boolean hasType(int type) {
|
||||
return types.contains(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Hashes a name with the parameters of this NSEC3 record.
|
||||
*
|
||||
* @param name The name to hash
|
||||
*
|
||||
* @return The hashed version of the name
|
||||
*
|
||||
* @throws NoSuchAlgorithmException The hash algorithm is unknown.
|
||||
*/
|
||||
public
|
||||
byte[] hashName(Name name) throws NoSuchAlgorithmException {
|
||||
return hashName(name, hashAlg, iterations, salt);
|
||||
}
|
||||
|
||||
static
|
||||
byte[] hashName(Name name, int hashAlg, int iterations, byte[] salt) throws NoSuchAlgorithmException {
|
||||
MessageDigest digest;
|
||||
switch (hashAlg) {
|
||||
case Digest.SHA1:
|
||||
digest = MessageDigest.getInstance("sha-1");
|
||||
break;
|
||||
default:
|
||||
throw new NoSuchAlgorithmException("Unknown NSEC3 algorithm" + "identifier: " + hashAlg);
|
||||
}
|
||||
byte[] hash = null;
|
||||
for (int i = 0; i <= iterations; i++) {
|
||||
digest.reset();
|
||||
if (i == 0) {
|
||||
digest.update(name.toWireCanonical());
|
||||
}
|
||||
else {
|
||||
digest.update(hash);
|
||||
}
|
||||
if (salt != null) {
|
||||
digest.update(salt);
|
||||
}
|
||||
hash = digest.digest();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
}
|
113
src/dorkbox/network/dns/records/NSECRecord.java
Normal file
113
src/dorkbox/network/dns/records/NSECRecord.java
Normal file
|
@ -0,0 +1,113 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Next SECure name - this record contains the following name in an
|
||||
* ordered list of names in the zone, and a set of types for which
|
||||
* records exist for this name. The presence of this record in a response
|
||||
* signifies a negative response from a DNSSEC-signed zone.
|
||||
* <p>
|
||||
* This replaces the NXT record.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @author David Blacka
|
||||
*/
|
||||
|
||||
public
|
||||
class NSECRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -5165065768816265385L;
|
||||
|
||||
private Name next;
|
||||
private TypeBitmap types;
|
||||
|
||||
NSECRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NSECRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
next = new Name(in);
|
||||
types = new TypeBitmap(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
// Note: The next name is not lowercased.
|
||||
next.toWire(out, null, false);
|
||||
types.toWire(out);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(next);
|
||||
|
||||
if (!types.empty()) {
|
||||
sb.append(' ');
|
||||
sb.append(types.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
next = st.getName(origin);
|
||||
types = new TypeBitmap(st);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NSEC Record from the given data.
|
||||
*
|
||||
* @param next The following name in an ordered list of the zone
|
||||
* @param types An array containing the types present.
|
||||
*/
|
||||
public
|
||||
NSECRecord(Name name, int dclass, long ttl, Name next, int[] types) {
|
||||
super(name, DnsRecordType.NSEC, dclass, ttl);
|
||||
this.next = checkName("next", next);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
DnsRecordType.check(types[i]);
|
||||
}
|
||||
this.types = new TypeBitmap(types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next name
|
||||
*/
|
||||
public
|
||||
Name getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of types defined for this name
|
||||
*/
|
||||
public
|
||||
int[] getTypes() {
|
||||
return types.toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether a specific type is in the set of types.
|
||||
*/
|
||||
public
|
||||
boolean hasType(int type) {
|
||||
return types.contains(type);
|
||||
}
|
||||
|
||||
}
|
30
src/dorkbox/network/dns/records/NSIDOption.java
Normal file
30
src/dorkbox/network/dns/records/NSIDOption.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
/**
|
||||
* The Name Server Identifier Option, define in RFC 5001.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see OPTRecord
|
||||
*/
|
||||
public
|
||||
class NSIDOption extends GenericEDNSOption {
|
||||
|
||||
private static final long serialVersionUID = 74739759292589056L;
|
||||
|
||||
NSIDOption() {
|
||||
super(EDNSOption.Code.NSID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an NSID option.
|
||||
*
|
||||
* @param data The contents of the option.
|
||||
*/
|
||||
public
|
||||
NSIDOption(byte[] data) {
|
||||
super(EDNSOption.Code.NSID, data);
|
||||
}
|
||||
|
||||
}
|
50
src/dorkbox/network/dns/records/NSRecord.java
Normal file
50
src/dorkbox/network/dns/records/NSRecord.java
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Name Server Record - contains the name server serving the named zone
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class NSRecord extends SingleCompressedNameBase {
|
||||
|
||||
private static final long serialVersionUID = 487170758138268838L;
|
||||
|
||||
NSRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NSRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new NS Record with the given data
|
||||
*
|
||||
* @param target The name server for the given domain
|
||||
*/
|
||||
public
|
||||
NSRecord(Name name, int dclass, long ttl, Name target) {
|
||||
super(name, DnsRecordType.NS, dclass, ttl, target, "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the NS Record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
78
src/dorkbox/network/dns/records/NULLRecord.java
Normal file
78
src/dorkbox/network/dns/records/NULLRecord.java
Normal file
|
@ -0,0 +1,78 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* The NULL Record. This has no defined purpose, but can be used to
|
||||
* hold arbitrary data.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class NULLRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -5796493183235216538L;
|
||||
|
||||
private byte[] data;
|
||||
|
||||
NULLRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NULLRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
data = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeByteArray(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(unknownToString(data));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
throw st.exception("no defined text format for NULL records");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a NULL record from the given data.
|
||||
*
|
||||
* @param data The contents of the record.
|
||||
*/
|
||||
public
|
||||
NULLRecord(Name name, int dclass, long ttl, byte[] data) {
|
||||
super(name, DnsRecordType.NULL, dclass, ttl);
|
||||
|
||||
if (data.length > 0xFFFF) {
|
||||
throw new IllegalArgumentException("data must be <65536 bytes");
|
||||
}
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the contents of this record.
|
||||
*/
|
||||
public
|
||||
byte[] getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
129
src/dorkbox/network/dns/records/NXTRecord.java
Normal file
129
src/dorkbox/network/dns/records/NXTRecord.java
Normal file
|
@ -0,0 +1,129 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.BitSet;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Next name - this record contains the following name in an ordered list
|
||||
* of names in the zone, and a set of types for which records exist for
|
||||
* this name. The presence of this record in a response signifies a
|
||||
* failed query for data in a DNSSEC-signed zone.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class NXTRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -8851454400765507520L;
|
||||
|
||||
private Name next;
|
||||
private BitSet bitmap;
|
||||
|
||||
NXTRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new NXTRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
next = new Name(in);
|
||||
bitmap = new BitSet();
|
||||
int bitmapLength = in.remaining();
|
||||
for (int i = 0; i < bitmapLength; i++) {
|
||||
int t = in.readU8();
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if ((t & (1 << (7 - j))) != 0) {
|
||||
bitmap.set(i * 8 + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
next.toWire(out, null, canonical);
|
||||
int length = bitmap.length();
|
||||
for (int i = 0, t = 0; i < length; i++) {
|
||||
t |= (bitmap.get(i) ? (1 << (7 - i % 8)) : 0);
|
||||
if (i % 8 == 7 || i == length - 1) {
|
||||
out.writeU8(t);
|
||||
t = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(next);
|
||||
int length = bitmap.length();
|
||||
for (short i = 0; i < length; i++) {
|
||||
if (bitmap.get(i)) {
|
||||
sb.append(" ");
|
||||
sb.append(DnsRecordType.string(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
next = st.getName(origin);
|
||||
bitmap = new BitSet();
|
||||
while (true) {
|
||||
Tokenizer.Token t = st.get();
|
||||
if (!t.isString()) {
|
||||
break;
|
||||
}
|
||||
int typecode = DnsRecordType.value(t.value, true);
|
||||
if (typecode <= 0 || typecode > 128) {
|
||||
throw st.exception("Invalid type: " + t.value);
|
||||
}
|
||||
bitmap.set(typecode);
|
||||
}
|
||||
st.unget();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an NXT Record from the given data
|
||||
*
|
||||
* @param next The following name in an ordered list of the zone
|
||||
* @param bitmap The set of type for which records exist at this name
|
||||
*/
|
||||
public
|
||||
NXTRecord(Name name, int dclass, long ttl, Name next, BitSet bitmap) {
|
||||
super(name, DnsRecordType.NXT, dclass, ttl);
|
||||
this.next = checkName("next", next);
|
||||
this.bitmap = bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the next name
|
||||
*/
|
||||
public
|
||||
Name getNext() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of types defined for this name
|
||||
*/
|
||||
public
|
||||
BitSet getBitmap() {
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
}
|
88
src/dorkbox/network/dns/records/OPENPGPKEYRecord.java
Normal file
88
src/dorkbox/network/dns/records/OPENPGPKEYRecord.java
Normal file
|
@ -0,0 +1,88 @@
|
|||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.OS;
|
||||
|
||||
/**
|
||||
* OPENPGPKEY Record - Stores an OpenPGP certificate associated with a name.
|
||||
* RFC 7929.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @author Valentin Hauner
|
||||
*/
|
||||
public
|
||||
class OPENPGPKEYRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -1277262990243423062L;
|
||||
|
||||
private byte[] cert;
|
||||
|
||||
OPENPGPKEYRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new OPENPGPKEYRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
cert = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeByteArray(cert);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
if (cert != null) {
|
||||
if (Options.check("multiline")) {
|
||||
sb.append("(")
|
||||
.append(OS.LINE_SEPARATOR);
|
||||
sb.append(Base64Fast.formatString(Base64Fast.encode2(cert), 64, "\t", true));
|
||||
}
|
||||
else {
|
||||
sb.append("\t");
|
||||
sb.append(Base64Fast.encode2(cert));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
cert = st.getBase64();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an OPENPGPKEY Record from the given data
|
||||
*
|
||||
* @param cert Binary data representing the certificate
|
||||
*/
|
||||
public
|
||||
OPENPGPKEYRecord(Name name, int dclass, long ttl, byte[] cert) {
|
||||
super(name, DnsRecordType.OPENPGPKEY, dclass, ttl);
|
||||
this.cert = cert;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary representation of the certificate
|
||||
*/
|
||||
public
|
||||
byte[] getCert() {
|
||||
return cert;
|
||||
}
|
||||
|
||||
}
|
232
src/dorkbox/network/dns/records/OPTRecord.java
Normal file
232
src/dorkbox/network/dns/records/OPTRecord.java
Normal file
|
@ -0,0 +1,232 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.constants.DnsResponseCode;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Options - describes Extended DNS (EDNS) properties of a DnsMessage.
|
||||
* No specific options are defined other than those specified in the
|
||||
* header. An OPT should be generated by Resolver.
|
||||
* <p>
|
||||
* EDNS is a method to extend the DNS protocol while providing backwards
|
||||
* compatibility and not significantly changing the protocol. This
|
||||
* implementation of EDNS is mostly complete at level 0.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see DnsMessage
|
||||
*/
|
||||
|
||||
public
|
||||
class OPTRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -6254521894809367938L;
|
||||
|
||||
private List options;
|
||||
|
||||
OPTRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new OPTRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
if (in.remaining() > 0) {
|
||||
options = new ArrayList();
|
||||
}
|
||||
while (in.remaining() > 0) {
|
||||
EDNSOption option = EDNSOption.fromWire(in);
|
||||
options.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
if (options == null) {
|
||||
return;
|
||||
}
|
||||
Iterator it = options.iterator();
|
||||
while (it.hasNext()) {
|
||||
EDNSOption option = (EDNSOption) it.next();
|
||||
option.toWire(out);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
if (options != null) {
|
||||
sb.append(options);
|
||||
sb.append(" ");
|
||||
}
|
||||
|
||||
sb.append(" ; payload ");
|
||||
sb.append(getPayloadSize());
|
||||
sb.append(", xrcode ");
|
||||
sb.append(getExtendedRcode());
|
||||
sb.append(", version ");
|
||||
sb.append(getVersion());
|
||||
sb.append(", flags ");
|
||||
sb.append(getFlags());
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
throw st.exception("no text format defined for OPT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if two OPTRecords are identical. This compares the name, type,
|
||||
* class, and rdata (with names canonicalized). Additionally, because TTLs
|
||||
* are relevant for OPT records, the TTLs are compared.
|
||||
*
|
||||
* @param arg The record to compare to
|
||||
*
|
||||
* @return true if the records are equal, false otherwise.
|
||||
*/
|
||||
public
|
||||
boolean equals(final Object arg) {
|
||||
return super.equals(arg) && ttl == ((OPTRecord) arg).ttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum allowed payload size.
|
||||
*/
|
||||
public
|
||||
int getPayloadSize() {
|
||||
return dclass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extended DnsResponseCode
|
||||
*
|
||||
* @see DnsResponseCode
|
||||
*/
|
||||
public
|
||||
int getExtendedRcode() {
|
||||
return (int) (ttl >>> 24);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest supported EDNS version
|
||||
*/
|
||||
public
|
||||
int getVersion() {
|
||||
return (int) ((ttl >>> 16) & 0xFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the EDNS flags
|
||||
*/
|
||||
public
|
||||
int getFlags() {
|
||||
return (int) (ttl & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an OPT Record with no data. This is normally called by
|
||||
* SimpleResolver, but can also be called by a server.
|
||||
*
|
||||
* @param payloadSize The size of a packet that can be reassembled on the
|
||||
* sending host.
|
||||
* @param xrcode The value of the extended rcode field. This is the upper
|
||||
* 16 bits of the full rcode.
|
||||
* @param flags Additional message flags.
|
||||
* @param version The EDNS version that this DNS implementation supports.
|
||||
* This should be 0 for dnsjava.
|
||||
*
|
||||
* @see ExtendedFlags
|
||||
*/
|
||||
public
|
||||
OPTRecord(int payloadSize, int xrcode, int version, int flags) {
|
||||
this(payloadSize, xrcode, version, flags, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an OPT Record. This is normally called by SimpleResolver, but can
|
||||
* also be called by a server.
|
||||
*
|
||||
* @param payloadSize The size of a packet that can be reassembled on the
|
||||
* sending host.
|
||||
* @param xrcode The value of the extended rcode field. This is the upper
|
||||
* 16 bits of the full rcode.
|
||||
* @param flags Additional message flags.
|
||||
* @param version The EDNS version that this DNS implementation supports.
|
||||
* This should be 0 for dnsjava.
|
||||
* @param options The list of options that comprise the data field. There
|
||||
* are currently no defined options.
|
||||
*
|
||||
* @see ExtendedFlags
|
||||
*/
|
||||
public
|
||||
OPTRecord(int payloadSize, int xrcode, int version, int flags, List options) {
|
||||
super(Name.root, DnsRecordType.OPT, payloadSize, 0);
|
||||
checkU16("payloadSize", payloadSize);
|
||||
checkU8("xrcode", xrcode);
|
||||
checkU8("version", version);
|
||||
checkU16("flags", flags);
|
||||
ttl = ((long) xrcode << 24) + ((long) version << 16) + flags;
|
||||
if (options != null) {
|
||||
this.options = new ArrayList(options);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an OPT Record with no data. This is normally called by
|
||||
* SimpleResolver, but can also be called by a server.
|
||||
*/
|
||||
public
|
||||
OPTRecord(int payloadSize, int xrcode, int version) {
|
||||
this(payloadSize, xrcode, version, 0, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all options in the OPTRecord. This returns a list of EDNSOptions.
|
||||
*/
|
||||
public
|
||||
List getOptions() {
|
||||
if (options == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
return Collections.unmodifiableList(options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all options in the OPTRecord with a specific code. This returns a list
|
||||
* of EDNSOptions.
|
||||
*/
|
||||
public
|
||||
List getOptions(int code) {
|
||||
if (options == null) {
|
||||
return Collections.EMPTY_LIST;
|
||||
}
|
||||
List list = Collections.EMPTY_LIST;
|
||||
for (Iterator it = options.iterator(); it.hasNext(); ) {
|
||||
EDNSOption opt = (EDNSOption) it.next();
|
||||
if (opt.getCode() == code) {
|
||||
if (list == Collections.EMPTY_LIST) {
|
||||
list = new ArrayList();
|
||||
}
|
||||
list.add(opt);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
45
src/dorkbox/network/dns/records/PTRRecord.java
Normal file
45
src/dorkbox/network/dns/records/PTRRecord.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Pointer Record - maps a domain name representing an Internet Address to
|
||||
* a hostname.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class PTRRecord extends SingleCompressedNameBase {
|
||||
|
||||
private static final long serialVersionUID = -8321636610425434192L;
|
||||
|
||||
PTRRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new PTRRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new PTR Record with the given data
|
||||
*
|
||||
* @param target The name of the machine with this address
|
||||
*/
|
||||
public
|
||||
PTRRecord(Name name, int dclass, long ttl, Name target) {
|
||||
super(name, DnsRecordType.PTR, dclass, ttl, target, "target");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the target of the PTR Record
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return getSingleName();
|
||||
}
|
||||
|
||||
}
|
109
src/dorkbox/network/dns/records/PXRecord.java
Normal file
109
src/dorkbox/network/dns/records/PXRecord.java
Normal file
|
@ -0,0 +1,109 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* X.400 mail mapping record.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class PXRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 1811540008806660667L;
|
||||
|
||||
private int preference;
|
||||
private Name map822;
|
||||
private Name mapX400;
|
||||
|
||||
PXRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new PXRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
preference = in.readU16();
|
||||
map822 = new Name(in);
|
||||
mapX400 = new Name(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(preference);
|
||||
map822.toWire(out, null, canonical);
|
||||
mapX400.toWire(out, null, canonical);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the PX Record to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(preference);
|
||||
sb.append(" ");
|
||||
sb.append(map822);
|
||||
sb.append(" ");
|
||||
sb.append(mapX400);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
preference = st.getUInt16();
|
||||
map822 = st.getName(origin);
|
||||
mapX400 = st.getName(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an PX Record from the given data
|
||||
*
|
||||
* @param preference The preference of this mail address.
|
||||
* @param map822 The RFC 822 component of the mail address.
|
||||
* @param mapX400 The X.400 component of the mail address.
|
||||
*/
|
||||
public
|
||||
PXRecord(Name name, int dclass, long ttl, int preference, Name map822, Name mapX400) {
|
||||
super(name, DnsRecordType.PX, dclass, ttl);
|
||||
|
||||
this.preference = checkU16("preference", preference);
|
||||
this.map822 = checkName("map822", map822);
|
||||
this.mapX400 = checkName("mapX400", mapX400);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the preference of the route.
|
||||
*/
|
||||
public
|
||||
int getPreference() {
|
||||
return preference;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the RFC 822 component of the mail address.
|
||||
*/
|
||||
public
|
||||
Name getMap822() {
|
||||
return map822;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the X.400 component of the mail address.
|
||||
*/
|
||||
public
|
||||
Name getMapX400() {
|
||||
return mapX400;
|
||||
}
|
||||
|
||||
}
|
95
src/dorkbox/network/dns/records/RPRecord.java
Normal file
95
src/dorkbox/network/dns/records/RPRecord.java
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Responsible Person Record - lists the mail address of a responsible person
|
||||
* and a domain where TXT records are available.
|
||||
*
|
||||
* @author Tom Scola (tscola@research.att.com)
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class RPRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 8124584364211337460L;
|
||||
|
||||
private Name mailbox;
|
||||
private Name textDomain;
|
||||
|
||||
RPRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new RPRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
mailbox = new Name(in);
|
||||
textDomain = new Name(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
mailbox.toWire(out, null, canonical);
|
||||
textDomain.toWire(out, null, canonical);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the RP Record to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(mailbox);
|
||||
sb.append(" ");
|
||||
sb.append(textDomain);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
mailbox = st.getName(origin);
|
||||
textDomain = st.getName(origin);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RP Record from the given data
|
||||
*
|
||||
* @param mailbox The responsible person
|
||||
* @param textDomain The address where TXT records can be found
|
||||
*/
|
||||
public
|
||||
RPRecord(Name name, int dclass, long ttl, Name mailbox, Name textDomain) {
|
||||
super(name, DnsRecordType.RP, dclass, ttl);
|
||||
|
||||
this.mailbox = checkName("mailbox", mailbox);
|
||||
this.textDomain = checkName("textDomain", textDomain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the mailbox address of the RP Record
|
||||
*/
|
||||
public
|
||||
Name getMailbox() {
|
||||
return mailbox;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text domain info of the RP Record
|
||||
*/
|
||||
public
|
||||
Name getTextDomain() {
|
||||
return textDomain;
|
||||
}
|
||||
|
||||
}
|
61
src/dorkbox/network/dns/records/RRSIGRecord.java
Normal file
61
src/dorkbox/network/dns/records/RRSIGRecord.java
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Recource Record Signature - An RRSIG provides the digital signature of an
|
||||
* RRset, so that the data can be authenticated by a DNSSEC-capable resolver.
|
||||
* The signature is generated by a key contained in a DNSKEY Record.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see RRset
|
||||
* @see DNSSEC
|
||||
* @see KEYRecord
|
||||
*/
|
||||
|
||||
public
|
||||
class RRSIGRecord extends SIGBase {
|
||||
|
||||
private static final long serialVersionUID = -2609150673537226317L;
|
||||
|
||||
RRSIGRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new RRSIGRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RRSIG Record from the given data
|
||||
*
|
||||
* @param covered The RRset type covered by this signature
|
||||
* @param alg The cryptographic algorithm of the key that generated the
|
||||
* signature
|
||||
* @param origttl The original TTL of the RRset
|
||||
* @param expire The time at which the signature expires
|
||||
* @param timeSigned The time at which this signature was generated
|
||||
* @param footprint The footprint/key id of the signing key.
|
||||
* @param signer The owner of the signing key
|
||||
* @param signature Binary data representing the signature
|
||||
*/
|
||||
public
|
||||
RRSIGRecord(Name name,
|
||||
int dclass,
|
||||
long ttl,
|
||||
int covered,
|
||||
int alg,
|
||||
long origttl,
|
||||
Date expire,
|
||||
Date timeSigned,
|
||||
int footprint,
|
||||
Name signer,
|
||||
byte[] signature) {
|
||||
super(name, DnsRecordType.RRSIG, dclass, ttl, covered, alg, origttl, expire, timeSigned, footprint, signer, signature);
|
||||
}
|
||||
|
||||
}
|
308
src/dorkbox/network/dns/records/RRset.java
Normal file
308
src/dorkbox/network/dns/records/RRset.java
Normal file
|
@ -0,0 +1,308 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsClass;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* A set of Records with the same name, type, and class. Also included
|
||||
* are all RRSIG records signing the data records.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see DnsRecord
|
||||
* @see RRSIGRecord
|
||||
*/
|
||||
|
||||
public
|
||||
class RRset implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -3270249290171239695L;
|
||||
|
||||
/*
|
||||
* rrs contains both normal and RRSIG records, with the RRSIG records
|
||||
* at the end.
|
||||
*/
|
||||
private List rrs;
|
||||
private short nsigs;
|
||||
private short position;
|
||||
|
||||
/**
|
||||
* Creates an RRset and sets its contents to the specified record
|
||||
*/
|
||||
public
|
||||
RRset(DnsRecord record) {
|
||||
this();
|
||||
safeAddRR(record);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty RRset
|
||||
*/
|
||||
public
|
||||
RRset() {
|
||||
rrs = new ArrayList(1);
|
||||
nsigs = 0;
|
||||
position = 0;
|
||||
}
|
||||
|
||||
private
|
||||
void safeAddRR(DnsRecord r) {
|
||||
if (!(r instanceof RRSIGRecord)) {
|
||||
if (nsigs == 0) {
|
||||
rrs.add(r);
|
||||
}
|
||||
else {
|
||||
rrs.add(rrs.size() - nsigs, r);
|
||||
}
|
||||
}
|
||||
else {
|
||||
rrs.add(r);
|
||||
nsigs++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RRset with the contents of an existing RRset
|
||||
*/
|
||||
public
|
||||
RRset(RRset rrset) {
|
||||
synchronized (rrset) {
|
||||
rrs = (List) ((ArrayList) rrset.rrs).clone();
|
||||
nsigs = rrset.nsigs;
|
||||
position = rrset.position;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Record to an RRset
|
||||
*/
|
||||
public synchronized
|
||||
void addRR(DnsRecord r) {
|
||||
if (rrs.size() == 0) {
|
||||
safeAddRR(r);
|
||||
return;
|
||||
}
|
||||
DnsRecord first = first();
|
||||
if (!r.sameRRset(first)) {
|
||||
throw new IllegalArgumentException("record does not match " + "rrset");
|
||||
}
|
||||
|
||||
if (r.getTTL() != first.getTTL()) {
|
||||
if (r.getTTL() > first.getTTL()) {
|
||||
r = r.cloneRecord();
|
||||
r.setTTL(first.getTTL());
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < rrs.size(); i++) {
|
||||
DnsRecord tmp = (DnsRecord) rrs.get(i);
|
||||
tmp = tmp.cloneRecord();
|
||||
tmp.setTTL(r.getTTL());
|
||||
rrs.set(i, tmp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rrs.contains(r)) {
|
||||
safeAddRR(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first record
|
||||
*
|
||||
* @throws IllegalStateException if the rrset is empty
|
||||
*/
|
||||
public synchronized
|
||||
DnsRecord first() {
|
||||
if (rrs.size() == 0) {
|
||||
throw new IllegalStateException("rrset is empty");
|
||||
}
|
||||
return (DnsRecord) rrs.get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a Record from an RRset
|
||||
*/
|
||||
public synchronized
|
||||
void deleteRR(DnsRecord r) {
|
||||
if (rrs.remove(r) && (r instanceof RRSIGRecord)) {
|
||||
nsigs--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all Records from an RRset
|
||||
*/
|
||||
public synchronized
|
||||
void clear() {
|
||||
rrs.clear();
|
||||
position = 0;
|
||||
nsigs = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator listing all (data) records.
|
||||
*
|
||||
* @param cycle If true, cycle through the records so that each Iterator will
|
||||
* start with a different record.
|
||||
*/
|
||||
public synchronized
|
||||
Iterator rrs(boolean cycle) {
|
||||
return iterator(true, cycle);
|
||||
}
|
||||
|
||||
private synchronized
|
||||
Iterator iterator(boolean data, boolean cycle) {
|
||||
int size, start, total;
|
||||
|
||||
total = rrs.size();
|
||||
|
||||
if (data) {
|
||||
size = total - nsigs;
|
||||
}
|
||||
else {
|
||||
size = nsigs;
|
||||
}
|
||||
if (size == 0) {
|
||||
return Collections.EMPTY_LIST.iterator();
|
||||
}
|
||||
|
||||
if (data) {
|
||||
if (!cycle) {
|
||||
start = 0;
|
||||
}
|
||||
else {
|
||||
if (position >= size) {
|
||||
position = 0;
|
||||
}
|
||||
start = position++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
start = total - nsigs;
|
||||
}
|
||||
|
||||
List list = new ArrayList(size);
|
||||
if (data) {
|
||||
list.addAll(rrs.subList(start, size));
|
||||
if (start != 0) {
|
||||
list.addAll(rrs.subList(0, start));
|
||||
}
|
||||
}
|
||||
else {
|
||||
list.addAll(rrs.subList(start, total));
|
||||
}
|
||||
|
||||
return list.iterator();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator listing all (data) records. This cycles through
|
||||
* the records, so each Iterator will start with a different record.
|
||||
*/
|
||||
public synchronized
|
||||
Iterator rrs() {
|
||||
return iterator(true, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an Iterator listing all signature records
|
||||
*/
|
||||
public synchronized
|
||||
Iterator sigs() {
|
||||
return iterator(false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of (data) records
|
||||
*/
|
||||
public synchronized
|
||||
int size() {
|
||||
return rrs.size() - nsigs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the RRset to a String
|
||||
*/
|
||||
public
|
||||
String toString() {
|
||||
if (rrs.size() == 0) {
|
||||
return ("{empty}");
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("{ ");
|
||||
sb.append(getName() + " ");
|
||||
sb.append(getTTL() + " ");
|
||||
sb.append(DnsClass.string(getDClass()) + " ");
|
||||
sb.append(DnsRecordType.string(getType()) + " ");
|
||||
sb.append(iteratorToString(iterator(true, false)));
|
||||
if (nsigs > 0) {
|
||||
sb.append(" sigs: ");
|
||||
sb.append(iteratorToString(iterator(false, false)));
|
||||
}
|
||||
sb.append(" }");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the records
|
||||
*
|
||||
* @see Name
|
||||
*/
|
||||
public
|
||||
Name getName() {
|
||||
return first().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the records
|
||||
*
|
||||
* @see DnsRecordType
|
||||
*/
|
||||
public
|
||||
int getType() {
|
||||
return first().getRRsetType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the class of the records
|
||||
*
|
||||
* @see DnsClass
|
||||
*/
|
||||
public
|
||||
int getDClass() {
|
||||
return first().getDClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ttl of the records
|
||||
*/
|
||||
public synchronized
|
||||
long getTTL() {
|
||||
return first().getTTL();
|
||||
}
|
||||
|
||||
private
|
||||
String iteratorToString(Iterator it) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (it.hasNext()) {
|
||||
DnsRecord rr = (DnsRecord) it.next();
|
||||
sb.append("[");
|
||||
rr.rdataToString(sb);
|
||||
sb.append("]");
|
||||
if (it.hasNext()) {
|
||||
sb.append(" ");
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
54
src/dorkbox/network/dns/records/RTRecord.java
Normal file
54
src/dorkbox/network/dns/records/RTRecord.java
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Route Through Record - lists a route preference and intermediate host.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class RTRecord extends U16NameBase {
|
||||
|
||||
private static final long serialVersionUID = -3206215651648278098L;
|
||||
|
||||
RTRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new RTRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an RT Record from the given data
|
||||
*
|
||||
* @param preference The preference of the route. Smaller numbers indicate
|
||||
* more preferred routes.
|
||||
* @param intermediateHost The domain name of the host to use as a router.
|
||||
*/
|
||||
public
|
||||
RTRecord(Name name, int dclass, long ttl, int preference, Name intermediateHost) {
|
||||
super(name, DnsRecordType.RT, dclass, ttl, preference, "preference", intermediateHost, "intermediateHost");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the preference of the route.
|
||||
*/
|
||||
public
|
||||
int getPreference() {
|
||||
return getU16Field();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the host to use as a router.
|
||||
*/
|
||||
public
|
||||
Name getIntermediateHost() {
|
||||
return getNameField();
|
||||
}
|
||||
|
||||
}
|
84
src/dorkbox/network/dns/records/SIG0.java
Normal file
84
src/dorkbox/network/dns/records/SIG0.java
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright (c) 2001-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
import java.util.Date;
|
||||
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.constants.DnsSection;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
|
||||
/**
|
||||
* Creates SIG(0) transaction signatures.
|
||||
*
|
||||
* @author Pasi Eronen
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class SIG0 {
|
||||
|
||||
/**
|
||||
* The default validity period for outgoing SIG(0) signed messages.
|
||||
* Can be overriden by the sig0validity option.
|
||||
*/
|
||||
private static final short VALIDITY = 300;
|
||||
|
||||
private
|
||||
SIG0() { }
|
||||
|
||||
/**
|
||||
* Sign a dnsMessage with SIG(0). The DNS key and private key must refer to the
|
||||
* same underlying cryptographic key.
|
||||
*
|
||||
* @param dnsMessage The dnsMessage to be signed
|
||||
* @param key The DNSKEY record to use as part of signing
|
||||
* @param privkey The PrivateKey to use when signing
|
||||
* @param previous If this dnsMessage is a response, the SIG(0) from the query
|
||||
*/
|
||||
public static
|
||||
void signMessage(DnsMessage dnsMessage, KEYRecord key, PrivateKey privkey, SIGRecord previous) throws DNSSEC.DNSSECException {
|
||||
|
||||
int validity = Options.intValue("sig0validity");
|
||||
if (validity < 0) {
|
||||
validity = VALIDITY;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
Date timeSigned = new Date(now);
|
||||
Date timeExpires = new Date(now + validity * 1000);
|
||||
|
||||
SIGRecord sig = DNSSEC.signMessage(dnsMessage, previous, key, privkey, timeSigned, timeExpires);
|
||||
|
||||
dnsMessage.addRecord(sig, DnsSection.ADDITIONAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a dnsMessage using SIG(0).
|
||||
*
|
||||
* @param dnsMessage The dnsMessage to be signed
|
||||
* @param b An array containing the dnsMessage in unparsed form. This is
|
||||
* necessary since SIG(0) signs the dnsMessage in wire format, and we can't
|
||||
* recreate the exact wire format (with the same name compression).
|
||||
* @param key The KEY record to verify the signature with.
|
||||
* @param previous If this dnsMessage is a response, the SIG(0) from the query
|
||||
*/
|
||||
public static
|
||||
void verifyMessage(DnsMessage dnsMessage, byte[] b, KEYRecord key, SIGRecord previous) throws DNSSEC.DNSSECException {
|
||||
SIGRecord sig = null;
|
||||
DnsRecord[] additional = dnsMessage.getSectionArray(DnsSection.ADDITIONAL);
|
||||
for (int i = 0; i < additional.length; i++) {
|
||||
if (additional[i].getType() != DnsRecordType.SIG) {
|
||||
continue;
|
||||
}
|
||||
if (((SIGRecord) additional[i]).getTypeCovered() != 0) {
|
||||
continue;
|
||||
}
|
||||
sig = (SIGRecord) additional[i];
|
||||
break;
|
||||
}
|
||||
DNSSEC.verifyMessage(dnsMessage, b, sig, previous, key);
|
||||
}
|
||||
|
||||
}
|
229
src/dorkbox/network/dns/records/SIGBase.java
Normal file
229
src/dorkbox/network/dns/records/SIGBase.java
Normal file
|
@ -0,0 +1,229 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.FormattedTime;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.OS;
|
||||
|
||||
/**
|
||||
* The base class for SIG/RRSIG records, which have identical formats
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
abstract
|
||||
class SIGBase extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -3738444391533812369L;
|
||||
|
||||
protected int covered;
|
||||
protected int alg, labels;
|
||||
protected long origttl;
|
||||
protected Date expire, timeSigned;
|
||||
protected int footprint;
|
||||
protected Name signer;
|
||||
protected byte[] signature;
|
||||
|
||||
protected
|
||||
SIGBase() {}
|
||||
|
||||
public
|
||||
SIGBase(Name name,
|
||||
int type,
|
||||
int dclass,
|
||||
long ttl,
|
||||
int covered,
|
||||
int alg,
|
||||
long origttl,
|
||||
Date expire,
|
||||
Date timeSigned,
|
||||
int footprint,
|
||||
Name signer,
|
||||
byte[] signature) {
|
||||
super(name, type, dclass, ttl);
|
||||
DnsRecordType.check(covered);
|
||||
TTL.check(origttl);
|
||||
this.covered = covered;
|
||||
this.alg = checkU8("alg", alg);
|
||||
this.labels = name.labels() - 1;
|
||||
if (name.isWild()) {
|
||||
this.labels--;
|
||||
}
|
||||
this.origttl = origttl;
|
||||
this.expire = expire;
|
||||
this.timeSigned = timeSigned;
|
||||
this.footprint = checkU16("footprint", footprint);
|
||||
this.signer = checkName("signer", signer);
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
covered = in.readU16();
|
||||
alg = in.readU8();
|
||||
labels = in.readU8();
|
||||
origttl = in.readU32();
|
||||
expire = new Date(1000 * in.readU32());
|
||||
timeSigned = new Date(1000 * in.readU32());
|
||||
footprint = in.readU16();
|
||||
signer = new Name(in);
|
||||
signature = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(covered);
|
||||
out.writeU8(alg);
|
||||
out.writeU8(labels);
|
||||
out.writeU32(origttl);
|
||||
out.writeU32(expire.getTime() / 1000);
|
||||
out.writeU32(timeSigned.getTime() / 1000);
|
||||
out.writeU16(footprint);
|
||||
signer.toWire(out, null, canonical);
|
||||
out.writeByteArray(signature);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the RRSIG/SIG Record to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(DnsRecordType.string(covered));
|
||||
sb.append(" ");
|
||||
sb.append(alg);
|
||||
sb.append(" ");
|
||||
sb.append(labels);
|
||||
sb.append(" ");
|
||||
sb.append(origttl);
|
||||
sb.append(" ");
|
||||
if (Options.check("multiline")) {
|
||||
sb.append("(\n\t");
|
||||
}
|
||||
sb.append(FormattedTime.format(expire));
|
||||
sb.append(" ");
|
||||
sb.append(FormattedTime.format(timeSigned));
|
||||
sb.append(" ");
|
||||
sb.append(footprint);
|
||||
sb.append(" ");
|
||||
sb.append(signer);
|
||||
if (Options.check("multiline")) {
|
||||
sb.append(OS.LINE_SEPARATOR);
|
||||
sb.append(Base64Fast.formatString(Base64Fast.encode2(signature), 64, "\t", true));
|
||||
}
|
||||
else {
|
||||
sb.append(" ");
|
||||
sb.append(Base64Fast.encode2(signature));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
String typeString = st.getString();
|
||||
covered = DnsRecordType.value(typeString);
|
||||
if (covered < 0) {
|
||||
throw st.exception("Invalid type: " + typeString);
|
||||
}
|
||||
String algString = st.getString();
|
||||
alg = DNSSEC.Algorithm.value(algString);
|
||||
if (alg < 0) {
|
||||
throw st.exception("Invalid algorithm: " + algString);
|
||||
}
|
||||
labels = st.getUInt8();
|
||||
origttl = st.getTTL();
|
||||
expire = FormattedTime.parse(st.getString());
|
||||
timeSigned = FormattedTime.parse(st.getString());
|
||||
footprint = st.getUInt16();
|
||||
signer = st.getName(origin);
|
||||
signature = st.getBase64();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the RRset type covered by this signature
|
||||
*/
|
||||
public
|
||||
int getTypeCovered() {
|
||||
return covered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cryptographic algorithm of the key that generated the signature
|
||||
*/
|
||||
public
|
||||
int getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of labels in the signed domain name. This may be
|
||||
* different than the record's domain name if the record is a wildcard
|
||||
* record.
|
||||
*/
|
||||
public
|
||||
int getLabels() {
|
||||
return labels;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the original TTL of the RRset
|
||||
*/
|
||||
public
|
||||
long getOrigTTL() {
|
||||
return origttl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which the signature expires
|
||||
*/
|
||||
public
|
||||
Date getExpire() {
|
||||
return expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time at which this signature was generated
|
||||
*/
|
||||
public
|
||||
Date getTimeSigned() {
|
||||
return timeSigned;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns The footprint/key id of the signing key.
|
||||
*/
|
||||
public
|
||||
int getFootprint() {
|
||||
return footprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner of the signing key
|
||||
*/
|
||||
public
|
||||
Name getSigner() {
|
||||
return signer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the binary data representing the signature
|
||||
*/
|
||||
public
|
||||
byte[] getSignature() {
|
||||
return signature;
|
||||
}
|
||||
|
||||
void setSignature(byte[] signature) {
|
||||
this.signature = signature;
|
||||
}
|
||||
|
||||
}
|
61
src/dorkbox/network/dns/records/SIGRecord.java
Normal file
61
src/dorkbox/network/dns/records/SIGRecord.java
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Signature - A SIG provides the digital signature of an RRset, so that
|
||||
* the data can be authenticated by a DNSSEC-capable resolver. The
|
||||
* signature is usually generated by a key contained in a KEYRecord
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see RRset
|
||||
* @see DNSSEC
|
||||
* @see KEYRecord
|
||||
*/
|
||||
|
||||
public
|
||||
class SIGRecord extends SIGBase {
|
||||
|
||||
private static final long serialVersionUID = 4963556060953589058L;
|
||||
|
||||
SIGRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new SIGRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SIG Record from the given data
|
||||
*
|
||||
* @param covered The RRset type covered by this signature
|
||||
* @param alg The cryptographic algorithm of the key that generated the
|
||||
* signature
|
||||
* @param origttl The original TTL of the RRset
|
||||
* @param expire The time at which the signature expires
|
||||
* @param timeSigned The time at which this signature was generated
|
||||
* @param footprint The footprint/key id of the signing key.
|
||||
* @param signer The owner of the signing key
|
||||
* @param signature Binary data representing the signature
|
||||
*/
|
||||
public
|
||||
SIGRecord(Name name,
|
||||
int dclass,
|
||||
long ttl,
|
||||
int covered,
|
||||
int alg,
|
||||
long origttl,
|
||||
Date expire,
|
||||
Date timeSigned,
|
||||
int footprint,
|
||||
Name signer,
|
||||
byte[] signature) {
|
||||
super(name, DnsRecordType.SIG, dclass, ttl, covered, alg, origttl, expire, timeSigned, footprint, signer, signature);
|
||||
}
|
||||
|
||||
}
|
178
src/dorkbox/network/dns/records/SMIMEARecord.java
Normal file
178
src/dorkbox/network/dns/records/SMIMEARecord.java
Normal file
|
@ -0,0 +1,178 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* S/MIME cert association, draft-ietf-dane-smime.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class SMIMEARecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 1640247915216425235L;
|
||||
|
||||
// Note; these are copied from the TLSA type.
|
||||
private int certificateUsage;
|
||||
private int selector;
|
||||
private int matchingType;
|
||||
private byte[] certificateAssociationData;
|
||||
|
||||
|
||||
public static
|
||||
class CertificateUsage {
|
||||
public static final int CA_CONSTRAINT = 0;
|
||||
public static final int SERVICE_CERTIFICATE_CONSTRAINT = 1;
|
||||
public static final int TRUST_ANCHOR_ASSERTION = 2;
|
||||
public static final int DOMAIN_ISSUED_CERTIFICATE = 3;
|
||||
private
|
||||
CertificateUsage() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Selector {
|
||||
/**
|
||||
* Full certificate; the Certificate binary structure defined in
|
||||
* [RFC5280]
|
||||
*/
|
||||
public static final int FULL_CERTIFICATE = 0;
|
||||
/**
|
||||
* SubjectPublicKeyInfo; DER-encoded binary structure defined in
|
||||
* [RFC5280]
|
||||
*/
|
||||
public static final int SUBJECT_PUBLIC_KEY_INFO = 1;
|
||||
|
||||
private
|
||||
Selector() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class MatchingType {
|
||||
/**
|
||||
* Exact match on selected content
|
||||
*/
|
||||
public static final int EXACT = 0;
|
||||
/**
|
||||
* SHA-256 hash of selected content [RFC6234]
|
||||
*/
|
||||
public static final int SHA256 = 1;
|
||||
/**
|
||||
* SHA-512 hash of selected content [RFC6234]
|
||||
*/
|
||||
public static final int SHA512 = 2;
|
||||
|
||||
private
|
||||
MatchingType() {}
|
||||
}
|
||||
|
||||
SMIMEARecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new SMIMEARecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
certificateUsage = in.readU8();
|
||||
selector = in.readU8();
|
||||
matchingType = in.readU8();
|
||||
certificateAssociationData = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(certificateUsage);
|
||||
out.writeU8(selector);
|
||||
out.writeU8(matchingType);
|
||||
out.writeByteArray(certificateAssociationData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(certificateUsage);
|
||||
sb.append(" ");
|
||||
sb.append(selector);
|
||||
sb.append(" ");
|
||||
sb.append(matchingType);
|
||||
sb.append(" ");
|
||||
sb.append(base16.toString(certificateAssociationData));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
certificateUsage = st.getUInt8();
|
||||
selector = st.getUInt8();
|
||||
matchingType = st.getUInt8();
|
||||
certificateAssociationData = st.getHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SMIMEA Record from the given data
|
||||
*
|
||||
* @param certificateUsage The provided association that will be used to
|
||||
* match the certificate presented in the S/MIME handshake.
|
||||
* @param selector The part of the S/MIME certificate presented by the server
|
||||
* that will be matched against the association data.
|
||||
* @param matchingType How the certificate association is presented.
|
||||
* @param certificateAssociationData The "certificate association data" to be
|
||||
* matched.
|
||||
*/
|
||||
public
|
||||
SMIMEARecord(Name name, int dclass, long ttl, int certificateUsage, int selector, int matchingType, byte[] certificateAssociationData) {
|
||||
super(name, DnsRecordType.SMIMEA, dclass, ttl);
|
||||
this.certificateUsage = checkU8("certificateUsage", certificateUsage);
|
||||
this.selector = checkU8("selector", selector);
|
||||
this.matchingType = checkU8("matchingType", matchingType);
|
||||
this.certificateAssociationData = checkByteArrayLength("certificateAssociationData", certificateAssociationData, 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate usage of the SMIMEA record
|
||||
*/
|
||||
public
|
||||
int getCertificateUsage() {
|
||||
return certificateUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selector of the SMIMEA record
|
||||
*/
|
||||
public
|
||||
int getSelector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the matching type of the SMIMEA record
|
||||
*/
|
||||
public
|
||||
int getMatchingType() {
|
||||
return matchingType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate associate data of this SMIMEA record
|
||||
*/
|
||||
public final
|
||||
byte[] getCertificateAssociationData() {
|
||||
return certificateAssociationData;
|
||||
}
|
||||
|
||||
}
|
186
src/dorkbox/network/dns/records/SOARecord.java
Normal file
186
src/dorkbox/network/dns/records/SOARecord.java
Normal file
|
@ -0,0 +1,186 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Start of Authority - describes properties of a zone.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class SOARecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 1049740098229303931L;
|
||||
|
||||
private Name host, admin;
|
||||
private long serial, refresh, retry, expire, minimum;
|
||||
|
||||
SOARecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new SOARecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
host = new Name(in);
|
||||
admin = new Name(in);
|
||||
serial = in.readU32();
|
||||
refresh = in.readU32();
|
||||
retry = in.readU32();
|
||||
expire = in.readU32();
|
||||
minimum = in.readU32();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
host.toWire(out, c, canonical);
|
||||
admin.toWire(out, c, canonical);
|
||||
out.writeU32(serial);
|
||||
out.writeU32(refresh);
|
||||
out.writeU32(retry);
|
||||
out.writeU32(expire);
|
||||
out.writeU32(minimum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(host);
|
||||
sb.append(" ");
|
||||
sb.append(admin);
|
||||
|
||||
if (Options.check("multiline")) {
|
||||
sb.append(" (\n\t\t\t\t\t");
|
||||
sb.append(serial);
|
||||
sb.append("\t; serial\n\t\t\t\t\t");
|
||||
sb.append(refresh);
|
||||
sb.append("\t; refresh\n\t\t\t\t\t");
|
||||
sb.append(retry);
|
||||
sb.append("\t; retry\n\t\t\t\t\t");
|
||||
sb.append(expire);
|
||||
sb.append("\t; expire\n\t\t\t\t\t");
|
||||
sb.append(minimum);
|
||||
sb.append(" )\t; minimum");
|
||||
}
|
||||
else {
|
||||
sb.append(" ");
|
||||
sb.append(serial);
|
||||
sb.append(" ");
|
||||
sb.append(refresh);
|
||||
sb.append(" ");
|
||||
sb.append(retry);
|
||||
sb.append(" ");
|
||||
sb.append(expire);
|
||||
sb.append(" ");
|
||||
sb.append(minimum);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
host = st.getName(origin);
|
||||
admin = st.getName(origin);
|
||||
serial = st.getUInt32();
|
||||
refresh = st.getTTLLike();
|
||||
retry = st.getTTLLike();
|
||||
expire = st.getTTLLike();
|
||||
minimum = st.getTTLLike();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SOA Record from the given data
|
||||
*
|
||||
* @param host The primary name server for the zone
|
||||
* @param admin The zone administrator's address
|
||||
* @param serial The zone's serial number
|
||||
* @param refresh The amount of time until a secondary checks for a new serial
|
||||
* number
|
||||
* @param retry The amount of time between a secondary's checks for a new
|
||||
* serial number
|
||||
* @param expire The amount of time until a secondary expires a zone
|
||||
* @param minimum The minimum TTL for records in the zone
|
||||
*/
|
||||
public
|
||||
SOARecord(Name name, int dclass, long ttl, Name host, Name admin, long serial, long refresh, long retry, long expire, long minimum) {
|
||||
super(name, DnsRecordType.SOA, dclass, ttl);
|
||||
this.host = checkName("host", host);
|
||||
this.admin = checkName("admin", admin);
|
||||
this.serial = checkU32("serial", serial);
|
||||
this.refresh = checkU32("refresh", refresh);
|
||||
this.retry = checkU32("retry", retry);
|
||||
this.expire = checkU32("expire", expire);
|
||||
this.minimum = checkU32("minimum", minimum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the primary name server
|
||||
*/
|
||||
public
|
||||
Name getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zone administrator's address
|
||||
*/
|
||||
public
|
||||
Name getAdmin() {
|
||||
return admin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zone's serial number
|
||||
*/
|
||||
public
|
||||
long getSerial() {
|
||||
return serial;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zone refresh interval
|
||||
*/
|
||||
public
|
||||
long getRefresh() {
|
||||
return refresh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the zone retry interval
|
||||
*/
|
||||
public
|
||||
long getRetry() {
|
||||
return retry;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time until a secondary expires a zone
|
||||
*/
|
||||
public
|
||||
long getExpire() {
|
||||
return expire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum TTL for records in the zone
|
||||
*/
|
||||
public
|
||||
long getMinimum() {
|
||||
return minimum;
|
||||
}
|
||||
|
||||
}
|
52
src/dorkbox/network/dns/records/SPFRecord.java
Normal file
52
src/dorkbox/network/dns/records/SPFRecord.java
Normal file
|
@ -0,0 +1,52 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
|
||||
/**
|
||||
* Sender Policy Framework (RFC 4408, experimental)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class SPFRecord extends TXTBase {
|
||||
|
||||
private static final long serialVersionUID = -2100754352801658722L;
|
||||
|
||||
SPFRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new SPFRecord();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SPF Record from the given data
|
||||
*
|
||||
* @param strings The text strings
|
||||
*
|
||||
* @throws IllegalArgumentException One of the strings has invalid escapes
|
||||
*/
|
||||
public
|
||||
SPFRecord(Name name, int dclass, long ttl, List strings) {
|
||||
super(name, DnsRecordType.SPF, dclass, ttl, strings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SPF Record from the given data
|
||||
*
|
||||
* @param string One text string
|
||||
*
|
||||
* @throws IllegalArgumentException The string has invalid escapes
|
||||
*/
|
||||
public
|
||||
SPFRecord(Name name, int dclass, long ttl, String string) {
|
||||
super(name, DnsRecordType.SPF, dclass, ttl, string);
|
||||
}
|
||||
|
||||
}
|
130
src/dorkbox/network/dns/records/SRVRecord.java
Normal file
130
src/dorkbox/network/dns/records/SRVRecord.java
Normal file
|
@ -0,0 +1,130 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Server Selection Record - finds hosts running services in a domain. An
|
||||
* SRV record will normally be named _<service>._<protocol>.domain
|
||||
* - examples would be _sips._tcp.example.org (for the secure SIP protocol) and
|
||||
* _http._tcp.example.com (if HTTP used SRV records)
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class SRVRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -3886460132387522052L;
|
||||
|
||||
private int priority, weight, port;
|
||||
private Name target;
|
||||
|
||||
SRVRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new SRVRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
priority = in.readU16();
|
||||
weight = in.readU16();
|
||||
port = in.readU16();
|
||||
target = new Name(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU16(priority);
|
||||
out.writeU16(weight);
|
||||
out.writeU16(port);
|
||||
target.toWire(out, null, canonical);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(priority + " ");
|
||||
sb.append(weight + " ");
|
||||
sb.append(port + " ");
|
||||
sb.append(target);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
priority = st.getUInt16();
|
||||
weight = st.getUInt16();
|
||||
port = st.getUInt16();
|
||||
target = st.getName(origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public
|
||||
Name getAdditionalName() {
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SRV Record from the given data
|
||||
*
|
||||
* @param priority The priority of this SRV. Records with lower priority
|
||||
* are preferred.
|
||||
* @param weight The weight, used to select between records at the same
|
||||
* priority.
|
||||
* @param port The TCP/UDP port that the service uses
|
||||
* @param target The host running the service
|
||||
*/
|
||||
public
|
||||
SRVRecord(Name name, int dclass, long ttl, int priority, int weight, int port, Name target) {
|
||||
super(name, DnsRecordType.SRV, dclass, ttl);
|
||||
this.priority = checkU16("priority", priority);
|
||||
this.weight = checkU16("weight", weight);
|
||||
this.port = checkU16("port", port);
|
||||
this.target = checkName("target", target);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the priority
|
||||
*/
|
||||
public
|
||||
int getPriority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the weight
|
||||
*/
|
||||
public
|
||||
int getWeight() {
|
||||
return weight;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port that the service runs on
|
||||
*/
|
||||
public
|
||||
int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host running that the service
|
||||
*/
|
||||
public
|
||||
Name getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
}
|
123
src/dorkbox/network/dns/records/SSHFPRecord.java
Normal file
123
src/dorkbox/network/dns/records/SSHFPRecord.java
Normal file
|
@ -0,0 +1,123 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* SSH Fingerprint - stores the fingerprint of an SSH host key.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class SSHFPRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -8104701402654687025L;
|
||||
private int alg;
|
||||
private int digestType;
|
||||
private byte[] fingerprint;
|
||||
|
||||
|
||||
public static
|
||||
class Algorithm {
|
||||
public static final int RSA = 1;
|
||||
public static final int DSS = 2;
|
||||
private
|
||||
Algorithm() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Digest {
|
||||
public static final int SHA1 = 1;
|
||||
|
||||
private
|
||||
Digest() {}
|
||||
}
|
||||
|
||||
SSHFPRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new SSHFPRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
alg = in.readU8();
|
||||
digestType = in.readU8();
|
||||
fingerprint = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(alg);
|
||||
out.writeU8(digestType);
|
||||
out.writeByteArray(fingerprint);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(alg);
|
||||
sb.append(" ");
|
||||
sb.append(digestType);
|
||||
sb.append(" ");
|
||||
sb.append(base16.toString(fingerprint));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
alg = st.getUInt8();
|
||||
digestType = st.getUInt8();
|
||||
fingerprint = st.getHex(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an SSHFP Record from the given data.
|
||||
*
|
||||
* @param alg The public key's algorithm.
|
||||
* @param digestType The public key's digest type.
|
||||
* @param fingerprint The public key's fingerprint.
|
||||
*/
|
||||
public
|
||||
SSHFPRecord(Name name, int dclass, long ttl, int alg, int digestType, byte[] fingerprint) {
|
||||
super(name, DnsRecordType.SSHFP, dclass, ttl);
|
||||
this.alg = checkU8("alg", alg);
|
||||
this.digestType = checkU8("digestType", digestType);
|
||||
this.fingerprint = fingerprint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key's algorithm.
|
||||
*/
|
||||
public
|
||||
int getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the public key's digest type.
|
||||
*/
|
||||
public
|
||||
int getDigestType() {
|
||||
return digestType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the fingerprint
|
||||
*/
|
||||
public
|
||||
byte[] getFingerPrint() {
|
||||
return fingerprint;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
|
||||
/**
|
||||
* Implements common functionality for the many record types whose format
|
||||
* is a single compressed name.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
abstract
|
||||
class SingleCompressedNameBase extends SingleNameBase {
|
||||
|
||||
private static final long serialVersionUID = -236435396815460677L;
|
||||
|
||||
protected
|
||||
SingleCompressedNameBase() {}
|
||||
|
||||
protected
|
||||
SingleCompressedNameBase(Name name, int type, int dclass, long ttl, Name singleName, String description) {
|
||||
super(name, type, dclass, ttl, singleName, description);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
singleName.toWire(out, c, canonical);
|
||||
}
|
||||
|
||||
}
|
66
src/dorkbox/network/dns/records/SingleNameBase.java
Normal file
66
src/dorkbox/network/dns/records/SingleNameBase.java
Normal file
|
@ -0,0 +1,66 @@
|
|||
// Copyright (c) 2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
|
||||
/**
|
||||
* Implements common functionality for the many record types whose format
|
||||
* is a single name.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
abstract
|
||||
class SingleNameBase extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = -18595042501413L;
|
||||
|
||||
protected Name singleName;
|
||||
|
||||
protected
|
||||
SingleNameBase() {}
|
||||
|
||||
protected
|
||||
SingleNameBase(Name name, int type, int dclass, long ttl) {
|
||||
super(name, type, dclass, ttl);
|
||||
}
|
||||
|
||||
protected
|
||||
SingleNameBase(Name name, int type, int dclass, long ttl, Name singleName, String description) {
|
||||
super(name, type, dclass, ttl);
|
||||
this.singleName = checkName(description, singleName);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
singleName = new Name(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
singleName.toWire(out, null, canonical);
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(singleName.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
singleName = st.getName(origin);
|
||||
}
|
||||
|
||||
protected
|
||||
Name getSingleName() {
|
||||
return singleName;
|
||||
}
|
||||
|
||||
}
|
285
src/dorkbox/network/dns/records/TKEYRecord.java
Normal file
285
src/dorkbox/network/dns/records/TKEYRecord.java
Normal file
|
@ -0,0 +1,285 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.constants.DnsResponseCode;
|
||||
import dorkbox.network.dns.utils.FormattedTime;
|
||||
import dorkbox.network.dns.utils.Options;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.util.Base64Fast;
|
||||
import dorkbox.util.OS;
|
||||
|
||||
/**
|
||||
* Transaction Key - used to compute and/or securely transport a shared
|
||||
* secret to be used with TSIG.
|
||||
*
|
||||
* @author Brian Wellington
|
||||
* @see TSIG
|
||||
*/
|
||||
|
||||
public
|
||||
class TKEYRecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 8828458121926391756L;
|
||||
|
||||
private Name alg;
|
||||
private Date timeInception;
|
||||
private Date timeExpire;
|
||||
private int mode, error;
|
||||
private byte[] key;
|
||||
private byte[] other;
|
||||
|
||||
/**
|
||||
* The key is assigned by the server (unimplemented)
|
||||
*/
|
||||
public static final int SERVERASSIGNED = 1;
|
||||
|
||||
/**
|
||||
* The key is computed using a Diffie-Hellman key exchange
|
||||
*/
|
||||
public static final int DIFFIEHELLMAN = 2;
|
||||
|
||||
/**
|
||||
* The key is computed using GSS_API (unimplemented)
|
||||
*/
|
||||
public static final int GSSAPI = 3;
|
||||
|
||||
/**
|
||||
* The key is assigned by the resolver (unimplemented)
|
||||
*/
|
||||
public static final int RESOLVERASSIGNED = 4;
|
||||
|
||||
/**
|
||||
* The key should be deleted
|
||||
*/
|
||||
public static final int DELETE = 5;
|
||||
|
||||
TKEYRecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new TKEYRecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
alg = new Name(in);
|
||||
timeInception = new Date(1000 * in.readU32());
|
||||
timeExpire = new Date(1000 * in.readU32());
|
||||
mode = in.readU16();
|
||||
error = in.readU16();
|
||||
|
||||
int keylen = in.readU16();
|
||||
if (keylen > 0) {
|
||||
key = in.readByteArray(keylen);
|
||||
}
|
||||
else {
|
||||
key = null;
|
||||
}
|
||||
|
||||
int otherlen = in.readU16();
|
||||
if (otherlen > 0) {
|
||||
other = in.readByteArray(otherlen);
|
||||
}
|
||||
else {
|
||||
other = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
alg.toWire(out, null, canonical);
|
||||
|
||||
out.writeU32(timeInception.getTime() / 1000);
|
||||
out.writeU32(timeExpire.getTime() / 1000);
|
||||
|
||||
out.writeU16(mode);
|
||||
out.writeU16(error);
|
||||
|
||||
if (key != null) {
|
||||
out.writeU16(key.length);
|
||||
out.writeByteArray(key);
|
||||
}
|
||||
else {
|
||||
out.writeU16(0);
|
||||
}
|
||||
|
||||
if (other != null) {
|
||||
out.writeU16(other.length);
|
||||
out.writeByteArray(other);
|
||||
}
|
||||
else {
|
||||
out.writeU16(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(alg);
|
||||
sb.append(" ");
|
||||
if (Options.check("multiline")) {
|
||||
sb.append("(")
|
||||
.append(OS.LINE_SEPARATOR)
|
||||
.append("\t");
|
||||
}
|
||||
sb.append(FormattedTime.format(timeInception));
|
||||
sb.append(" ");
|
||||
sb.append(FormattedTime.format(timeExpire));
|
||||
sb.append(" ");
|
||||
sb.append(modeString());
|
||||
sb.append(" ");
|
||||
sb.append(DnsResponseCode.TSIGstring(error));
|
||||
if (Options.check("multiline")) {
|
||||
sb.append(OS.LINE_SEPARATOR);
|
||||
if (key != null) {
|
||||
sb.append(Base64Fast.formatString(Base64Fast.encode2(key), 64, "\t", true));
|
||||
sb.append(OS.LINE_SEPARATOR);
|
||||
}
|
||||
if (other != null) {
|
||||
sb.append(Base64Fast.formatString(Base64Fast.encode2(other), 64, "\t", true));
|
||||
}
|
||||
sb.append(" )");
|
||||
}
|
||||
else {
|
||||
sb.append(" ");
|
||||
if (key != null) {
|
||||
sb.append("\t");
|
||||
sb.append(Base64Fast.encode2(key));
|
||||
|
||||
sb.append(" ");
|
||||
}
|
||||
if (other != null) {
|
||||
sb.append("\t");
|
||||
sb.append(Base64Fast.encode2(other));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
throw st.exception("no text format defined for TKEY");
|
||||
}
|
||||
|
||||
protected
|
||||
String modeString() {
|
||||
switch (mode) {
|
||||
case SERVERASSIGNED:
|
||||
return "SERVERASSIGNED";
|
||||
case DIFFIEHELLMAN:
|
||||
return "DIFFIEHELLMAN";
|
||||
case GSSAPI:
|
||||
return "GSSAPI";
|
||||
case RESOLVERASSIGNED:
|
||||
return "RESOLVERASSIGNED";
|
||||
case DELETE:
|
||||
return "DELETE";
|
||||
default:
|
||||
return Integer.toString(mode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TKEY Record from the given data.
|
||||
*
|
||||
* @param alg The shared key's algorithm
|
||||
* @param timeInception The beginning of the validity period of the shared
|
||||
* secret or keying material
|
||||
* @param timeExpire The end of the validity period of the shared
|
||||
* secret or keying material
|
||||
* @param mode The mode of key agreement
|
||||
* @param error The extended error field. Should be 0 in queries
|
||||
* @param key The shared secret
|
||||
* @param other The other data field. Currently unused
|
||||
* responses.
|
||||
*/
|
||||
public
|
||||
TKEYRecord(Name name,
|
||||
int dclass,
|
||||
long ttl,
|
||||
Name alg,
|
||||
Date timeInception,
|
||||
Date timeExpire,
|
||||
int mode,
|
||||
int error,
|
||||
byte[] key,
|
||||
byte other[]) {
|
||||
super(name, DnsRecordType.TKEY, dclass, ttl);
|
||||
this.alg = checkName("alg", alg);
|
||||
this.timeInception = timeInception;
|
||||
this.timeExpire = timeExpire;
|
||||
this.mode = checkU16("mode", mode);
|
||||
this.error = checkU16("error", error);
|
||||
this.key = key;
|
||||
this.other = other;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared key's algorithm
|
||||
*/
|
||||
public
|
||||
Name getAlgorithm() {
|
||||
return alg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the beginning of the validity period of the shared secret or
|
||||
* keying material
|
||||
*/
|
||||
public
|
||||
Date getTimeInception() {
|
||||
return timeInception;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the end of the validity period of the shared secret or
|
||||
* keying material
|
||||
*/
|
||||
public
|
||||
Date getTimeExpire() {
|
||||
return timeExpire;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key agreement mode
|
||||
*/
|
||||
public
|
||||
int getMode() {
|
||||
return mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the extended error
|
||||
*/
|
||||
public
|
||||
int getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the shared secret or keying material
|
||||
*/
|
||||
public
|
||||
byte[] getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the other data
|
||||
*/
|
||||
public
|
||||
byte[] getOther() {
|
||||
return other;
|
||||
}
|
||||
|
||||
}
|
176
src/dorkbox/network/dns/records/TLSARecord.java
Normal file
176
src/dorkbox/network/dns/records/TLSARecord.java
Normal file
|
@ -0,0 +1,176 @@
|
|||
// Copyright (c) 1999-2004 Brian Wellington (bwelling@xbill.org)
|
||||
|
||||
package dorkbox.network.dns.records;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import dorkbox.network.dns.Compression;
|
||||
import dorkbox.network.dns.DnsInput;
|
||||
import dorkbox.network.dns.DnsOutput;
|
||||
import dorkbox.network.dns.Name;
|
||||
import dorkbox.network.dns.constants.DnsRecordType;
|
||||
import dorkbox.network.dns.utils.Tokenizer;
|
||||
import dorkbox.network.dns.utils.base16;
|
||||
|
||||
/**
|
||||
* Transport Layer Security Authentication
|
||||
*
|
||||
* @author Brian Wellington
|
||||
*/
|
||||
|
||||
public
|
||||
class TLSARecord extends DnsRecord {
|
||||
|
||||
private static final long serialVersionUID = 356494267028580169L;
|
||||
private int certificateUsage;
|
||||
private int selector;
|
||||
private int matchingType;
|
||||
private byte[] certificateAssociationData;
|
||||
|
||||
|
||||
public static
|
||||
class CertificateUsage {
|
||||
public static final int CA_CONSTRAINT = 0;
|
||||
public static final int SERVICE_CERTIFICATE_CONSTRAINT = 1;
|
||||
public static final int TRUST_ANCHOR_ASSERTION = 2;
|
||||
public static final int DOMAIN_ISSUED_CERTIFICATE = 3;
|
||||
private
|
||||
CertificateUsage() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class Selector {
|
||||
/**
|
||||
* Full certificate; the Certificate binary structure defined in
|
||||
* [RFC5280]
|
||||
*/
|
||||
public static final int FULL_CERTIFICATE = 0;
|
||||
/**
|
||||
* SubjectPublicKeyInfo; DER-encoded binary structure defined in
|
||||
* [RFC5280]
|
||||
*/
|
||||
public static final int SUBJECT_PUBLIC_KEY_INFO = 1;
|
||||
|
||||
private
|
||||
Selector() {}
|
||||
}
|
||||
|
||||
|
||||
public static
|
||||
class MatchingType {
|
||||
/**
|
||||
* Exact match on selected content
|
||||
*/
|
||||
public static final int EXACT = 0;
|
||||
/**
|
||||
* SHA-256 hash of selected content [RFC6234]
|
||||
*/
|
||||
public static final int SHA256 = 1;
|
||||
/**
|
||||
* SHA-512 hash of selected content [RFC6234]
|
||||
*/
|
||||
public static final int SHA512 = 2;
|
||||
|
||||
private
|
||||
MatchingType() {}
|
||||
}
|
||||
|
||||
TLSARecord() {}
|
||||
|
||||
@Override
|
||||
DnsRecord getObject() {
|
||||
return new TLSARecord();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrFromWire(DnsInput in) throws IOException {
|
||||
certificateUsage = in.readU8();
|
||||
selector = in.readU8();
|
||||
matchingType = in.readU8();
|
||||
certificateAssociationData = in.readByteArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
void rrToWire(DnsOutput out, Compression c, boolean canonical) {
|
||||
out.writeU8(certificateUsage);
|
||||
out.writeU8(selector);
|
||||
out.writeU8(matchingType);
|
||||
out.writeByteArray(certificateAssociationData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts rdata to a String
|
||||
*/
|
||||
@Override
|
||||
void rrToString(StringBuilder sb) {
|
||||
sb.append(certificateUsage);
|
||||
sb.append(" ");
|
||||
sb.append(selector);
|
||||
sb.append(" ");
|
||||
sb.append(matchingType);
|
||||
sb.append(" ");
|
||||
sb.append(base16.toString(certificateAssociationData));
|
||||
}
|
||||
|
||||
@Override
|
||||
void rdataFromString(Tokenizer st, Name origin) throws IOException {
|
||||
certificateUsage = st.getUInt8();
|
||||
selector = st.getUInt8();
|
||||
matchingType = st.getUInt8();
|
||||
certificateAssociationData = st.getHex();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an TLSA Record from the given data
|
||||
*
|
||||
* @param certificateUsage The provided association that will be used to
|
||||
* match the certificate presented in the TLS handshake.
|
||||
* @param selector The part of the TLS certificate presented by the server
|
||||
* that will be matched against the association data.
|
||||
* @param matchingType How the certificate association is presented.
|
||||
* @param certificateAssociationData The "certificate association data" to be
|
||||
* matched.
|
||||
*/
|
||||
public
|
||||
TLSARecord(Name name, int dclass, long ttl, int certificateUsage, int selector, int matchingType, byte[] certificateAssociationData) {
|
||||
super(name, DnsRecordType.TLSA, dclass, ttl);
|
||||
this.certificateUsage = checkU8("certificateUsage", certificateUsage);
|
||||
this.selector = checkU8("selector", selector);
|
||||
this.matchingType = checkU8("matchingType", matchingType);
|
||||
this.certificateAssociationData = checkByteArrayLength("certificateAssociationData", certificateAssociationData, 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate usage of the TLSA record
|
||||
*/
|
||||
public
|
||||
int getCertificateUsage() {
|
||||
return certificateUsage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the selector of the TLSA record
|
||||
*/
|
||||
public
|
||||
int getSelector() {
|
||||
return selector;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the matching type of the TLSA record
|
||||
*/
|
||||
public
|
||||
int getMatchingType() {
|
||||
return matchingType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the certificate associate data of this TLSA record
|
||||
*/
|
||||
public final
|
||||
byte[] getCertificateAssociationData() {
|
||||
return certificateAssociationData;
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user