.. include:: vars.rst .. _section-natTraversal: ************* NAT Traversal ************* Introduction ============ |RTI_CDS| incorporates functionality that allows |CONNEXT| applications situated behind Network Address Translators (NATs) to discover and communicate with each other using UDP. This is possible when |CDS| is configured to use |RTI_w_TM| |RTI_RWT| [#f1]_. For further details, see the :link_um:`Real-Time WAN Transport in the Core Libraries User's Manual `. .. note:: For a better understanding of this section, we recommend that you become familiar with the basic concepts explained in :ref:`section-Introduction-Basics`. We also assume that you are familiar with NAT traversal concepts and challenges. You can refer to :ref:`section-natTraversal-KeyTerms` for a list of definitions and conventions used in this section. |CDS| **can assist in the discovery and NAT traversal** in the scenario depicted in :numref:`FigureCdsNatUseCase`. Communication between two remote |DPs| that sit behind NATs cannot occur by any means, because they are unable to know how to reach each other. .. figure:: static/CdsNatUseCase.svg :figwidth: 100 % :name: FigureCdsNatUseCase :align: center Communication challenge between applications behind NATs |DPs| sitting behind a NAT are only aware of their own private IP transport addresses (``iAddr:iPort``). These are the only addresses they can exchange as part of the *locators list* they announce in their |DP| announcements. In addition, their actual public IP transport addresses depend on the *NAT forwarding rules*, which are for the most part dynamic and impossible to know beforehand – unless a static configuration is set in the NAT-enabled routers. In this situation, the only alternative is to consider a third player that can inform the remote |DPs| how they can reach each other through their public addresses. This third player is |CDS|, in combination with the |RTI_RWT| (RWT), which is used in the |DPs|. .. figure:: static/CdsNatTraversalConceptBasic.svg :figwidth: 100 % :name: FigureCdsNatTraversalConceptBasic :align: center Public address resolution through |CDS| :numref:`FigureCdsNatTraversalConceptBasic` shows how |CDS| acts as the entity that provides the **resolution of public IP transport addresses**. |CDS| acts as an externally reachable service that obtains the public IP transport addresses from a |DP| and provides them to the other |DPs| using RTPS locators. A resolved public IP transport address is called a *service reflexive address (SRA)*. Let's examine :numref:`FigureCdsNatTraversalConceptBasic` in more detail to understand how |CDS| assists with the NAT traversal. The scenario depicts two |DPs| behind NATs. Each |DP| sends a *participant announcement* (or *PA*) to |CDS| containing WAN locators. These locators can be UUID locators or UUID+PUBLIC locators depending on the configuration of |RTI_RWT|. |CDS| cannot forward the original *PAs* to peer |DPs| if they contain UUID locators, which are unreachable. Instead, |CDS| will obtain the service reflexive address ``eA:eP``, where ``eA`` is the public IPv4 address and ``eP`` is the public UDP port, and use it to replace the original UUID locator in the *PA* with a UUID+PUBLIC locator. |DPs| receive the forwarded and modified *PAs* from |CDS|. These contain the public service reflexive addresses that are **potentially reachable, thus making peer-to-peer communication possible**. Note that we say the *SRAs* are *potentially reachable*. The point is that these addresses will be reachable depending on the type of NAT that the |DP| sits behind. We will see in further sections that only *Cone NATs* allow this communication, whereas *Symmetric NATs* don't. To help you understand this behavior, see :ref:`section-Examples-UdpWanTransport`, where you will emulate the scenario described above in :numref:`FigureCdsNatTraversalConceptBasic`. In that example, we will analyze step-by-step what you need to configure in |CDS| and the application |DPs|. You can run the example first if you want to see it in action. .. seealso:: `Network Address Translation `_ `UDP Hole Punching `_ .. rubric:: Footnotes .. [#f1] |RTI_RWT| may require an additional license. Contact support@rti.com or your sales representative at RTI for further information. Running |CDS| with |RTI_RWT| ========================================== To perform the public address resolution needed to assist in the discovery and communication of remote |DPs| behind NATs, you will need to run a |CDS| instance on a publicly reachable host and enable |RTI_RWT| (RWT). For that, you will need to configure the following |CDS| parameters: - Service or host port ``host_port``: This is the UDP port number where the |CDS| instance will listen for *PAs*. This number shall be within the valid range for UDP ports and not taken by any other application running on the host. - Public IPv4 address ``public_addr``: This is the publicly reachable address that external |DPs| can use to access the service host. - Public port ``public_port``: This is the UDP port number that external remote |DPs| use to communicate with the service running on ``host_port``. If the service host is directly accessible to the WAN with no firewalls/NAT, the ``host_port`` is the same as the ``public_port``, and ``public_addr`` also matches the local host address. If the service host is behind a NAT, then ``public_port`` represents the *forwarded port* statically configured in the NAT device, and **can be a different number than** ``host_port``; also the ``public_addr`` **will be different than the local host address**. |CDS| configuration ------------------- To run |CDS| using RWT, we will need to specify the ``host_port`` and ``public_addr``. For example, in the following configuration: .. code-block:: xml :emphasize-lines: 4,5,8,9 builtin.udpv4_wan 7400 dds.transport.UDPv4_WAN.builtin.public_address 216.58.194.174 - ```` is set to the ``host_port``. - The RWT property ``public_address`` is set to the ``public_addr``. In our example, we use one of the builtin configurations that enables RWT and parameterizes the values for the ```` and ``public_address`` property using XML configuration variables. This way allows you to reuse the configuration with different values for each deployed |CDS| instance. .. note:: With the above configuration, if CDS is behind a NAT-enabled router, the ``host_port`` must be the same as the ``public_port``. If you want to use a different ``public_port``, it will be necessary to configure the property ``dds.transport.UDPv4_WAN.builtin.comm_ports``. For additional information on this property, see the :link_um:`Real-Time WAN Transport in the Core Libraries User's Manual `. Application |DP| configuration ------------------------------ This is a very simple step where the application |DP| is configured to use RWT and include the |CDS| instance as part of the initial peers. To enable RWT, simply select the corresponding builtin transport element in the |DP| QoS configuration: .. code-block:: xml :emphasize-lines: 4,5,6 ... UDPv4_WAN Then when you run the application, set the initial peers to the |CDS|, which is identified as follows: .. code-block:: console rtps@public_addr:public_port where ``public_addr`` and ``public_port`` are the properties described above and determine the public IP transport address that shall be reachable by external applications. To set the initial peers, you can use two methods: - Using the NDDS_DISCOVERY_PEERS environment: .. code-block:: console export NDDS_DISCOVERY_PEERS=rtps@udpv4_wan://216.58.194.174:7400 - Configuring the ``initial_peers`` QoS: .. code-block:: xml :emphasize-lines: 4,5,6 ... rtps@udpv4_wan://216.58.194.174:7400 .. warning:: The assumption is that ```` is set to true (which is the default value). This is important or else communication between |DPs| will not occur. Then just run your applications with this setup and they will communicate over the WAN using DDS, purely peer-to-peer. To understand how this is possible, let's look at :numref:`FigureCdsNatTraversalConceptDetail`. .. figure:: static/CdsNatTraversalConceptDetail.svg :figwidth: 100 % :name: FigureCdsNatTraversalConceptDetail :align: center Resolution of public address for |DPs| behind Cone NATs In this scenario, there are two |DPs| behind Cone NATs, each uniquely identified by a *global unique identifier* (GUID). The |DP| with ``GUID=1`` has two private IP transport addresses, ``iA1:iP1`` and ``iA1:iP2`` (for simplicity, :numref:`FigureCdsNatTraversalConceptDetail` only shows ``iA1:iP1``). ``iA1:iP1`` is used to exchange DDS discovery traffic, ``iA1:iP2`` is used to exchange user data traffic. |DP| ``GUID=1`` sends a |DP| announcement ``PA1`` containing two UUID locators, each one associated with one of the private IP transport addresses. Upon reception of ``PA1``, |CDS| inspects the received UDP packet that contains the announcement and extracts the public IP transport addresses (``eA1:eP1`` and ``eA2:eP2``) for each one of the UUID locators. These are the service reflexive addresses (SRAs) described above. The key step occurs when |CDS| **modifies the original announcement** ``PA1`` to extend each UUID WAN locator so it contains the associated SRA. This extended announcement ``PA1'`` is the one forwarded to the |DP| with ``GUID=2``, which can then use the SRA addresses to communicate peer-to-peer with |DP| ``GUID=1``. The same process applies to |DP| ``GUID=2`` and, in general, to any remote |DP| in the domain. In some cases, it is desirable to use a single public address for communication. This can be achieved by updating the configuration of RWT in the |DPs| as follows: .. code-block:: xml :emphasize-lines: 5,6,7,8 ... 16000 With this configuration, the |DP| with ``GUID=1`` will have only one private IP transport address, ``iA1:iP1``, where ``iP1`` is 16000. The communication with the |DP| will occur on a single public address ``eA1:eP1``. For additional details on how to configure RWT, see the :link_um:`Real-Time WAN Transport in the Core Libraries User's Manual `. Communication between |DPs| --------------------------- So far, we have explained the address resolution step that |CDS| provides so that application |DPs| that sit behind NATs can communicate between themselves. The address resolution is just the first step in providing the |DPs| with the public addresses of their peers. The second step is to establish communication between them: that occurs solely through RWT, without needing |CDS|. :numref:`FigureCdsUdpWanUserTraffic` provides a simplified view of how the communication is possible when the |DPs| are configured to use a single UDP port for communication (single WAN locator). .. figure:: static/CdsUdpWanUserTraffic.svg :figwidth: 100 % :name: FigureCdsUdpWanUserTraffic :align: center Direct communication over the WAN between |DPs| behind Cone NATs A local |DP| ``P1`` will receive the resolved public address of a peer application |DP| ``P2`` from |CDS|, that is, ``eA2:eP2``. This is the address |DP| ``P1`` uses to reach the peer remote |DP| ``P2``. In the process of sending DDS traffic ``D1`` to |DP| ``P2``, the NAT will temporarily open a hole ``H1``. When ``D1`` arrives at the host of ``P2``, the NAT will let the incoming traffic come through hole ``H2``. This is possible because: - |DP| ``P2`` is in parallel performing the same communication protocol, hence opening a temporary hole ``H2``. - Both |DPs| sit behind NATs that always perform the same mapping between a private address ``iA:iP`` and a public address ``eA:eP``, no matter the destination. This category of NATs includes: - *Full-cone* - *Restricted-cone* - *Port-restricted cone* This is not true for Symmetric NATs, which change the mapping based on the destination, so it's not possible to use the SRA that |CDS| obtains. .. _section-netTraversal-communicationScenarios: Communication scenarios using |CDS| =================================== |CDS| support two basic WAN connectivity secenarios: #. Communication between |DPs| behind Cone-NATs. #. Communication with a |DP| with well-known, reachable public IP addresses. If the |DP| is behind a NAT, these public addresses must be statically configured in the NAT-enabled router. For additional information see the :link_um:`Real-Time WAN Transport in the Core Libraries User's Manual `. .. _section-natTraversal-debugging: Debugging |CDS| with the UDP WAN Transport ========================================== You can find out how |CDS| is resolving addresses and for which |DPs|. Locator content depends on the transport implementation. The locators for |RTI_RWT| convey the following information: - **Flags**: Indicate the type of WAN locator and included information. - **UUID**: Unique identifier that typically refers to a single network interface. - **Public address**: Contains the public IPv4 network address and UDP public port. See the :link_locator_format:`locator format section<>` in *RTI Connext DDS Core Libraries User's Manual* for more information about locators. You can obtain locator resolution information in two ways: **logging** and **remote administration**. Logging ------- Run |CDS| with ``-verbosity ALL`` to enable the output of resolution log messages. The WAN locators will be represented with the following string format: .. code-block:: console f=,u={,P=} You will find two type of messages: - **New resolution**: This is a log message generated in the event of resolving the IP public address for a UUID WAN locator. The log message will provide two important pieces of information. In the log context, in the content between the ``[]``, you will find the full WAN locator address in hexadecimal; in the message portion of the log, you will find the UUID and its resolved IP public address. For example, this log: .. code-block:: C [...|RESOLVE{UUID+PUBLIC=0x07BD73FC,0x9ED500AB,0x6D40DCD4:0xBC4E31D3}] \ f=7,u={BD,73,FC,9E,D5,00,AB,6D,40},P=188.78.49.211:56532 shows the following information: - UUID: ``BD,73,FC,9E,D5,00,AB,6D,40``. Note that these nine bytes are the same as the first portion of the hexadecimal address in the log context. - Public IPv4 Address: ``188.78.49.211`` - Public UDP Source Port: ``56532`` - **Resolution status**: This is a log message displayed upon reception and forwarding of a |DP| announcement (PA). This message displays the set of |DP| locators in JSON format, for both meta-traffic and user-traffic, including the original locators received in the announcement and their resolved equivalent. For example: .. code-block:: C [...|DATAP{GUID=0x0101C372,0x17D4CED6,0xEA7B3DA5:0x000001C1}] { "locators": { "original":{ "metatraffic": [ "udpv4_wan://f=1,u={BD,73,FC,9E,D5,00,AB,6D,40},P=10.0.2.15:0:32410" ], "default":[ "udpv4_wan://f=1,u={BD,73,FC,9E,D5,00,AB,6D,40},P=10.0.2.15:0:32411" ] }, "resolved":{ "metatraffic": [ "udpv4_wan://f=7,u={BD,73,FC,9E,D5,00,AB,6D,40},P=188.78.49.211:56532:32410" ], "default": [ "udpv4_wan://f=7,u={BD,73,FC,9E,D5,00,AB,6D,40},P=188.78.49.211:51788:32411" ] } } } The last part of the context portion of the log identifies the remote |DP| for which the locators are displayed; in this case it provides the GUID in hexadecimal format (``GUID=0x0101C372,...``). The message portion of the log shows that there are two UUID locators, one for each type of traffic, and it shows that each of them has been resolved properly, displaying the resolved public address in a format similar to the resolution log shown above. Note that the number of items between the ``original`` and ``resolved`` lists may differ and, in fact, ``length(resolved) <= length(original)``. If a UUID locator is not resolved or the resolved list is empty, it may be an indication of a connectivity problem. For example, the following log indicates that UUID locators have not been resolved: .. code-block:: C [...|DATAP{GUID=0x0101C372,0x17D4CED6,0xEA7B3DA5:0x000001C1}] { "locators": { "original": { "metatraffic": [ "udpv4_wan://f=1,u={BD,73,FC,9E,D5,00,AB,6D,40},P=10.0.2.15:0:32410" ], "default": [ "udpv4_wan://f=1,u={BD,73,FC,9E,D5,00,AB,6D,40},P=10.0.2.15:0:32411" ] }, "resolved":{ "metatraffic": [], "default": [] } } } If you run into this situation, you can check that: - |CDS| and the host it runs on are properly configured to receive external traffic on the receive port. - The remote |DPs| have properly set their initial peers to the public transport address where |CDS| is reachable. Note that this address will be different than the host address of |CDS| if it runs behind a NAT. Administration -------------- You can obtain a one-time snapshot of the locator resolution state for a given |DP| using the remote administration capabilities (:ref:`section-cloud-discovery-service-administration`). |CDS| offers a remote operation to retrieve the locator resolution state for a specified remote |DP| (see :ref:`the API specification `). For example, consider the resolution state log shown above. You could obtain the |DP| locators by issuing the following command: .. code-block:: C method: GET resource: /cloud_discovery_services/[name]/database/locators string_body: "0x0101C372,0x17D4CED6,0xEA7B3DA5:0x000001C1" and you will get a response containing the resolution state in JSON format: .. code-block:: json { "locators": { "original":{ "metatraffic":[ "udpv4_wan://f=1,u={BD,73,FC,9E,D5,00,AB,6D,40},P=10.0.2.15:0:32410" ], "default":[ "udpv4_wan://f=1,u={BD,73,FC,9E,D5,00,AB,6D,40},P=10.0.2.15:0:32411" ] }, "resolved":{ "metatraffic":[ "udpv4_wan://f=7,u={BD,73,FC,9E,D5,00,AB,6D,40},P=188.78.49.211:56532:32410" ], "default":[ "udpv4_wan://f=7,u={BD,73,FC,9E,D5,00,AB,6D,40},P=188.78.49.211:51788:32411" ] } } } Identifying the NAT type ------------------------ As we have mentioned, peer-to-peer communication between the remote |DPs| can only occur if they sit behind Cone NATs. Communication will not be possible if any of them is behind a Symmetric NAT. Therefore, it is mandatory that you verify the type of NAT your applications run. There are multiple third-party utilities that you can download to find out about the NAT shielding your computer. One example is `natat `_, a small open-source utility you can run locally to find out your NAT kind. .. _section-natTraversal-KeyTerms: Key Terms ========= .. glossary:: NAT Traversal A mechanism to establish peer-to-peer connections across gateways that sit behind NATs. IP Transport Address (or Address) The combination of the IPv4 address and the UDP port where an application accepts incoming traffic. Sometimes you will also see the term "address" being used to refer to an IP transport address when the context is clear. Public IP Transport Address (or Public Address) An IP transport address for an application that is routable on a WAN. When the WAN is the Internet, the term "Internet-routable address" can be used instead. Private IP Transport Address (or Private Address) The IP transport address of an application that sits behind a NAT. This address is not reachable from external applications running outside the NAT. ``eAddr:ePort`` A public IP transport address, where ``eAddr`` is the public or external IPv4 address and ``ePort`` is the UDP public or external port. ``iAddr:iPort`` A private IP transport address, where ``iAddr`` is the private IPv4 address and ``iPort`` is the UDP host port. Service Reflexive Address The public IP transport address that |CDS| obtains from the incoming UDP packets and is used for address resolution. RTPS Locator (or Locator) A DDS endpoint (DataWriter or DataReader) address unit that consists of a transport class, RTPS port, and locator transport address (128-bit). Reachable locator: Locator associated with a DDS endpoint (DataWriter or DataReader) to which another DDS endpoint can send data. RTPS WAN Locator (or WAN Locator) A locator for |RTI_RWT|. RTPS UUID WAN Locator (or UUID Locator) A WAN locator for |RTI_RWT| that is not reachable. |CDS| transforms UUID locators into UUID+PUBLIC locators by associating a public IP transport address to the UUID. The public IP transport address for the UUID locator is the service reflexive address. RTPS UUID+PUBLIC WAN Locator (or UUID+PUBLIC Locator) A WAN locator for |RTI_RWT| that is reachable. The locator encapsulates a public IP transport address as part of the locator address. Address Resolution The process of identifying the public address at which an application behind a NAT is reachable. NAT forwarding mapping A static configuration in the NAT device that allows mapping a public address to a private address, so external applications can send and receive data. Application or Remote |DP| A |DP| that is part of a |CONNEXT| application. UDP Hole-Punching A NAT traversal mechanism that consists of creating a temporary UDP forwarding mapping for an internal address. GUID string representation A representation of a |DP| GUID, in a hexadecimal string with the following notation: ``host_id,app_id,instance_id:object_id``.