Cleaned up host file configuration parsing
This commit is contained in:
parent
6eee42cb35
commit
924fbb5e5d
|
@ -22,4 +22,24 @@ import java.net.Inet6Address
|
||||||
/**
|
/**
|
||||||
* A container of hosts file entries
|
* A container of hosts file entries
|
||||||
*/
|
*/
|
||||||
data class HostsFileEntries(val ipv4Entries: Map<String, Inet4Address> = emptyMap(), val ipv6Entries: Map<String, Inet6Address> = emptyMap())
|
data class HostsFileEntries(val ipv4Entries: Map<String, Inet4Address> = emptyMap(),
|
||||||
|
val ipv6Entries: Map<String, Inet6Address> = emptyMap()) {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as HostsFileEntries
|
||||||
|
|
||||||
|
if (ipv4Entries != other.ipv4Entries) return false
|
||||||
|
if (ipv6Entries != other.ipv6Entries) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = ipv4Entries.hashCode()
|
||||||
|
result = 31 * result + ipv6Entries.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ package dorkbox.netUtil.dnsUtils
|
||||||
|
|
||||||
import dorkbox.netUtil.Common.OS_WINDOWS
|
import dorkbox.netUtil.Common.OS_WINDOWS
|
||||||
import dorkbox.netUtil.Common.logger
|
import dorkbox.netUtil.Common.logger
|
||||||
import dorkbox.netUtil.IP.toBytes
|
import dorkbox.netUtil.IPv4
|
||||||
|
import dorkbox.netUtil.IPv6
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.net.Inet4Address
|
import java.net.Inet4Address
|
||||||
import java.net.Inet6Address
|
import java.net.Inet6Address
|
||||||
|
@ -89,12 +90,14 @@ object HostsFileParser {
|
||||||
* @return a [HostsFileEntries]
|
* @return a [HostsFileEntries]
|
||||||
*/
|
*/
|
||||||
fun parse(file: File, vararg charsets: Charset): HostsFileEntries {
|
fun parse(file: File, vararg charsets: Charset): HostsFileEntries {
|
||||||
|
val hostsFileEntries = HostsFileEntries()
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (file.exists() && file.isFile) {
|
if (file.exists() && file.isFile) {
|
||||||
for (charset in charsets) {
|
for (charset in charsets) {
|
||||||
BufferedReader(InputStreamReader(FileInputStream(file), charset)).use { reader ->
|
BufferedReader(InputStreamReader(FileInputStream(file), charset)).use { reader ->
|
||||||
val entries = parse(reader)
|
val entries = parse(reader)
|
||||||
if (entries != HostsFileEntries()) {
|
if (entries != hostsFileEntries) {
|
||||||
return entries
|
return entries
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -104,7 +107,7 @@ object HostsFileParser {
|
||||||
logger.warn("Failed to load and parse hosts file at " + file.path, e)
|
logger.warn("Failed to load and parse hosts file at " + file.path, e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return HostsFileEntries()
|
return hostsFileEntries
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -115,74 +118,70 @@ object HostsFileParser {
|
||||||
* @return a [HostsFileEntries]
|
* @return a [HostsFileEntries]
|
||||||
*/
|
*/
|
||||||
fun parse(reader: Reader): HostsFileEntries {
|
fun parse(reader: Reader): HostsFileEntries {
|
||||||
val buff = BufferedReader(reader)
|
|
||||||
|
|
||||||
return try {
|
val ipv4Entries = mutableMapOf<String, Inet4Address>()
|
||||||
val ipv4Entries = mutableMapOf<String, Inet4Address>()
|
val ipv6Entries = mutableMapOf<String, Inet6Address>()
|
||||||
val ipv6Entries = mutableMapOf<String, Inet6Address>()
|
|
||||||
|
|
||||||
var line: String
|
reader.useLines { lines ->
|
||||||
while (buff.readLine().also { line = it } != null) {
|
lines.map { line ->
|
||||||
// remove comment
|
// remove comments
|
||||||
val commentPosition = line.indexOf('#')
|
val commentPosition = line.indexOf('#')
|
||||||
if (commentPosition != -1) {
|
if (commentPosition != -1) {
|
||||||
line = line.substring(0, commentPosition)
|
line.substring(0, commentPosition)
|
||||||
|
} else {
|
||||||
|
line
|
||||||
}
|
}
|
||||||
|
}.map { line ->
|
||||||
|
// trim lines
|
||||||
|
line.trim()
|
||||||
|
}.filter { line ->
|
||||||
// skip empty lines
|
// skip empty lines
|
||||||
line = line.trim { it <= ' ' }
|
line.isNotEmpty()
|
||||||
if (line.isEmpty()) {
|
}.map { line ->
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// split
|
// split
|
||||||
val lineParts: MutableList<String> = ArrayList()
|
val lineParts = mutableListOf<String>()
|
||||||
for (s in WHITESPACES.split(line)) {
|
for (s in WHITESPACES.split(line)) {
|
||||||
if (s.isNotEmpty()) {
|
if (s.isNotEmpty()) {
|
||||||
lineParts.add(s)
|
lineParts.add(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lineParts
|
||||||
|
}.filter { lineParts ->
|
||||||
// a valid line should be [IP, hostname, alias*]
|
// a valid line should be [IP, hostname, alias*]
|
||||||
if (lineParts.size < 2) {
|
// skip invalid lines!
|
||||||
// skip invalid line
|
lineParts.size >= 2
|
||||||
continue
|
}.forEach { lineParts ->
|
||||||
|
val ip = lineParts[0]
|
||||||
|
val ipBytes = when {
|
||||||
|
IPv4.isValid(ip) -> IPv4.toBytes(ip)
|
||||||
|
IPv6.isValid(ip) -> IPv6.toBytes(ip)
|
||||||
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
val ipBytes = toBytes(lineParts[0])
|
if (ipBytes != null) {
|
||||||
if (ipBytes.isEmpty()) {
|
// loop over hostname and aliases, skip invalid IP
|
||||||
// skip invalid IP
|
for (i in 1 until lineParts.size) {
|
||||||
continue
|
val hostname = lineParts[i]
|
||||||
}
|
val hostnameLower = hostname.toLowerCase(Locale.ENGLISH)
|
||||||
|
val address = InetAddress.getByAddress(hostname, ipBytes)
|
||||||
// loop over hostname and aliases
|
if (address is Inet4Address) {
|
||||||
for (i in 1 until lineParts.size) {
|
val previous = ipv4Entries.put(hostnameLower, address)
|
||||||
val hostname = lineParts[i]
|
if (previous != null) {
|
||||||
val hostnameLower = hostname.toLowerCase(Locale.ENGLISH)
|
// restore, we want to keep the first entry
|
||||||
val address = InetAddress.getByAddress(hostname, ipBytes)
|
ipv4Entries[hostnameLower] = previous
|
||||||
if (address is Inet4Address) {
|
}
|
||||||
val previous = ipv4Entries.put(hostnameLower, address)
|
} else {
|
||||||
if (previous != null) {
|
val previous = ipv6Entries.put(hostnameLower, address as Inet6Address)
|
||||||
// restore, we want to keep the first entry
|
if (previous != null) {
|
||||||
ipv4Entries[hostnameLower] = previous
|
// restore, we want to keep the first entry
|
||||||
}
|
ipv6Entries[hostnameLower] = previous
|
||||||
} else {
|
}
|
||||||
val previous = ipv6Entries.put(hostnameLower, address as Inet6Address)
|
|
||||||
if (previous != null) {
|
|
||||||
// restore, we want to keep the first entry
|
|
||||||
ipv6Entries[hostnameLower] = previous
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HostsFileEntries(ipv4Entries, ipv6Entries)
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
buff.close()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
logger
|
|
||||||
.warn("Failed to close a reader", e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return HostsFileEntries(ipv4Entries, ipv6Entries)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,7 @@ import com.sun.jna.Pointer
|
||||||
import com.sun.jna.platform.win32.WinError
|
import com.sun.jna.platform.win32.WinError
|
||||||
import dorkbox.netUtil.Common
|
import dorkbox.netUtil.Common
|
||||||
import dorkbox.netUtil.Dns
|
import dorkbox.netUtil.Dns
|
||||||
import dorkbox.netUtil.IPv4
|
import dorkbox.netUtil.IP
|
||||||
import dorkbox.netUtil.IPv6
|
|
||||||
import dorkbox.netUtil.jna.windows.IPHlpAPI
|
import dorkbox.netUtil.jna.windows.IPHlpAPI
|
||||||
import dorkbox.netUtil.jna.windows.structs.IP_ADAPTER_ADDRESSES_LH
|
import dorkbox.netUtil.jna.windows.structs.IP_ADAPTER_ADDRESSES_LH
|
||||||
import dorkbox.netUtil.jna.windows.structs.IP_ADAPTER_DNS_SERVER_ADDRESS_XP
|
import dorkbox.netUtil.jna.windows.structs.IP_ADAPTER_DNS_SERVER_ADDRESS_XP
|
||||||
|
@ -189,7 +188,7 @@ object ResolveConf {
|
||||||
var maybeIP = line.substring(i)
|
var maybeIP = line.substring(i)
|
||||||
|
|
||||||
// There MIGHT be a port appended onto the IP address so we attempt to extract it.
|
// There MIGHT be a port appended onto the IP address so we attempt to extract it.
|
||||||
if (!IPv4.isValid(maybeIP) && !IPv6.isValid(maybeIP)) {
|
if (!IP.isValid(maybeIP)) {
|
||||||
i = maybeIP.lastIndexOf('.')
|
i = maybeIP.lastIndexOf('.')
|
||||||
require(i + 1 >= maybeIP.length) {
|
require(i + 1 >= maybeIP.length) {
|
||||||
"error parsing label ${NAMESERVER_ROW_LABEL} in file $path. invalid IP value: $line"
|
"error parsing label ${NAMESERVER_ROW_LABEL} in file $path. invalid IP value: $line"
|
||||||
|
|
Loading…
Reference in New Issue