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.util.Collections; 014import java.util.Set; 015 016import org.minidns.MiniDnsException; 017import org.minidns.MiniDnsException.NullResultException; 018import org.minidns.dnsmessage.DnsMessage; 019import org.minidns.dnsmessage.Question; 020import org.minidns.dnsmessage.DnsMessage.RESPONSE_CODE; 021import org.minidns.dnssec.DnssecResultNotAuthenticException; 022import org.minidns.dnssec.UnverifiedReason; 023import org.minidns.record.Data; 024 025public class ResolverResult<D extends Data> { 026 027 protected final Question question; 028 private final RESPONSE_CODE responseCode; 029 private final Set<D> data; 030 private final boolean isAuthenticData; 031 protected final Set<UnverifiedReason> unverifiedReasons; 032 protected final DnsMessage answer; 033 034 ResolverResult(Question question , DnsMessage answer, Set<UnverifiedReason> unverifiedReasons) throws NullResultException { 035 if (answer == null) { 036 throw new MiniDnsException.NullResultException(question.asMessageBuilder().build()); 037 } 038 039 this.question = question; 040 this.responseCode = answer.responseCode; 041 this.answer = answer; 042 043 Set<D> r = answer.getAnswersFor(question); 044 if (r == null) { 045 this.data = Collections.emptySet(); 046 } else { 047 this.data = Collections.unmodifiableSet(r); 048 } 049 050 if (unverifiedReasons == null) { 051 this.unverifiedReasons = null; 052 isAuthenticData = false; 053 } else { 054 this.unverifiedReasons = Collections.unmodifiableSet(unverifiedReasons); 055 isAuthenticData = this.unverifiedReasons.isEmpty(); 056 } 057 } 058 059 public boolean wasSuccessful() { 060 return responseCode == RESPONSE_CODE.NO_ERROR; 061 } 062 063 public Set<D> getAnswers() { 064 throwIseIfErrorResponse(); 065 return data; 066 } 067 068 public Set<D> getAnswersOrEmptySet() { 069 return data; 070 } 071 072 public RESPONSE_CODE getResponseCode() { 073 return responseCode; 074 } 075 076 public boolean isAuthenticData() { 077 throwIseIfErrorResponse(); 078 return isAuthenticData; 079 } 080 081 /** 082 * Get the reasons the result could not be verified if any exists. 083 * 084 * @return The reasons the result could not be verified or <code>null</code>. 085 */ 086 public Set<UnverifiedReason> getUnverifiedReasons() { 087 throwIseIfErrorResponse(); 088 return unverifiedReasons; 089 } 090 091 public Question getQuestion() { 092 return question; 093 } 094 095 public void throwIfErrorResponse() throws ResolutionUnsuccessfulException { 096 ResolutionUnsuccessfulException resolutionUnsuccessfulException = getResolutionUnsuccessfulException(); 097 if (resolutionUnsuccessfulException != null) throw resolutionUnsuccessfulException; 098 } 099 100 private ResolutionUnsuccessfulException resolutionUnsuccessfulException; 101 102 public ResolutionUnsuccessfulException getResolutionUnsuccessfulException() { 103 if (wasSuccessful()) return null; 104 105 if (resolutionUnsuccessfulException == null) { 106 resolutionUnsuccessfulException = new ResolutionUnsuccessfulException(question, responseCode); 107 } 108 109 return resolutionUnsuccessfulException; 110 } 111 112 private DnssecResultNotAuthenticException dnssecResultNotAuthenticException; 113 114 public DnssecResultNotAuthenticException getDnssecResultNotAuthenticException() { 115 if (!wasSuccessful()) 116 return null; 117 if (isAuthenticData) 118 return null; 119 120 if (dnssecResultNotAuthenticException == null) { 121 dnssecResultNotAuthenticException = DnssecResultNotAuthenticException.from(getUnverifiedReasons()); 122 } 123 124 return dnssecResultNotAuthenticException; 125 } 126 127 /** 128 * Get the raw answer DNS message we received. <b>This is likely not what you want</b>, try {@link #getAnswers()} instead. 129 * 130 * @return the raw answer DNS Message. 131 * @see #getAnswers() 132 */ 133 public DnsMessage getRawAnswer() { 134 return answer; 135 } 136 137 @Override 138 public final String toString() { 139 StringBuilder sb = new StringBuilder(); 140 141 sb.append(getClass().getName()).append('\n') 142 .append("Question: ").append(question).append('\n') 143 .append("Response Code: ").append(responseCode).append('\n'); 144 145 if (responseCode == RESPONSE_CODE.NO_ERROR) { 146 if (isAuthenticData) { 147 sb.append("Results verified via DNSSEC\n"); 148 } 149 if (hasUnverifiedReasons()) { 150 sb.append(unverifiedReasons).append('\n'); 151 } 152 sb.append(answer.answerSection); 153 } 154 155 return sb.toString(); 156 } 157 158 boolean hasUnverifiedReasons() { 159 return unverifiedReasons != null && !unverifiedReasons.isEmpty(); 160 } 161 162 protected void throwIseIfErrorResponse() { 163 ResolutionUnsuccessfulException resolutionUnsuccessfulException = getResolutionUnsuccessfulException(); 164 if (resolutionUnsuccessfulException != null) 165 throw new IllegalStateException("Can not perform operation because the DNS resolution was unsuccessful", 166 resolutionUnsuccessfulException); 167 } 168}