001/* 002 * Copyright 2015-2018 the original author or authors 003 * 004 * This software is licensed under the Apache License, Version 2.0, 005 * the GNU Lesser General Public License version 2 or later ("LGPL") 006 * and the WTFPL. 007 * You may choose either license to govern your use of this software only 008 * upon the condition that you accept all of the terms of either 009 * the Apache License 2.0, the LGPL 2.1+ or the WTFPL. 010 */ 011package org.minidns.hla; 012 013import java.io.IOException; 014import java.net.Inet4Address; 015import java.net.Inet6Address; 016import java.net.InetAddress; 017 018import org.minidns.AbstractDnsClient; 019import org.minidns.dnsmessage.DnsMessage; 020import org.minidns.dnsmessage.Question; 021import org.minidns.dnsname.DnsName; 022import org.minidns.iterative.ReliableDnsClient; 023import org.minidns.record.Data; 024import org.minidns.record.PTR; 025import org.minidns.record.SRV; 026import org.minidns.record.Record.TYPE; 027import org.minidns.util.InetAddressUtil; 028 029/** 030 * The high-level MiniDNS resolving API. It is designed to be easy to use. 031 * <p> 032 * A simple exammple how to resolve the IPv4 address of a given domain: 033 * </p> 034 * <pre> 035 * {@code 036 * ResolverResult<A> result = DnssecResolverApi.INSTANCE.resolve("verteiltesysteme.net", A.class); 037 * if (!result.wasSuccessful()) { 038 * RESPONSE_CODE responseCode = result.getResponseCode(); 039 * // Perform error handling. 040 * … 041 * return; 042 * } 043 * if (!result.isAuthenticData()) { 044 * // Response was not secured with DNSSEC. 045 * … 046 * return; 047 * } 048 * Set<A> answers = result.getAnswers(); 049 * for (A a : answers) { 050 * InetAddress inetAddress = a.getInetAddress(); 051 * // Do someting with the InetAddress, e.g. connect to. 052 * … 053 * } 054 * } 055 * </pre> 056 * <p> 057 * MiniDNS also supports SRV resource records as first class citizens: 058 * </p> 059 * <pre> 060 * {@code 061 * SrvResolverResult result = DnssecResolverApi.INSTANCE.resolveSrv(SrvType.xmpp_client, "example.org") 062 * if (!result.wasSuccessful()) { 063 * RESPONSE_CODE responseCode = result.getResponseCode(); 064 * // Perform error handling. 065 * … 066 * return; 067 * } 068 * if (!result.isAuthenticData()) { 069 * // Response was not secured with DNSSEC. 070 * … 071 * return; 072 * } 073 * List<ResolvedSrvRecord> srvRecords = result.getSortedSrvResolvedAddresses(); 074 * // Loop over the domain names pointed by the SRV RR. MiniDNS will return the list 075 * // correctly sorted by the priority and weight of the related SRV RR. 076 * for (ResolvedSrvRecord srvRecord : srvRecord) { 077 * // Loop over the Internet Address RRs resolved for the SRV RR. The order of 078 * // the list depends on the prefered IP version setting of MiniDNS. 079 * for (InternetAddressRR inetAddressRR : srvRecord.addresses) { 080 * InetAddress inetAddress = inetAddressRR.getInetAddress(); 081 * int port = srvAddresses.port; 082 * // Try to connect to inetAddress at port. 083 * … 084 * } 085 * } 086 * } 087 * </pre> 088 * 089 * @author Florian Schmaus 090 * 091 */ 092public class ResolverApi { 093 094 public static final ResolverApi INSTANCE = new ResolverApi(new ReliableDnsClient()); 095 096 private final AbstractDnsClient dnsClient; 097 098 public ResolverApi(AbstractDnsClient dnsClient) { 099 this.dnsClient = dnsClient; 100 } 101 102 public final <D extends Data> ResolverResult<D> resolve(String name, Class<D> type) throws IOException { 103 return resolve(DnsName.from(name), type); 104 } 105 106 public final <D extends Data> ResolverResult<D> resolve(DnsName name, Class<D> type) throws IOException { 107 TYPE t = TYPE.getType(type); 108 Question q = new Question(name, t); 109 return resolve(q); 110 } 111 112 public <D extends Data> ResolverResult<D> resolve(Question question) throws IOException { 113 DnsMessage dnsMessage = dnsClient.query(question); 114 115 return new ResolverResult<D>(question, dnsMessage, null); 116 } 117 118 public SrvResolverResult resolveSrv(SrvType type, String serviceName) throws IOException { 119 return resolveSrv(type.service, type.proto, DnsName.from(serviceName)); 120 } 121 122 public SrvResolverResult resolveSrv(SrvType type, DnsName serviceName) throws IOException { 123 return resolveSrv(type.service, type.proto, serviceName); 124 } 125 126 public SrvResolverResult resolveSrv(SrvService service, SrvProto proto, String name) throws IOException { 127 return resolveSrv(service.dnsName, proto.dnsName, DnsName.from(name)); 128 } 129 130 public SrvResolverResult resolveSrv(SrvService service, SrvProto proto, DnsName name) throws IOException { 131 return resolveSrv(service.dnsName, proto.dnsName, name); 132 } 133 134 public SrvResolverResult resolveSrv(DnsName service, DnsName proto, DnsName name) throws IOException { 135 DnsName srvRrName = DnsName.from(service, proto, name); 136 return resolveSrv(srvRrName); 137 } 138 139 public SrvResolverResult resolveSrv(String name) throws IOException { 140 return resolveSrv(DnsName.from(name)); 141 } 142 143 public ResolverResult<PTR> reverseLookup(CharSequence inetAddressCs) throws IOException { 144 InetAddress inetAddress = InetAddress.getByName(inetAddressCs.toString()); 145 return reverseLookup(inetAddress); 146 } 147 148 public ResolverResult<PTR> reverseLookup(InetAddress inetAddress) throws IOException { 149 if (inetAddress instanceof Inet4Address) { 150 return reverseLookup((Inet4Address) inetAddress); 151 } else if (inetAddress instanceof Inet6Address) { 152 return reverseLookup((Inet6Address) inetAddress); 153 } else { 154 throw new IllegalArgumentException("The given InetAddress '" + inetAddress + "' is neither of type Inet4Address or Inet6Address"); 155 } 156 } 157 158 public ResolverResult<PTR> reverseLookup(Inet4Address inet4Address) throws IOException { 159 DnsName reversedIpAddress = InetAddressUtil.reverseIpAddressOf(inet4Address); 160 DnsName dnsName = DnsName.from(reversedIpAddress, DnsName.IN_ADDR_ARPA); 161 return resolve(dnsName, PTR.class); 162 } 163 164 public ResolverResult<PTR> reverseLookup(Inet6Address inet6Address) throws IOException { 165 DnsName reversedIpAddress = InetAddressUtil.reverseIpAddressOf(inet6Address); 166 DnsName dnsName = DnsName.from(reversedIpAddress, DnsName.IP6_ARPA); 167 return resolve(dnsName, PTR.class); 168 } 169 170 /** 171 * Resolve the {@link SRV} resource record for the given name. After ensuring that the resolution was successful 172 * with {@link SrvResolverResult#wasSuccessful()} , and, if DNSSEC was used, that the results could be verified with 173 * {@link SrvResolverResult#isAuthenticData()}, simply use {@link SrvResolverResult#getSortedSrvResolvedAddresses()} to 174 * retrieve the resolved IP addresses. 175 * <p> 176 * The name of SRV records is "_[service]._[protocol].[serviceDomain]", for example "_xmpp-client._tcp.example.org". 177 * </p> 178 * 179 * @param name the name to resolve. 180 * @return a <code>SrvResolverResult</code> instance which can be used to retrieve the addresses. 181 * @throws IOException if an IO exception occurs. 182 */ 183 public SrvResolverResult resolveSrv(DnsName name) throws IOException { 184 ResolverResult<SRV> result = resolve(name, SRV.class); 185 return new SrvResolverResult(result, this); 186 187 } 188 189 public final AbstractDnsClient getClient() { 190 return dnsClient; 191 } 192}