package mireka.transmission.immediate.dns; import java.net.InetAddress; import javax.annotation.concurrent.ThreadSafe; import mireka.smtp.EnhancedStatus; import mireka.smtp.SendException; import org.xbill.DNS.AAAARecord; import org.xbill.DNS.ARecord; import org.xbill.DNS.Lookup; import org.xbill.DNS.Name; import org.xbill.DNS.Record; /** * The AddressLookup class queries the IP address of an MTA or domain by * querying the A and AAAA records assigned to the domain name of the MTA. * <p> * This implementation uses Dnsjava, therefore it can provide much more * precise error messages than the InetAddress. It also respects DNS TTL * values. */ @ThreadSafe public class AddressLookup { public InetAddress[] queryAddresses(Name name) throws SendException { Record[] records = queryAddressRecords(name); InetAddress[] addresses = convertAddressRecordsToAddresses(records); return addresses; } private Record[] queryAddressRecords(Name name) throws SendException { Lookup lookup = new Lookup(name); Record[] records = lookup.run(); switch (lookup.getResult()) { case Lookup.SUCCESSFUL: return records; case Lookup.TYPE_NOT_FOUND: throw new SendException("Host " + name + " has no address record (" + lookup.getErrorString() + ")", EnhancedStatus.PERMANENT_UNABLE_TO_ROUTE); case Lookup.HOST_NOT_FOUND: throw new SendException("Host " + name + " is not found (" + lookup.getErrorString() + ")", EnhancedStatus.PERMANENT_UNABLE_TO_ROUTE); case Lookup.TRY_AGAIN: throw new SendException( "DNS network failure while looking up address of " + name + ": " + lookup.getErrorString(), EnhancedStatus.TRANSIENT_DIRECTORY_SERVER_FAILURE); case Lookup.UNRECOVERABLE: throw new SendException( "Unrecoverable DNS error while looking up address of " + name + ": " + lookup.getErrorString(), EnhancedStatus.PERMANENT_UNABLE_TO_ROUTE); default: throw new SendException( "Unknown DNS status while looking up address of " + name + ": " + lookup.getResult() + ". " + lookup.getErrorString(), EnhancedStatus.PERMANENT_INTERNAL_ERROR); } } private InetAddress[] convertAddressRecordsToAddresses(Record[] records) { InetAddress[] addresses = new InetAddress[records.length]; for (int i = 0; i < records.length; i++) { Record record = records[i]; if (record instanceof ARecord) { addresses[i] = ((ARecord) record).getAddress(); } else if (record instanceof AAAARecord) { addresses[i] = ((AAAARecord) record).getAddress(); } else { throw new RuntimeException(); } } return addresses; } }