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.util.ArrayList; 015import java.util.Collections; 016import java.util.List; 017import java.util.Set; 018 019import org.minidns.AbstractDnsClient.IpVersionSetting; 020import org.minidns.MiniDnsException.NullResultException; 021import org.minidns.dnsname.DnsName; 022import org.minidns.record.A; 023import org.minidns.record.AAAA; 024import org.minidns.record.InternetAddressRR; 025import org.minidns.record.SRV; 026import org.minidns.util.SrvUtil; 027 028public class SrvResolverResult extends ResolverResult<SRV> { 029 030 private final ResolverApi resolver; 031 private final IpVersionSetting ipVersion; 032 033 private List<ResolvedSrvRecord> sortedSrvResolvedAddresses; 034 035 SrvResolverResult(ResolverResult<SRV> srvResult, ResolverApi resolver) throws NullResultException { 036 super(srvResult.question, srvResult.answer, srvResult.unverifiedReasons); 037 this.resolver = resolver; 038 this.ipVersion = resolver.getClient().getPreferedIpVersion(); 039 } 040 041 public List<ResolvedSrvRecord> getSortedSrvResolvedAddresses() throws IOException { 042 if (sortedSrvResolvedAddresses != null) { 043 return sortedSrvResolvedAddresses; 044 } 045 046 throwIseIfErrorResponse(); 047 048 List<SRV> srvRecords = SrvUtil.sortSrvRecords(getAnswers()); 049 050 List<ResolvedSrvRecord> res = new ArrayList<>(srvRecords.size()); 051 for (SRV srvRecord : srvRecords) { 052 ResolverResult<A> aRecordsResult = null; 053 ResolverResult<AAAA> aaaaRecordsResult = null; 054 Set<A> aRecords = Collections.emptySet(); 055 if (ipVersion.v4) { 056 aRecordsResult = resolver.resolve(srvRecord.target, A.class); 057 if (aRecordsResult.wasSuccessful() && !aRecordsResult.hasUnverifiedReasons()) { 058 aRecords = aRecordsResult.getAnswers(); 059 } 060 } 061 062 Set<AAAA> aaaaRecords = Collections.emptySet(); 063 if (ipVersion.v6) { 064 aaaaRecordsResult = resolver.resolve(srvRecord.target, AAAA.class); 065 if (aaaaRecordsResult.wasSuccessful() && !aaaaRecordsResult.hasUnverifiedReasons()) { 066 aaaaRecords = aaaaRecordsResult.getAnswers(); 067 } 068 } 069 070 if (aRecords.isEmpty() && aaaaRecords.isEmpty()) { 071 // TODO Possibly check for (C|D)NAME usage and throw a meaningful exception that it is not allowed for 072 // the target of an SRV to be an alias as per RFC 2782. 073 /* 074 ResolverResult<CNAME> cnameRecordResult = resolve(srvRecord.name, CNAME.class); 075 if (cnameRecordResult.wasSuccessful()) { 076 } 077 */ 078 continue; 079 } 080 081 List<InternetAddressRR> srvAddresses = new ArrayList<>(aRecords.size() + aaaaRecords.size()); 082 switch (ipVersion) { 083 case v4only: 084 srvAddresses.addAll(aRecords); 085 break; 086 case v6only: 087 srvAddresses.addAll(aaaaRecords); 088 break; 089 case v4v6: 090 srvAddresses.addAll(aRecords); 091 srvAddresses.addAll(aaaaRecords); 092 break; 093 case v6v4: 094 srvAddresses.addAll(aaaaRecords); 095 srvAddresses.addAll(aRecords); 096 break; 097 } 098 099 ResolvedSrvRecord resolvedSrvAddresses = new ResolvedSrvRecord(question.name, srvRecord, srvAddresses, 100 aRecordsResult, aaaaRecordsResult); 101 res.add(resolvedSrvAddresses); 102 } 103 104 sortedSrvResolvedAddresses = res; 105 106 return res; 107 } 108 109 public static class ResolvedSrvRecord { 110 public final DnsName name; 111 public final SRV srv; 112 public final List<InternetAddressRR> addresses; 113 public final ResolverResult<A> aRecordsResult; 114 public final ResolverResult<AAAA> aaaaRecordsResult; 115 116 /** 117 * The port announced by the SRV RR. This is simply a shortcut for <code>srv.port</code>. 118 */ 119 public final int port; 120 121 private ResolvedSrvRecord(DnsName name, SRV srv, List<InternetAddressRR> addresses, ResolverResult<A> aRecordsResult, ResolverResult<AAAA> aaaaRecordsResult) { 122 this.name = name; 123 this.srv = srv; 124 this.addresses = Collections.unmodifiableList(addresses); 125 this.port = srv.port; 126 this.aRecordsResult = aRecordsResult; 127 this.aaaaRecordsResult = aaaaRecordsResult; 128 } 129 } 130}