Skip to content

NIP-66: Define output tags for ssl, geo, and net checks; fix timeout/l-tag/c-tag docs #2171

@VincenzoImp

Description

@VincenzoImp

Summary

This PR proposes additions to NIP-66 to standardize the output format for checks that are already declarable in kind 10166 but lack defined result tags in kind 30166. It also fixes several inconsistencies in the current specification.


Part 1: Bug Fixes

1.1 Fix timeout tag format documentation

The current specification text contradicts the example:

Index 1 is the monitor's timeout in milliseconds. Index 2 describes what test the timeout is used for.

But the example shows:

[ "timeout", "open", "5000" ]

Here index 1 is the test type and index 2 is milliseconds. The example is correct, the text should be updated to match:

-- Index `1` is the monitor's timeout in milliseconds. Index `2` describes what test the timeout is used for.
+- Index `1` is the test type (e.g., `open`, `read`, `write`). Index `2` is the timeout in milliseconds.

1.2 Document the l (language) tag

The example includes ["l", "en", "ISO-639-1"] but the l tag is not documented. Add to the tags list:

+- `l` - Language tag. Index `1` is the ISO-639-1 language code, index `2` is the standard identifier (`ISO-639-1`).

1.3 Clarify c tag check values

The specification lists check examples as open, read, write, auth, nip11, dns, geo, but the example uses ws instead of open/read/write.

Clarify that:

  • open - Tests WebSocket connection establishment
  • read - Tests subscription/read capability
  • write - Tests event publishing capability
  • ssl - Tests SSL/TLS certificate (should be added to spec text)

Update the example to use consistent values:

-[ "c", "ws" ],
+[ "c", "open" ],
+[ "c", "read" ],
+[ "c", "write" ],

Part 2: New Output Tags

Current state

NIP-66 currently allows monitors to declare checks via the c tag, but while open, read, and write have corresponding output tags (rtt-open, rtt-read, rtt-write), the checks ssl, geo, and dns have no standardized output format.

2.1 Add SSL/TLS tags

Define output tags for the ssl check (clearnet wss:// relays only):

+- `ssl` - Certificate validity status: `valid` or `!valid`
+- `ssl-expires` - Certificate expiration as Unix timestamp in seconds
+- `ssl-issuer` - Certificate Authority (CA) organization name

2.2 Add Network tags

Define output tags for a new net check:

+- `net-ip` - Resolved IPv4 address of the relay
+- `net-ipv6` - Resolved IPv6 address of the relay (if available)
+- `net-asn` - Autonomous System Number
+- `net-asn-org` - ASN organization name

2.3 Add Geographic tags

Define output tags for the geo check, complementing the existing g (geohash) tag:

+- `geo-country` - ISO 3166-1 alpha-2 country code
+- `geo-city` - City name
+- `geo-lat` - Latitude coordinate as decimal string
+- `geo-lon` - Longitude coordinate as decimal string
+- `geo-tz` - IANA timezone identifier

2.4 Add net check type

Add net (network/ASN lookup) to the list of check types in kind 10166.

2.5 Formal check-to-output mapping

Replace the informal list of check examples with a formal table:

Check Description Output Tags
open Connection test rtt-open
read Read/subscription test rtt-read
write Write/publish test rtt-write
nip11 NIP-11 document fetch content
ssl SSL/TLS certificate check ssl, ssl-expires, ssl-issuer
geo Geographic location lookup g, geo-country, geo-city, geo-lat, geo-lon, geo-tz
net Network/ASN lookup net-ip, net-ipv6, net-asn, net-asn-org

2.6 Reorganize tag documentation

Group tags by category for clarity:

  • Basic Tags: d, n, T, N, R, t, k, l
  • RTT Tags: rtt-open, rtt-read, rtt-write
  • SSL/TLS Tags: ssl, ssl-expires, ssl-issuer
  • Network Tags: net-ip, net-ipv6, net-asn, net-asn-org
  • Geographic Tags: g, geo-country, geo-city, geo-lat, geo-lon, geo-tz

Design Decisions

Why separate net-* from geo-*?

ASN and IP are network identifiers, not geographic locations. A relay in Amsterdam hosted on Cloudflare would have:

  • geo-city: Amsterdam (physical server location)
  • net-asn-org: Cloudflare (network provider)

These are semantically different concepts derived from different data sources (GeoIP City vs GeoIP ASN databases).

Why include net-ipv6?

IPv6 adoption continues to grow. Some users/networks are IPv6-only or prefer IPv6 for direct connectivity (less NAT traversal). Knowing if a relay supports IPv6 helps clients make informed routing decisions.

Why include geo-lat/geo-lon when g (geohash) exists?

For convenience. Clients can read coordinates directly without implementing geohash decoding. The g tag remains the canonical location identifier for filtering.

Why only three SSL fields?

Minimalism. Only fields useful for client decision-making are included:

  • ssl - Filter relays by certificate validity
  • ssl-expires - Alert before expiration
  • ssl-issuer - Trust assessment based on CA

Detailed SSL data (cipher, fingerprint, protocol version) is better suited for specialized security audit tools.


Examples

Kind 30166 (Relay Discovery Event)

{
  "kind": 30166,
  "tags": [
    ["d", "wss://relay.example.com/"],
    ["n", "clearnet"],
    ["N", "1"],
    ["R", "!payment"],
    ["l", "en", "ISO-639-1"],

    ["rtt-open", "89"],
    ["rtt-read", "123"],
    ["rtt-write", "156"],

    ["ssl", "valid"],
    ["ssl-expires", "1735689600"],
    ["ssl-issuer", "Let's Encrypt"],

    ["net-ip", "93.184.216.34"],
    ["net-ipv6", "2606:2800:220:1:248:1893:25c8:1946"],
    ["net-asn", "15169"],
    ["net-asn-org", "Google LLC"],

    ["g", "u173zq37x"],
    ["geo-country", "NL"],
    ["geo-city", "Amsterdam"],
    ["geo-lat", "52.3676"],
    ["geo-lon", "4.9041"],
    ["geo-tz", "Europe/Amsterdam"]
  ]
}

Kind 10166 (Monitor Announcement)

{
  "kind": 10166,
  "tags": [
    ["frequency", "3600"],
    ["timeout", "open", "5000"],
    ["timeout", "read", "3000"],
    ["timeout", "write", "3000"],
    ["timeout", "ssl", "5000"],
    ["c", "open"],
    ["c", "read"],
    ["c", "write"],
    ["c", "nip11"],
    ["c", "ssl"],
    ["c", "geo"],
    ["c", "net"],
    ["g", "u173zq37x"]
  ]
}

Backwards Compatibility

  • All proposed tags are optional
  • Existing clients can safely ignore unknown tags
  • No changes to required fields or existing tag semantics
  • Follows existing NIP-66 conventions (e.g., ! prefix for false values)
  • Bug fixes clarify existing behavior without breaking changes

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions