package org.freertr.pack; import java.util.ArrayList; import java.util.List; /** * domain name protocol (rfc1035) packet * * @author matecsaba */ public class packDns { /** * create instance */ public packDns() { } /** * default port number */ public final static int portNum = 53; /** * identifier */ public int id; /** * result code */ public int result; /** * operation code */ public int opcode; /** * recursion available */ public boolean recAvail; /** * recursion desired */ public boolean recDsrd; /** * truncated */ public boolean truncated; /** * authoritative answer */ public boolean authoritative; /** * query/response */ public boolean response; /** * queries */ public List queries = new ArrayList(); /** * answers */ public List answers = new ArrayList(); /** * name servers */ public List servers = new ArrayList(); /** * additional records */ public List addition = new ArrayList(); /** * standard query */ public final static int opcodeQuery = 0; /** * inverse query */ public final static int opcodeInquery = 1; /** * server status */ public final static int opcodeStatus = 2; /** * success */ public final static int resultSuccess = 0; /** * format error */ public final static int resultFormat = 1; /** * server error */ public final static int resultServer = 2; /** * name error */ public final static int resultName = 3; /** * not implemented */ public final static int resultSupport = 4; /** * not allowed */ public final static int resultRefused = 5; /** * recursion available */ public final int flagRecAvail = 0x0080; /** * recursion desired */ public final int flagRecDsrd = 0x0100; /** * truncated packet */ public final int flagTruncated = 0x0200; /** * authoritative answer */ public final int flagAuthoritative = 0x0400; /** * response */ public final int flagResponse = 0x8000; /** * convert opcode to string * * @param i opcode * @return string representing opcode */ public static String opcode2str(int i) { switch (i) { case opcodeQuery: return "query"; case opcodeInquery: return "inverse"; case opcodeStatus: return "status"; default: return "unknown=" + i; } } /** * convert result to string * * @param i result * @return string representing result */ public static String result2str(int i) { switch (i) { case resultSuccess: return "success"; case resultFormat: return "formatError"; case resultServer: return "serverError"; case resultName: return "nameError"; case resultSupport: return "notImplemented"; case resultRefused: return "refused"; default: return "unknown=" + i; } } private String listRRs(List lst) { String s = ""; for (int i = 0; i < lst.size(); i++) { packDnsRec ntry = lst.get(i); if (ntry == null) { continue; } List l = ntry.toUserStr(" ", "", false); for (int o = 0; o < l.size(); o++) { s += "(" + l.get(o) + ")"; } } return s; } public String toString() { return "op=" + opcode2str(opcode) + " res=" + result2str(result) + " id=" + id + " resp=" + response + " author=" + authoritative + " trunc=" + truncated + " recAvail=" + recAvail + " recDesired=" + recDsrd + " query=" + listRRs(queries) + " answer=" + listRRs(answers) + " server=" + listRRs(servers) + " addition=" + listRRs(addition); } private boolean readRRs(packHolder pck, List lst, int max, int beg, boolean question) { for (int i = 0; i < max;) { packDnsRec rr = new packDnsRec(); if (rr.parseHeader(pck, beg, question)) { return true; } lst.add(rr); i += rr.res.size(); } return false; } private int countRRs(List lst) { int o = 0; for (int i = 0; i < lst.size(); i++) { o += lst.get(i).res.size(); } return o; } private void writeRRs(packHolder pck, List lst, boolean question) { for (int i = 0; i < lst.size(); i++) { packDnsRec ntry = lst.get(i); ntry.createHeader(pck, question); } } /** * parse header * * @param pck packet to use * @return false if successful, true if error happened */ public boolean parseHeader(packHolder pck) { int msgBeg = pck.dataSize(); id = pck.msbGetW(0); // id int flag = pck.msbGetW(2); // flags recAvail = (flag & flagRecAvail) != 0; recDsrd = (flag & flagRecDsrd) != 0; truncated = (flag & flagTruncated) != 0; authoritative = (flag & flagAuthoritative) != 0; response = (flag & flagResponse) != 0; result = flag & 0xf; opcode = (flag >>> 11) & 0xf; int que = pck.msbGetW(4); // questions int ans = pck.msbGetW(6); // answers int aut = pck.msbGetW(8); // authoritative int add = pck.msbGetW(10); // additional pck.getSkip(12); readRRs(pck, queries, que, msgBeg, true); readRRs(pck, answers, ans, msgBeg, false); readRRs(pck, servers, aut, msgBeg, false); readRRs(pck, addition, add, msgBeg, false); return false; } /** * create header * * @param pck packet to use */ public void createHeader(packHolder pck) { int flag = (result & 0xf) | ((opcode & 0xf) << 11); if (recAvail) { flag |= flagRecAvail; } if (recDsrd) { flag |= flagRecDsrd; } if (truncated) { flag |= flagTruncated; } if (authoritative) { flag |= flagAuthoritative; } if (response) { flag |= flagResponse; } pck.msbPutW(0, id); pck.msbPutW(2, flag); pck.msbPutW(4, queries.size()); pck.msbPutW(6, countRRs(answers)); pck.msbPutW(8, countRRs(servers)); pck.msbPutW(10, countRRs(addition)); pck.putSkip(12); writeRRs(pck, queries, true); writeRRs(pck, answers, false); writeRRs(pck, servers, false); writeRRs(pck, addition, false); pck.merge2beg(); } }