/*
* Copyright 2009 NCHOVY
*
* 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 org.krakenapps.dns;
/**
* @author mindori
*/
public class DnsFlags {
private boolean isQuery;
private byte opCode;
private boolean isAuthoritativeAnswer;
private boolean isTruncated;
private boolean isRecursionDesired;
private boolean isRecursionAvailable;
// reserved bit(== 0)
private boolean isAnswerAuthenticated;
private boolean isNonAuthenticatedDataOK;
private DnsResponseCode responseCode = DnsResponseCode.NO_ERROR;
public DnsFlags() {
}
public DnsFlags(short bits) {
setBits(bits);
}
public short getBits() {
short bits = 0;
bits |= bit(!isQuery) << 15;
bits |= opCode << 11;
bits |= bit(isAuthoritativeAnswer) << 10;
bits |= bit(isTruncated) << 9;
bits |= bit(isRecursionDesired) << 8;
bits |= bit(isRecursionAvailable) << 7;
bits |= bit(isAnswerAuthenticated) << 5;
bits |= bit(isNonAuthenticatedDataOK) << 4;
bits |= responseCode.getCode();
return bits;
}
private int bit(boolean b) {
return b ? 1 : 0;
}
public void setBits(short bits) {
short s = bits;
setQuery(((s & 0x8000) >> 15) == 0);
setOpCode((byte) ((s & 0x7800) >> 11));
setAuthoritativeAnswer(((s & 0x0400) >> 10) != 0);
setTruncated(((s & 0x0200) >> 9) != 0);
setRecursionDesired(((s & 0x0100) >> 8) != 0);
setRecursionAvailable(((s & 0x0080) >> 7) != 0);
setAnswerAuthenticated(((s & 0x0020) >> 5) != 0);
setNonAuthenticatedDataOK(((s & 0x0010) >> 4) != 0);
DnsResponseCode rcode = DnsResponseCode.parse(s & 0xf);
if (rcode == null)
throw new IllegalStateException("invalid response code: " + (s & 0xf));
setResponseCode(rcode);
}
public boolean isQuery() {
return isQuery;
}
public void setQuery(boolean isQuery) {
this.isQuery = isQuery;
}
public byte getOpCode() {
return opCode;
}
public void setOpCode(byte opCode) {
if (opCode < 0 || opCode > 2)
throw new IllegalArgumentException("invalid dns opcode: " + opCode);
this.opCode = opCode;
}
public boolean isAuthoritativeAnswer() {
return isAuthoritativeAnswer;
}
public void setAuthoritativeAnswer(boolean isAuthoritativeAnswer) {
this.isAuthoritativeAnswer = isAuthoritativeAnswer;
}
public boolean isTruncated() {
return isTruncated;
}
public void setTruncated(boolean isTruncated) {
this.isTruncated = isTruncated;
}
public boolean isRecursionDesired() {
return isRecursionDesired;
}
public void setRecursionDesired(boolean isRecursionDesired) {
this.isRecursionDesired = isRecursionDesired;
}
public boolean isRecursionAvailable() {
return isRecursionAvailable;
}
public void setRecursionAvailable(boolean isRecursionAvailable) {
this.isRecursionAvailable = isRecursionAvailable;
}
public boolean isAnswerAuthenticated() {
return isAnswerAuthenticated;
}
public void setAnswerAuthenticated(boolean isAnswerAuthenticated) {
this.isAnswerAuthenticated = isAnswerAuthenticated;
}
public boolean isNonAuthenticatedDataOK() {
return isNonAuthenticatedDataOK;
}
public void setNonAuthenticatedDataOK(boolean isNonAuthenticatedDataOK) {
this.isNonAuthenticatedDataOK = isNonAuthenticatedDataOK;
}
public DnsResponseCode getResponseCode() {
return responseCode;
}
public void setResponseCode(DnsResponseCode responseCode) {
this.responseCode = responseCode;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
if (opCode == 0)
sb.append("standard query");
else if (opCode == 1)
sb.append("inverse query");
else if (opCode == 2)
sb.append("server status request");
if (!isQuery)
sb.append(" response ");
else
sb.append(" ");
String flagsDesc = getFlagsDesc();
if (!flagsDesc.isEmpty()) {
sb.append("(");
sb.append(flagsDesc);
sb.append(") ");
}
return sb.toString();
}
private String getFlagsDesc() {
StringBuilder sb = new StringBuilder();
boolean first = true;
if (isAuthoritativeAnswer) {
if (first)
first = false;
else
sb.append(" ");
sb.append("AA");
}
if (isTruncated) {
if (first)
first = false;
else
sb.append(" ");
sb.append("TC");
}
if (isRecursionDesired) {
if (first)
first = false;
else
sb.append(" ");
sb.append("RD");
}
if (isRecursionAvailable) {
if (first)
first = false;
else
sb.append(" ");
sb.append("RA");
}
if (responseCode != DnsResponseCode.NO_ERROR) {
if (first)
first = false;
else
sb.append(" ");
sb.append(responseCode.getDescription());
}
return sb.toString();
}
}