WIP cleaning up DNS flags

This commit is contained in:
nathan 2018-03-28 14:27:37 +02:00
parent c69d048a75
commit f889399ecf
8 changed files with 324 additions and 155 deletions

View File

@ -0,0 +1,81 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed 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.constants;
import dorkbox.network.dns.Mnemonic;
/**
* Constants and functions relating to EDNS flags.
*
* @author Brian Wellington
*/
public
enum ExtendedFlags {
/**
* dnssec ok
*/
DO(0x8000, "do");
private static Mnemonic extflags = new Mnemonic("EDNS Flag", Mnemonic.CASE_LOWER);
static {
extflags.setMaximum(0xFFFF);
extflags.setPrefix("FLAG");
extflags.setNumericAllowed(true);
extflags.add(DO.flagValue, "do");
}
private final byte flagValue;
private final String textValue;
ExtendedFlags(final int flagValue, final String textValue) {
this.flagValue = (byte) flagValue;
this.textValue = textValue;
}
public
byte value() {
return flagValue;
}
public
String string() {
return textValue;
}
/**
* 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);
}
}

View File

@ -3,103 +3,147 @@
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
* In DNS query header there is a flag field in the second 16 bit word in query from bit 5 through bit 11 ([RFC1035] section 4.1.1)
*
* https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-12
*/
public final
class Flags {
private static Mnemonic flags = new Mnemonic("DNS Header Flag", Mnemonic.CASE_LOWER);
public
enum Flags {
/**
* query/response
*/
public static final byte QR = 0;
QR(0, "qr"),
/**
* authoritative answer
*/
public static final byte AA = 5;
AA(5, "aa"),
/**
* truncated
*/
public static final byte TC = 6;
TC(6, "tc"),
/**
* recursion desired
*/
public static final byte RD = 7;
RD(7, "rd"),
/**
* recursion available
*/
public static final byte RA = 8;
RA(8, "ra"),
/**
* RESERVED
*/
RESERVED(9, "__"),
/**
* authenticated data
*/
public static final byte AD = 10;
AD(10, "ad"),
/**
* (security) checking disabled
*/
public static final byte CD = 11;
CD(11, "cd"),
/**
* dnssec ok (extended)
*/
public static final int DO = ExtendedFlags.DO;
DO(ExtendedFlags.DO.value(), ExtendedFlags.DO.string());
private static Mnemonic flags = new Mnemonic("DNS Header Flag", Mnemonic.CASE_LOWER);
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");
flags.add(QR.flagValue, "qr");
flags.add(AA.flagValue, "aa");
flags.add(TC.flagValue, "tc");
flags.add(RD.flagValue, "rd");
flags.add(RA.flagValue, "ra");
flags.add(AD.flagValue, "ad");
flags.add(CD.flagValue, "cd");
}
private final byte flagValue;
private final String textValue;
Flags(final int flagValue, final String textValue) {
this.flagValue = (byte) flagValue;
this.textValue = textValue;
}
public
byte value() {
return flagValue;
}
public
String string() {
return textValue;
}
private
Flags() {}
/**
* Converts a numeric Flag into a String
*/
public static
String string(int i) {
return flags.getText(i);
Flags toFlag(final int flagBit) {
for (Flags flag : values()) {
if (flag.value() == flagBit) {
return flag;
}
}
throw new IllegalArgumentException("Invalid flag " + flagBit);
}
/**
* Converts a String representation of an Flag into its numeric value
*/
public static
int value(String s) {
return flags.getValue(s);
Flags toFlag(final String flagName) {
for (Flags flag : values()) {
if (flag.string().equals(flagName)) {
return flag;
}
}
throw new IllegalArgumentException("Invalid flag " + flagName);
}
// /**
// * 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.
* 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)) {
// Checks that a numeric value is within the range
if (index < 0 || index > 0xF || (index >= 1 && index <= 4) || (index >= 12)) {
return false;
}
return true;
}
}

View File

@ -1,51 +0,0 @@
// 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);
}
}

View File

