Skip to content

ANTA catalog for STUN tests

VerifyStunClient

Verifies the configuration of the STUN client, specifically the IPv4 source address and port.

Optionally, it can also verify the public address and port.

Expected Results
  • Success: The test will pass if the STUN client is correctly configured with the specified IPv4 source address/port and public address/port.
  • Failure: The test will fail if the STUN client is not configured or if the IPv4 source address, public address, or port details are incorrect.
Examples
anta.tests.stun:
  - VerifyStunClient:
      stun_clients:
        - source_address: 172.18.3.2
          public_address: 172.18.3.21
          source_port: 4500
          public_port: 6006
        - source_address: 100.64.3.2
          public_address: 100.64.3.21
          source_port: 4500
          public_port: 6006

Inputs

Name Type Description Default

ClientAddress

Name Type Description Default
source_address IPv4Address
IPv4 source address of STUN client.
-
source_port Port
Source port number for STUN client.
4500
public_address IPv4Address | None
Optional IPv4 public address of STUN client.
None
public_port Port | None
Optional public port number for STUN client.
None
Source code in anta/tests/stun.py
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
class VerifyStunClient(AntaTest):
    """
    Verifies the configuration of the STUN client, specifically the IPv4 source address and port.

    Optionally, it can also verify the public address and port.

    Expected Results
    ----------------
    * Success: The test will pass if the STUN client is correctly configured with the specified IPv4 source address/port and public address/port.
    * Failure: The test will fail if the STUN client is not configured or if the IPv4 source address, public address, or port details are incorrect.

    Examples
    --------
    ```yaml
    anta.tests.stun:
      - VerifyStunClient:
          stun_clients:
            - source_address: 172.18.3.2
              public_address: 172.18.3.21
              source_port: 4500
              public_port: 6006
            - source_address: 100.64.3.2
              public_address: 100.64.3.21
              source_port: 4500
              public_port: 6006
    ```
    """

    name = "VerifyStunClient"
    description = "Verifies the STUN client is configured with the specified IPv4 source address and port. Validate the public IP and port if provided."
    categories: ClassVar[list[str]] = ["stun"]
    commands: ClassVar[list[AntaCommand | AntaTemplate]] = [AntaTemplate(template="show stun client translations {source_address} {source_port}")]

    class Input(AntaTest.Input):
        """Input model for the VerifyStunClient test."""

        stun_clients: list[ClientAddress]

        class ClientAddress(BaseModel):
            """Source and public address/port details of STUN client."""

            source_address: IPv4Address
            """IPv4 source address of STUN client."""
            source_port: Port = 4500
            """Source port number for STUN client."""
            public_address: IPv4Address | None = None
            """Optional IPv4 public address of STUN client."""
            public_port: Port | None = None
            """Optional public port number for STUN client."""

    def render(self, template: AntaTemplate) -> list[AntaCommand]:
        """Render the template for each STUN translation."""
        return [template.render(source_address=client.source_address, source_port=client.source_port) for client in self.inputs.stun_clients]

    @AntaTest.anta_test
    def test(self) -> None:
        """Main test function for VerifyStunClient."""
        self.result.is_success()

        # Iterate over each command output and corresponding client input
        for command, client_input in zip(self.instance_commands, self.inputs.stun_clients):
            bindings = command.json_output["bindings"]
            source_address = str(command.params.source_address)
            source_port = command.params.source_port

            # If no bindings are found for the STUN client, mark the test as a failure and continue with the next client
            if not bindings:
                self.result.is_failure(f"STUN client transaction for source `{source_address}:{source_port}` is not found.")
                continue

            # Extract the public address and port from the client input
            public_address = client_input.public_address
            public_port = client_input.public_port

            # Extract the transaction ID from the bindings
            transaction_id = next(iter(bindings.keys()))

            # Prepare the actual and expected STUN data for comparison
            actual_stun_data = {
                "source ip": get_value(bindings, f"{transaction_id}.sourceAddress.ip"),
                "source port": get_value(bindings, f"{transaction_id}.sourceAddress.port"),
            }
            expected_stun_data = {"source ip": source_address, "source port": source_port}

            # If public address is provided, add it to the actual and expected STUN data
            if public_address is not None:
                actual_stun_data["public ip"] = get_value(bindings, f"{transaction_id}.publicAddress.ip")
                expected_stun_data["public ip"] = str(public_address)

            # If public port is provided, add it to the actual and expected STUN data
            if public_port is not None:
                actual_stun_data["public port"] = get_value(bindings, f"{transaction_id}.publicAddress.port")
                expected_stun_data["public port"] = public_port

            # If the actual STUN data does not match the expected STUN data, mark the test as failure
            if actual_stun_data != expected_stun_data:
                failed_log = get_failed_logs(expected_stun_data, actual_stun_data)
                self.result.is_failure(f"For STUN source `{source_address}:{source_port}`:{failed_log}")