/* Returns true if the message could be rendered. */ private boolean toWire(DNSOutput out, int maxLength) { if (maxLength < Header.LENGTH) return false; Header newheader = null; int tempMaxLength = maxLength; if (tsigkey != null) tempMaxLength -= tsigkey.recordLength(); OPTRecord opt = getOPT(); byte[] optBytes = null; if (opt != null) { optBytes = opt.toWire(Section.ADDITIONAL); tempMaxLength -= optBytes.length; } int startpos = out.current(); header.toWire(out); Compression c = new Compression(); int flags = header.getFlagsByte(); int additionalCount = 0; for (int i = 0; i < 4; i++) { int skipped; if (sections[i] == null) continue; skipped = sectionToWire(out, i, c, tempMaxLength); if (skipped != 0 && i != Section.ADDITIONAL) { flags = Header.setFlag(flags, Flags.TC, true); out.writeU16At(header.getCount(i) - skipped, startpos + 4 + 2 * i); for (int j = i + 1; j < Section.ADDITIONAL; j++) out.writeU16At(0, startpos + 4 + 2 * j); break; } if (i == Section.ADDITIONAL) additionalCount = header.getCount(i) - skipped; } if (optBytes != null) { out.writeByteArray(optBytes); additionalCount++; } if (flags != header.getFlagsByte()) out.writeU16At(flags, startpos + 2); if (additionalCount != header.getCount(Section.ADDITIONAL)) out.writeU16At(additionalCount, startpos + 10); if (tsigkey != null) { TSIGRecord tsigrec = tsigkey.generate(this, out.toByteArray(), tsigerror, querytsig); tsigrec.toWire(out, Section.ADDITIONAL, c); out.writeU16At(additionalCount + 1, startpos + 10); } return true; }
/* Returns true if the message could be rendered. */ private boolean toWire(DNSOutput out, int maxLength) { if (maxLength < Header.LENGTH) return false; Header newheader = null; int tempMaxLength = maxLength; if (tsigkey != null) tempMaxLength -= tsigkey.recordLength(); int startpos = out.current(); header.toWire(out); Compression c = new Compression(); for (int i = 0; i < 4; i++) { int skipped; if (sections[i] == null) continue; skipped = sectionToWire(out, i, c, tempMaxLength); if (skipped != 0) { if (i != Section.ADDITIONAL) { if (newheader == null) newheader = (Header) header.clone(); newheader.setFlag(Flags.TC); int count = newheader.getCount(i); newheader.setCount(i, count - skipped); for (int j = i + 1; j < 4; j++) newheader.setCount(j, 0); out.save(); out.jump(startpos); newheader.toWire(out); out.restore(); } break; } } if (tsigkey != null) { TSIGRecord tsigrec = tsigkey.generate(this, out.toByteArray(), tsigerror, querytsig); if (newheader == null) newheader = (Header) header.clone(); tsigrec.toWire(out, Section.ADDITIONAL, c); newheader.incCount(Section.ADDITIONAL); out.save(); out.jump(startpos); newheader.toWire(out); out.restore(); } return true; }
/** * Sends a message to a single server and waits for a response. No checking is done to ensure that * the response is associated with the query. * * @param query The query to send. * @return The response. * @throws IOException An error occurred while sending or receiving. */ public Message send(Message query) throws IOException { if (Options.check("verbose")) System.err.println( "Sending to " + address.getAddress().getHostAddress() + ":" + address.getPort()); if (query.getHeader().getOpcode() == Opcode.QUERY) { Record question = query.getQuestion(); if (question != null && question.getType() == Type.AXFR) return sendAXFR(query); } query = (Message) query.clone(); applyEDNS(query); if (tsig != null) { tsig.apply(query, null); } byte[] out = query.toWire(Message.MAXLENGTH); int udpSize = maxUDPSize(query); boolean tcp = false; long endTime = System.currentTimeMillis() + timeoutValue; do { byte[] b_in; if (useTCP || out.length > udpSize) { tcp = true; } if (tcp) { b_in = TCPClient.sendrecv(localAddress, address, out, endTime); } else { b_in = UDPClient.sendrecv(localAddress, address, out, udpSize, endTime); } /* * Check that the response is long enough. */ if (b_in.length < Header.LENGTH) { throw new WireParseException("invalid DNS header - " + "too short"); } /* * Check that the response ID matches the query ID. We want * to check this before actually parsing the message, so that * if there's a malformed response that's not ours, it * doesn't confuse us. */ int id = ((b_in[0] & 0xFF) << 8) + (b_in[1] & 0xFF); int qid = query.getHeader().getID(); if (id != qid) { String error = "invalid message id: expected " + qid + "; got id " + id; if (tcp) { throw new WireParseException(error); } else { if (Options.check("verbose")) { System.err.println(error); } continue; } } Message response = parseMessage(b_in); verifyTSIG(query, response, b_in, tsig); if (!tcp && !ignoreTruncation && response.getHeader().getFlag(Flags.TC)) { tcp = true; continue; } return response; } while (true); }
private void verifyTSIG(Message query, Message response, byte[] b, TSIG tsig) { if (tsig == null) return; int error = tsig.verify(response, b, query.getTSIG()); if (Options.check("verbose")) System.err.println("TSIG verify: " + Rcode.TSIGstring(error)); }