Add public IP detection (from network interfaces), node outputs a warning if no public IP detected or specified in the config.

This commit is contained in:
Andrius Dagys 2017-03-03 13:30:46 +00:00
parent e8a10f2f2c
commit 97b3c35ec2
3 changed files with 98 additions and 12 deletions

View File

@ -22,9 +22,8 @@ import net.corda.node.services.config.FullNodeConfiguration
import net.corda.node.services.messaging.ArtemisMessagingComponent.NetworkMapAddress
import net.corda.node.services.messaging.ArtemisMessagingServer
import net.corda.node.services.messaging.NodeMessagingClient
import net.corda.node.services.transactions.PersistentUniquenessProvider
import net.corda.node.services.transactions.RaftUniquenessProvider
import net.corda.node.services.transactions.RaftValidatingNotaryService
import net.corda.node.services.transactions.*
import net.corda.node.utilities.AddressUtils
import net.corda.node.utilities.AffinityExecutor
import java.io.RandomAccessFile
import java.lang.management.ManagementFactory
@ -122,16 +121,47 @@ class Node(override val configuration: FullNodeConfiguration,
override fun makeMessagingService(): MessagingServiceInternal {
userService = RPCUserServiceImpl(configuration)
val serverAddress = with(configuration) {
messagingServerAddress ?: {
messageBroker = ArtemisMessagingServer(this, artemisAddress, services.networkMapCache, userService)
artemisAddress
}()
}
val serverAddress = configuration.messagingServerAddress ?: makeLocalMessageBroker()
val myIdentityOrNullIfNetworkMapService = if (networkMapAddress != null) obtainLegalIdentity().owningKey else null
return NodeMessagingClient(configuration, serverAddress, myIdentityOrNullIfNetworkMapService, serverThread, database,
networkMapRegistrationFuture)
return NodeMessagingClient(
configuration,
serverAddress,
myIdentityOrNullIfNetworkMapService,
serverThread,
database,
networkMapRegistrationFuture
)
}
private fun makeLocalMessageBroker(): HostAndPort {
with(configuration) {
val useHost = tryDetectIfNotPublicHost(artemisAddress.hostText)
val useAddress = useHost?.let { HostAndPort.fromParts(it, artemisAddress.port) } ?: artemisAddress
messageBroker = ArtemisMessagingServer(this, useAddress, services.networkMapCache, userService)
return useAddress
}
}
/**
* Checks whether the specified [host] is a public IP address or hostname. If not, tries to discover the current
* machine's public IP address to be used instead. Note that it will only work if the machine is internet-facing.
* If none found, outputs a warning message.
*/
private fun tryDetectIfNotPublicHost(host: String): String? {
if (!AddressUtils.isPublic(host)) {
val foundPublicIP = AddressUtils.tryDetectPublicIP()
if (foundPublicIP == null) {
val message = "The specified messaging host \"$host\" is private, " +
"this node will not be reachable by any other nodes outside the private network."
println("WARNING: $message")
log.warn(message)
} else {
log.info("Detected public IP: $foundPublicIP. This will be used instead the provided \"$host\" as the advertised address.")
}
return foundPublicIP?.hostAddress
}
return null
}
override fun startMessagingService(rpcOps: RPCOps) {

View File

@ -0,0 +1,25 @@
package net.corda.node.utilities
import java.net.InetAddress
import java.net.NetworkInterface
object AddressUtils {
/** Returns the first public IP address found on any of the network interfaces, or `null` if none found. */
fun tryDetectPublicIP(): InetAddress? {
for (int in NetworkInterface.getNetworkInterfaces()) {
for (address in int.inetAddresses) {
if (isPublic(address)) return address
}
}
return null
}
/** Returns `true` if the provided `address` is a public IP address or hostname. */
fun isPublic(address: InetAddress): Boolean {
return !(address.isSiteLocalAddress || address.isAnyLocalAddress ||
address.isLinkLocalAddress || address.isLoopbackAddress ||
address.isMulticastAddress)
}
fun isPublic(hostText: String) = isPublic(InetAddress.getByName(hostText))
}

View File

@ -0,0 +1,31 @@
package net.corda.node.utilities
import org.junit.Test
import java.net.InetAddress
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class AddressUtilsTests {
@Test
fun `correctly determines if the provided address is public`() {
val hostName = InetAddress.getLocalHost()
assertFalse { AddressUtils.isPublic(hostName) }
assertFalse { AddressUtils.isPublic("localhost") }
assertFalse { AddressUtils.isPublic("127.0.0.1") }
assertFalse { AddressUtils.isPublic("::1") }
assertFalse { AddressUtils.isPublic("0.0.0.0") }
assertFalse { AddressUtils.isPublic("::") }
assertFalse { AddressUtils.isPublic("10.0.0.0") }
assertFalse { AddressUtils.isPublic("10.255.255.255") }
assertFalse { AddressUtils.isPublic("192.168.0.10") }
assertFalse { AddressUtils.isPublic("192.168.255.255") }
assertFalse { AddressUtils.isPublic("172.16.0.0") }
assertFalse { AddressUtils.isPublic("172.31.255.255") }
assertTrue { AddressUtils.isPublic("172.32.0.0") }
assertTrue { AddressUtils.isPublic("192.169.0.0") }
assertTrue { AddressUtils.isPublic("11.0.0.0") }
assertTrue { AddressUtils.isPublic("corda.net") }
assertTrue { AddressUtils.isPublic("2607:f298:5:110f::eef:8729") }
}
}