proxystore.p2p.nat¶
Tools for checking NAT mapping behavior using STUN.
This module implements the mapping behavior discovery procedure of RFC 5780 using RFC 5389 binding requests.
The classic NAT taxonomy of RFC 3489 (full-cone, restricted-cone, and so on) was deprecated because real NATs do not fall into those categories: mapping behavior and filtering behavior are independent. Only mapping behavior affects whether NAT traversal works. A NAT which assigns the same external address regardless of the destination (endpoint-independent mapping) can be traversed by hole-punching, even when it filters unsolicited traffic, because the relay server coordinates both peers to send simultaneously. A NAT which assigns a different external address per destination (address-dependent mapping, historically "symmetric") cannot, because the address a peer learns is not the address it must send to.
Determining filtering behavior would require the RFC 3489 CHANGE-REQUEST attribute, which needs a STUN server listening on two IP addresses. Such servers are increasingly rare, and the answer would not change the advice given here, so this module does not use them.
NatMapping
¶
Bases: Enum
How a NAT assigns external addresses to outbound flows.
NoNat
class-attribute
instance-attribute
¶
Host is not behind a NAT and is directly reachable.
EndpointIndependent
class-attribute
instance-attribute
¶
Host is behind a NAT which reuses one external address for all peers.
AddressDependent
class-attribute
instance-attribute
¶
Host is behind a NAT which uses a different address for each peer.
Result
¶
Bases: NamedTuple
Result of a NAT mapping behavior check.
Attributes:
-
mapping(NatMapping) –Mapping behavior of the NAT this host is behind.
-
external_ip(str) –External IP of this host.
-
external_port(int) –External port of this host. This is only stable across peers when
mappingis notAddressDependent. -
hole_punching_likely(bool) –Whether NAT traversal is expected to work.
check_nat
async
¶
Check the NAT mapping behavior of this host.
Sends STUN binding requests from a single socket to several servers on different IP addresses. If every server reflects the same external address then the NAT reuses one mapping for all destinations and hole-punching can work. If the addresses differ then the mapping is address-dependent and a relay is required.
Parameters:
-
source_ip(str, default:'0.0.0.0') –Address to bind to.
-
source_port(int, default:0) –Port to bind to. The default binds an ephemeral port.
-
timeout(float, default:2.0) –Maximum number of seconds to wait for responses.
Returns:
-
Result–Result describing the mapping behavior and external address.
Raises:
-
RuntimeError–if fewer than two STUN servers respond, in which case the mapping behavior cannot be determined.
Source code in proxystore/p2p/nat.py
231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 | |
check_nat_and_log
async
¶
check_nat_and_log(
source_ip: str = "0.0.0.0",
source_port: int = 0,
timeout: float = 2.0,
) -> None
Check the NAT mapping behavior of this host and log the results.
Wrapper around check_nat()
that logs the results rather than return them.
Parameters:
-
source_ip(str, default:'0.0.0.0') –Address to bind to.
-
source_port(int, default:0) –Port to bind to. The default binds an ephemeral port.
-
timeout(float, default:2.0) –Maximum number of seconds to wait for responses.