/* ** This file is part of Filius, a network construction and simulation software. ** ** Originally created at the University of Siegen, Institute "Didactics of ** Informatics and E-Learning" by a students' project group: ** members (2006-2007): ** André Asschoff, Johannes Bade, Carsten Dittich, Thomas Gerding, ** Nadja Haßler, Ernst Johannes Klebert, Michell Weyer ** supervisors: ** Stefan Freischlad (maintainer until 2009), Peer Stechert ** Project is maintained since 2010 by Christian Eibl <filius@c.fameibl.de> ** and Stefan Freischlad ** Filius 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 2 of the License, or ** (at your option) version 3. ** ** Filius 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 Filius. If not, see <http://www.gnu.org/licenses/>. */ package filius.software.dns; import java.util.LinkedList; import java.util.concurrent.TimeoutException; import filius.Main; import filius.exception.VerbindungsException; import filius.hardware.Verbindung; import filius.software.clientserver.ClientAnwendung; import filius.software.transportschicht.UDPSocket; import filius.software.vermittlungsschicht.IP; /** * Ausschnitt aus dem RFC 1035: <br /> * <b>Question section format </b> <br /> * The question section is used to carry the "question" in most queries, i.e., * the parameters that define what is being asked. The section contains QDCOUNT * (usually 1) entries, each of the following format: ... * <ol> * <li> QNAME a domain name represented as a sequence of labels, where each * label consists of a length octet followed by that number of octets. The * domain name terminates with the zero length octet for the null label of the * root. Note that this field may be an odd number of octets; no padding is * used. </li> * <li> QTYPE a two octet code which specifies the type of the query. The values * for this field include all codes valid for a TYPE field, together with some * more general codes which can match more than one type of RR. </li> * <li> QCLASS a two octet code that specifies the class of the query. For * example, the QCLASS field is IN for the Internet. </li> * </ol> * * <b> Resource record format </b> <br /> * The answer, authority, and additional sections all share the same format: a * variable number of resource records, where the number of records is specified * in the corresponding count field in the header. Each resource record has the * following format: ... * <ol> * <li> NAME a domain name to which this resource record pertains. </li> * <li> TYPE two octets containing one of the RR type codes. This field * specifies the meaning of the data in the RDATA field. </li> * <li> CLASS two octets which specify the class of the data in the RDATA field. * </li> * <li> TTL a 32 bit unsigned integer that specifies the time interval (in * seconds) that the resource record may be cached before it should be * discarded. Zero values are interpreted to mean that the RR can only be used * for the transaction in progress, and should not be cached. </li> * <li> RDLENGTH an unsigned 16 bit integer that specifies the length in octets * of the RDATA field. </li> * <li> RDATA a variable length string of octets that describes the resource. * The format of this information varies according to the TYPE and CLASS of the * resource record. For example, the if the TYPE is A and the CLASS is IN, the * RDATA field is a 4 octet ARPA Internet address. </li> * </ol> */ public class Resolver extends ClientAnwendung { /** * Methode zum Abruf eines Resource Record. Das Rueckgabeformat ist NAME * TYPE CLASS TTL RDATA (Bsp. web.de. A IN 3600 217.72.195.42) * * @param typ * @param domainname * @return einen Resource Record oder 'null', wenn ein Fehler bei der * Verbindung auftritt */ /** * Methode zum Versenden einer Anfrage und zur Rueckgabe der * DNS-Server-Antwort als DNSNachricht */ private DNSNachricht holeResourceRecord(String typ, String domainname, String dnsServer) { if (dnsServer == null || dnsServer.trim().equals("")) { return null; } DNSNachricht anfrage = new DNSNachricht(DNSNachricht.QUERY); anfrage.hinzuQuery(domainname + " " + typ + " IN"); String antwortStr; try { UDPSocket socket = new UDPSocket(getSystemSoftware(), dnsServer, 53); socket.verbinden(); socket.senden(anfrage.toString()); antwortStr = socket.empfangen(Verbindung.holeRTT()); socket.schliessen(); } catch (VerbindungsException e) { return null; } if (antwortStr == null) { return null; } DNSNachricht antwort = new DNSNachricht(antwortStr); if (antwort.getId() != anfrage.getId()) { return null; } return antwort; } public String holeIterativ(String typ, String domain) { String server = getSystemSoftware().getDNSServer(); if (server == null || server.trim().equals("")) { return null; } DNSNachricht antwort; String res; for (int i = 0; i < 10; i++) { antwort = holeResourceRecord(typ, domain, server); if (antwort == null) { return null; } LinkedList<ResourceRecord> records = new LinkedList<ResourceRecord>(); records.addAll(antwort.holeAntwortResourceRecords()); records.addAll(antwort.holeAuthoritativeResourceRecords()); records.addAll(antwort.holeZusatzResourceRecords()); res = durchsucheRecordListe(typ, domain, records); if (res != null) { return res; } res = durchsucheRecordListe(ResourceRecord.ADDRESS, records); if (res == null || res == server) { return null; } server = res; } return null; } /** * Methode zur Aufloesung eines Domainnamens zu einer IP-Adresse. * * @param domainname * @return */ public String holeIPAdresse(String domain) { if (domain.equalsIgnoreCase("localhost")) { return "127.0.0.1"; } String adresse = IP.ipCheck(domain); if (adresse != null) { return adresse; } return holeIterativ(ResourceRecord.ADDRESS, domain); } public String holeIPAdresseMailServer(String domain) { String mxdomain = holeIterativ(ResourceRecord.MAIL_EXCHANGE, domain); if (mxdomain == null) { return null; } return holeIterativ(ResourceRecord.ADDRESS, mxdomain); } private String durchsucheRecordListe(String typ, LinkedList<ResourceRecord> liste) { for (ResourceRecord rr : liste) { if (rr.getType().equals(typ)) { return rr.getRdata(); } } return null; } private String durchsucheRecordListe(String typ, String domainname, LinkedList<ResourceRecord> liste) { Main.debug.println("INVOKED ("+this.hashCode()+", T"+this.getId()+") "+getClass()+" (Resolver), durchsucheRecordListe("+typ+","+domainname+","+liste+")"); for (ResourceRecord rr : liste) { if (rr.getDomainname().equalsIgnoreCase(domainname) && rr.getType().equals(typ)) { return rr.getRdata(); } } return null; } }