Added toLongSafe

This commit is contained in:
nathan 2020-08-11 16:24:23 +02:00
parent 0074adf5ea
commit 7c6e072739
1 changed files with 115 additions and 75 deletions

View File

@ -1,3 +1,5 @@
@file:Suppress("unused")
package dorkbox.netUtil package dorkbox.netUtil
import dorkbox.executor.Executor import dorkbox.executor.Executor
@ -15,7 +17,11 @@ import java.util.regex.Pattern
*/ */
object Mac { object Mac {
enum class MacDelimiter(val delimiter: String) { enum class MacDelimiter(val delimiter: String) {
COLON(":"), PERIOD("."), SPACE(" "); COLON(":"),
PERIOD("."),
SPACE(" ");
val regex = delimiter.toRegex()
} }
private const val MAC_ADDRESS_LENGTH = 6 private const val MAC_ADDRESS_LENGTH = 6
@ -52,7 +58,8 @@ object Mac {
} catch (e: Exception) { } catch (e: Exception) {
if (logger != null) { if (logger != null) {
logger.error("Unable to get MAC address for IP '{}'", ip, e) logger.error("Unable to get MAC address for IP '{}'", ip, e)
} else { }
else {
e.printStackTrace() e.printStackTrace()
} }
} }
@ -81,7 +88,8 @@ object Mac {
} catch (e: Exception) { } catch (e: Exception) {
if (logger != null) { if (logger != null) {
logger.error("Unable to get MAC address for IP '{}'", ip, e) logger.error("Unable to get MAC address for IP '{}'", ip, e)
} else { }
else {
e.printStackTrace() e.printStackTrace()
} }
} }
@ -108,83 +116,109 @@ object Mac {
} }
/** /**
* will also make sure that this mac doesn't already exist * Removes a mac that was in use, to free it's use later on
*
* @return a unique MAC that can be used for VPN devices + setup. This is a LOWERCASE string!
*/ */
val fakeMac: String fun freeFakeMac(fakeMacs: Iterable<String>) {
get() { synchronized(fakeMacsInUse) {
synchronized(fakeMacsInUse) { fakeMacs.forEach {
var mac = fakeVpnMacUnsafe fakeMacsInUse.remove(it)
// gotta make sure it doesn't already exist
while (fakeMacsInUse.contains(mac)) {
mac = fakeVpnMacUnsafe
}
fakeMacsInUse.add(mac)
return mac
} }
} }
}
/** /**
* will also make sure that this mac doesn't already exist * will also make sure that this mac doesn't already exist
* *
* @return a unique MAC that can be used for VPN devices + setup. This is a LOWERCASE string! * @return a unique MAC that can be used for VPN devices + setup. This is a LOWERCASE string!
*/ */
val fakeDockerMac: String fun fakeMac(): String {
get() { synchronized(fakeMacsInUse) {
synchronized(fakeMacsInUse) { var mac = fakeVpnMacUnsafe()
var mac = fakeDockerMacUnsafe
// gotta make sure it doesn't already exist // gotta make sure it doesn't already exist
while (fakeMacsInUse.contains(mac)) { while (fakeMacsInUse.contains(mac)) {
mac = fakeDockerMacUnsafe mac = fakeVpnMacUnsafe()
}
fakeMacsInUse.add(mac)
return mac
} }
fakeMacsInUse.add(mac)
return mac
} }
}
/**
* will also make sure that this mac doesn't already exist
*
* @return a unique MAC that can be used for VPN devices + setup. This is a LOWERCASE string!
*/
fun fakeDockerMac(): String {
synchronized(fakeMacsInUse) {
var mac = fakeDockerMacUnsafe()
// gotta make sure it doesn't already exist
while (fakeMacsInUse.contains(mac)) {
mac = fakeDockerMacUnsafe()
}
fakeMacsInUse.add(mac)
return mac
}
}
/** /**
* http://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines * http://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines
* *
* @return a mac that is safe to use for fake interfaces. THIS IS LOWERCASE! * @return a mac that is safe to use for fake interfaces. THIS IS LOWERCASE!
*/ */
val fakeVpnMacUnsafe: String fun fakeVpnMac(): String {
get() { var mac = fakeVpnMacUnsafe()
var vpnID = randHex
while (vpnID == "d0") {
// this is what is used for docker. NEVER assign it to a VPN mac!!
vpnID = randHex
}
return "02:$vpnID:$randHex:$randHex:$randHex:$randHex" synchronized(fakeMacsInUse) {
// gotta make sure it doesn't already exist
while (fakeMacsInUse.contains(mac)) {
mac = fakeVpnMacUnsafe()
}
fakeMacsInUse.add(mac)
} }
return mac
}
/** /**
* http://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines * http://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines
* *
* @return a mac that is safe to use for fake interfaces. THIS IS LOWERCASE! * @return a mac that is safe to use for fake interfaces. THIS IS LOWERCASE!
*/ */
val fakeDockerMacUnsafe: String fun fakeVpnMacUnsafe(): String {
get() { var vpnID = randHex
return "02:d0:$randHex:$randHex:$randHex:$randHex" while (vpnID == "d0") {
// this is what is used for docker. NEVER assign it to a VPN mac!!
vpnID = randHex
} }
return "02:$vpnID:$randHex:$randHex:$randHex:$randHex"
}
/**
* http://serverfault.com/questions/40712/what-range-of-mac-addresses-can-i-safely-use-for-my-virtual-machines
*
* @return a mac that is safe to use for fake interfaces. THIS IS LOWERCASE!
*/
fun fakeDockerMacUnsafe(): String {
return "02:d0:$randHex:$randHex:$randHex:$randHex"
}
/** /**
* will also make sure that this mac doesn't already exist * will also make sure that this mac doesn't already exist
* *
* @return a unique MAC that can be used for VPN devices + setup * @return a unique MAC that can be used for VPN devices + setup
*/ */
fun getFakeVpnMac(vpnKeyDirForExistingVpnMacs: String): String { fun fakeVpnMacWithDir(vpnKeyDirForExistingVpnMacs: String): String {
synchronized(fakeMacsInUse) { synchronized(fakeMacsInUse) {
var mac = fakeVpnMacUnsafe var mac = fakeVpnMacUnsafe()
// gotta make sure it doesn't already exist // gotta make sure it doesn't already exist
while (fakeMacsInUse.contains(mac) || File(vpnKeyDirForExistingVpnMacs, "$mac.crt").exists()) { while (fakeMacsInUse.contains(mac) || File(vpnKeyDirForExistingVpnMacs, "$mac.crt").exists()) {
mac = fakeVpnMacUnsafe mac = fakeVpnMacUnsafe()
} }
fakeMacsInUse.add(mac) fakeMacsInUse.add(mac)
@ -198,7 +232,8 @@ object Mac {
return if (i < 16) { return if (i < 16) {
"0" + Integer.toHexString(i) "0" + Integer.toHexString(i)
} else { }
else {
Integer.toHexString(i) Integer.toHexString(i)
} }
} }
@ -215,14 +250,14 @@ object Mac {
(0..8).forEach { index -> (0..8).forEach { index ->
val byte = macBytes[index] val byte = macBytes[index]
if (buf.isNotEmpty()) { if (buf.isNotEmpty()) {
buf.append(':'); buf.append(':')
} }
if (byte in 0..15) { if (byte in 0..15) {
buf.append('0'); buf.append('0')
} }
buf.append(Integer.toHexString(byte.toUByte().toInt())) buf.append(Integer.toHexString(byte.toInt() and 0xFF))
} }
return buf.toString() return buf.toString()
@ -234,21 +269,21 @@ object Mac {
val macBytes = toBytes(mac) val macBytes = toBytes(mac)
// mac should have 6 bytes. // mac should have 6 bytes.
var bytesWritten = 0; var bytesWritten = 0
(0..8).forEach { index -> (0..8).forEach { index ->
val byte = macBytes[index] val byte = macBytes[index]
if (bytesWritten != 0) { if (bytesWritten != 0) {
writer.write(":"); writer.write(":")
bytesWritten++; bytesWritten++
} }
if (byte in 0..15) { if (byte in 0..15) {
writer.append('0'); writer.append('0')
} }
writer.write(Integer.toHexString(byte.toUByte().toInt())) writer.write(Integer.toHexString(byte.toInt() and 0xFF))
bytesWritten += 2; bytesWritten += 2
} }
} }
@ -290,7 +325,8 @@ object Mac {
buf.append('0') buf.append('0')
} }
buf.append(Integer.toHexString(b.toUByte().toInt()).toUpperCase()) buf.append(Integer.toHexString(b.toInt() and 0xFF)
.toUpperCase())
} }
return buf.toString() return buf.toString()
} }
@ -300,17 +336,17 @@ object Mac {
return BigInteger(s, 16).toByteArray() return BigInteger(s, 16).toByteArray()
} }
fun toLongSafe(macAsString: String): Long {
return toLong(macAsString, getMacDelimiter(macAsString))
}
fun toLong(mac: String): Long { fun toLong(mac: String): Long {
return toLong(mac, MacDelimiter.COLON) return toLong(mac, MacDelimiter.COLON)
} }
fun toLong(mac: ByteArray): Long { fun toLong(mac: ByteArray): Long {
return ((mac[5].toLong() and 0xff) return ((mac[5].toLong() and 0xff) + (mac[4].toLong() and 0xff shl 8) + (mac[3].toLong() and 0xff shl 16) + (mac[2].toLong() and 0xff shl 24) + (mac[1].toLong() and 0xff shl 32) + (mac[0].toLong() and 0xff shl 40))
+ (mac[4].toLong() and 0xff shl 8)
+ (mac[3].toLong() and 0xff shl 16)
+ (mac[2].toLong() and 0xff shl 24)
+ (mac[1].toLong() and 0xff shl 32)
+ (mac[0].toLong() and 0xff shl 40))
} }
fun toLong(mac: String, delimiter: MacDelimiter? = MacDelimiter.COLON): Long { fun toLong(mac: String, delimiter: MacDelimiter? = MacDelimiter.COLON): Long {
@ -319,8 +355,9 @@ object Mac {
val elements: Array<String?> val elements: Array<String?>
if (delimiter != null) { if (delimiter != null) {
elements = mac.split(delimiter.delimiter.toRegex()).toTypedArray() elements = mac.split(delimiter.regex).toTypedArray()
} else { }
else {
elements = arrayOfNulls(MAC_ADDRESS_LENGTH) elements = arrayOfNulls(MAC_ADDRESS_LENGTH)
var index = 0 var index = 0
var substringPos = 0 var substringPos = 0
@ -333,7 +370,8 @@ object Mac {
for (i in 0 until MAC_ADDRESS_LENGTH) { for (i in 0 until MAC_ADDRESS_LENGTH) {
val element = elements[i] val element = elements[i]
addressInBytes[i] = element!!.toInt(16).toByte() addressInBytes[i] = element!!.toInt(16)
.toByte()
} }
} catch (e: Exception) { } catch (e: Exception) {
Common.logger.error("Error parsing MAC address '{}'", mac, e) Common.logger.error("Error parsing MAC address '{}'", mac, e)
@ -350,7 +388,8 @@ object Mac {
// Check whether mac is separated by a colon, period, space, or nothing at all. // Check whether mac is separated by a colon, period, space, or nothing at all.
// Must standardize to a colon. // Must standardize to a colon.
var normalizedMac: String = macAsString var normalizedMac: String = macAsString
if (normalizedMac.split(COLON_REGEX).toTypedArray().size != 6) { if (normalizedMac.split(COLON_REGEX)
.toTypedArray().size != 6) {
// Does not already use colons, must modify the mac to use colons. // Does not already use colons, must modify the mac to use colons.
when { when {
@ -374,7 +413,8 @@ object Mac {
// Reconstruct the string, adding colons. // Reconstruct the string, adding colons.
normalizedMac = if (index != MAC_ADDRESS_LENGTH - 1) { normalizedMac = if (index != MAC_ADDRESS_LENGTH - 1) {
normalizedMac + macAsString.substring(substringPos, substringPos + 2) + ":" normalizedMac + macAsString.substring(substringPos, substringPos + 2) + ":"
} else { }
else {
normalizedMac + macAsString.substring(substringPos, substringPos + 2) normalizedMac + macAsString.substring(substringPos, substringPos + 2)
} }
@ -389,29 +429,29 @@ object Mac {
} }
/** /**
* Returns the type of delmiter based on how a mac address is constructed. Returns null if no delimiter. * Returns the type of delmiter based on how a mac address is constructed. Returns ":" if no delimiter could be detected.
*
* @return a MacDelimiter if there is one, or null if the mac address is one long string. * @return a MacDelimiter if there is one, or null if the mac address is one long string.
*/ */
fun getMacDelimiter(macAsString: String): MacDelimiter? { fun getMacDelimiter(macAsString: String): MacDelimiter? {
when { return when {
macAsString.contains(":") -> { macAsString.contains(":") -> {
return MacDelimiter.COLON MacDelimiter.COLON
} }
macAsString.contains(".") -> { macAsString.contains(".") -> {
return MacDelimiter.PERIOD MacDelimiter.PERIOD
} }
macAsString.contains(" ") -> { macAsString.contains(" ") -> {
return MacDelimiter.SPACE MacDelimiter.SPACE
} }
else -> return null else -> MacDelimiter.COLON
} }
} }
fun assign(interfaceName: String, macAddress: String) { fun assign(interfaceName: String, macAddress: String) {
if (Common.OS_LINUX) { if (Common.OS_LINUX) {
Executor.run("/sbin/ifconfig", interfaceName, "hw", "ether", macAddress); Executor.run("/sbin/ifconfig", interfaceName, "hw", "ether", macAddress)
throw RuntimeException("NOT IMPL.") }
} else { else {
throw RuntimeException("NOT IMPL.") throw RuntimeException("NOT IMPL.")
} }
} }