Urgent bug fix for V1 to make sure the network map node rejects any node registration containing an address already belonging to another node. (#2398)

This is to prevent the duplicate address being propagated to the network, where the nodes have a DB constraint for address uniqueness, and thus they fall over when receiving the node with the duplicate address.
This commit is contained in:
Shams Asari 2018-01-19 17:21:13 +00:00 committed by GitHub
parent 254dfb43c3
commit 0c68b57cf4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 2 deletions

View File

@ -260,6 +260,12 @@ abstract class AbstractNetworkMapService(services: ServiceHubInternal,
return RegistrationResponse("Minimum platform version requirement not met: $minimumPlatformVersion")
}
val entryWithSameAddress = nodeRegistrations.entries.find { it.key != identity && it.value.reg.node.addresses.any { it in node.addresses } }
if (entryWithSameAddress != null) {
logger.warn("Registration from $node contains address of existing node $entryWithSameAddress")
return RegistrationResponse("Address already taken!")
}
// Update the current value atomically, so that if multiple updates come
// in on different threads, there is no risk of a race condition while checking
// sequence numbers.

View File

@ -5,6 +5,7 @@ import net.corda.core.identity.CordaX500Name
import net.corda.core.messaging.SingleMessageRecipient
import net.corda.core.node.NodeInfo
import net.corda.core.serialization.deserialize
import net.corda.core.utilities.NetworkHostAndPort
import net.corda.core.utilities.getOrThrow
import net.corda.node.internal.StartedNode
import net.corda.nodeapi.internal.ServiceInfo
@ -129,6 +130,28 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
assertThat(alice.fetchMap()).containsOnly(Added(mapServiceNode), Added(alice))
}
// The MockNode already registers with the network map and so we if want to force another registration we have to
// use a serial value higher than the current time, hence the use of MAX_VALUE.
@Test
fun `register node with same address as previously registered node`() {
val address = NetworkHostAndPort("localhost", 1001)
val aliceResponse = alice.registration(ADD, nodeAddresses = listOf(address), serial = Long.MAX_VALUE)
assertThat(aliceResponse.getOrThrow().error).isNull()
val bob = mockNet.createNode(mapServiceNode.network.myAddress, nodeFactory = nodeFactory, legalName = BOB.name)
val bobResponse = bob.registration(ADD, nodeAddresses = listOf(address), serial = Long.MAX_VALUE)
assertThat(bobResponse.getOrThrow().error).isEqualTo("Address already taken!")
}
@Test
fun `node can re-register using same address`() {
val address = NetworkHostAndPort("localhost", 1001)
val response1 = alice.registration(ADD, nodeAddresses = listOf(address), serial = Long.MAX_VALUE-1)
assertThat(response1.getOrThrow().error).isNull()
val response2 = alice.registration(ADD, nodeAddresses = listOf(address, NetworkHostAndPort("localhost", 1002)), serial = Long.MAX_VALUE)
assertThat(response2.getOrThrow().error).isNull()
}
@Test
fun `subscribed while new node registers`() {
val updates = alice.subscribe()
@ -213,7 +236,8 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
private var lastSerial = Long.MIN_VALUE
private fun StartedNode<*>.registration(addOrRemove: AddOrRemove,
serial: Long? = null): CordaFuture<RegistrationResponse> {
nodeAddresses: List<NetworkHostAndPort> = emptyList(),
serial: Long? = null): CordaFuture<RegistrationResponse> {
val distinctSerial = if (serial == null) {
++lastSerial
} else {
@ -221,7 +245,7 @@ abstract class AbstractNetworkMapServiceTest<out S : AbstractNetworkMapService>
serial
}
val expires = Instant.now() + NetworkMapService.DEFAULT_EXPIRATION_PERIOD
val nodeRegistration = NodeRegistration(info, distinctSerial, addOrRemove, expires)
val nodeRegistration = NodeRegistration(info.copy(addresses = nodeAddresses), distinctSerial, addOrRemove, expires)
val request = RegistrationRequest(nodeRegistration.toWire(services.keyManagementService, info.chooseIdentity().owningKey), network.myAddress)
val response = services.networkService.sendRequest<RegistrationResponse>(REGISTER_TOPIC, request, mapServiceNode.network.myAddress)
mockNet.runNetwork()