@ -138,33 +138,40 @@ class Header implements Cloneable {
* @see Flags
*/
public
void setFlag(int bit) {
checkFlag(bit);
flags = setFlag(flags, bit, true);
void setFlag(Flags flag) {
checkFlag(flag);
flags = setFlag(flags, flag, true);
}
static private
void checkFlag(int bit) {
if (!validFlag(bit)) {
throw new IllegalArgumentException("invalid flag bit " + bit);
void checkFlag(int flag) {
if (!Flags.isFlag(flag)) {
throw new IllegalArgumentException("invalid flag bit " + flag);
}
}
static private
boolean validFlag(int bit) {
return (bit >= 0 && bit <= 0xF && Flags.isFlag(bit));
void checkFlag(Flags flag) {
if (!validFlag(flag)) {
throw new IllegalArgumentException("invalid flag bit " + flag);
}
}
static private
boolean validFlag(Flags flag) {
return flag != null && (flag.value() >= 0 && flag.value() <= 0xF && Flags.isFlag(flag.value()));
}
static
int setFlag(int flags, int bit, boolean value) {
checkFlag(bit);
int setFlag(int flags, Flags flag, boolean value) {
checkFlag(flag);
// bits are indexed from left to right
if (value) {
return flags |= (1 << (15 - bit));
return flags |= (1 << (15 - flag.value()));
}
else {
return flags &= ~(1 << (15 - bit));
return flags &= ~(1 << (15 - flag.value()));
}
}
@ -174,15 +181,15 @@ class Header implements Cloneable {
* @see Flags
*/
public
void unsetFlag(int bit) {
checkFlag(bit);
flags = setFlag(flags, bit, false);
void unsetFlag(Flags flag) {
checkFlag(flag);
flags = setFlag(flags, flag, false);
}
boolean[] getFlags() {
boolean[] array = new boolean[16];
for (int i = 0; i < array.length; i++) {
if (validFlag(i)) {
if (Flags.isFlag(i)) {
array[i] = getFlag(i);
}
}
@ -195,10 +202,21 @@ class Header implements Cloneable {
* @see Flags
*/
public
boolean getFlag(int bit) {
checkFlag(bit);
boolean getFlag(Flags flag) {
// bit s are indexed from left to right
return (flags & (1 << (15 - flag.value()))) != 0;
}
/**
* Retrieves a flag.
*
* @param flagValue ALWAYS checked before using, so additional checks are not necessary
* @see Flags
*/
private
boolean getFlag(int flagValue) {
// bits are indexed from left to right
return (flags & (1 << (15 - bit))) != 0;
return (flags & (1 << (15 - flagValue))) != 0;
}
void setCount(int field, int value) {
@ -328,13 +346,13 @@ class Header implements Cloneable {
/**
* 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));
if (Flags.isFlag(i) && getFlag(i)) {
Flags flag = Flags.toFlag(i);
sb.append(flag.string());
sb.append(" ");
}
}

View File

@ -34,7 +34,7 @@
//
package dorkbox.network.dns;
import dorkbox.network.dns.records.ExtendedFlags;
import dorkbox.network.dns.constants.ExtendedFlags;
import junit.framework.TestCase;
public
@ -42,7 +42,7 @@ class ExtendedFlagsTest extends TestCase {
public
void test_string() {
// a regular one
assertEquals("do", ExtendedFlags.string(ExtendedFlags.DO));
assertEquals("do", ExtendedFlags.DO.string());
// one that doesn't exist
assertTrue(ExtendedFlags.string(1)
@ -65,7 +65,7 @@ class ExtendedFlagsTest extends TestCase {
public
void test_value() {
// regular one
assertEquals(ExtendedFlags.DO, ExtendedFlags.value("do"));
assertEquals(ExtendedFlags.DO.value(), ExtendedFlags.value("do"));
// one thats undefined but within range
assertEquals(16, ExtendedFlags.value("FLAG16"));

View File

@ -42,42 +42,61 @@ class FlagsTest extends TestCase {
public
void test_string() {
// a regular one
assertEquals("aa", Flags.string(Flags.AA));
assertEquals("aa", Flags.AA.string());
// one that doesn't exist
assertTrue(Flags.string(12)
.startsWith("flag"));
try {
Flags.toFlag(12);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException ignored) {
}
try {
Flags.string(-1);
Flags.toFlag(-1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
} catch (IllegalArgumentException ignored) {
}
// (max is 0xF)
try {
Flags.string(0x10);
Flags.toFlag(0x10);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
} catch (IllegalArgumentException ignored) {
}
}
public
void test_value() {
// regular one
assertEquals(Flags.CD, Flags.value("cd"));
assertEquals(Flags.CD, Flags.toFlag("cd"));
// one thats undefined but within range
assertEquals(13, Flags.value("FLAG13"));
// one that's undefined but within range
try {
Flags.toFlag("FLAG13");
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException ignored) {
}
// one thats undefined but out of range
assertEquals(-1, Flags.value("FLAG" + 0x10));
// one that's undefined but out of range
try {
Flags.toFlag("FLAG" + 0x10);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException ignored) {
}
// something that unknown
assertEquals(-1, Flags.value("THIS IS DEFINITELY UNKNOWN"));
// something that's unknown
try {
Flags.toFlag("THIS IS DEFINITELY UNKNOWN");
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException ignored) {
}
// empty string
assertEquals(-1, Flags.value(""));
try {
Flags.toFlag("");
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException ignored) {
}
}
public
@ -85,8 +104,9 @@ class FlagsTest extends TestCase {
try {
Flags.isFlag(-1);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
} catch (IllegalArgumentException ignored) {
}
assertTrue(Flags.isFlag(0));
assertFalse(Flags.isFlag(1)); // opcode
assertFalse(Flags.isFlag(2));
@ -102,11 +122,12 @@ class FlagsTest extends TestCase {
assertFalse(Flags.isFlag(12));
assertFalse(Flags.isFlag(13));
assertFalse(Flags.isFlag(14));
assertFalse(Flags.isFlag(14));
assertFalse(Flags.isFlag(15));
try {
Flags.isFlag(16);
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
} catch (IllegalArgumentException ignored) {
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2018 dorkbox, llc.
*
* Licensed 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;
import org.junit.Test;
import dorkbox.network.dns.constants.DnsClass;
import dorkbox.network.dns.exceptions.TextParseException;
import dorkbox.network.dns.server.Response;
import dorkbox.network.dns.zone.AbstractZone;
import dorkbox.network.dns.zone.ZoneDatabase;
import dorkbox.network.dns.zone.ZoneType;
import junit.framework.TestCase;
public
class ZoneDatabaseTest extends TestCase {
class TestZone extends AbstractZone {
public
TestZone(String name) throws TextParseException {
super(ZoneType.master, Name.fromString(name));
}
@Override
public
Response find(final Name qname, final int recordType) {
return null;
}
}
@Test
public
void testFind() throws TextParseException {
ZoneDatabase db = new ZoneDatabase();
db.add(new TestZone("example.com."));
db.add(new TestZone("example.co.jp."));
db.add(new TestZone("jp."));
db.add(new TestZone("ne.jp."));
assertNotNull(db.prepare(Name.fromString("jp."), DnsClass.IN));
assertNull(db.prepare(Name.fromString("com."), DnsClass.IN));
}
}

View File

@ -165,23 +165,23 @@ class HeaderTest extends TestCase {
public
void test_flags() {
m_h.setFlag(0);
m_h.setFlag(5);
assertTrue(m_h.getFlag(0));
m_h.setFlag(Flags.toFlag(0));
m_h.setFlag(Flags.toFlag(5));
assertTrue(m_h.getFlag(Flags.toFlag(0)));
assertTrue(m_h.getFlags()[0]);
assertTrue(m_h.getFlag(5));
assertTrue(m_h.getFlag(Flags.toFlag(5)));
assertTrue(m_h.getFlags()[5]);
m_h.unsetFlag(0);
assertFalse(m_h.getFlag(0));
m_h.unsetFlag(Flags.toFlag(0));
assertFalse(m_h.getFlag(Flags.toFlag(0)));
assertFalse(m_h.getFlags()[0]);
assertTrue(m_h.getFlag(5));
assertTrue(m_h.getFlag(Flags.toFlag(5)));
assertTrue(m_h.getFlags()[5]);
m_h.unsetFlag(5);
assertFalse(m_h.getFlag(0));
m_h.unsetFlag(Flags.toFlag(5));
assertFalse(m_h.getFlag(Flags.toFlag(0)));
assertFalse(m_h.getFlags()[0]);
assertFalse(m_h.getFlag(5));
assertFalse(m_h.getFlag(Flags.toFlag(5)));
assertFalse(m_h.getFlags()[5]);
boolean[] flags = m_h.getFlags();
@ -196,47 +196,47 @@ class HeaderTest extends TestCase {
public
void test_flags_invalid() {
try {
m_h.setFlag(-1);
m_h.setFlag(Flags.toFlag(-1));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.setFlag(1);
m_h.setFlag(Flags.toFlag(1));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.setFlag(16);
m_h.setFlag(Flags.toFlag(16));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.unsetFlag(-1);
m_h.unsetFlag(Flags.toFlag(-1));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.unsetFlag(13);
m_h.unsetFlag(Flags.toFlag(13));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.unsetFlag(16);
m_h.unsetFlag(Flags.toFlag(16));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.getFlag(-1);
m_h.getFlag(Flags.toFlag(-1));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.getFlag(4);
m_h.getFlag(Flags.toFlag(4));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
try {
m_h.getFlag(16);
m_h.getFlag(Flags.toFlag(16));
fail("IllegalArgumentException not thrown");
} catch (IllegalArgumentException e) {
}
@ -280,7 +280,7 @@ class HeaderTest extends TestCase {
if ((i > 0 && i < 5) || i > 11) {
continue;
}
assertFalse(m_h.getFlag(i));
assertFalse(m_h.getFlag(Flags.toFlag(i)));
}
}
@ -305,9 +305,9 @@ class HeaderTest extends TestCase {
m_h.setOpcode(0xE); // 1110
assertEquals(0xE, m_h.getOpcode());
assertFalse(m_h.getFlag(0));
assertFalse(m_h.getFlag(Flags.toFlag(0)));
for (int i = 5; i < 12; ++i) {
assertFalse(m_h.getFlag(i));
assertFalse(m_h.getFlag(Flags.toFlag(i)));
}
assertEquals(0, m_h.getRcode());
}
@ -446,7 +446,7 @@ class HeaderTest extends TestCase {
if ((i > 0 && i < 5) || i > 11) {
continue;
}
assertEquals(m_h.getFlag(i), h2.getFlag(i));
assertEquals(m_h.getFlag(Flags.toFlag(i)), h2.getFlag(Flags.toFlag(i)));
}
for (int i = 0; i < 4; ++i) {
assertEquals(m_h.getCount(i), h2.getCount(i));