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.dnsserverlookup;
012
013import org.minidns.util.PlatformDetection;
014
015import java.io.BufferedReader;
016import java.io.File;
017import java.io.FileInputStream;
018import java.io.IOException;
019import java.io.InputStreamReader;
020import java.util.ArrayList;
021import java.util.List;
022import java.util.logging.Level;
023import java.util.logging.Logger;
024import java.util.regex.Matcher;
025import java.util.regex.Pattern;
026
027public class UnixUsingEtcResolvConf extends AbstractDnsServerLookupMechanism {
028
029    public static final DnsServerLookupMechanism INSTANCE = new UnixUsingEtcResolvConf();
030    public static final int PRIORITY = 2000;
031
032    private static final Logger LOGGER = Logger.getLogger(UnixUsingEtcResolvConf.class.getName());
033
034    private static final String RESOLV_CONF_FILE = "/etc/resolv.conf";
035    private static final Pattern NAMESERVER_PATTERN = Pattern.compile("^nameserver\\s+(.*)$");
036
037    private static List<String> cached;
038    private static long lastModified;
039
040    private UnixUsingEtcResolvConf() {
041        super(UnixUsingEtcResolvConf.class.getSimpleName(), PRIORITY);
042    }
043
044    @Override
045    public List<String> getDnsServerAddresses() {
046        File file = new File(RESOLV_CONF_FILE);
047        if (!file.exists()) {
048            // Not very unixoid systems
049            return null;
050        }
051
052        long currentLastModified = file.lastModified();
053        if (currentLastModified == lastModified && cached != null) {
054            return cached;
055        }
056
057        List<String> servers = new ArrayList<>();
058        BufferedReader reader = null;
059        try {
060            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
061            String line;
062            while ((line = reader.readLine()) != null) {
063                Matcher matcher = NAMESERVER_PATTERN.matcher(line);
064                if (matcher.matches()) {
065                    servers.add(matcher.group(1).trim());
066                }
067            }
068        } catch (IOException e) {
069            LOGGER.log(Level.WARNING, "Could not read from " + RESOLV_CONF_FILE, e);
070            return null;
071        } finally {
072            if (reader != null) try {
073                reader.close();
074            } catch (IOException e) {
075                LOGGER.log(Level.WARNING, "Could not close reader", e);
076            }
077        }
078
079        if (servers.isEmpty()) {
080            LOGGER.fine("Could not find any nameservers in " + RESOLV_CONF_FILE);
081            return null;
082        }
083
084        cached = servers;
085        lastModified = currentLastModified;
086
087        return cached;
088    }
089
090    @Override
091    public boolean isAvailable() {
092        if (PlatformDetection.isAndroid()) {
093            // Don't rely on resolv.conf when on Android
094            return false;
095        }
096
097        File file = new File(RESOLV_CONF_FILE);
098        if (!file.exists()) {
099            // Not very unixoid systems
100            return false;
101        }
102        return true;
103    }
104
105}