/******************************************************************************* * gMix open source project - https://svs.informatik.uni-hamburg.de/gmix/ * Copyright (C) 2014 SVS * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. *******************************************************************************/ package staticContent.evaluation.traceParser.engine.protocolHeaderParser; import java.util.Arrays; import staticContent.framework.util.Util; /** * Can only read the first 12 bytes of a DNS header ("last" supported field: "Total Additional RRs") yet. */ public class DNSpacket { public enum OPcode { QUERY, IQUERY, STATUS, UNKNOWN, NOTIFY, UPDATE, RESERVED6, RESERVED7, RESERVED8, RESERVED9, RESERVED10, RESERVED11, RESERVED12, RESERVED13, RESERVED14, RESERVED15, }; public enum ReturnCode { NO_ERROR, // 0 FORMAT_ERROR, SERVER_FAILURE, NAME_ERROR, NOT_IMPLEMENTED, REFUSED, YX_DOMAIN, YXRR_SET, NXRR_SET, NOT_ZONE, // 10 UNKNOWN_11, UNKNOWN_12, UNKNOWN_13, UNKNOWN_14, UNKNOWN_15, BADVERS_BADSIG, BADKEY, BADTIME, BADMODE, BADNAME, // 20 BADALG, BADTRUNC, UNKNOWN // 23 - 65535 }; public static OPcode getOPcodeByUnsignedByteID(byte code) { return OPcode.values()[Util.unsignedByteToShort(code)]; } public static OPcode getOPcodeByID(int code) { return OPcode.values()[code]; } public static ReturnCode getReturnCodeByUnsignedByteID(byte code) { int index = Util.unsignedByteToShort(code); if (index > 22) return ReturnCode.UNKNOWN; else return ReturnCode.values()[index]; } public static ReturnCode getReturnCodeByID(int code) { if (code > 22) return ReturnCode.UNKNOWN; else return ReturnCode.values()[code]; } public static int getTransactionId(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 0, 2)); } public static byte[] getTransactionIdRaw(byte[] packet) { return Arrays.copyOfRange(packet, 0, 2); } public static String getTransactionIdAsString(byte[] packet) { return Util.toHex(Arrays.copyOfRange(packet, 0, 2)); } public static boolean isRequest(byte[] packet) { return !Util.getBitAt(7, packet[2]); } public static boolean isQuery(byte[] packet) { return isRequest(packet); } public static boolean isReply(byte[] packet) { return Util.getBitAt(7, packet[2]); } public static boolean isResponse(byte[] packet) { return isReply(packet); } public static int getOPcodeAsInt(byte[] packet) { byte result = 0; result = Util.setBitAt(3, Util.getBitAt(6, packet[2]), result); result = Util.setBitAt(2, Util.getBitAt(5, packet[2]), result); result = Util.setBitAt(1, Util.getBitAt(4, packet[2]), result); result = Util.setBitAt(0, Util.getBitAt(3, packet[2]), result); return Util.unsignedByteToShort(result); } public static OPcode getOPcode(byte[] packet) { return getOPcodeByID(getOPcodeAsInt(packet)); } public static boolean isAuthoritativeAnswer(byte[] packet) { return Util.getBitAt(2, packet[2]); } public static boolean isTruncated(byte[] packet) { return Util.getBitAt(1, packet[2]); } public static boolean isRecursionDesired(byte[] packet) { return Util.getBitAt(0, packet[2]); } public static boolean isRecursionAvailable(byte[] packet) { return Util.getBitAt(7, packet[3]); } public static boolean isZ(byte[] packet) { return Util.getBitAt(6, packet[3]); } public static boolean isAuthenticatedData(byte[] packet) { return Util.getBitAt(5, packet[3]); } public static boolean isCheckingDisabled(byte[] packet) { return Util.getBitAt(4, packet[3]); } public static boolean isNoneAuthenticatedDataAcceptable(byte[] packet) { return isCheckingDisabled(packet); } public static ReturnCode getReturnCode(byte[] packet) { return getReturnCodeByID(packet[3] & (0x0f)); } public static int getTotalQuestions(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 4, 6)); } public static int getTotalAnswerRRs(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 6, 8)); } public static int getTotalAuthorityRRs(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 8, 10)); } public static int getTotalAdditionalRRs(byte[] packet) { return Util.unsignedShortToInt(Arrays.copyOfRange(packet, 10, 12)); } public static String toString(byte[] packet) { StringBuffer sb = new StringBuffer(); sb.append("DNS header: \n"); sb.append(" transaction ID: " +DNSpacket.getTransactionId(packet) +"\n"); boolean isRequest = DNSpacket.isRequest(packet); sb.append(" is query (request): " +isRequest +"\n"); sb.append(" is resonse (reply): " +DNSpacket.isReply(packet) +"\n"); sb.append(" OP code: " +DNSpacket.getOPcode(packet) +"\n"); if (isRequest) { sb.append(" is truncated: " +DNSpacket.isTruncated(packet) +"\n"); sb.append(" is recursion desired: " +DNSpacket.isRecursionDesired(packet) +"\n"); sb.append(" is none authenticated data accepatble: " +DNSpacket.isNoneAuthenticatedDataAcceptable(packet) +"\n"); sb.append(" total questions: " +DNSpacket.getTotalQuestions(packet) +"\n"); sb.append(" total answer RRs: " +DNSpacket.getTotalAnswerRRs(packet) +"\n"); sb.append(" total authority RRs: " +DNSpacket.getTotalAuthorityRRs(packet) +"\n"); sb.append(" total additional RRs: " +DNSpacket.getTotalAdditionalRRs(packet)); } else { // reply sb.append(" is authoritative answer: " +DNSpacket.isAuthoritativeAnswer(packet) +"\n"); sb.append(" is truncated: " +DNSpacket.isTruncated(packet) +"\n"); sb.append(" is recursion desired: " +DNSpacket.isRecursionDesired(packet) +"\n"); sb.append(" is recursion available: " +DNSpacket.isRecursionAvailable(packet) +"\n"); sb.append(" is Z: " +DNSpacket.isZ(packet) +"\n"); sb.append(" is authenticated data: " +DNSpacket.isAuthenticatedData(packet) +"\n"); sb.append(" is none authenticated data accepatble: " +DNSpacket.isNoneAuthenticatedDataAcceptable(packet) +"\n"); sb.append(" return code: " +DNSpacket.getReturnCode(packet) +"\n"); sb.append(" total questions: " +DNSpacket.getTotalQuestions(packet) +"\n"); sb.append(" total answer RRs: " +DNSpacket.getTotalAnswerRRs(packet) +"\n"); sb.append(" total authority RRs: " +DNSpacket.getTotalAuthorityRRs(packet) +"\n"); sb.append(" total additional RRs: " +DNSpacket.getTotalAdditionalRRs(packet)); } return sb.toString(); } }