@Override public void run() { while (running) { try { buf.clear(); SocketAddress src = channel.receive(buf); buf.flip(); if (src != null) { log.debug("Received datagram from " + src); Message message = new Message(buf); if (message.getHeader().getOpcode() == Opcode.QUERY) { // Dispatch workers.execute(new ForwardTask(channel, src, message, workers)); } } } catch (IOException e) { e.printStackTrace(); } } }
static void doAXFR(Message response) throws IOException { System.out.println("; java dig 0.0 <> " + name + " axfr"); if (response.isSigned()) { System.out.print(";; TSIG "); if (response.isVerified()) System.out.println("ok"); else System.out.println("failed"); } if (response.getRcode() != Rcode.NOERROR) { System.out.println(response); return; } Record [] records = response.getSectionArray(Section.ANSWER); for (int i = 0; i < records.length; i++) System.out.println(records[i]); System.out.print(";; done ("); System.out.print(response.getHeader().getCount(Section.ANSWER)); System.out.print(" records, "); System.out.print(response.getHeader().getCount(Section.ADDITIONAL)); System.out.println(" additional)"); }
/** * Dns lookup more efficient than the INetAddress.getHostName(ip) * * @param hostIp * @return * @throws IOException */ public String dnsLookup(final String hostIp) { try { final Name name = ReverseMap.fromAddress(hostIp); final int type = Type.PTR; final int dclass = DClass.IN; final Record rec = Record.newRecord(name, type, dclass); final Message query = Message.newQuery(rec); final Message response = _resolver.send(query); final Record[] answers = response.getSectionArray(Section.ANSWER); if (answers.length > 0) { String ret = answers[0].rdataToString(); if (ret.endsWith(".")) { ret = ret.substring(0, ret.length() - 1); } return ret; } } catch (final IOException e) { LOGGER.warn("Failed to resolve hostname for " + hostIp, e); } return UNKNOWN_HOST; }
public static int getPortFromResponse(Message m) { for (int i = 0; i < 4; i++) { try { // Can do something with the counts field here, instead of // cycling through all of these Record[] records = m.getSectionArray(i); if (records != null) { for (int j = 0; j < records.length; j++) { if ((records[j]).getClass().equals(TXTRecord.class)) { return Integer.valueOf( ((String) (((TXTRecord) (records[j])) .getStrings().get(0)))).intValue(); } } } } catch (IndexOutOfBoundsException e) { // carry on! } } return -999; }
@Test public void testPublishDomainFails_whenDnsUpdateReturnsError() throws Exception { DomainResource domain = persistActiveDomain("example.tld") .asBuilder() .setNameservers(ImmutableSet.of(Key.create(persistActiveHost("ns1.example.tld")))) .build(); persistResource(domain); when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL)); VerifyException thrown = expectThrows( VerifyException.class, () -> { writer.publishDomain("example.tld"); writer.commit(); }); assertThat(thrown).hasMessageThat().contains("SERVFAIL"); }
@Test public void testPublishHostFails_whenDnsUpdateReturnsError() throws Exception { HostResource host = persistActiveSubordinateHost("ns1.example.tld", persistActiveDomain("example.tld")) .asBuilder() .setInetAddresses(ImmutableSet.of(InetAddresses.forString("10.0.0.1"))) .build(); persistResource(host); when(mockResolver.send(any(Message.class))).thenReturn(messageWithResponseCode(Rcode.SERVFAIL)); VerifyException thrown = expectThrows( VerifyException.class, () -> { writer.publishHost("ns1.example.tld"); writer.commit(); }); assertThat(thrown).hasMessageThat().contains("SERVFAIL"); }
/** * @param ip, like "192.168.1.1" * @return the complete DNS record for that IP. */ @Converter public static Record toRecord(String ip) throws IOException { Resolver res = new ExtendedResolver(); Name name = ReverseMap.fromAddress(ip); int type = Type.PTR; int dclass = DClass.IN; Record rec = Record.newRecord(name, type, dclass); Message query = Message.newQuery(rec); Message response = res.send(query); Record[] answers = response.getSectionArray(Section.ANSWER); if (answers.length == 0) { return null; } else { return answers[0]; } }
@Test @Ignore("Testing behind nat produces timeouts") public void testDigForMonkey() throws Exception { resultEndpoint.expectedMessageCount(1); resultEndpoint.expectedMessagesMatches(new Predicate() { public boolean matches(Exchange exchange) { String str = ((Message) exchange.getIn().getBody()).getSectionArray(Section.ANSWER)[0].rdataToString(); return RESPONSE_MONKEY.equals(str); } }); Map<String, Object> headers = new HashMap<String, Object>(); headers.put("dns.name", "monkey.wp.dg.cx"); headers.put("dns.type", "TXT"); template.sendBodyAndHeaders(null, headers); resultEndpoint.assertIsSatisfied(); }
private static void dump(DatagramPacket packet, boolean send) { if (!verbose) { return; } StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); out.println((send ? "Sent to " : "Received from ") + packet.getAddress().getHostAddress()); byte[] data = Bytes.sub(packet.getData(), packet.getOffset(), packet.getLength()); Bytes.dump(out, data); try { out.println(new Message(data)); } catch (IOException e) { out.println(e.getMessage()); } Log.d(sw.toString()); }
public static void main(String[] args) throws Exception { try (DatagramSocket socket = new DatagramSocket()) { Message message = new Message(); Header header = message.getHeader(); header.setOpcode(Opcode.QUERY); header.setID(1); header.setRcode(Rcode.NOERROR); header.setFlag(Flags.RD); message.addRecord(Record.newRecord(new Name("www.xqbase.com."), Type.A, DClass.IN), Section.QUESTION); byte[] data = message.toWire(); DatagramPacket packet = new DatagramPacket(data, data.length, new InetSocketAddress("localhost", 53)); socket.send(packet); data = new byte[65536]; packet = new DatagramPacket(data, data.length); socket.setSoTimeout(2000); socket.receive(packet); Message response = new Message(Bytes.left(data, packet.getLength())); System.out.println(response); } }
private String[] findAddressesRecursive(Set<Name> stack, Name target) throws IOException { String[] ipv4Addresses = null; String[] ipv6Addresses = null; Message ipv4 = lookup(stack, getRoots(), Message.newQuery(Record.newRecord(target, Type.A, DClass.IN))); if (ipv4 != null) ipv4Addresses = findAddresses(target, ipv4.getSectionArray(Section.ANSWER)); Message ipv6 = lookup(stack, getRoots(), Message.newQuery(Record.newRecord(target, Type.AAAA, DClass.IN))); if (ipv6 != null) ipv6Addresses = findAddresses(target, ipv6.getSectionArray(Section.ANSWER)); String[] addresses = new String[0]; if (ipv4Addresses != null) addresses = ipv4Addresses; if (ipv6Addresses != null) { String[] concatAddresses = new String[addresses.length + ipv6Addresses.length]; System.arraycopy(addresses, 0, concatAddresses, 0, addresses.length); System.arraycopy(ipv6Addresses, 0, concatAddresses, addresses.length, ipv6Addresses.length); addresses = concatAddresses; } if (addresses.length == 0) return null; return addresses; }
private Message getCached(Message query) { Cache cache = getCache(); if (cache == null) return null; Record question = query.getQuestion(); RRset[] rrsets = cache.findAnyRecords(question.getName(), question.getType()); if (rrsets == null) return null; Message msg = new Message(); for (RRset rrset : rrsets) { @SuppressWarnings("unchecked") Iterator<Record> recordsIter = rrset.rrs(); while (recordsIter.hasNext()) { msg.addRecord(recordsIter.next(), Section.ANSWER); } } return msg; }
private void processDNSKEYResponse(Message request, SMessage response, FindKeyState state) { Name qname = request.getQuestion().getName(); int qclass = request.getQuestion().getDClass(); SRRset dnskeyRrset = response.findAnswerRRset(qname, Type.DNSKEY, qclass); if (dnskeyRrset == null) { // If the DNSKEY rrset was missing, this is the end of the line. state.keyEntry = KeyEntry.newBadKeyEntry(qname, qclass, DEFAULT_TA_BAD_KEY_TTL); state.keyEntry.setBadReason(R.get("dnskey.no_rrset", qname)); return; } state.keyEntry = this.valUtils.verifyNewDNSKEYs(dnskeyRrset, state.dsRRset, DEFAULT_TA_BAD_KEY_TTL); // If the key entry isBad or isNull, then we can move on to the next // state. if (!state.keyEntry.isGood()) { return; } // The DNSKEY validated, so cache it as a trusted key rrset. this.keyCache.store(state.keyEntry); // If good, we stay in the FINDKEY state. this.processFindKey(state); }
@Test public void testUnsignedThatMustBeSigned() throws IOException { Name query = Name.fromString("www.ingotronic.ch."); // prepare a faked, unsigned response message that must have a signature // to be valid Message message = new Message(); message.addRecord(Record.newRecord(query, Type.A, DClass.IN), Section.QUESTION); message.addRecord(new ARecord(query, Type.A, DClass.IN, InetAddress.getByName(localhost)), Section.ANSWER); add("www.ingotronic.ch./A", message); Message response = resolver.send(createMessage("www.ingotronic.ch./A")); assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD)); assertEquals(Rcode.SERVFAIL, response.getRcode()); assertEquals("validate.bogus.missingsig", getReason(response)); }
@Test public void testDNameWithNoCnameIsValid() throws IOException { Message m = resolver.send(createMessage("www.isc.ingotronic.ch./A")); Message message = messageFromString(m.toString().replaceAll("(.*CNAME.*)", "").replaceAll("\n\n", "\n")); add("www.isc.ingotronic.ch./A", message); Message response = resolver.send(createMessage("www.isc.ingotronic.ch./A")); assertTrue("AD flag must be set", response.getHeader().getFlag(Flags.AD)); assertEquals(Rcode.NOERROR, response.getRcode()); assertNull(getReason(response)); Lookup l = new Lookup("www.isc.ingotronic.ch"); l.setResolver(resolver); Record[] results = l.run(); assertTrue(results != null); assertTrue(results.length >= 1); }
@Test public void testModifiedSignature() throws IOException { Name query = Name.fromString("www.ingotronic.ch."); // prepare a faked, unsigned response message that must have a signature // to be valid Message message = new Message(); message.addRecord(Record.newRecord(query, Type.A, DClass.IN), Section.QUESTION); message.addRecord(new ARecord(query, Type.A, DClass.IN, InetAddress.getByName(localhost)), Section.ANSWER); message.addRecord(new RRSIGRecord(query, DClass.IN, 0, Type.A, Algorithm.RSASHA256, 5, new Date(System.currentTimeMillis() + 5000), new Date(System.currentTimeMillis() - 5000), 1234, Name.fromString("ingotronic.ch."), new byte[] { 1, 2, 3 }), Section.ANSWER); add("www.ingotronic.ch./A", message); Message response = resolver.send(createMessage("www.ingotronic.ch./A")); assertFalse("AD flag must not be set", response.getHeader().getFlag(Flags.AD)); assertEquals(Rcode.SERVFAIL, response.getRcode()); assertTrue(getReason(response).startsWith("failed.answer.positive:{ www.ingotronic.ch.")); }
public static void main(String[] args) throws Exception { String filename = "to_resolve_50k.txt"; UDPExecutorServiceDemo demo = new UDPExecutorServiceDemo(); if (args.length == 1) { filename = args[0]; } List<String> toResolve = Utils.loadFile(filename); for (String name : toResolve) { Message message = Utils.makeQuery(name, demo.getCounter().getAndIncrement()); demo.getMessages().put(message.getHeader().getID(), message); demo.getResolver().sendAsync(message, demo.getResponseQueue()); } System.out.println(MessageFormat.format("Sending {0} queries asynchronously", demo.getCounter().get())); //Setting the timeout to 2 x the resolver timeout. long timeout = System.currentTimeMillis() + (demo.getResolver().getTimeoutMillis() * 2); while (System.currentTimeMillis() < timeout) { demo.getIncomingExecutorService().submit(new UDPReceiver(demo.getResponseQueue(), demo.getGoodCounter(), demo.getBadCounter(), demo.getMessages(), demo.getResponses())); } //TODO We could do something with the results at this point, or requeue messages that failed. demo.generateStatistics(); demo.getIncomingExecutorService().shutdownNow(); System.out.println("Done...."); }
public UDPReceiver(final ResponseQueue queue, final AtomicInteger good, final AtomicInteger bad, final ConcurrentMap<Integer, Message> messages, ConcurrentMap<Integer, Response> responses) { this.queue = queue; this.good = good; this.bad = bad; this.messages = messages; this.responses = responses; }
public static synchronized Message makeQuery(String nameString, int id) throws TextParseException { Name name = Name.fromString(nameString, Name.root); Record question = Record.newRecord(name, Type.A, DClass.ANY); Message query = Message.newQuery(question); query.getHeader().setID(id); return query; }
@Test public void testDnsQuery() throws Exception { Message message = Message.newQuery(new ARecord(new Name("notblocked.example.com."), 0x01, 3600, Inet4Address.getByAddress(new byte[]{0, 0, 0, 0}) )); UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(message.toWire()) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastResponse); assertNotNull(mockEventLoop.lastOutgoing); assertEquals(Inet4Address.getByAddress(new byte[]{8, 8, 8, 8}), mockEventLoop.lastOutgoing.getAddress()); }
@Test public void testNoQueryDnsQuery() throws Exception { Message message = new Message(); UdpPacket.Builder payLoadBuilder = new UdpPacket.Builder() .srcPort(UdpPort.DOMAIN) .dstPort(UdpPort.DOMAIN) .srcAddr(InetAddress.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr(InetAddress.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder( new UnknownPacket.Builder() .rawData(message.toWire()) ); IpPacket ipOutPacket = new IpV4Packet.Builder() .version(IpVersion.IPV4) .tos(IpV4Rfc791Tos.newInstance((byte) 0)) .protocol(IpNumber.UDP) .srcAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 4, 4})) .dstAddr((Inet4Address) Inet4Address.getByAddress(new byte[]{8, 8, 8, 8})) .correctChecksumAtBuild(true) .correctLengthAtBuild(true) .payloadBuilder(payLoadBuilder) .build(); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); assertNull(mockEventLoop.lastResponse); assertNull(mockEventLoop.lastOutgoing); dnsPacketProxy.handleDnsRequest(ipOutPacket.getRawData()); }
/** * Send a query. This kicks off the whole process. * * @param query * @param id * @param responseQueue * @param endTime */ public void sendQuery(Message query, Object id, ResponseQueue responseQueue, long endTime) { this.responseQueue = responseQueue; this.id = id; this.query = query; this.endTime = endTime; startTimer(); startConnect(); }
/** * Send a query using a ResolverListener. This kicks off the whole process. * * @param query * @param id * @param listener * @param endTime */ public void sendQuery(Message query, Object id, ResolverListener listener, long endTime) { this.listener = listener; this.id = id; this.query = query; this.endTime = endTime; startTimer(); startConnect(); }
/** * A packet is available. Decode it and act accordingly. If the packet is * truncated over UDP, and ignoreTruncation is false, then a tcp query is * run to return the whole response. * * @param data * @param ignoreMe */ @Override public void dataAvailable(byte[] data, Connection ignoreMe) { // Now get the data, and send it back to the listener. try { disconnect(ignoreMe); Message message = NonblockingResolver.parseMessage(data); if (message != null && LOG.isTraceEnabled()) { LOG.trace("dataAvailable(" + data.length + " bytes)"); LOG.trace(message); } NonblockingResolver.verifyTSIG(query, message, data, tsig); // Now check that we got the whole message, if we're asked to do so if (!tcp && !ignoreTruncation && message.getHeader().getFlag(Flags.TC)) { // Redo the query, but use tcp this time. tcp = true; // Now start again with a TCP connection startConnect(); return; } if (query.getHeader().getID() != message.getHeader().getID()) { // System.out.println("Query wrong id! Expected " + query.getHeader().getID() + " but got " + message.getHeader().getID()); return; } returnResponse(message); } catch (IOException e) { returnException(e, null); } }
/** * Return the response to the listener * * @param message the response */ private void returnResponse(Message message) { boolean needToRespond = false; synchronized (lock) { if (!answered) { answered = true; needToRespond = true; } } if (needToRespond) { // Stop the timer! cancelTimer(); returnResponse(listener, responseQueue, message, id); } }
/** * Return the response to the listener * * @param message the response */ private void returnResponse(Message message, QueryData qData) { if (!qData.isAnswered()) { qData.setAnswered(true); // Stop the timer! cancelTimer(qData); returnResponse(qData.getListener(), qData.getResponseQueue(), message, qData.getId()); } }
@Override protected void commitUnchecked() { try { Message response = transport.send(update); verify( response.getRcode() == Rcode.NOERROR, "DNS server failed domain update for '%s' rcode: %s", zoneName, Rcode.string(response.getRcode())); } catch (IOException e) { throw new RuntimeException("publishDomain failed for zone: " + zoneName, e); } }
/** * Sends a DNS "query" message (most likely an UPDATE) and returns the response. The response is * checked for matching ID and opcode. * * @param query a message to send * @return the response received from the server * @throws IOException if the Socket input/output streams throws one * @throws IllegalArgumentException if the query is too large to be sent (> 65535 bytes) */ public Message send(Message query) throws IOException { try (Socket socket = factory.createSocket(InetAddress.getByName(updateHost), DNS_PORT)) { socket.setSoTimeout(updateTimeout); writeMessage(socket.getOutputStream(), query); Message response = readMessage(socket.getInputStream()); checkValidResponse(query, response); return response; } }
private void checkValidResponse(Message query, Message response) { verify( response.getHeader().getID() == query.getHeader().getID(), "response ID %s does not match query ID %s", response.getHeader().getID(), query.getHeader().getID()); verify( response.getHeader().getOpcode() == query.getHeader().getOpcode(), "response opcode '%s' does not match query opcode '%s'", Opcode.string(response.getHeader().getOpcode()), Opcode.string(query.getHeader().getOpcode())); }
private void writeMessage(OutputStream outputStream, Message message) throws IOException { byte[] messageData = message.toWire(); checkArgument( messageData.length <= MESSAGE_MAXIMUM_LENGTH, "DNS request message larger than maximum of %s: %s", MESSAGE_MAXIMUM_LENGTH, messageData.length); ByteBuffer buffer = ByteBuffer.allocate(messageData.length + MESSAGE_LENGTH_FIELD_BYTES); buffer.putShort((short) messageData.length); buffer.put(messageData); outputStream.write(buffer.array()); }
private Message readMessage(InputStream inputStream) throws IOException { DataInputStream stream = new DataInputStream(inputStream); int length = stream.readUnsignedShort(); byte[] messageData = new byte[length]; stream.readFully(messageData); return new Message(messageData); }
private Message messageWithResponseCode(int responseCode) { Message message = new Message(); message.getHeader().setOpcode(Opcode.UPDATE); message.getHeader().setFlag(Flags.QR); message.getHeader().setRcode(responseCode); return message; }
@Before public void before() throws Exception { simpleQuery = Message.newQuery(Record.newRecord(Name.fromString("example.com."), Type.A, DClass.IN)); expectedResponse = responseMessageWithCode(simpleQuery, Rcode.NOERROR); when(mockFactory.createSocket(InetAddress.getByName(UPDATE_HOST), DnsMessageTransport.DNS_PORT)) .thenReturn(mockSocket); resolver = new DnsMessageTransport(mockFactory, UPDATE_HOST, Duration.ZERO); }
@Test public void testReceivedMessageWithLengthHasCorrectContent() throws Exception { ByteArrayInputStream inputStream = new ByteArrayInputStream(messageToBytesWithLength(expectedResponse)); when(mockSocket.getInputStream()).thenReturn(inputStream); when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream()); Message actualResponse = resolver.send(simpleQuery); assertThat(base16().encode(actualResponse.toWire())) .isEqualTo(base16().encode(expectedResponse.toWire())); }
@Test public void testEofReceivingResponse() throws Exception { byte[] messageBytes = messageToBytesWithLength(expectedResponse); ByteArrayInputStream inputStream = new ByteArrayInputStream(Arrays.copyOf(messageBytes, messageBytes.length - 1)); when(mockSocket.getInputStream()).thenReturn(inputStream); when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream()); assertThrows(EOFException.class, () -> resolver.send(new Message())); }
@Test public void testTimeoutReceivingResponse() throws Exception { InputStream mockInputStream = mock(InputStream.class); when(mockInputStream.read()).thenThrow(new SocketTimeoutException("testing")); when(mockSocket.getInputStream()).thenReturn(mockInputStream); when(mockSocket.getOutputStream()).thenReturn(new ByteArrayOutputStream()); Duration testTimeout = Duration.standardSeconds(1); DnsMessageTransport resolver = new DnsMessageTransport(mockFactory, UPDATE_HOST, testTimeout); Message expectedQuery = new Message(); assertThrows(SocketTimeoutException.class, () -> resolver.send(expectedQuery)); verify(mockSocket).setSoTimeout((int) testTimeout.getMillis()); }
private Message responseMessageWithCode(Message query, int responseCode) { Message message = new Message(query.getHeader().getID()); message.getHeader().setOpcode(query.getHeader().getOpcode()); message.getHeader().setFlag(Flags.QR); message.getHeader().setRcode(responseCode); return message; }
private byte[] messageToBytesWithLength(Message message) { byte[] bytes = message.toWire(); ByteBuffer buffer = ByteBuffer.allocate(bytes.length + DnsMessageTransport.MESSAGE_LENGTH_FIELD_BYTES); buffer.putShort((short) bytes.length); buffer.put(bytes); return buffer.array(); }
@Override public void process(Exchange exchange) throws Exception { String server = exchange.getIn().getHeader(DnsConstants.DNS_SERVER, String.class); SimpleResolver resolver = new SimpleResolver(server); int type = Type.value(exchange.getIn().getHeader(DnsConstants.DNS_TYPE, String.class)); if (type == -1) { // default: if unparsable value given, use A. type = Type.A; } String dclassValue = exchange.getIn().getHeader(DnsConstants.DNS_CLASS, String.class); if (dclassValue == null) { dclassValue = ""; } int dclass = DClass.value(dclassValue); if (dclass == -1) { // by default, value is IN. dclass = DClass.IN; } Name name = Name.fromString(exchange.getIn().getHeader(DnsConstants.DNS_NAME, String.class), Name.root); Record rec = Record.newRecord(name, type, dclass); Message query = Message.newQuery(rec); Message response = resolver.send(query); exchange.getIn().setBody(response); }