001/* 002 * Copyright 2015-2024 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.Set; 015 016import org.minidns.DnsCache; 017import org.minidns.MiniDnsException.NullResultException; 018import org.minidns.cache.LruCache; 019import org.minidns.cache.MiniDnsCacheFactory; 020import org.minidns.dnsmessage.Question; 021import org.minidns.dnsname.DnsName; 022import org.minidns.dnssec.DnssecClient; 023import org.minidns.dnssec.DnssecQueryResult; 024import org.minidns.dnssec.DnssecUnverifiedReason; 025import org.minidns.iterative.ReliableDnsClient.Mode; 026import org.minidns.record.Data; 027import org.minidns.record.Record.TYPE; 028 029public class DnssecResolverApi extends ResolverApi { 030 031 public static final DnssecResolverApi INSTANCE = new DnssecResolverApi(); 032 033 private final DnssecClient dnssecClient; 034 private final DnssecClient iterativeOnlyDnssecClient; 035 private final DnssecClient recursiveOnlyDnssecClient; 036 037 public DnssecResolverApi() { 038 this(new MiniDnsCacheFactory() { 039 @Override 040 public DnsCache newCache() { 041 return new LruCache(); 042 } 043 }); 044 } 045 046 public DnssecResolverApi(MiniDnsCacheFactory cacheFactory) { 047 this(new DnssecClient(cacheFactory.newCache()), cacheFactory); 048 } 049 050 private DnssecResolverApi(DnssecClient dnssecClient, MiniDnsCacheFactory cacheFactory) { 051 super(dnssecClient); 052 this.dnssecClient = dnssecClient; 053 054 // Set the *_ONLY_DNSSEC ResolverApi. It is important that the two do *not* share the same cache, since we 055 // probably fall back to iterativeOnly and in that case do not want the cached results of the recursive result. 056 iterativeOnlyDnssecClient = new DnssecClient(cacheFactory.newCache()); 057 iterativeOnlyDnssecClient.setMode(Mode.iterativeOnly); 058 059 recursiveOnlyDnssecClient = new DnssecClient(cacheFactory.newCache()); 060 recursiveOnlyDnssecClient.setMode(Mode.recursiveOnly); 061 } 062 063 @Override 064 public <D extends Data> ResolverResult<D> resolve(Question question) throws IOException { 065 DnssecQueryResult dnssecMessage = dnssecClient.queryDnssec(question); 066 return toResolverResult(question, dnssecMessage); 067 } 068 069 /** 070 * Resolve the given name and type which is expected to yield DNSSEC authenticated results. 071 * 072 * @param name the DNS name to resolve. 073 * @param type the class of the RR type to resolve. 074 * @param <D> the RR type to resolve. 075 * @return the resolver result. 076 * @throws IOException in case an exception happens while resolving. 077 * @see #resolveDnssecReliable(Question) 078 */ 079 public <D extends Data> ResolverResult<D> resolveDnssecReliable(String name, Class<D> type) throws IOException { 080 return resolveDnssecReliable(DnsName.from(name), type); 081 } 082 083 /** 084 * Resolve the given name and type which is expected to yield DNSSEC authenticated results. 085 * 086 * @param name the DNS name to resolve. 087 * @param type the class of the RR type to resolve. 088 * @param <D> the RR type to resolve. 089 * @return the resolver result. 090 * @throws IOException in case an exception happens while resolving. 091 * @see #resolveDnssecReliable(Question) 092 */ 093 public <D extends Data> ResolverResult<D> resolveDnssecReliable(DnsName name, Class<D> type) throws IOException { 094 TYPE t = TYPE.getType(type); 095 Question q = new Question(name, t); 096 return resolveDnssecReliable(q); 097 } 098 099 /** 100 * Resolve the given question which is expected to yield DNSSEC authenticated results. 101 * 102 * @param question the question to resolve. 103 * @param <D> the RR type to resolve. 104 * @return the resolver result. 105 * @throws IOException in case an exception happens while resolving. 106 */ 107 public <D extends Data> ResolverResult<D> resolveDnssecReliable(Question question) throws IOException { 108 DnssecQueryResult dnssecMessage = recursiveOnlyDnssecClient.queryDnssec(question); 109 if (dnssecMessage == null || !dnssecMessage.isAuthenticData()) { 110 dnssecMessage = iterativeOnlyDnssecClient.queryDnssec(question); 111 } 112 return toResolverResult(question, dnssecMessage); 113 } 114 115 public DnssecClient getDnssecClient() { 116 return dnssecClient; 117 } 118 119 private static <D extends Data> ResolverResult<D> toResolverResult(Question question, DnssecQueryResult dnssecMessage) throws NullResultException { 120 Set<DnssecUnverifiedReason> unverifiedReasons = dnssecMessage.getUnverifiedReasons(); 121 122 return new ResolverResult<D>(question, dnssecMessage.dnsQueryResult, unverifiedReasons); 123 } 124}