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.dnsserverlookup; 012 013import org.minidns.util.PlatformDetection; 014 015import java.io.BufferedReader; 016import java.io.IOException; 017import java.io.InputStream; 018import java.io.InputStreamReader; 019import java.io.LineNumberReader; 020import java.net.InetAddress; 021import java.net.UnknownHostException; 022import java.nio.charset.StandardCharsets; 023import java.util.ArrayList; 024import java.util.HashSet; 025import java.util.List; 026import java.util.Set; 027import java.util.logging.Level; 028 029/** 030 * Try to retrieve the list of DNS server by executing getprop. 031 */ 032public final class AndroidUsingExec extends AbstractDnsServerLookupMechanism { 033 034 public static final DnsServerLookupMechanism INSTANCE = new AndroidUsingExec(); 035 public static final int PRIORITY = AndroidUsingReflection.PRIORITY - 1; 036 037 private AndroidUsingExec() { 038 super(AndroidUsingExec.class.getSimpleName(), PRIORITY); 039 } 040 041 @Override 042 public List<String> getDnsServerAddresses() { 043 try { 044 Process process = Runtime.getRuntime().exec("getprop"); 045 InputStream inputStream = process.getInputStream(); 046 LineNumberReader lnr = new LineNumberReader( 047 new InputStreamReader(inputStream, StandardCharsets.UTF_8)); 048 Set<String> server = parseProps(lnr, true); 049 if (server.size() > 0) { 050 List<String> res = new ArrayList<>(server.size()); 051 res.addAll(server); 052 return res; 053 } 054 } catch (IOException e) { 055 LOGGER.log(Level.WARNING, "Exception in findDNSByExec", e); 056 } 057 return null; 058 } 059 060 @Override 061 public boolean isAvailable() { 062 return PlatformDetection.isAndroid(); 063 } 064 065 private static final String PROP_DELIM = "]: ["; 066 static Set<String> parseProps(BufferedReader lnr, boolean logWarning) throws UnknownHostException, IOException { 067 String line = null; 068 Set<String> server = new HashSet<String>(6); 069 070 while ((line = lnr.readLine()) != null) { 071 int split = line.indexOf(PROP_DELIM); 072 if (split == -1) { 073 continue; 074 } 075 String property = line.substring(1, split); 076 077 int valueStart = split + PROP_DELIM.length(); 078 int valueEnd = line.length() - 1; 079 if (valueEnd < valueStart) { 080 // This can happen if a newline sneaks in as the first character of the property value. For example 081 // "[propName]: [\n…]". 082 if (logWarning) { 083 LOGGER.warning("Malformed property detected: \"" + line + '"'); 084 } 085 continue; 086 } 087 088 String value = line.substring(valueStart, valueEnd); 089 090 if (value.isEmpty()) { 091 continue; 092 } 093 094 if (property.endsWith(".dns") || property.endsWith(".dns1") || 095 property.endsWith(".dns2") || property.endsWith(".dns3") || 096 property.endsWith(".dns4")) { 097 098 // normalize the address 099 100 InetAddress ip = InetAddress.getByName(value); 101 102 if (ip == null) continue; 103 104 value = ip.getHostAddress(); 105 106 if (value == null) continue; 107 if (value.length() == 0) continue; 108 109 server.add(value); 110 } 111 } 112 113 return server; 114 } 115}