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