mirror of
https://github.com/logos-storage/logos-storage-nim.git
synced 2026-08-03 07:23:20 +00:00
Refactor tests
This commit is contained in:
parent
b33031cdef
commit
37fd43221f
11
build.nims
11
build.nims
@ -72,9 +72,7 @@ task testStorage, "Build & run Logos Storage tests":
|
||||
task testIntegration, "Run integration tests":
|
||||
buildBinary "storage",
|
||||
outName = "storage",
|
||||
params =
|
||||
"-d:chronicles_runtime_filtering -d:chronicles_log_level=TRACE " &
|
||||
"-d:storage_enable_nat_simulation=true"
|
||||
params = "-d:chronicles_runtime_filtering -d:chronicles_log_level=TRACE"
|
||||
test "testIntegration"
|
||||
# use params to enable logging from the integration test executable
|
||||
# test "testIntegration", params = "-d:chronicles_sinks=textlines[notimestamps,stdout],textlines[dynamic] " &
|
||||
@ -94,6 +92,13 @@ task testNatPcpMapping, "Run PCP NAT integration test (requires miniupnpd contai
|
||||
putEnv("STORAGE_INTEGRATION_TEST_INCLUDES", "nat/testnatpcp.nim")
|
||||
test "testIntegration", outName = "testIntegrationNatPcp"
|
||||
|
||||
task testNatNotReachable,
|
||||
"Run NAT not-reachable scenario (needs the image + podman-compose)":
|
||||
test "integration/nat/not-reachable/testnotreachable", outName = "testNatNotReachable"
|
||||
|
||||
task testNatReachable, "Run NAT reachable scenario (needs the image + podman-compose)":
|
||||
test "integration/nat/reachable/testreachable", outName = "testNatReachable"
|
||||
|
||||
task build, "build Logos Storage binary":
|
||||
storageTask()
|
||||
|
||||
|
||||
23
openapi.yaml
23
openapi.yaml
@ -564,29 +564,6 @@ paths:
|
||||
"500":
|
||||
description: Well it was bad-bad
|
||||
|
||||
"/debug/nat/filtering":
|
||||
post:
|
||||
summary: "Set NAT simulation filtering behavior at runtime"
|
||||
description: "Only available on nodes started with --nat-simulation. Used for testing NAT transitions."
|
||||
tags: [Debug]
|
||||
operationId: setNatFiltering
|
||||
|
||||
parameters:
|
||||
- in: query
|
||||
name: filtering
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
enum: [endpoint-independent, address-dependent, address-and-port-dependent, double-nat]
|
||||
|
||||
responses:
|
||||
"200":
|
||||
description: Filtering behavior updated successfully
|
||||
"400":
|
||||
description: Missing or invalid filtering value, or NAT simulation not active
|
||||
"500":
|
||||
description: Internal error
|
||||
|
||||
"/debug/info":
|
||||
get:
|
||||
summary: "Gets node information"
|
||||
|
||||
@ -73,7 +73,6 @@ proc defaultDataDir*(): string =
|
||||
const
|
||||
storage_enable_api_debug_peers* {.booldefine.} = false
|
||||
storage_enable_log_counter* {.booldefine.} = false
|
||||
storage_enable_nat_simulation* {.booldefine.} = false
|
||||
|
||||
DefaultThreadCount* = ThreadCount(0)
|
||||
|
||||
@ -368,14 +367,6 @@ type
|
||||
name: "nat-port-mapping-recheck-period"
|
||||
.}: int
|
||||
|
||||
natSimulation* {.
|
||||
desc:
|
||||
"Simulate NAT filtering behavior for testing: endpoint-independent, address-dependent, address-and-port-dependent",
|
||||
defaultValue: string.none,
|
||||
name: "nat-simulation",
|
||||
hidden
|
||||
.}: Option[string]
|
||||
|
||||
autonatServer* {.
|
||||
desc: "Enable AutoNAT server to help other nodes check their reachability",
|
||||
defaultValue: false,
|
||||
|
||||
@ -128,6 +128,9 @@ proc stop*(m: NatPortMapper) =
|
||||
proc isPortMapped*(m: NatPortMapper, port: Port): bool =
|
||||
m.activeTcpPort.isSome and m.activeTcpPort.get == port
|
||||
|
||||
method hasActiveMapping*(m: NatPortMapper): bool {.base, gcsafe.} =
|
||||
m.tcpMappingId.isSome and m.udpMappingId.isSome
|
||||
|
||||
proc announcePeerInfoAddrs*(discovery: Discovery, peerInfo: PeerInfo, udpPort: Port) =
|
||||
## Announces peerInfo.addrs to the DHT, excluding relay circuit addresses:
|
||||
## they are announced via onReservation and must not enter the DHT routing
|
||||
@ -192,11 +195,11 @@ method handleNatStatus*(
|
||||
if dialBackAddr.isNone:
|
||||
warn "Got empty dialback address in AutoNat when node is NotReachable"
|
||||
|
||||
if m.tcpMappingId.isSome and m.udpMappingId.isSome:
|
||||
if m.hasActiveMapping():
|
||||
m.close()
|
||||
|
||||
discovery.announceDirectAddrs(@[], udpPort = discoveryPort)
|
||||
elif m.tcpMappingId.isSome and m.udpMappingId.isSome:
|
||||
elif m.hasActiveMapping():
|
||||
warn "Not Reachable with active port mapping. The port mapping will be deleted and relay will start."
|
||||
|
||||
# The mapping was created the the node is still not reachable.
|
||||
|
||||
@ -40,7 +40,6 @@ import ../stores/repostore
|
||||
import ../blockexchange
|
||||
import ../units
|
||||
import ../utils/options
|
||||
import ../utils/natsimulation
|
||||
import ../nat
|
||||
|
||||
import ./coders
|
||||
@ -565,7 +564,6 @@ proc initDebugApi(
|
||||
autonat: Option[AutonatV2Service],
|
||||
autoRelay: Option[AutoRelayService],
|
||||
natMapper: Option[NatPortMapper],
|
||||
natRouter: Option[NatRouter],
|
||||
router: var RestRouter,
|
||||
) =
|
||||
let allowedOrigin = router.allowedOrigin
|
||||
@ -630,28 +628,6 @@ proc initDebugApi(
|
||||
trace "Excepting processing request", exc = exc.msg
|
||||
return RestApiResponse.error(Http500, headers = headers)
|
||||
|
||||
when storage_enable_nat_simulation:
|
||||
router.api(MethodPost, "/api/storage/v1/debug/nat/filtering") do(
|
||||
filtering: Option[string]
|
||||
) -> RestApiResponse:
|
||||
var headers = buildCorsHeaders("POST", allowedOrigin)
|
||||
|
||||
without natSimulation =? natRouter:
|
||||
return RestApiResponse.error(
|
||||
Http400, "NAT simulation not active on this node", headers = headers
|
||||
)
|
||||
|
||||
without res =? filtering and filtering =? res:
|
||||
return
|
||||
RestApiResponse.error(Http400, "Missing filtering value", headers = headers)
|
||||
|
||||
let behavior = FilteringBehavior.fromString(filtering).valueOr:
|
||||
return
|
||||
RestApiResponse.error(Http400, "Invalid filtering value", headers = headers)
|
||||
|
||||
natSimulation.setFiltering(behavior)
|
||||
return RestApiResponse.response("", headers = headers)
|
||||
|
||||
when storage_enable_api_debug_peers:
|
||||
router.api(MethodGet, "/api/storage/v1/debug/peer/{peerId}") do(
|
||||
peerId: PeerId
|
||||
@ -679,13 +655,12 @@ proc initRestApi*(
|
||||
autonat: Option[AutonatV2Service],
|
||||
autoRelay: Option[AutoRelayService],
|
||||
natMapper: Option[NatPortMapper],
|
||||
natRouter: Option[NatRouter],
|
||||
corsAllowedOrigin: ?string,
|
||||
): RestRouter =
|
||||
var router = RestRouter.init(validate, corsAllowedOrigin)
|
||||
|
||||
initDataApi(node, repoStore, router)
|
||||
initNodeApi(node, conf, router)
|
||||
initDebugApi(node, conf, autonat, autoRelay, natMapper, natRouter, router)
|
||||
initDebugApi(node, conf, autonat, autoRelay, natMapper, router)
|
||||
|
||||
return router
|
||||
|
||||
@ -22,6 +22,7 @@ import pkg/libp2p/protocols/connectivity/autonatv2/[service, client]
|
||||
import pkg/libp2p/protocols/connectivity/relay/client as relayClientModule
|
||||
import pkg/libp2p/protocols/connectivity/relay/relay as relayModule
|
||||
import pkg/libp2p/services/autorelayservice
|
||||
import pkg/libp2p/transports/tcptransport
|
||||
import pkg/confutils
|
||||
import pkg/confutils/defs
|
||||
import pkg/stew/io2
|
||||
@ -43,11 +44,15 @@ import ./storagetypes
|
||||
import ./logutils
|
||||
import ./nat
|
||||
import ./utils/natutils
|
||||
import ./utils/natsimulation
|
||||
|
||||
logScope:
|
||||
topics = "storage node"
|
||||
|
||||
const StorageTransportFlags = {ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay}
|
||||
|
||||
proc tcpTransportBuilder(config: TransportConfig): Transport {.gcsafe, raises: [].} =
|
||||
TcpTransport.new(StorageTransportFlags, config.upgr)
|
||||
|
||||
type
|
||||
StorageServer* = ref object
|
||||
config: StorageConf
|
||||
@ -237,8 +242,10 @@ proc new*(
|
||||
config: StorageConf,
|
||||
privateKey: StoragePrivateKey,
|
||||
logFile: Option[IoHandle] = IoHandle.none,
|
||||
transportBuilder: TransportBuilder = tcpTransportBuilder,
|
||||
): StorageServer =
|
||||
## create StorageServer including setting up datastore, repostore, etc
|
||||
## create StorageServer including setting up datastore, repostore, etc.
|
||||
## ``transportBuilder`` defaults to TCP; tests inject a simulated NAT transport.
|
||||
|
||||
if err =? config.validateAutonatConfig().errorOption:
|
||||
raise newException(StorageError, err.msg)
|
||||
@ -320,32 +327,7 @@ proc new*(
|
||||
# addresses.
|
||||
switchBuilder = switchBuilder.withAddressPolicy(dialableAddressPolicy)
|
||||
|
||||
var natRouter: Option[NatRouter]
|
||||
let switch =
|
||||
when storage_enable_nat_simulation:
|
||||
if config.natSimulation.isSome:
|
||||
# Provide a NAT simulation useful for testing NAT Traversal
|
||||
let filtering = FilteringBehavior.fromString(config.natSimulation.get).valueOr(
|
||||
AddressAndPortDependent
|
||||
)
|
||||
let router = NatRouter.new(filtering)
|
||||
natRouter = some(router)
|
||||
switchBuilder
|
||||
.withNatTransport(router, {ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay})
|
||||
.build()
|
||||
else:
|
||||
switchBuilder
|
||||
.withTcpTransport({ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay})
|
||||
.build()
|
||||
else:
|
||||
if config.natSimulation.isSome:
|
||||
raise newException(
|
||||
StorageError,
|
||||
"--nat-simulation requires a build with -d:storage_enable_nat_simulation=true",
|
||||
)
|
||||
switchBuilder
|
||||
.withTcpTransport({ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay})
|
||||
.build()
|
||||
let switch = switchBuilder.withTransport(transportBuilder).build()
|
||||
|
||||
var taskPool: Taskpool
|
||||
|
||||
@ -500,10 +482,6 @@ proc new*(
|
||||
)
|
||||
)
|
||||
|
||||
# natRouter is some only when using nat simulation
|
||||
if natRouter.isSome:
|
||||
natRouter.get.natMapper = natMapper
|
||||
|
||||
peerInfoObserver =
|
||||
some(setupPeerInfoObserver(switch, autonatService.get, discovery, natMapper.get))
|
||||
|
||||
@ -529,7 +507,7 @@ proc new*(
|
||||
restServer = RestServerRef
|
||||
.new(
|
||||
storageNode.initRestApi(
|
||||
config, repoStore, autonatService, autoRelayService, natMapper, natRouter,
|
||||
config, repoStore, autonatService, autoRelayService, natMapper,
|
||||
config.apiCorsAllowedOrigin,
|
||||
),
|
||||
initTAddress(config.apiBindAddress.get(), config.apiPort),
|
||||
|
||||
@ -1,132 +0,0 @@
|
||||
import std/options
|
||||
import pkg/chronos
|
||||
import pkg/questionable/results
|
||||
|
||||
import ../multinodes
|
||||
import ../storageclient
|
||||
import ../storageconfig
|
||||
import ../nathelper
|
||||
|
||||
export nathelper
|
||||
|
||||
const DetectionTimeout = 15_000
|
||||
|
||||
# Reminder: multinodesuite setup the first node as bootstrap node
|
||||
multinodesuite "AutoNAT detection":
|
||||
let natConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
test "node is reachable when using bootstrap node on same network", natConfig:
|
||||
let node2 = clients()[1]
|
||||
await node2.client.checkReachable()
|
||||
|
||||
let endpointIndependentConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "endpoint-independent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
# EIF = Endpoint Independent Filtering
|
||||
test "node with simulated EIF nat is detected as reachable", endpointIndependentConfig:
|
||||
let node2 = clients()[1]
|
||||
await node2.client.checkReachable()
|
||||
|
||||
let autonatConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "address-and-port-dependent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
# APDF = Address and Port-Dependent Filtering
|
||||
test "node with simulated APDF nat is detected as not reachable and starts relay",
|
||||
autonatConfig:
|
||||
let node2 = clients()[1]
|
||||
await node2.client.checkNotReachable()
|
||||
|
||||
let transitionConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "address-and-port-dependent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
# APDF = Address and Port-Dependent Filtering
|
||||
# EIF = Endpoint Independent Filtering
|
||||
test "node with simulated APDF nat recovers to reachable and stops relay when nat switches to EIF nat",
|
||||
transitionConfig:
|
||||
let node2 = clients()[1]
|
||||
|
||||
await node2.client.checkNotReachable()
|
||||
check (await node2.client.setNatFiltering("endpoint-independent")).isOk
|
||||
await node2.client.checkReachable()
|
||||
|
||||
let natToSimConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "endpoint-independent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
# APDF = Address and Port-Dependent Filtering
|
||||
test "reachable node becomes not reachable and starts relay when nat switches to APDF nat",
|
||||
natToSimConfig:
|
||||
let node2 = clients()[1]
|
||||
|
||||
await node2.client.checkReachable()
|
||||
check (await node2.client.setNatFiltering("address-and-port-dependent")).isOk
|
||||
await node2.client.checkNotReachable()
|
||||
|
||||
let doubleNatConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "double-nat")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
test "node behind double NAT is detected as not reachable and starts relay",
|
||||
doubleNatConfig:
|
||||
let node2 = clients()[1]
|
||||
await node2.client.checkNotReachable()
|
||||
|
||||
let multiNatConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 3)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "address-and-port-dependent")
|
||||
.withNatSimulation(idx = 2, "address-and-port-dependent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
# APDF = Address and Port-Dependent Filtering
|
||||
test "two nodes with simulated APDF nat starts relay through the same relay node",
|
||||
multiNatConfig:
|
||||
let node2 = clients()[1]
|
||||
let node3 = clients()[2]
|
||||
|
||||
await node2.client.checkNotReachable()
|
||||
await node3.client.checkNotReachable()
|
||||
@ -1,74 +0,0 @@
|
||||
import std/[json, sequtils]
|
||||
import pkg/chronos
|
||||
import pkg/questionable/results
|
||||
|
||||
import ../multinodes
|
||||
import ../storageclient
|
||||
import ../storageconfig
|
||||
import ../nathelper
|
||||
|
||||
const
|
||||
RelayTimeout = 30_000
|
||||
PollInterval = 1_000
|
||||
|
||||
multinodesuite "NAT download":
|
||||
let natDownloadConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 3)
|
||||
.withRelay(idx = 0)
|
||||
.withNatSimulation(idx = 2, "address-and-port-dependent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
# APDF = Address and Port-Dependent Filtering
|
||||
test "node 3 with simulated APDF downloads content from reachable seed node 2",
|
||||
natDownloadConfig:
|
||||
let seed = clients()[1]
|
||||
let natNode = clients()[2]
|
||||
|
||||
let content = "content for nat download test"
|
||||
let cid = (await seed.client.upload(content)).get
|
||||
|
||||
check eventuallySafe(
|
||||
(await natNode.client.download(cid)).isOk,
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
check (await natNode.client.download(cid)).get == content
|
||||
|
||||
# APDF = Address and Port-Dependent Filtering
|
||||
test "reachable node 2 downloads content from node 3 with simulated APDF via relay",
|
||||
natDownloadConfig:
|
||||
let seed = clients()[1]
|
||||
let natNode = clients()[2]
|
||||
|
||||
check eventuallySafe(
|
||||
(await natNode.client.natRelayRunning()).get(),
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
# relayRunning only means the service started: the reservation itself
|
||||
# takes a few more seconds, so we have to poll.
|
||||
proc advertisesCircuitAddr(): Future[bool] {.async.} =
|
||||
let info = (await natNode.client.info()).get
|
||||
let addrs = info["addrs"].getElems.mapIt(it.getStr)
|
||||
return addrs.anyIt("p2p-circuit" in it)
|
||||
|
||||
check eventuallySafe(
|
||||
await advertisesCircuitAddr(), timeout = RelayTimeout, pollInterval = PollInterval
|
||||
)
|
||||
|
||||
let content = "content seeded from nat node"
|
||||
let cid = (await natNode.client.upload(content)).get
|
||||
|
||||
check eventuallySafe(
|
||||
(await seed.client.download(cid)).isOk,
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
check (await seed.client.download(cid)).get == content
|
||||
@ -44,25 +44,3 @@ multinodesuite "Rest API validation":
|
||||
check:
|
||||
response.status == 400
|
||||
(await response.body) == "Incorrect Cid"
|
||||
|
||||
test "nat/filtering returns 400 when nat simulation not active", config:
|
||||
let response = await client.post(
|
||||
client.buildUrl("/debug/nat/filtering?filtering=endpoint-independent")
|
||||
)
|
||||
check response.status == 400
|
||||
|
||||
let natSimConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 1)
|
||||
.withNatSimulation(idx = 0, "address-and-port-dependent").some
|
||||
)
|
||||
|
||||
test "nat/filtering returns 400 for invalid filtering value", natSimConfig:
|
||||
let response = await client.post(
|
||||
client.buildUrl("/debug/nat/filtering?filtering=not-a-valid-value")
|
||||
)
|
||||
check response.status == 400
|
||||
|
||||
test "nat/filtering returns 400 when filtering param is missing", natSimConfig:
|
||||
let response = await client.post(client.buildUrl("/debug/nat/filtering"))
|
||||
check response.status == 400
|
||||
|
||||
@ -283,12 +283,3 @@ proc natPortMapping*(
|
||||
return info.get()["nat"]["portMapping"].getStr().success
|
||||
except KeyError as e:
|
||||
return failure e.msg
|
||||
|
||||
proc setNatFiltering*(
|
||||
client: StorageClient, filtering: string
|
||||
): Future[?!void] {.async: (raises: [CancelledError, HttpError]).} =
|
||||
let response =
|
||||
await client.post(client.baseurl & "/debug/nat/filtering?filtering=" & filtering)
|
||||
if response.status != 200:
|
||||
return failure "Failed to set NAT filtering: " & $response.status
|
||||
return success()
|
||||
|
||||
@ -346,15 +346,6 @@ proc isBootstrapNode*(config: StorageConfig): bool {.raises: [].} =
|
||||
|
||||
return false
|
||||
|
||||
proc withNatSimulation*(
|
||||
self: StorageConfigs, idx: int, filtering: string
|
||||
): StorageConfigs {.raises: [StorageConfigError].} =
|
||||
self.checkBounds idx
|
||||
|
||||
var startConfig = self
|
||||
startConfig.configs[idx].addCliOption("--nat-simulation", filtering)
|
||||
return startConfig
|
||||
|
||||
proc withAutonatServer*(
|
||||
self: StorageConfigs, idx: int
|
||||
): StorageConfigs {.raises: [StorageConfigError].} =
|
||||
|
||||
@ -1,93 +0,0 @@
|
||||
import std/[json, strutils, sequtils]
|
||||
import pkg/chronos
|
||||
import pkg/questionable/results
|
||||
|
||||
import ../integration/multinodes
|
||||
import ../integration/storageclient
|
||||
import ../integration/storageconfig
|
||||
|
||||
import ../integration/nathelper
|
||||
|
||||
multinodesuite "AutoNAT PCP port mapping":
|
||||
let pcpConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "address-and-port-dependent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
|
||||
test "node behind NAT maps ports via PCP and exposes mapping in debug info", pcpConfig:
|
||||
let node2 = clients()[1]
|
||||
|
||||
await node2.client.checkNotReachable(relayRunning = false)
|
||||
|
||||
check eventuallySafe(
|
||||
block:
|
||||
let res = await node2.client.natPortMapping()
|
||||
res.isOk and res.get == "pcp",
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
await node2.client.checkReachable()
|
||||
|
||||
await node2.stop()
|
||||
|
||||
let relayFallbackConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "double-nat")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
# Increase the max queue to trigger the AutoNat 2 times
|
||||
.withNatMaxQueueSize(2).some
|
||||
)
|
||||
|
||||
test "node behind double NAT falls back to relay after PCP mapping does not help",
|
||||
relayFallbackConfig:
|
||||
let node2 = clients()[1]
|
||||
|
||||
await node2.client.checkNotReachable(relayRunning = false)
|
||||
|
||||
check eventuallySafe(
|
||||
block:
|
||||
let res = await node2.client.natPortMapping()
|
||||
res.isOk and res.get == "pcp",
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
# Wait for next Autonat iteration
|
||||
await sleepAsync(6.seconds)
|
||||
|
||||
await node2.client.checkNotReachable()
|
||||
|
||||
test "reachable node downloads content uploaded by node behind NAT after PCP mapping",
|
||||
pcpConfig:
|
||||
let node1 = clients()[0]
|
||||
let node2 = clients()[1]
|
||||
|
||||
check eventuallySafe(
|
||||
block:
|
||||
let res = await node2.client.natPortMapping()
|
||||
res.isOk and res.get == "pcp",
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
let content = "content uploaded by nat node"
|
||||
let cid = (await node2.client.upload(content)).get
|
||||
|
||||
check eventuallySafe(
|
||||
(await node1.client.download(cid)).isOk,
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
check (await node1.client.download(cid)).get == content
|
||||
@ -1,94 +0,0 @@
|
||||
import std/[json, strutils, sequtils]
|
||||
import pkg/chronos
|
||||
import pkg/questionable/results
|
||||
|
||||
import ../integration/multinodes
|
||||
import ../integration/storageclient
|
||||
import ../integration/storageconfig
|
||||
|
||||
import ../integration/nathelper
|
||||
|
||||
multinodesuite "AutoNAT UPnP port mapping":
|
||||
let upnpConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "address-and-port-dependent")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
.withNatMaxQueueSize(1).some
|
||||
)
|
||||
|
||||
test "node behind NAT maps ports via UPnP and exposes mapping in debug info",
|
||||
upnpConfig:
|
||||
let node2 = clients()[1]
|
||||
|
||||
await node2.client.checkNotReachable(relayRunning = false)
|
||||
|
||||
check eventuallySafe(
|
||||
block:
|
||||
let res = await node2.client.natPortMapping()
|
||||
res.isOk and res.get == "upnp",
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
await node2.client.checkReachable()
|
||||
|
||||
await node2.stop()
|
||||
|
||||
let relayFallbackConfig = NodeConfigs(
|
||||
clients: StorageConfigs
|
||||
.init(nodes = 2)
|
||||
.withRelay(0)
|
||||
.withNatSimulation(idx = 1, "double-nat")
|
||||
.withNatNumPeersToAsk(1)
|
||||
.withNatMinConfidence(0.5)
|
||||
.withNatScheduleInterval(NatScheduleInterval)
|
||||
# Increase the max queue to trigger the AutoNat 2 times
|
||||
.withNatMaxQueueSize(2).some
|
||||
)
|
||||
|
||||
test "node behind double NAT falls back to relay after UPnP mapping does not help",
|
||||
relayFallbackConfig:
|
||||
let node2 = clients()[1]
|
||||
|
||||
await node2.client.checkNotReachable(relayRunning = false)
|
||||
|
||||
check eventuallySafe(
|
||||
block:
|
||||
let res = await node2.client.natPortMapping()
|
||||
res.isOk and res.get == "upnp",
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
# Wait for next Autonat iteration
|
||||
await sleepAsync(6.seconds)
|
||||
|
||||
await node2.client.checkNotReachable()
|
||||
|
||||
test "reachable node downloads content uploaded by node behind NAT after UPnP mapping",
|
||||
upnpConfig:
|
||||
let node1 = clients()[0]
|
||||
let node2 = clients()[1]
|
||||
|
||||
check eventuallySafe(
|
||||
block:
|
||||
let res = await node2.client.natPortMapping()
|
||||
res.isOk and res.get == "upnp",
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
let content = "content uploaded by nat node"
|
||||
let cid = (await node2.client.upload(content)).get
|
||||
|
||||
check eventuallySafe(
|
||||
(await node1.client.download(cid)).isOk,
|
||||
timeout = RelayTimeout,
|
||||
pollInterval = PollInterval,
|
||||
)
|
||||
|
||||
check (await node1.client.download(cid)).get == content
|
||||
@ -1,11 +1,8 @@
|
||||
# NAT simulation for integration testing.
|
||||
#
|
||||
# Testing NAT traversal in CI requires controlling inbound/outbound filtering
|
||||
# rules, which is not possible with real network interfaces. This module wraps
|
||||
# the TCP transport to enforce configurable filtering behaviors (endpoint-
|
||||
# independent, address-dependent, address-and-port-dependent, double NAT) at
|
||||
# the connection level, so the full AutoNAT detection and relay
|
||||
# stack can be exercised without actual NAT hardware.
|
||||
# It simulates the filtering behaviors (endpoint-independent, address-dependent,
|
||||
# address-and-port-dependent, double NAT) at the connection level, so the full
|
||||
# AutoNAT detection and relay stack can be exercised without actual NAT hardware.
|
||||
|
||||
{.push raises: [].}
|
||||
|
||||
@ -18,7 +15,7 @@ import pkg/libp2p/transports/tcptransport
|
||||
import pkg/libp2p/transports/transport
|
||||
import pkg/libp2p/wire
|
||||
|
||||
import ../nat
|
||||
import ../../storage/nat
|
||||
|
||||
logScope:
|
||||
topics = "nat simulation"
|
||||
241
tests/storage/testnatdetection.nim
Normal file
241
tests/storage/testnatdetection.nim
Normal file
@ -0,0 +1,241 @@
|
||||
## NAT detection unit tests: real AutoNAT v2 detecting
|
||||
## through the NAT simulation, feeding storage's handleNatStatus, which drives
|
||||
## the relay and client mode.
|
||||
##
|
||||
## The MockNatPortMapper simulates a failing port mapping. This is not the aspect
|
||||
## of the NAT detection that is being tested: we want to test the NAT detection
|
||||
## logic itself, not the port mapping logic.
|
||||
|
||||
import std/options
|
||||
import pkg/chronos
|
||||
import pkg/libp2p except setup
|
||||
import pkg/libp2p/protocols/connectivity/autonatv2/service except setup
|
||||
import pkg/libp2p/protocols/connectivity/autonatv2/client except setup
|
||||
import pkg/libp2p/protocols/connectivity/autonatv2/types as autonatv2Types
|
||||
import pkg/libp2p/protocols/connectivity/relay/client as relayClientModule
|
||||
import pkg/libp2p/services/autorelayservice except setup
|
||||
import pkg/libp2p/observedaddrmanager
|
||||
|
||||
import ./helpers
|
||||
import ./natsimulation
|
||||
import ../asynctest
|
||||
import ../../storage/utils/natutils
|
||||
import ../../storage/nat
|
||||
import ../../storage/discovery
|
||||
import ../../storage/rng
|
||||
|
||||
const
|
||||
flags = {ServerFlags.ReuseAddr}
|
||||
listenAddr = "/ip4/127.0.0.1/tcp/0"
|
||||
discoveryPort = Port(8090)
|
||||
# ms — AutoNAT probe + confidence + reaction
|
||||
detectTimeout = 20000
|
||||
|
||||
type MockNatPortMapper = ref object of NatPortMapper
|
||||
|
||||
method mapNatPorts*(
|
||||
m: MockNatPortMapper
|
||||
): Future[Option[(Port, Port, MappingProtocol)]] {.
|
||||
async: (raises: [CancelledError]), gcsafe
|
||||
.} =
|
||||
none((Port, Port, MappingProtocol))
|
||||
|
||||
# Captures the candidate addresses the service sends and answers Reachable, so
|
||||
# the service flips to reachable and runs its address mapper — without dialing.
|
||||
type MockAutonatV2Client = ref object of AutonatV2Client
|
||||
reqAddrs: seq[MultiAddress]
|
||||
|
||||
method sendDialRequest*(
|
||||
self: MockAutonatV2Client, pid: PeerId, testAddrs: seq[MultiAddress]
|
||||
): Future[AutonatV2Response] {.
|
||||
async: (raises: [AutonatV2Error, CancelledError, DialFailedError, LPStreamError])
|
||||
.} =
|
||||
self.reqAddrs = testAddrs
|
||||
AutonatV2Response(reachability: Reachable)
|
||||
|
||||
proc serverSwitch(): Switch =
|
||||
SwitchBuilder
|
||||
.new()
|
||||
.withRng(Rng.instance())
|
||||
.withPrivateKey(PrivateKey.random(Rng.instance()).get())
|
||||
.withAddresses(@[MultiAddress.init(listenAddr).get()])
|
||||
.withTcpTransport(flags)
|
||||
.withNoise()
|
||||
.withYamux()
|
||||
.withAutonatV2Server()
|
||||
.build()
|
||||
|
||||
asyncchecksuite "NAT detection - simulated NAT":
|
||||
var
|
||||
natNode: Switch
|
||||
autonat: AutonatV2Service
|
||||
relay: AutoRelayService
|
||||
disc: Discovery
|
||||
server: Switch
|
||||
|
||||
proc setupTopology(router: NatRouter) {.async.} =
|
||||
let relayClient = relayClientModule.RelayClient.new()
|
||||
natNode = SwitchBuilder
|
||||
.new()
|
||||
.withRng(Rng.instance())
|
||||
.withPrivateKey(PrivateKey.random(Rng.instance()).get())
|
||||
.withAddresses(@[MultiAddress.init(listenAddr).get()])
|
||||
.withNatTransport(router, flags)
|
||||
.withNoise()
|
||||
.withYamux()
|
||||
.withCircuitRelay(relayClient)
|
||||
.build()
|
||||
|
||||
relay = AutoRelayService.new(1, relayClient, nil, Rng.instance())
|
||||
autorelayservice.setup(relay, natNode)
|
||||
disc = Discovery.new(PrivateKey.random(Rng.instance()).get(), announceAddrs = @[])
|
||||
# nodes start in client mode until Reachable
|
||||
disc.protocol.clientMode = true
|
||||
|
||||
# Setup real AutoNAT v2 client using nat simulation
|
||||
let autonatClient = AutonatV2Client.new(natNode.rng)
|
||||
client.setup(autonatClient, natNode)
|
||||
natNode.mount(autonatClient)
|
||||
|
||||
# Setup AutoNAT v2 service with maxQueueSize=1 and minConfidence=0.5,
|
||||
# so a single dial-back answer (confidence 1.0) is needed.
|
||||
let config = AutonatV2ServiceConfig.new(
|
||||
scheduleInterval = Opt.some(1.seconds),
|
||||
askNewConnectedPeers = true,
|
||||
numPeersToAsk = 1,
|
||||
maxQueueSize = 1,
|
||||
minConfidence = 0.5,
|
||||
)
|
||||
autonat = AutonatV2Service.new(natNode.rng, autonatClient, config)
|
||||
service.setup(autonat, natNode)
|
||||
|
||||
autonat.setStatusAndConfidenceHandler(
|
||||
proc(
|
||||
reachability: NetworkReachability,
|
||||
confidence: Opt[float],
|
||||
addrs: Opt[MultiAddress],
|
||||
) {.async: (raises: [CancelledError]).} =
|
||||
# One call to our handleNatStatus handler
|
||||
await MockNatPortMapper().handleNatStatus(
|
||||
reachability, addrs, discoveryPort, disc, natNode, relay
|
||||
)
|
||||
)
|
||||
|
||||
# Create and start one Autonat server (maxQueueSize=1 and minConfidence=0.5)
|
||||
server = serverSwitch()
|
||||
await server.start()
|
||||
|
||||
# Start the NAT node and connect to the Autonat server (bootstrap node in our network).
|
||||
# Then start the Autonat service on the NAT node.
|
||||
await natNode.start()
|
||||
await natNode.connect(server.peerInfo.peerId, server.peerInfo.addrs)
|
||||
await autonat.start(natNode)
|
||||
|
||||
teardown:
|
||||
await autonat.stop(natNode)
|
||||
|
||||
if relay.isRunning:
|
||||
await relay.stop(natNode)
|
||||
|
||||
await natNode.stop()
|
||||
await server.stop()
|
||||
|
||||
test "node behind EIF nat ends up reachable: no relay, not in client mode":
|
||||
await setupTopology(NatRouter.new(EndpointIndependent))
|
||||
check eventually(
|
||||
not relay.isRunning and not disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
test "node behind APDF nat ends up not reachable: relay running, client mode":
|
||||
await setupTopology(NatRouter.new(AddressAndPortDependent))
|
||||
check eventually(
|
||||
relay.isRunning and disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
test "node behind double NAT ends up not reachable: relay running, client mode":
|
||||
await setupTopology(NatRouter.new(DoubleNat))
|
||||
check eventually(
|
||||
relay.isRunning and disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
test "node recovers (relay stops) when nat switches from APDF to EIF":
|
||||
let router = NatRouter.new(AddressAndPortDependent)
|
||||
await setupTopology(router)
|
||||
check eventually(
|
||||
relay.isRunning and disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
router.setFiltering(EndpointIndependent)
|
||||
check eventually(
|
||||
not relay.isRunning and not disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
test "node degrades (relay starts) when nat switches from EIF to APDF":
|
||||
let router = NatRouter.new(EndpointIndependent)
|
||||
await setupTopology(router)
|
||||
check eventually(
|
||||
not relay.isRunning and not disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
router.setFiltering(AddressAndPortDependent)
|
||||
check eventually(
|
||||
relay.isRunning and disc.protocol.clientMode, timeout = detectTimeout
|
||||
)
|
||||
|
||||
asyncchecksuite "NAT detection - dial request candidates":
|
||||
# This detects is useful to detect behaviour changes in libp2p
|
||||
# that may break our autonat dial request candidate handling.
|
||||
#
|
||||
# By default, Autonat V2 dials the addresses passed to peerInfo.addrs and
|
||||
# uses the first attempt to dial as the primary candidate.
|
||||
#
|
||||
# With enableDialableCandidates, Autonat V2 also dials the guessDialableAddress
|
||||
# as first candidate and use the most observed address as the fallback.
|
||||
var sw: Switch
|
||||
|
||||
setup:
|
||||
sw = newStandardSwitch()
|
||||
await sw.start()
|
||||
|
||||
teardown:
|
||||
await sw.stop()
|
||||
|
||||
test "autonat handles the observed dialable address":
|
||||
let mockClient = MockAutonatV2Client()
|
||||
let autonat = AutonatV2Service.new(
|
||||
Rng.instance(),
|
||||
mockClient,
|
||||
AutonatV2ServiceConfig.new(
|
||||
enableDialableCandidates = true, maxQueueSize = 1, minConfidence = 0.5
|
||||
),
|
||||
)
|
||||
service.setup(autonat, sw)
|
||||
await autonat.start(sw) # registers the address mapper on peerInfo
|
||||
|
||||
# observations before the manager trusts an addr in libp2p; the observed
|
||||
# port (4001) differs from our listen port on purpose (see dialable below)
|
||||
let quorum = 3
|
||||
let observed = MultiAddress.init("/ip4/8.8.8.8/tcp/4001").expect("valid")
|
||||
for _ in 0 ..< quorum:
|
||||
discard sw.peerStore.identify.observedAddrManager.addObservation(observed)
|
||||
|
||||
let sw2 = newStandardSwitch()
|
||||
await sw2.start()
|
||||
await sw.connect(sw2.peerInfo.peerId, sw2.peerInfo.addrs)
|
||||
|
||||
# The dialable candidate keeps our real listen port and swaps in the
|
||||
# observed IP. It must be reached via AutoNAT and peerInfo, so it can only
|
||||
# come from guessDialableAddr.
|
||||
let tcpPart = sw.peerInfo.listenAddrs[0][1].expect("valid")
|
||||
let dialable =
|
||||
concat(MultiAddress.init("/ip4/8.8.8.8").expect("valid"), tcpPart).expect("valid")
|
||||
|
||||
# Phase 1: it is submitted as a dial candidate, not 127.0.0.1 from
|
||||
# newStandardSwitch.
|
||||
check eventually(dialable in mockClient.reqAddrs)
|
||||
|
||||
# Phase 2: the address mapper promotes it into peerInfo.
|
||||
check eventually(dialable in sw.peerInfo.addrs)
|
||||
|
||||
await autonat.stop(sw)
|
||||
await sw2.stop()
|
||||
@ -3,11 +3,7 @@ import pkg/chronos
|
||||
import pkg/libp2p/[multiaddress, multihash, multicodec]
|
||||
import pkg/libp2p/protocols/connectivity/autonat/types
|
||||
import pkg/libp2p/protocols/connectivity/autonatv2/service except setup
|
||||
import pkg/libp2p/protocols/connectivity/autonatv2/client except setup
|
||||
import pkg/libp2p/protocols/connectivity/autonatv2/types as autonatv2Types
|
||||
import pkg/libp2p/protocols/connectivity/relay/client as relayClientModule
|
||||
import pkg/libp2p/protocols/connectivity/dcutr/core as dcutrCore
|
||||
import pkg/libp2p/multistream
|
||||
import pkg/libp2p/services/autorelayservice except setup
|
||||
import pkg/results
|
||||
|
||||
@ -21,6 +17,7 @@ import ../../storage/utils
|
||||
|
||||
type MockNatPortMapper = ref object of NatPortMapper
|
||||
mappedPorts: Option[(Port, Port, MappingProtocol)]
|
||||
activeMapping: bool
|
||||
|
||||
method mapNatPorts*(
|
||||
m: MockNatPortMapper
|
||||
@ -29,18 +26,10 @@ method mapNatPorts*(
|
||||
.} =
|
||||
m.mappedPorts
|
||||
|
||||
type MockAutonatV2Client = ref object of AutonatV2Client
|
||||
reqAddrs: seq[MultiAddress]
|
||||
method hasActiveMapping*(m: MockNatPortMapper): bool =
|
||||
m.activeMapping
|
||||
|
||||
method sendDialRequest*(
|
||||
self: MockAutonatV2Client, pid: PeerId, testAddrs: seq[MultiAddress]
|
||||
): Future[AutonatV2Response] {.
|
||||
async: (raises: [AutonatV2Error, CancelledError, DialFailedError, LPStreamError])
|
||||
.} =
|
||||
self.reqAddrs = testAddrs
|
||||
AutonatV2Response(reachability: Unknown)
|
||||
|
||||
asyncchecksuite "NAT - handleNatStatus":
|
||||
asyncchecksuite "NAT reaction - port mapping":
|
||||
var sw: Switch
|
||||
var key: PrivateKey
|
||||
var disc: Discovery
|
||||
@ -78,7 +67,7 @@ asyncchecksuite "NAT - handleNatStatus":
|
||||
check not autoRelay.isRunning
|
||||
check disc.protocol.clientMode
|
||||
|
||||
test "handleNatStatus starts autoRelay when NotReachable and no dialBackAddr":
|
||||
test "handleNatStatus starts autoRelay when NotReachable and no dialBackAddr but no mapped ports":
|
||||
let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol)))
|
||||
|
||||
autorelayservice.setup(autoRelay, sw)
|
||||
@ -102,7 +91,32 @@ asyncchecksuite "NAT - handleNatStatus":
|
||||
check disc.announceAddrs == newSeq[MultiAddress]()
|
||||
check disc.protocol.clientMode
|
||||
|
||||
test "handleNatStatus stops relay and exits client mode when Reachable":
|
||||
test "handleNatStatus tears down an active mapping and starts relay when NotReachable with dialBackAddr":
|
||||
let dialBack = MultiAddress.init("/ip4/1.2.3.4/tcp/8080").expect("valid")
|
||||
let mapper = MockNatPortMapper(activeMapping: true)
|
||||
|
||||
autorelayservice.setup(autoRelay, sw)
|
||||
await mapper.handleNatStatus(
|
||||
NotReachable, Opt.some(dialBack), discoveryPort, disc, sw, autoRelay
|
||||
)
|
||||
|
||||
check autoRelay.isRunning
|
||||
check disc.announceAddrs == newSeq[MultiAddress]()
|
||||
check disc.protocol.clientMode
|
||||
|
||||
test "handleNatStatus tears down an active mapping and starts relay when NotReachable without dialBackAddr":
|
||||
let mapper = MockNatPortMapper(activeMapping: true)
|
||||
|
||||
autorelayservice.setup(autoRelay, sw)
|
||||
await mapper.handleNatStatus(
|
||||
NotReachable, Opt.none(MultiAddress), discoveryPort, disc, sw, autoRelay
|
||||
)
|
||||
|
||||
check autoRelay.isRunning
|
||||
check disc.announceAddrs == newSeq[MultiAddress]()
|
||||
check disc.protocol.clientMode
|
||||
|
||||
test "handleNatStatus stops relay and exits client mode when mapping is created and node is Reachable":
|
||||
let mapper = MockNatPortMapper(mappedPorts: none((Port, Port, MappingProtocol)))
|
||||
|
||||
disc.protocol.clientMode = true
|
||||
@ -129,6 +143,22 @@ asyncchecksuite "NAT - handleNatStatus":
|
||||
check not autoRelay.isRunning
|
||||
check disc.announceAddrs == newSeq[MultiAddress]()
|
||||
|
||||
asyncchecksuite "NAT reaction - address announcing":
|
||||
var sw: Switch
|
||||
var key: PrivateKey
|
||||
var disc: Discovery
|
||||
|
||||
setup:
|
||||
key = PrivateKey.random(Rng.instance()).get()
|
||||
disc = Discovery.new(key, announceAddrs = @[])
|
||||
sw = newStandardSwitch()
|
||||
await sw.start()
|
||||
|
||||
teardown:
|
||||
await sw.stop()
|
||||
|
||||
let discoveryPort = Port(8090)
|
||||
|
||||
test "announcePeerInfoAddrs excludes relay circuit addresses":
|
||||
let circuitAddr = MultiAddress
|
||||
.init("/ip4/1.2.3.4/tcp/4040/p2p/" & $sw.peerInfo.peerId & "/p2p-circuit")
|
||||
@ -192,56 +222,3 @@ asyncchecksuite "NAT - handleNatStatus":
|
||||
await sw.peerInfo.update()
|
||||
|
||||
check disc.announceAddrs == newSeq[MultiAddress]()
|
||||
|
||||
test "autonat dial request includes the observed addresses as candidates":
|
||||
# The dial request includes the addresses observed by other peers, so a NATed node submits
|
||||
# a dialable candidate even though its listen addrs are private.
|
||||
let client = MockAutonatV2Client()
|
||||
let autonat = AutonatV2Service.new(
|
||||
Rng.instance(),
|
||||
client,
|
||||
AutonatV2ServiceConfig.new(enableDialableCandidates = true),
|
||||
)
|
||||
service.setup(autonat, sw)
|
||||
await autonat.start(sw)
|
||||
|
||||
let observed = MultiAddress.init("/ip4/8.8.8.8/tcp/4001").expect("valid")
|
||||
for _ in 0 ..< 3: # minCount: 3 observations before the manager trusts an addr
|
||||
discard sw.peerStore.identify.observedAddrManager.addObservation(observed)
|
||||
|
||||
let sw2 = newStandardSwitch()
|
||||
await sw2.start()
|
||||
await sw.connect(sw2.peerInfo.peerId, sw2.peerInfo.addrs)
|
||||
|
||||
check eventually(observed in client.reqAddrs)
|
||||
|
||||
await autonat.stop(sw)
|
||||
await sw2.stop()
|
||||
|
||||
asyncchecksuite "NAT - Hole punching":
|
||||
test "setupHolePunching mounts the dcutr protocol on the switch":
|
||||
let sw = newStandardSwitch()
|
||||
discard setupHolePunching(sw)
|
||||
check sw.ms.handlers.anyIt(dcutrCore.DcutrCodec in it.protos)
|
||||
|
||||
test "holePunchIfRelayed returns early when the peer has no connections":
|
||||
let sw1 = newStandardSwitch()
|
||||
let sw2 = newStandardSwitch()
|
||||
await allFutures(sw1.start(), sw2.start())
|
||||
|
||||
await holePunchIfRelayed(sw1, sw2.peerInfo.peerId)
|
||||
|
||||
await allFutures(sw1.stop(), sw2.stop())
|
||||
|
||||
test "holePunchIfRelayed returns early when a direct connection already exists":
|
||||
let sw1 = newStandardSwitch()
|
||||
let sw2 = newStandardSwitch()
|
||||
await allFutures(sw1.start(), sw2.start())
|
||||
|
||||
await sw1.connect(sw2.peerInfo.peerId, sw2.peerInfo.addrs)
|
||||
check sw1.isConnected(sw2.peerInfo.peerId)
|
||||
|
||||
await holePunchIfRelayed(sw1, sw2.peerInfo.peerId)
|
||||
|
||||
check sw1.isConnected(sw2.peerInfo.peerId)
|
||||
await allFutures(sw1.stop(), sw2.stop())
|
||||
@ -6,7 +6,7 @@ import ./helpers
|
||||
import ../asynctest
|
||||
import ../../storage/rng
|
||||
import ../../storage/nat
|
||||
import ../../storage/utils/natsimulation
|
||||
import ./natsimulation
|
||||
|
||||
const flags = {ServerFlags.ReuseAddr}
|
||||
const listenAddr = "/ip4/127.0.0.1/tcp/0"
|
||||
@ -44,7 +44,7 @@ proc newNatSwitch(router: NatRouter, rng: Rng): Switch =
|
||||
.withYamux()
|
||||
.build()
|
||||
|
||||
asyncchecksuite "NatTransport - Endpoint-Independent Filtering":
|
||||
asyncchecksuite "Nat transport - Endpoint-Independent Filtering":
|
||||
var bootstrap, natNode: Switch
|
||||
|
||||
setup:
|
||||
@ -62,7 +62,7 @@ asyncchecksuite "NatTransport - Endpoint-Independent Filtering":
|
||||
await bootstrap.connect(natNode.peerInfo.peerId, natNode.peerInfo.addrs)
|
||||
check bootstrap.isConnected(natNode.peerInfo.peerId)
|
||||
|
||||
asyncchecksuite "NatTransport - Address-Dependent Filtering":
|
||||
asyncchecksuite "Nat transport - Address-Dependent Filtering":
|
||||
var bootstrap, thirdNode, natNode: Switch
|
||||
|
||||
setup:
|
||||
@ -94,7 +94,7 @@ asyncchecksuite "NatTransport - Address-Dependent Filtering":
|
||||
test "bootstrap cannot connect to nat node without a pre-existing connection":
|
||||
check await cannotConnect(bootstrap, natNode)
|
||||
|
||||
asyncchecksuite "NatTransport - Address-and-Port-Dependent Filtering":
|
||||
asyncchecksuite "Nat transport - Address-and-Port-Dependent Filtering":
|
||||
var bootstrap, thirdNode, natNode: Switch
|
||||
|
||||
setup:
|
||||
@ -125,7 +125,7 @@ asyncchecksuite "NatTransport - Address-and-Port-Dependent Filtering":
|
||||
await natNode.connect(bootstrap.peerInfo.peerId, bootstrap.peerInfo.addrs)
|
||||
check await cannotConnect(thirdNode, natNode)
|
||||
|
||||
asyncchecksuite "NatTransport - Double NAT":
|
||||
asyncchecksuite "Nat transport - Double NAT":
|
||||
var bootstrap, natNode: Switch
|
||||
var router: NatRouter
|
||||
|
||||
@ -148,7 +148,7 @@ asyncchecksuite "NatTransport - Double NAT":
|
||||
|
||||
check await cannotConnect(bootstrap, natNode)
|
||||
|
||||
asyncchecksuite "NatTransport - Port Mapping":
|
||||
asyncchecksuite "Nat transport - Port Mapping":
|
||||
var bootstrap, natNode: Switch
|
||||
var router: NatRouter
|
||||
|
||||
|
||||
2
vendor/nim-boringssl
vendored
2
vendor/nim-boringssl
vendored
@ -1 +1 @@
|
||||
Subproject commit f8111056182cf6abd9e35de77a919e873ef94652
|
||||
Subproject commit e77caabae78fbc9aa5b78a0a521181b077c82571
|
||||
2
vendor/nim-lsquic
vendored
2
vendor/nim-lsquic
vendored
@ -1 +1 @@
|
||||
Subproject commit 00e4b7dfaa197cd120267aa897b33b0914166b45
|
||||
Subproject commit 2f01046bf1d513de8b5f8296c3d8bec819ab0cb9
|
||||
2
vendor/nim-protobuf-serialization
vendored
2
vendor/nim-protobuf-serialization
vendored
@ -1 +1 @@
|
||||
Subproject commit f45476a3c1f4e7bff73845e6450d686be040ddeb
|
||||
Subproject commit d9aa950b9d9e8bfc8a201740042b5e8ea5880875
|
||||
Loading…
x
Reference in New Issue
Block a user