The
  Registration
  Data
  Access
  Protocol
  
    
    
    
    
    
    
    
  
  
    
    
    
    
    
    
  
  
    
    
    
    
    
    
  
  
    
    
    
    
    
    
  

Introduction

The Registration Data Access Protocol (RDAP) is the successor protocol to the Whois protocol. It was first ratified by the Internet Engineering Task Force (IETF) in March 2015 by their WEIRDS working group, and initial server and client implementations were released shortly thereafter by the many Regional Internet Registries (RIRs) in June 2015.

In the years since RDAP became standardized, extensions have been added and profiles have been specified. While this is a clear sign of the success of the protocol, the amount of information spread across RFCs, IANA registries and other documents makes specification information more difficult to acquire and implementations harder to develop and deploy.

This book is intended to describe RDAP a in way the RFCs do not, and in many cases cannot describe the protocol and its ecosystem through the use of mdbook, the many mdbook plugins, annotated examples, easier to read language and references to other materials.

It is also not intended as a replacement for the RFCs and other specifications governing RDAP. However, it is intended to offer clearer text, more complete context, and more examples than one might find in the other sources. Additionally, this book will cover background, the ecosystem, and popular conventions that are not well documented in other places. This should aid users, developers and others involved in the efforts of implementing RDAP clients and servers.

Version

This book is a living document and is updated on an as-needed basis.

The version you are reading was built on Wed Aug 28 23:47:59 UTC 2024.

Contributing

Contributions to this book are welcome. See Contributing.

Copyright (C) 2024 Andrew Newton and contributors.

License

The source for this book is released under the Apache License, Version 2.0.

History of RDAP

The Registration Data Access Protocol (RDAP) is the successor protocol to the Whois protocol. It was first ratified by the IETF in March 2015 by their WEIRDS working group, and initial server and client implementations were released by the American Registry for Internet Numbers (ARIN), the Latin American and Caribbean Internet Address Registry (LACNIC), and Asia Pacific Network Information Centre (APNIC) in June 2015. The following year the RIPE NCC deployed their service followed by AfriNIC.

Adoption by the DNRs was much slower. By 2018, only six registries had deployed RDAP services. However, in August 2019 ICANN stipulated that all registries and registrars were to deploy RDAP..

As of 2024, all 5 RIRs have deployed RDAP, all gTLDs have deployed RDAP, and 25% of ccTLDs have deployed RDAP according to the RDAP Deployment Dashboard.

2024 RDAP Deployment according to rdap.org 2024 RDAP deployment according to rdap.org

The Before Time

The Whois protocol has its origins in the very early days of computer networking and predates both DNS and the Internet. Before RDAP, there were many attempts at creating a successor protocol.

In 1994, Network Solutions published a specification for Referral Whois (RWhois) as Informational RFC 1714. Network Solutions was eventually purchased by VeriSign and then spun off into a domain registrar. RWhois is in limited use today by some Internet Service Providers in the ARIN region.

In 1995, the IETF published the Whois++ specification as a standards track protocol, RFC 1835. This protocol never found widespread deployment and is now considered Historic by the IETF.

In 1996, Sandia National Laboratory published an Informational RFC on using the X.500 Directory Access Protocol as a “white pages” service for the United States: RFC 1943.

And in December 2003, VeriSign published information on an experiment to use LDAP to replace Whois: RFC 3663. It was this experiment that led VeriSign to the conclusion that a protocol specifically designed for the problem space of Internet registries should be developed, and this led to the formation of the IETF’s Cross Registry Information Service Protocol (CRISP) working group.

The CRISP working group eventually produced the Internet Registry Information Service (IRIS) protocol, which used XML as its data serialization form and defined multiple application-layer transports which could be signaled using S-NAPTR DNS records. The original application transport was BEEP, but a simpler TCP-based protocol called XPC was also developed. IRIS also had a UDP-based transport called LWZ and defined a lightweight domain availability schema called DCHK.

Ultimately, VeriSign never deployed IRIS. However, IRIS DCHK was used by DeNIC and Afnic. The CRISP Requirements (RFC 3707) were used as an input to the WEIRDS working group which produced the RDAP specifications.

In 2010, ARIN developed Whois-RWS (where RWS stands for RESTful Web Service), which is an HTTP-based system for retrieving Whois information. With the experience of Whois-RWS and encouragement from ICANN staff to help pursue the SSAC 051 goals, the WEIRDS BoF was held in 2011 kicking off the WEIRDS working group, which then created the RDAP specifications.

%%{init: { 'logLevel': 'debug', 'theme': 'base' } }%%

timeline
    title History of Whois and RDAP
    section Pre-RDAP
      1980s : 1982 - First Whois RFC (812) : 1985 - Second Whois RFC (954)
      1990s : 1994 - RWhois : 1995 - Whois++ : 1996 - X.500 Whtie Pages
      2000s : 2003 - Whois in LDAP : 2004 - Third Whois RFC (3912) : 2004 - CRISP Working Group Started : 2005 - First IRIS RFC
      2010 : ARIN's Whois-RWS
    section RDAP
      2012 : WEIRDS Working Group Started
      2015 : First RDAP RFCs

Uses of RDAP

Being the replacement protocol for Whois, RDAP is used in much the same way for the two primary use cases1:

  • To find information about IP networks and ASNs.
  • To find information about domain names.

Similar to Whois, in the RDAP ecosystem there are RDAP clients that talk to RDAP servers. The clients execute RDAP queries (sometimes for people, but most often as automation), and the servers are operated by domain registries and registrars (see DNRs) or Regional Internet Registries.

Unlike Whois2, RDAP has standardized and structured output, protocol-level redirects, links to other resources (including other RDAP resources), formalized methods to find authoritative servers, and much more.

Who Actually Uses RDAP?

There is a common misperception that the main users of RDAP, and Whois, are humans. While there are no hard numbers for the total number of RDAP or Whois queries across all authoritative servers, there are a couple of readily available data points to suggest that most RDAP queries are “bots”.

ARIN, just one of the 5 RIRs, reports upwards of 700 million queries per month. And https://rdap.org, which is a redirect service and not an authoritative server, reports daily query rates of 10 million (approximately 300 million per month).

In terms of web traffic, any websites pulling in 300 million monthly hits would be in the top 50 of the world. If RDAP was pulling in anywhere close to this many “eyeballs”, we would all know it.

Therefore, these queries are from “bots” or more plainly said, scripts. This is stated in RFC 7480, Section 3:

A client implementation should be possible using common operating system scripting tools (e.g., bash and wget).

While it is well-known there is a lot of automation used for data mining of both RDAP and Whois, many network operators create scripts to query RDAP for very legitimate, operational reasons such as log analysis, inventory management, intrusion detection, etc…

Writing Simple RDAP Clients

Writing custom RDAP clients can be quite easy. Here are some examples in this chapter:

  1. A Bash Shell Example: Finding IP Networks - finding the start, end addresses, and CIDR blocks of public IP networks.
  2. A Python Example: Finding Protected Domains - list domains that are not protected.
  3. A Rust Example: Networks of Nameservers - get the networks of the nameservers of a list of domain names.
1

Whois is also used for other purposes, but these are the ones that generate most traffic and have the highest uses.

2

Whois can do some of these things, but they are not standardized and vary depending on client.

Bash: Finding IP Networks

Let’s say you are a network operator and are given a text file with IP addresses with the task of finding their registered CIDR blocks, perhaps for creating an access control list.

199.43.0.0
149.112.152.0
101.100.49.1  

You have been asked to provide this information in a CSV file.

Using a simple bash script, the curl command, and jq, you come up with this very simple solution (source code is here):

echo "start address", "end address", "cidr block" > ip_inventory.csv
cat ip_inventory.txt | while read ip
do
curl -s -L \
  -H "accept: application/rdap+json" \
  https://rdap-bootstrap.arin.net/bootstrap/ip/$ip | 
  jq -r \
  '. | [.startAddress, .endAddress, "\(.cidr0_cidrs[0].v4prefix)/\(.cidr0_cidrs[0].length)"] | @csv' \
  >> ip_inventory.csv
done  

How does this work? First, the script pipes the inventory text file into a loop and executes a curl command for each IP address. Then curl pipes its output to jq which appends the information to the CSV file.

Here is what to note about the curl command:

  1. The -s suppresses progress output so only JSON is passed to jq.
  2. The accept header is set to the RDAP media type.
  3. The target is a bootstrap server that redirects queries to the appropriate authoritative server.
  4. The -L instructs curl to follow redirects.

These last two items are important to understand. The set of IP addresses are not all registered with the same RIR, yet the script has no logic to find the right server to query. Instead, all queries are sent to a “redirect” server which then redirects curl to the right place.

The jq command does the parsing of the JSON and converting it to CSV. There are a couple of interesting things to note here:

  1. “startAddress” and “endAddress” are defined in RFC 9083
  2. “cidr0_cidrs” is from an RDAP extension used by the RIRs for expressing CIDR blocks.

The final result is this CSV file:

start address, end address, cidr block
"199.43.0.0","199.43.0.255","199.43.0.0/24"
"149.112.152.0","149.112.155.255","149.112.152.0/22"
"101.100.0.0","101.100.127.255","101.100.0.0/17"  

Finding Protected Domains With Python

Let’s say you work for an organization with many domain names, and you have been tasked with making sure each of those domain names is safe from malicious modification. That is, each domain needs to be “locked”.

This can be accomplished using the status array of a domain, and if the domain does not have the right set of status values then the domain’s registrar should be contacted.

Here is a simple Python script to do this (source code is here):

import sys
import whoisit

whoisit.bootstrap()

needed_status = set(["client delete prohibited", "client transfer prohibited", "client update prohibited"])

domains = sys.argv[1:]
for domain in domains:
  results = whoisit.domain(domain)
  registrar = results["entities"]["registrar"][0]["name"]
  status = results["status"]
  if needed_status.difference(status):
    print(f"WARNING: {domain} is not properly protected. Contact {registrar}. Status: {status}")
  else:
    print(f"OK: {domain} Status: {status}")


How does this work? Using the whoisit library, the code first initializes its bootstrap information, and then loops over a list of domain names given on the command line.

For each domain, it compares the status values to verify that each domain has the “client delete prohibited”, “client transfer prohibited”, and “client update prohibited” values. If the domain does not have those values, it prints a warning and the name of the domain registrar to contact.


This simple example uses the client’s built-in bootstrapping feature, however it does not save the bootstrapping information for later use as is best practice and suggested by the whoisit library.


Here is an example of running the command:

python main.py foo.com bar.com bar.net fake.com example.com
OK: foo.com Status: ['client delete prohibited', 'client transfer prohibited', 'client update prohibited']
WARNING: bar.com is not properly protected. Contact GoDaddy.com, LLC. Status: ['delete prohibited', 'transfer prohibited', 'renew prohibited', 'update prohibited']
WARNING: bar.net is not properly protected. Contact GoDaddy.com, LLC. Status: ['delete prohibited', 'transfer prohibited', 'renew prohibited', 'update prohibited']
WARNING: fake.com is not properly protected. Contact IONOS SE. Status: ['client transfer prohibited']
OK: example.com Status: ['client delete prohibited', 'client transfer prohibited', 'client update prohibited']

Rust: Networks of Nameservers

Because both DNS registries and IP address registries use RDAP, writing a custom client to look for the networks where a domain name’s nameservers are located is easy to accomplish.

This example uses Rust, and is a bit longer than the previous examples because it loops over a list of domains to find their IP addresses, then loops over those IP addresses to get the network information.

The complete source code may be found here, but the meat of the code is below:

    for domain_name in domains_names {
        println!("domain: {domain_name}");
        let query = QueryType::from_str(&domain_name)?;
        let response = rdap_bootstrapped_request(&query, &client, &store, |_| {}).await?;
        let RdapResponse::Domain(domain) = response.rdap else {
            panic!("response is not a domain")
        };
        let name_servers = domain.nameservers.unwrap_or_default();
        for ns in name_servers {
            let ns_name = ns.ldh_name.clone().unwrap_or(
                ns.unicode_name
                    .clone()
                    .unwrap_or("No Nameserver Name Given".to_string()),
            );
            if let Some(ip_addresses) = ns.ip_addresses.as_ref() {
                let all_ips = vec![
                    ip_addresses.v6.clone().unwrap_or_default(),
                    ip_addresses.v4.clone().unwrap_or_default(),
                ]
                .into_iter()
                .flatten()
                .collect::<Vec<String>>();
                for ip in all_ips {
                    let ip_query = QueryType::from_str(&ip).unwrap();
                    let RdapResponse::Network(ip_response) =
                        rdap_bootstrapped_request(&ip_query, &client, &store, |_| {})
                            .await
                            .unwrap()
                            .rdap
                    else {
                        panic!("response is not IP network")
                    };
                    let start_ip = ip_response
                        .start_address
                        .unwrap_or("NO START IP".to_string());
                    let end_ip = ip_response.end_address.unwrap_or("NO END IP".to_string());
                    println!("{ns_name}({ip}) is in network {start_ip} - {end_ip}");
                }
            }
        }
    }  

This code uses the ICANN RDAP Client Library, and consists of three nested loops. Each loop uses the same Client and uses the built-in bootstrapping mechanism. The outermost loop iterates over the domain names querying for each, the next loop gets the IP addresses of the nameservers returned in those domain name lookups, and the innermost loop then queries for the IP networks of the IP addresses of the nameservers.

When it is run, it takes domain names as command line arguments. Here is the sample output:

$ cargo run -- iana.org icann.org
   Compiling rust_domain_ip v0.1.0 (/home/andy/projects/rdap_guide/src/examples/clients/rust_domain_ip)
    Finished dev [unoptimized + debuginfo] target(s) in 2.64s
     Running `target/debug/rust_domain_ip iana.org icann.org`
domain: iana.org
ns.icann.org(2001:500:89::53) is in network 2001:500:89:: - 2001:500:89:ffff:ffff:ffff:ffff:ffff
ns.icann.org(199.4.138.53) is in network 199.4.138.0 - 199.4.138.255
domain: icann.org
ns.icann.org(2001:500:89::53) is in network 2001:500:89:: - 2001:500:89:ffff:ffff:ffff:ffff:ffff
ns.icann.org(199.4.138.53) is in network 199.4.138.0 - 199.4.138.255

The Protocol

The core of RDAP is a simple REST-like protocol using JSON.


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  RDAP
  JSON
  HTTP
  
  HTTPS
  
    
    
    
    
    
    
  

It defines only the GET and HEAD HTTP methods, and URL paths are defined as patterns. The following is the output of the HTTPie program invoked to get information about example.com from IANA’s RDAP servers: http https://rdap.iana.org/domain/example.com accept:application/rdap+json.

GET /domain/example.com HTTP/1.1
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Host: rdap.iana.org
User-Agent: HTTPie/3.2.2
accept: application/rdap+json



HTTP/1.1 200 OK
Strict-Transport-Security: max-age=48211200; preload
access-control-allow-origin: *
content-length: 984
content-type: application/rdap+json
date: Sat, 27 Apr 2024 19:44:49 GMT
server: uvicorn

{
    "entities": [
        {
            "objectClassName": "entity",
            "roles": [
                "registrant"
            ],
            "vcardArray": [
                "vcard",
                [
                    [
                        "version",
                        {},
                        "text",
                        "4.0"
                    ],
                    [
                        "fn",
                        {},
                        "text",
                        "Internet Assigned Numbers Authority"
                    ],
                    [
                        "role",
                        {},
                        "text",
                        "Registrant"
                    ]
                ]
            ]
        }
    ],
    "events": [
        {
            "eventAction": "last changed",
            "eventDate": "1992-01-01T00:00:00+00:00"
        },
        {
            "eventAction": "registration",
            "eventDate": "1992-01-01T00:00:00+00:00"
        }
    ],
    "ldhName": "example.com",
    "links": [
        {
            "href": "https://rdap.iana.org/domain/example.com",
            "rel": "self",
            "type": "application/rdap+json",
            "value": "https://rdap.iana.org/domain/example.com"
        }
    ],
    "notices": [
        {
            "description": [
                "Terms of Service"
            ],
            "links": [
                {
                    "href": "https://www.icann.org/privacy/tos",
                    "rel": "alternate",
                    "type": "text/html"
                }
            ],
            "title": "Terms of Service"
        },
        {
            "description": [
                "Privacy Policy"
            ],
            "links": [
                {
                    "href": "https://www.icann.org/privacy/policy",
                    "rel": "alternate",
                    "type": "text/html"
                }
            ],
            "title": "Privacy Policy"
        }
    ],
    "objectClassName": "domain",
    "rdapConformance": [
        "rdap_level_0"
    ],
    "secureDNS": {
        "delegationSigned": false
    },
    "status": [
        "active"
    ]
}  
    

This output shows an HTTP GET request of /domain/example.com from the client with a 200 OK response from the server. The response contains JSON, most of which is directly defined in RFC 9083. The parts not defined in RFC 9083 are jCard which is a JSON encoding of vCard, the standard most users encounter when exchanging contact data (aka business cards) over email.

Breaking down the output, the following is the HTTP request:

GET /domain/example.com HTTP/1.1
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Host: rdap.iana.org
User-Agent: HTTPie/3.2.2
accept: application/rdap+json    

This is all normal HTTP semantics. The RDAP specific parts are the URL, which has the defined /domain path (See Lookups and Searches), and the media type of application/rdap+json in the accept header.

The next section shows the HTTP response.


HTTP/1.1 200 OK
Strict-Transport-Security: max-age=48211200; preload
access-control-allow-origin: *
content-length: 984
content-type: application/rdap+json
date: Sat, 27 Apr 2024 19:44:49 GMT
server: uvicorn    

Here, the important parts to note are the media type in the content-type header, which uses the RDAP media type, and the access-control-allow-origin header, which is used to allow web browsers to run JavaScript sourced from one website to use the RDAP content from an RDAP HTTP server.

Next comes the JSON, which has no strict order (because JSON defines none and RDAP enforces none). To help make sense of this, the sections of JSON are re-ordered for illustrative purposes.

The rdapConformance array is an RDAP structure containing protocol and extension compatibility information. At a minimum, it must contain the string “rdap_level_0”. This array shows up in every RDAP response. Here, it is lines 98-100:

    "rdapConformance": [
        "rdap_level_0"
    ],    

Each RDAP response is either a single object (the result of a lookup) or an array of objects (the result of a search). Every object must have an objectClassName to inform the client which object(s) is in the response. Here it is on line 97:

    "objectClassName": "domain",    

Lines 60 and lines 101 to 106 have information specific to domain objects. Line 60 describes the ASCII version of the domain name:

    "ldhName": "example.com",    

While lines 101 to 106 describe the state of the domain:

    "secureDNS": {
        "delegationSigned": false
    },
    "status": [
        "active"
    ]

And this domain object has other information embedded in it using common data structures found in all the objects classes:

  • Lines 19 to 49: entities or the domain’s “contacts”.
  • Lines 50 to 59: events such as when the domain was first registered.
  • Lines 61 to 68: links to other information relevant to the domain.

Finally, there are notices from the server operator (lines 69 to 96):

    "notices": [
        {
            "description": [
                "Terms of Service"
            ],
            "links": [
                {
                    "href": "https://www.icann.org/privacy/tos",
                    "rel": "alternate",
                    "type": "text/html"
                }
            ],
            "title": "Terms of Service"
        },
        {
            "description": [
                "Privacy Policy"
            ],
            "links": [
                {
                    "href": "https://www.icann.org/privacy/policy",
                    "rel": "alternate",
                    "type": "text/html"
                }
            ],
            "title": "Privacy Policy"
        }
    ],    

Lookups and Searches

The example above shows a query for a specific domain registration. RDAP breaks down queries into two types: lookups and searches. Queries for a specific registry item or object, such as the one above, are lookups. Queries for multiple registry objects are searches. Each query is specified by a unique path.

RFC 9082 defines six types of lookups:

RFC 9082 defines the following searches:

These are the core queries defined by RDAP. However, RDAP has an extension mechanism that allows for other lookups and searches to be defined.

HTTP

RDAP is intrinsically tied to being used over HTTP. RFC 7480, Section 3 has this wording:

This document only describes how RDAP is transported using HTTP with this format.

Some may interpret that sentence to mean RDAP is only defined over HTTP, which is true, but it could also be interpreted to mean that another RFC may define RDAP over another transport, which could also be true (in the future).

However, RDAP is intrinsically tied to being used over HTTP. While it may be possible to map RDAP onto another transport, RDAP’s explicit use of http and https URLs in addition to URL path definitions and query parameters would likely make it a hard fit for any other mechanism.

HTTPS

Support for HTTPS by both RDAP clients and servers is a requirement. This is stated in RFC 7480 in both Sections 4 and 7.

This wording does not preclude the use of insecure HTTP, though at the time of ratification of RFC 7480 the IESG asked for the use of HTTPS to be mandatory. It was not made mandatory at the time due to known issues with load balancers. Should the IETF ever revisit this requirement, it almost certainly would mandate usage of HTTPS.

Therefore, it is best that all production deployments support HTTPS and redirect all insecure HTTP queries to HTTPS, especially as all RDAP software is to support HTTPS to be compliant with the standards. For gTLDs, HTTPS is the only allowable form of RDAP.

HTTP Versions

When RDAP was ratified in 2015, HTTP 1.1 was the most current version of HTTP. RFC 7480 makes a direct reference to RFC 7230, which is the clarified HTTP 1.1 specification. However, at that time HTTP 2.0 was in progress within the IETF and RFC 7480 contains this sentence:

This protocol is forward compatible with HTTP 2.0.

So which version of HTTP is required by the RDAP specifications? That would be HTTP 1.1.

However, this does not preclude service of RDAP over HTTP 2.0 or 3.0. And practically speaking, most server and client libraries and frameworks that support HTTP 2.0 and/or 3.0 also support 1.1 at the time of this writing.

TLS

Since 2021, the IETF has deprecated versions of TLS below 1.2 (i.e. SSLv1, SSLv2, SSLv3, TLS 1.0 and TLS 1.1). According to RFC 9325, both servers and clients MUST NOT negotiate a downgrade to these protocols.

RFC 9325 also lists a number of issues server operators must take when using TLS 1.2. As these issues are not present with TLS 1.3, it makes more sense for most server operators to only support TLS 1.3.

Practically speaking, this means clients must support both TLS 1.2 and TLS 1.3.

Even with TLS 1.3, there are a few precautions both clients and servers should take.

  1. Servers should abort a handshake when the server name in the SNI does not match. Clients should do the same unless explicitly commanded to ignore the mismatch by the user.
  2. Clients and servers should abort a handshake when there is no agreed upon protocol in the ALPN.
  3. Servers should use key sizes no smaller than the following:
    1. DH - 2048 bits
    2. ECDH - 224 bits
    3. RSA - 2048 bits w/ SHA-256

As for TLS 1.2, RFC 9325 only recommends the usage of these cipher suites:

  • TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
  • TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
  • TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384

TLS 1.3 Early Data

TLS 1.3 has a feature known as “Early Data” or zero round-trip time (0-RTT). How this feature is used with HTTP is defined in RFC 8470, which describes a few measures to thwart replay attacks.

AS RDAP has no PUT, POST, DELETE, and PATCH methods and is only a data retrieval protocol for (mostly) public data, replay attacks are not usually of great concern. However, RDAP server operators using authorization to provided differentiated access to RDAP data should take the precautions outlined in RFC 8470.

TLSA Records

Authentication, that is the act of verifying the identity of the other party, in TLS uses X.509 (PKIX) cryptographic certificates. In normal TLS usage, these certificates are transferred during the TLS handshake and verified by a client (and/or server) using a set of pre-configured certificates that are either embedded in the software or are part of the operating system (or both). TLSA is a means to use DNS to provide another source of those set of valid certificates in which to validate the other party in a TLS handshake.

TLSA is part of the DNS-Based Authentication of Named Entities (DANE) specifications and is defined in RFC 7671.

Though usage of TLSA with RDAP is encouraged by ICANN, for all practical purposes TLSA is not used in RDAP despite its deployment by many gTLD registries. The reason for this is that there are no known HTTP client libraries that support TLSA nor are there any known RDAP clients using TLSA. Additionally, the IETF has not published any guidelines on usage of TLSA with HTTP as it has done with SMTP. As outlined in this slide presentation from Shumon Huque, HTTP using protocols have a series of challenges for which TLSA is not ideal. Though not yet a standard, RFC 9102 describes an experimental feature of TLS to use DANE without TLSA.

Should an RDAP service wish to use TLSA, the following suggestions are made in the absence of any other HTTP or RDAP specific TLSA guidelines:

  • Certificate usage should be 3 (DANE-EE) which identifies the certificate in use by the RDAP server.
  • Selector should be 1 (SPKI) which ties the TLSA record to the Subject Public Key Identifier of the certificate thus avoiding the need to refresh the TLSA record when the certificate is re-issued unless it is also re-keyed.
  • Matching type should be 1 (SHA-256) as SHA-512 is not mandatory to implement by DNSSEC client libraries.

Client implementers wishing to support TLSA should be aware of the requirements to do so, which are:

  1. Either the client is to fully validate DNSSEC records or is to have a secure channel to a DNS resolver which does so.
  2. There may be multiple TLSA records, so each record must be evaluated until one is found to work.
  3. If no TLSA records are found to work, the TLS handshake must fall back to normal certificate validation.

Headers

As RDAP uses HTTP and therefore any of the headers used by HTTP may be applicable. However, there are a few that are mandatory to use and others that are suggested to use. Implementers should be aware that HTTP header names are often capitalized (e.g. User-Agent) but in reality they are case-insensitive.

Using the example from earlier, we can see the various headers in both the request and response:

GET /domain/example.com HTTP/1.1
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
Host: rdap.iana.org
User-Agent: HTTPie/3.2.2
accept: application/rdap+json



HTTP/1.1 200 OK
Strict-Transport-Security: max-age=48211200; preload
access-control-allow-origin: *
content-length: 984
content-type: application/rdap+json
date: Sat, 27 Apr 2024 19:44:49 GMT
server: uvicorn    

The Accept and Content-Type Headers

RFC 9083 defines the media type (formally called a MIME type) used by RDAP, which is application/rdap+json.

Usage of this media type is defined in RFC 7480:

To indicate to servers that an RDAP response is desired, clients include an Accept header field with an RDAP-specific JSON media type, the generic JSON media type, or both. Servers receiving an RDAP request return an entity with a Content-Type header containing the RDAP-specific JSON media type.

This means clients should use application/rdap+json, application/json or both in the accept header, but servers must return application/rdap+json in the content-type header.

Cross-Origin Resource Sharing (CORS)

This header helps RDAP clients running in a web-browser to query RDAP servers by lifting the “same-origin” restriction browsers usually place on in-browser applications. RFC 7480 recommends setting it to “*”:

access-control-allow-origin: *

The ICANN gTLD specifications mandate the usage of this header.

HTTP Strict Transport Security (HSTS) Header

Though not specified in any RDAP specification, usage of the HTTP Strict Transport Security (HSTS) header, defined in RFC 6797, is good practice and beneficial to in-browser RDAP clients. The max-age, which is the number of seconds a client should remember a site should always use HTTPS, should be a very long value as RDAP servers should always use HTTPS. One suggestion would be the number of seconds in a year, 31,541,000.

strict-transport-security: max-age=3154100

The Host Header

Also, not explicitly stated in any of the RDAP specifications, it is recommended that clients send requests with a host header because many RDAP servers for ccTLDs and gTLDs server more than one TLD. The host header is sometimes used by RDAP servers to route requests to the correct back-end service. This is especially helpful to servers when responding to a /help request as there is nothing the URL of the request that may be used for request routing.

Response Types

Section 5 of RFC 7480 outlines the various types of responses a server might send. These types are categorized by the HTTP status code sent back to a client. This RFC describes some specific scenarios but does not preclude other status codes as defined by HTTP.

Much of this may seem obvious today, but when the RFC was being specified there were many questions in the IETF as to how RESTful services were to work, especially given a somewhat known operational model for Whois. Simply put, the descriptions in this RFC are provided to help implementers bridge the gap from Whois to RDAP.

Positive Answers

A positive answer is one that includes a response containing the information being querying and uses the 200 (OK) status code.


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  Client
  
  Server
  GET /ip/101.100.49.1
  HTTP/1.1 200 OK
  
    
    
  
  
    
    
  

Not Found

If a client queries for a registration that the server cannot provide, the response code is 404 (NOT FOUND).


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  Client
  
  Server
  GET /ip/127.0.0.1
  HTTP/1.1 404 NOT FOUND
  
    
    
  
  
    
    
  

Rate Limiting

Because RDAP servers (and Whois server) are often the target of data mining, the RFC 7480 does describe using the 429 (TOO MANY REQUESTS) status code. While clients should be capable of either back-off retries or bubbling up this error to the user, in practice servers that are under load don’t respond at all.


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  Client
  
  Server
  GET /ip/101.100.49.1
  HTTP/1.1 429 TOO MANY REQUESTS
  
    
    
  
  
    
    
  

Redirects

There are many cases in which an RDAP server returns a redirect, especially the RIRs. RFC 7480 does not specify which is appropriate to use leaving that decision up to the server operator. The RFC simply lists the available types of redirects:

  • 301 (MOVED PERMANENTLY)
  • 302 (FOUND)
  • 303 (SEE OTHER)
  • 307 (TEMPORARY REDIRECT)

  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  Client
  
  Server
  GET /ip/101.100.49.1
  HTTP/1.1 301 MOVED PERMANENTLY
  location: https://rdap.apnic.net/ip/101.100.49.1
  
    
    
  
  
    
    
  

Clients should be prepared to handle all of them, and any RDAP client directly processing redirects (i.e. not relying on an HTTP library to follow redirects automatically) needs to have logic handle redirect loops.

Typically, redirection only has one or two sequences.

sequenceDiagram
    create participant ARIN
    Client->>ARIN: GET /ip/101.100.49.1
    ARIN->>Client: HTTP/1.1 301 MOVED PERMANENTLY
    create participant APNIC
    Client->>APNIC: GET /ip/101.100.49.1
    APNIC->>Client: HTTP/1.1 200 OK

RDAP URLs

RDAP does not define its own URI scheme. It simply uses the “https” (and sometimes “http”) URI schemes because RDAP takes advantage of all the features HTTP has to offer. This is one of the major contrasts between RDAP and protocols like WHOIS, which has no URI scheme, and IRIS, which defined its own application transport and therefore its own URI scheme.


The distinction between a URI and a URL is beyond the scope of this document. For simplicity, a URI is a super type of URL (and URN). That is, a URL is a type of URI. With regard to HTTP and RDAP specifically, the terms can be used interchangeably.


Base URLs

RDAP defines URLs starting with a base URL. This is, a server operator defines a base URL such as https://foo.example/ or https://bar.example/v1 or https://baz.example/rdap and the clients know that queries can be appended to these URLs.

For example, if a server advertises its base URL as https://baz.example/rdap then a client can formulate a domain query by appending /domain/some-domain.example to get the final URL https://baz.example/rdap/domain/some-domain.example.

While some RDAP clients can take base URLs as arguments, most RDAP clients learn of base URLs via bootstrapping.

RFC 9082 and Paths

RFC 9082 defines the URL queries for RDAP. Each query in RDAP has a defined pattern of URL paths and query parameters that are appended to base URLs.

Queries are broken into two types, lookups and searches. And there is a psuedo-lookup for server help.

Lookups

Lookups are queries that return one object for a specific item in the registry. RFC 9082 defines six types of lookups:

PathReturned Object Class
/ipIP Network
/autnumAutnum
/domainDomain
/nameserverNameserver
/entityEntity

IP And CIDR Lookups

The /ip path can be used to lookup IP networks either using a single IP address or using CIDR notation. Here are examples from RFC 9082 for an IP network lookup by a single IP address and CIDR block:

LookupExample
Single IP Addresshttps://example.com/rdap/ip/192.0.2.0
CIDR notationhttps://example.com/ip/192.0.2.0/24

As IP networks are a hierarchy, with larger networks at the top and smaller, enclosed networks going down, this query is for the smallest IP network that fully encloses either the IP address or CIDR block. The term for this is “most-specific”.

ASN Lookups

Autonomous System Numbers (ASN) lookups are done using the /autnum path. This is simply done using by appending the ASN as an integer to the path:

https://example.com/autnum/65538

Domain Lookups

Domain lookups use the /domain path for fully qualified ASCII and IDN domains and IPv4 and IPv6 reverse DNS domains:

LookupExample
Fully Qualified ASCIIhttps://example.com/domain/blah.example.com
Fully Qualified IDNhttps://example.com/domain/日本語.example.com
IPv4 Reverse DNShttps://example.com/rdap/domain/2.0.192.in-addr.arpa
IPv6 Reverse DNShttps://example.com/rdap/domain/1.0.0.0.8.b.d.0.1.0.0.2.ip6.arpa

Nameserver Lookups

For registries and registrars following the “host object” model (see nameserver server children), nameservers may be queried using their fully qualified host name with the /nameserver path:

http://example.com/nameserver/ns1.example.com

Entity Lookups

RDAP entities are the only registration objects that do not have a “natural key”. Therefore, an entity lookup uses the entities handle using the /entity path:

https://example.com/entity/foo-bar

Searches

RFC 9082 defines 3 types of domain searches, 2 types of nameserver searches, and 2 types of entity searches.

Each search query yields an array of object instances corresponding to the search type (i.e. domain searches produce an array of domains, etc…).

Searches are not as thoroughly implemented as lookups.

Domain Searches

Domain searches use the /domains path, and each search type uses a specific query parameter.

  • /domains?name=<DOMAIN SEARCH PATTERN> - searches for domain registrations by a domain name search pattern.
  • /domains?nsLdhName=<NAMESERVER SEARCH PATTERN> - searches for domain registrations by a nameserver host name search pattern of a domain.
  • /domains?nsIp=<NAMESERVER IP ADDRESS> - searches for domain registrations by a nameserver IP address of a domain.

The <DOMAIN SEARCH PATTERN> and <NAMESERVER SEARCH PATTERN> are partial string searches as defined by RFC 9082. These patterns use the ‘*’ (asterisk) character to signify zero or more of any character, such “ex*.com”. In other words, “ex*.com” would match domains “examiner.com” and “extraordinary.com” if both were in the RDAP server. However, the ‘*’ does not cross the domain zone boundary (i.e. the ‘.’ character), so “ex*.com” would not match “examiner.org” or “extraordinary.net”.

There is no requirement for the ‘*’ character to appear at the end of the domain label, so these search patterns are not strictly suffix searches. However, the \* may only appear once in a domain label.

The <NAMESERVER IP ADDRESS> is what it sounds like, either an IPv4 or IPv6 address.

The expected response to a domain search query is a domainSearchResult.

Nameserver Searches

Nameserver searches use the /nameservers path, and each search type uses a specific query parameter.

  • /nameservers?name=<NAMESERVER SEARCH PATTERN> - searches for nameserver objects by a hostname search pattern.
  • /nameservers?ip=<NAMESERVER IP ADDRESS> - searches for nameserver objects by a nameserver IP address.

Here, <NAMESERVER SEARCH PATTERN> and <NAMESERVER IP ADDRESS> have the same meaning as they do above.

The expected response to a nameserver search query is a nameserverSearchResult.

Entity Searches

Entity searches use the /entities path with the following query parameters:

  • /entities?fn=<ENTITY NAME SEARCH PATTERN> - searches for entities by a name pattern.
  • /entities?handle=<ENTITY HANDLE SEARCH PATTERN> - searches for entities by a handle pattern.

Like the search patterns above, the <ENTITY NAME SEARCH PATTERN> and the <ENTITY HANDLE SEARCH PATTERN> are partial string searches. The only difference is that these are searches are not bounded by domain labels.

The expected response to an entity search query is an entitySearchResult.

Server Help

RDAP defines one psuedo-lookup for server help. This simply uses the /help path and produces a help response.

Unknown Query Parameters

In RDAP, clients may attach “unknown” query parameters (i.e. undefined query parameters) for the purposes of “cache busting” (see RFC 7480 Appendix B). Servers are to ignore unknown query parameters, which also means they should not put them in redirects unless for a well-defined and intentional purpose.

JSON

The JSON used in RDAP is defined in RFC 9083. This JSON is described in two broad categories, common data types and object classes. An object class defines registrations in a registry, and they are definitions commonly found among those definitions are the common data types.

RFC 9083 also defines arrays for the results of searches, which are composed of the object classes, error responses, and the special response to a /help query.


Readers should be aware that the JSON used throughout this section is annotated with comments for illustrative purposes. However, legal JSON does not allow comments.


Common Data Types

RFC 9083 defines the formats for various string types used in the JSON for things like IP addresses, URIs, etc… Most are just references to the canonical RFCs defining their formats. However, there are two definitions that implementers and users of RDAP should take note:

handle

A handle is just a reference, often an opaque one (i.e. without meaning). This term comes for the older Whois era in which registrations at the InterNIC were identified by a “handle”.

RFC 9083 defines them as so:

DNRs and RIRs have registry-unique identifiers that may be used to specifically reference an object instance. The semantics of this data type as found in this document are to be a registry-unique reference to the closest enclosing object where the value is found. The data type names “registryId”, “roid”, “nic-handle”, “registrationNo”, etc., are terms often synonymous with this data type. In this document, the term “handle” is used. The term exposed to users by clients is a presentation issue beyond the scope of this document. This value is a simple character string.

date and time

Date and time values in RDAP are expressed using RFC 3339 format, which is a simplified profile of ISO 8601 date and time. Therefore, if an RFC 3339 specific library is not available, then an ISO 8601 can be used for parsing and, with some wrapping, serializing.

Here are some examples:

  • 1990-12-31T23:59:59Z - 31st of December 1990, at 1 second before midnight.
  • 1990-12-31T23:59:60Z - a leap second at the end of 1990.
  • 1996-12-19T16:39:57-08:00 - a date and time offset from UTC by -8 hours.

The benefit of using RFC 3339 date and time values is that they are somewhat readable to most humans, but they also can be sorted alphabetically.

Common Data Structures

The common data structures are simply definitions of JSON that are commonly found in the object classes. These are:

The RDAP Conformance Array

This is a special array that must only appear in the top most JSON of an RDAP response. It is used by a server to signal to a client the RDAP version supported by the server (there is only one) and any extensions.

"rdapConformance" :
[
  "rdap_level_0"
]

In the original versions of RDAP (RFC 7483), this array was not mandatory. However, RFC 9083 made it a requirement of all responses.

"rdapConformance" :
[
  "rdap_level_0",     // rdap version 0
  "lunarNIC_level_0"  // an extension
]

When used in response to a /help query, this array must list all extensions the server supports. However, when used for any other response it must only list the extensions used in that response.

The links array contains objects which represent a link and its metadata, as defined by RFC 8288.

{
  "value" :    "https://example.com/context_uri", // REQUIRED - the context of the link
  "rel" :      "self",                            // REQUIRED - the relationship of the link
  "href" :     "https://example.com/target_uri",  // REQUIRED - the URL
  "hreflang" : [ "en", "ch" ],                    // a list of language tags
  "title" :    "title",                           // presentation name of the link
  "media" :    "screen",                          // display medium 
  "type" :     "application/json"                 // media type
}

In the original versions of RDAP (RFC 7483), the value property was optional. RFC 9083 made it a requirement but never defined its meaning. There is no consensus what this string must contain other than it is a URI and somehow relevant to either the object or response in which it is found.

The rel property can only have values found in the IANA Link Relations protocol parameter registry.

Though not required, the type property indicates to clients the type of data to be found when the link, that is the value of href, is followed – especially for HTTP/HTTPS URLs. When the media type used is the RDAP JSON media type “application/rdap+json”, this indicates to RDAP clients that the link is a “referral”. Note that the concept of a “referral” is not formally defined in the RDAP specifications though in practice they are treated this way, such as when a domain registry provides links to a domain registration in a domain registrar.

Notices and Remarks

The notices and remarks arrays are identical except for their names. The difference between the two is that notices are related to the response as a whole while the remarks are related to the object in which they are found. Therefore, notices are only found in the top-most level of an RDAP response while remarks may be found in an RDAP object.

"notices" :    // or "remarks"
[
  {
    "title" : "Enhance Your Calm",
    "type": "result set truncated due to excessive load", // from RDAP JSON Values
    "description" :  // REQUIRED
    [
      "Some data has been truncated because of too many queries.",
      "Calm down and come back later."
    ],
    "links" :  // this is the same structure defined above
    [
      {
        "value" : "https://example.net/entity/XXXX",
        "rel" : "about",
        "type" : "text/html",
        "href" : "https://www.example.com/take-it-easy.html"
      }
    ]
  }
]

The only required property of a notice or remark is description, which is an array of strings. Each string is meant to be a separate paragraph.

If present, the value of the type property must come from the IANA RDAP JSON Values Registry. Clients can use this information to customize how the present the information to a user.

For completeness, here is the following example from above but as a remark:

"remarks" :
[
  {
    "title" : "Enhance Your Calm",

    // the type changes from "result set truncated due to excessive load" to
    // "object truncated due to excessive load" because a remark is an
    // object class level attribute whereas a notice is a response level
    // attribute.
    "type": "object truncated due to excessive load",

    "description" :  // REQUIRED
    [
      "Some data has been truncated because of too many queries.",
      "Calm down and come back later."
    ],
    "links" :
    [
      {
        "value" : "https://example.net/entity/XXXX",
        "rel" : "about",
        "type" : "text/html",
        "href" : "https://www.example.com/take-it-easy.html"
      }
    ]
  }
]

Events

The events data structure is an array of event objects describing what happened at what time and, optionally, by whom.

"events" :
[
  {
    "eventAction" : "last update of RDAP database", // REQUIRED - from RDAP JSON Values
    "eventActor" : "IANA-ID-2332",
    "eventDate" : "1990-12-31T23:59:59Z",   // REQUIRED - RFC 3339 format
    "links" :  // this is the same structure defined above
    [
      {
        "value" : "https://example.net/domain/foo.example",
        "rel" : "about",
        "type" : "text/html",
        "href" : "https://www.example.com/update-frequency.html"
      }
    ]
  }
]

The eventAction property must come from the IANA RDAP JSON Values Registry. And the eventDate property is a string containing an RFC 3339 date and time (see this for caveats and usage).

If the eventActor is an RDAP entity, then the links array may contain a referral to the entity by using a rel of “related” and a type of “application/rdap+json”.

Public IDs

The objects in this array denote non-URI public identifiers.

"publicIds":
[
  {
    "type": "IANA Registrar ID", // REQUIRED
    "identifier": "1"            // REQUIRED
  }
]

Both type and identifier are strings of free form text. In practice, they are mostly used to identify gTLD registrars by their IANA registration number.

Language Identifier

This is a simple string name “lang”, and it contains a language identifier. The format for language identifiers is defined in RFC 5646 which can look like “en” (for English) or “de-AT” for German used in Austria or combinations of language, script, region and variant subtags that are found in the IANA Language Subtag Registry.

The format can get very complicated but in practice is usually just a language subtag, such as “en”, or a language subtag followed by a region subtag, such as “en-US”.

"lang" : "en-UK"

According to RFC 9083, this property may appear in any JSON object in RDAP except the jCard structures. In practice, it is seldom used and only sensible inside a remark or notice.

Status

The status array contains a list of strings, each with a value that must come from the IANA RDAP JSON Values Registry.

"status" : [ "active", "locked" ]

Port 43 Whois Server

The “port43” string contains either the hostname or IP address of a Whois server that might contain the same information. The reason this is not represented in a “links” object is that a URI for Whois was never defined. In practice, this information is useless.

"port43" : "whois.example.com"

Object Class Name

Each RDAP object must have a string named “objectClassName”. The string must have one of the following values depending on the object class being represented:

  • domain
  • ip network
  • autnum
  • entity
  • nameserver

This string is the discriminator used by clients when parsing the JSON object into an RDAP object class.

"objectClassName" : "ip network"

Object Classes

In RDAP, the information being queried is an RDAP object, and the types or classes of those objects are known as object classes. They are defined in RFC 9083. Each instance of an object class is REQUIRED to have the objectClassName attribute.

RDAP defines 5 core object classes:

  • Entity - a person, organization, group, etc…
  • Domain - a DNS registration
  • Nameserver - a nameserver (i.e. DNS host) registration
  • IP Network - an IP address block registration
  • Autnum - an Autonomous System Number block registration

Object classes are composed of the common data structures as well as other JSON structures specific to each. Many of these common structures are repeated in each object class, and they generally have the following form:

{
  "objectClassName" : "different for every object class",
  "handle" : "registry-unique-id",
  "status" : [ 
    // ... 
  ],
  "entities" : [
    // ...  
  ],
  "links" : [
    // ...
  ],
  "remarks" : [
    // ...
  ],
  "events" : [
    // ...
  ],
  "port43" : "whois.somewhere"

  // the structures specific to each object class
  // ...
}

When objects are returned as the top-most value of the response, such as in responses to lookups, they would have the rdapConformance array and optionally some notices.

{
  "rdapConformance" : [ "rdap_level_0" ],
  "notices" : [
    // ...  
  ],
  "objectClassName" : "different for every object class",
  "handle" : "registry-unique-id",

  // etc, ...
}

As hinted at above, all the object classes can have child entities. And some can have child IP networks, child autnums, and child nameservers. The diagram below depicts these relationships.

---
title: RDAP Object Classes
---
erDiagram
    Entity ||--o{ Entity : "has subordinate contacts"
    Entity ||--o{ "IP Network": "associate with"
    Entity ||--o{ Autnum: "associate with"
    "IP Network" ||--o{ Entity : "has contacts"
    Autnum ||--o{ Entity : "has contacts"
    Domain ||--o{ Entity : "has contacts"
    Domain ||--o{ Nameserver : "served by"
    Domain ||--o| "IP Network" : "reverse DNS"
    Nameserver ||--o{ Entity : "has contacts"

Entity

An entity represents a person, organization, role or group of people. In Whois parlance, these are often called “contacts”.

The entity object class has the following JSON data structures:

NameValue
objectClassName(REQUIRED) must be “entity”. See objectClassName
handlea registry-unique string identifier. See handle.
vcardArraysee jCard/vCard
rolesan array of strings describing the role the entity fulfills with repect to the object that is its parent. These values must be registered in the IANA RDAP JSON Values registry.
publicIdsa common type defined here
entitiesan array of objects as defined by this object class. See entity children.
remarksa common type defined here
linksa common type defined here
eventsa common type defined here
asEventActoran array of events without the eventActor JSON member. These are meant to define the entity as being the event actor. This is seldom used.
statusa common type defined here
port43a common type defined here
networksan array of IP networks. See IP network children.
autnumsan array of autnums. See autnum children.

The following is a contrived example of an entity. Keep in mind that rdapConformance and notices are common to all RDAP responses.

{
    "rdapConformance":[
        "rdap_level_0"
    ],
    "notices":[
        {
            "title":"Terms of Use",
            "description":[
                "The data and services are subject to the Terms of Use available at: https://www.arin.net/whois_tou.html"
            ],
            "links":[
                {
                    "value":"http://nic.lunar/entity/example",
                    "rel":"terms-of-service",
                    "type":"text/html",
                    "href":"https://www.nic.lunar/rdap_tou.html"
                }
            ]
        }
    ],
    "handle":"entity-dnr",
    "objectClassName":"entity",
    "vcardArray" : [
        "vcard",
        [
            ["version", {}, "text", "4.0"],
            ["fn", {}, "text", "Allice Allison"],
            ["kind", {}, "text", "individual"],
            ["lang", { "pref": "1" }, "language-tag", "fr"],
            ["lang", { "pref": "2" }, "language-tag", "en"],
            ["org", { "type": "work" }, "text", "Registry of the Moon"],
            ["title", {}, "text", "Research Scientist"],
            ["role", {}, "text", "Project Lead"],
            ["adr",
                { "type": "work" },
                "text",
                [
                    "",
                    "",
                    "123 Maple Syrup Lane",
                    "Quebec",
                    "QC",
                    "G1V 2M2",
                    "Canada"
                ]
            ],
            ["tel",
                { "type": ["work", "voice"], "pref": "1" },
                "uri",
                "tel:+1-418-555-9254;ext=102"
            ],
            ["tel",
                { "type": ["work", "cell", "voice", "video", "text"] },
                "uri",
                "tel:+1-418-555-6501"
            ],
            ["email",
                { "type": "work" },
                "text",
                "allice.allison@nic.lunar"
            ]
        ]
    ],
    "status":[ "validated", "locked" ],
    "publicIds" :
    [
      {
        "type": "IANA Registry",
        "identifier" : "1"
      }
    ],
    "remarks":[
        {
            "title": "A Poem",
            "description":[
                "She sells sea shells down by the sea shore.",
                "Originally written by Terry Sullivan."
            ]
        },
        {
            "title": "A Story",
            "description":[
                "It was the best of times, it was the worst of times, it was the age of wisdom, it was the age of foolishness, it was the epoch of belief, it was the epoch of incredulity, it was the season of Light, it was the season of Darkness, it was the spring of hope, it was the winter of despair, we had everything before us, we had nothing before us, we were all going direct to heaven, we were all going direct the other way - in short, the period was so far like the present period, that some of its noisiest authorities insisted on its being received, for good or for evil, in the superlative degree of comparison only.",
                "By Charles Dickens"
            ]
        }
    ],
    "links":[
        {
            "value":"https://rdap.nic.lunar/entity/entity-dnr",
            "rel":"self",
            "href":"https://rdap.nic.lunar/entity/entity-dnr"
        }
    ],
    "port43":"whois.nic.lunar",
    "events":[
        {
            "eventAction":"registration",
            "eventDate":"1990-12-31T23:59:60Z"
        },
        {
            "eventAction":"last changed",
            "eventDate":"1991-12-31T23:59:60Z",
            "eventActor":"joe@bob.com"
        }
    ]
}

Domain

A domain object represents a domain registration. This is the most complicated of all the object classes.

The domain object class has the following JSON data structures:

NameValue
objectClassName(REQUIRED) must be “domain”. See objectClassName.
handlea registry-unique string identifier. See handle.
ldhNamea letters-digits-hyphens (ldh, aka ASCII-only) domain name.
unicodeNamethe U-label version of an Internationalized Domain Name (IDN).
variantsset of variant IDNs for this domain. See variants.
nameserversan array of nameserver objects. See nameserver children.
secureDNSDNSSEC information. See DNSSEC data.
publicIdsa common type defined here
entitiesan array of entity objects. See entity children.
remarksa common type defined here
linksa common type defined here
eventsa common type defined here
statusa common type defined here
port43a common type defined here
networka single instance of IP networks.

The following is a contrived example of a domain. Keep in mind that rdapConformance is common to all RDAP responses.

{
  "objectClassName" : "domain",
  "handle" : "ex1-1",
  "ldhName" : "xn--fo-5ja.example",
  "unicodeName" : "fóo.example",
  "status" : [ "locked", "transfer prohibited" ],
  "nameservers" :
  [
    {
      "objectClassName" : "nameserver",
      "handle" : "ns1-1",
      "ldhName" : "ns1.example.com",
      "status" : [ "active" ],
      "ipAddresses" :
      {
        "v6": [ "2001:db8::123", "2001:db8::124" ],
        "v4": [ "192.0.2.1", "192.0.2.2" ]
      },
      "links" :
      [
        {
          "value" : "https://example.net/nameserver/ns1.example.com",
          "rel" : "self",
          "href" : "https://example.net/nameserver/ns1.example.com",
          "type" : "application/rdap+json"
        }
      ],
      "events" :
      [
        {
          "eventAction" : "registration", "eventDate" : "1990-12-31T23:59:59Z"
        },
        {
          "eventAction" : "last changed", "eventDate" : "1991-12-31T23:59:59Z"
        }
      ]
    },
    {
      "objectClassName" : "nameserver",
      "handle" : "ns2-1",
      "ldhName" : "ns2.example.com",
      "status" : [ "active" ],
      "ipAddresses" :
      {
        "v6" : [ "2001:db8::125", "2001:db8::126" ],
        "v4" : [ "192.0.2.3", "192.0.2.4" ]
      },
      "links" :
      [
        {
          "value" : "https://example.net/nameserver/ns2.example.com",
          "rel" : "self",
          "href" : "https://example.net/nameserver/ns2.example.com",
          "type" : "application/rdap+json"
        }
      ],
      "events" :
      [
        {
          "eventAction" : "registration", "eventDate" : "1990-12-31T23:59:59Z"
        },
        {
          "eventAction" : "last changed", "eventDate" : "1991-12-31T23:59:59Z"
        }
      ]
    }
  ],
  "links" :
  [
    {
      "value": "https://example.net/domain/xn--fo-5ja.example",
      "rel" : "self",
      "href" : "https://example.net/domain/xn--fo-5ja.example",
      "type" : "application/rdap+json"
    }
  ],
  "events" :
  [
    {
      "eventAction" : "registration", "eventDate" : "1990-12-31T23:59:59Z"
    },
    {
      "eventAction" : "last changed", "eventDate" : "1991-12-31T23:59:59Z",
      "eventActor" : "alice@example.com"
    },
    {
      "eventAction" : "transfer", "eventDate" : "1991-12-31T23:59:59Z",
      "eventActor" : "alice@example.com"
    },
    {
      "eventAction" : "expiration", "eventDate" : "2016-12-31T23:59:59Z",
      "eventActor" : "alice@example.com"
    }
  ],
  "entities" :
  [
    {
      "objectClassName" : "entity",
      "handle" : "regnt1-1",
      "status" : [ "validated" ],
      "roles" : [ "registrant" ],
      "vcardArray":[
        "vcard",
        [ [ "version", {}, "text", "4.0" ],
          [ "fn", {}, "text", "Alice Allison" ],
          [ "kind", {}, "text", "individual" ],
          [ "email", { "type":"work" }, "text", "alice@example.com" ] ]
      ],
      "links" :
      [
        {
          "value" : "https://example.net/entity/regnt1-1",
          "rel" : "self",
          "href" : "https://example.net/entity/regnt1-1",
          "type" : "application/rdap+json"
        }
      ],
      "events" :
      [
        {
          "eventAction" : "registration", "eventDate" : "2015-12-31T23:59:59Z"
        },
        {
          "eventAction" : "last changed", "eventDate" : "2016-12-31T23:59:59Z"
        }
      ]
    }
  ]
}

Variants

The variants structure describes domains that are internationalized variants of the domain registration. This is an array of objects, each with the following members:

NameValue
relationarray of strings, each a “domain variant relation” from the RDAP JSON Values IANA Registry.
idnTablethe name of the IDN table.
variantNamesarray of objects in the form {"ldhName": "xn--fo-5ja.example", "unicodeName": "fóo.example"}

The following excerpt is an example from RFC 9083:

"variants" :
[
  {
    "relation" : [ "registered", "conjoined" ],
    "variantNames" :
    [
      {
        "ldhName" : "xn--fo-cka.example",
        "unicodeName" : "fõo.example"
      },
      {
        "ldhName" : "xn--fo-fka.example",
        "unicodeName" : "föo.example"
      }
    ]
  },
  {
    "relation" : [ "unregistered", "registration restricted" ],
    "idnTable": ".EXAMPLE Swedish",
    "variantNames" :
    [
      {
        "ldhName": "xn--fo-8ja.example",
        "unicodeName" : "fôo.example"
      }
    ]
  }
]

DNSSEC

The secureDNS structure describes the information about the domain’s DNS Security Extensions (DNSSEC). The topic of DNSSEC is broad. For understanding the meaning of the fields of this structure, readers should consult RFC 4034.

One interesting aspect of the secureDNS information is that RDAP can convey their updates separately from the domain name itself using the links and events.

NameValue
zoneSignedtrue if the domain’s zone is signed, otherwise false.
delegationSignedtrue if the domain’s parent zone has signed the delegation to this domain, otherwise false.
dsDataan array of objects describing Delegation Signer objects. See below.
keyDataan array of objects describing DNS Key objects. See below.

dsData

NameValue
keyTagthe integer of the key tag field of a DS record.
algorithmthe integer of the algorithm field of a DS record.
digeststring containing the hexadecimal digest of the DS record.
digestTypethe integer of the digest type of DS record.
linksa common type defined here
eventsa common type defined here

keyData

NameValue
flagthe integer of the flag field of a DNSKEY record.
protocolthe integer of the protocol field of a DNSKEY record.
publicKeystring containing the hexadecimal digest of a DNSKEY record public key.
algorithmthe integer of the algorithm field of a DNSKEY record.
linksa common type defined here
eventsa common type defined here

secureDNS example

"secureDNS" : {
  "delegationSigned" : true,
  "dsData" : [
    {
      "algorithm" : 13,
      "digest" : "B9BEC0EAC0F064929C8586DB185537787015EC3A48F0894BEA74DEEA452F3060",
      "digestType" : 2,
      "events" : [
        {
          "eventAction" : "registration",
          "eventDate" : "2018-03-27T20:09:08Z"
        },
        {
          "eventAction" : "last changed",
          "eventDate" : "2022-04-27T20:19:46Z"
        }
      ],
      "keyTag" : 47828
    }
  ]
}

Nameserver Children

Registries can differ in how they model nameservers, often referred to as “hosts”. None of the RIRs allow direct registration of nameservers as they must be carefully managed to compose reverse DNS. Some DNRs do allow direct registration of nameservers and some do not.

When a registry treats nameservers a “firs-class” objects (objects with a registration distinct from other objects), this is often called the “host object” model. Otherwise, this is often called the “host attribute” model.

The example given above shows a “host object” model. The “host attribute” model is usually much simpler, where the nameservers do not have a handle or other meta-data separate from the domain. The following is an example.

"nameserver" : [
  {
    "objectClassName" : "nameserver",
    "ldhName" : "ns1.example.com"
  },
  {
    "objectClassName" : "nameserver",
    "ldhName" : "ns2.example.com"
  }
]

Sometimes they may include the IP addresses of the nameservers.

"nameserver" : [
  {
    "objectClassName" : "nameserver",
    "ldhName" : "ns1.example.com",
    "ipAddresses" :
    {
      "v6": [ "2001:db8::123", "2001:db8::124" ],
      "v4": [ "192.0.2.1", "192.0.2.2" ]
    }
  },
  {
    "objectClassName" : "nameserver",
    "ldhName" : "ns2.example.com",
    "ipAddresses" :
    {
      "v6" : [ "2001:db8::125", "2001:db8::126" ],
      "v4" : [ "192.0.2.3", "192.0.2.4" ]
    },
  }
]

Nameserver

The nameserver object class represents nameservers, or hosts as they are often called. They are most commonly children of domain objects (see above), but can be registerable objects as well.

The nameserver object class has the following structures:

NameValue
objectClassName(REQUIRED) must be “nameserver”. See objectClassName.
handlea registry-unique string identifier. See handle.
ldhNamea letters-digits-hyphens (ldh, aka ASCII-only) fully-qualified domain name of the nameserver.
unicodeNamethe U-label version of Internationalized Domain Name (IDN) of the nameserver.
ipAddressesan array of objects, each with a v4 and v6 string array containing the IP addresses of the nameserver.
entitiesan array of entity objects. See entity children.
remarksa common type defined here
linksa common type defined here
eventsa common type defined here
statusa common type defined here
port43a common type defined here

The following is a contrived example of a nameserver. Keep in mind that rdapConformance is common to all RDAP responses.

{
   "rdapConformance" : [
      "rdap_level_0"
   ],
   "objectClassName" : "nameserver",
   "handle" : "ns1-1",
   "ldhName" : "ns1.xn--fo-5ja.example",
   "unicodeName" : "ns1.foo.example",
   "ipAddresses" : {
      "v4" : [
         "192.0.2.1",
         "192.0.2.2"
      ],
      "v6" : [
         "2001:db8::123"
      ]
   },
   "links" : [
      {
         "href" : "https://example.com/nameserver/ns1.xn--fo-5ja.example",
         "rel" : "self",
         "value" : "https://example.com/nameserver/ns1.xn--fo-5ja.example"
      }
   ],
   "remarks" : [
      {
         "description" : [
            "This is a sacrificial nameserver.",
            "It is used for the temporary assignment of domains before deletion."
         ]
      }
   ],
   "status" : [
      "active"
   ],
   "events" : [
      {
         "eventAction" : "registration",
         "eventDate" : "1990-12-31T23:59:60Z"
      },
      {
         "eventAction" : "last changed",
         "eventActor" : "alice@example.com",
         "eventDate" : "1991-12-31T23:59:60Z"
      }
   ]
}

IP Network

The “ip network” object class represents the registration of an IP address block. As not all INRRs require registrations on CIDR block boundaries, the IP address object defines the registration with a startAddress and endAddress.

This object class has the following structures:

NameValue
objectClassName(REQUIRED) must be “ip network”. See objectClassName.
handlea registry-unique string identifier. See handle.
startAddressa string containing the start IP address.
endAddressa string containing the end IP address.
ipVersiona string of either “v4” or “v6” denoting the IP address family version.
namea name for the registration usually given by the registration holder.
typea string containing an RIR classification of the registration.
countrya string with the ISO 3166-2 Alpha2 country code where the network originates traffic.
parentHandlethe handle of the parent network.
entitiesan array of entity objects. See entity children.
remarksa common type defined here
linksa common type defined here
eventsa common type defined here
statusa common type defined here
port43a common type defined here

The following is an example of an IP network taken from APNIC and edited for educational purposes. Keep in mind that rdapConformance and notices are common to all RDAP responses.

{
   "rdapConformance" : [ "rdap_level_0" ],
   "notices" : [
      {
         "title" : "Whois Inaccuracy Reporting",
         "description" : [ "If you see inaccuracies in the results, please visit: " ],
         "links" : [
            {
               "href" : "https://www.apnic.net/manage-ip/using-whois/abuse-and-spamming/invalid-contact-form",
               "rel" : "inaccuracy-report",
               "type" : "text/html",
               "value" : "https://rdap.apnic.net/ip/101.1.1.1"
            }
         ]
      }
   ],
   "objectClassName" : "ip network",
   "handle" : "101.1.0.0 - 101.1.3.255",
   "ipVersion" : "v4",
   "startAddress" : "101.1.0.0",
   "endAddress" : "101.1.3.255",
   "country" : "CN",
   "name" : "CHINANET-FJ",
   "status" : [ "active" ],
   "type" : "ALLOCATED PORTABLE",
   "entities" : [
      {
         "objectClassName" : "entity",
         "handle" : "IRT-CHINANET-CN",
         "roles" : [
            "abuse"
         ],
         "remarks" : [
            {
               "title" : "remarks",
               "description" : [ "anti-spam@chinatelecom.cn was validated on 2024-04-15" ]
            }
         ],
         "vcardArray" : [
            "vcard",
            [
               [ "version", {}, "text", "4.0" ],
               [ "fn", {}, "text", "IRT-CHINANET-CN" ],
               [ "kind", {}, "text", "group" ],
               [
                  "adr",
                  {
                     "label" : "No.31 ,jingrong street,beijing\n100032"
                  },
                  "text",
                  [ "", "", "", "", "", "", "" ]
               ],
               [ "email", {}, "text", "anti-spam@chinatelecom.cn" ]
            ]
         ],
         "events" : [
            { "eventAction" : "registration", "eventDate" : "2010-11-15T00:31:55Z" },
            { "eventAction" : "last changed", "eventDate" : "2024-04-15T01:54:23Z" }
         ],
         "links" : [
            {
               "href" : "https://rdap.apnic.net/entity/IRT-CHINANET-CN",
               "rel" : "self",
               "type" : "application/rdap+json",
               "value" : "https://rdap.apnic.net/ip/101.1.1.1"
            }
         ],
      },
   ],
   "events" : [
      { "eventAction" : "registration", "eventDate" : "2011-04-14T02:07:48Z" },
      { "eventAction" : "last changed", "eventDate" : "2021-06-15T08:05:33Z" }
   ],
   "links" : [
      {
         "href" : "https://rdap.apnic.net/ip/101.1.0.0/22",
         "rel" : "self",
         "type" : "application/rdap+json",
         "value" : "https://rdap.apnic.net/ip/101.1.1.1"
      },
      {
         "href" : "https://netox.apnic.net/search/101.1.0.0%2F22?utm_source=rdap&utm_medium=result&utm_campaign=rdap_result",
         "rel" : "related",
         "type" : "text/html",
         "value" : "https://rdap.apnic.net/ip/101.1.1.1"
      }
   ],
   "remarks" : [
      {
         "title" : "description",
         "description" : [
            "CHINANET FUJIAN PROVINCE NETWORK",
            "China Telecom",
            "No.31,jingrong street",
            "Beijing 100032"
         ]
      }
   ],
}

Autnum

The “autnum” object class represents a registration of a block of Autonomous System Numbers (ASNs). To some, the fact that they are represented as a block instead of a single ASN may seem odd as it is rare that a network is allocated more than one at a time. However, both the IANA and ARIN allocate them in blocks, though this is rare for ARIN.

Similar to the IP Network object class, these blocks are represented with a startNum and a endNum.

It has the following structures:

NameValue
objectClassName(REQUIRED) must be “autnum”. See objectClassName.
handlea registry-unique string identifier. See handle.
startNuma string containing the starting ASN.
endAddressa string containing the ending ASN.
namea name for the registration usually given by the registration holder.
typea string containing an RIR classification of the registration.
countrya string with the ISO 3166-2 Alpha2 country code where the network originates traffic.
entitiesan array of entity objects. See entity children.
remarksa common type defined here
linksa common type defined here
eventsa common type defined here
statusa common type defined here
port43a common type defined here

The following is an example of an autnum taken from APNIC and edited for educational purposes. Keep in mind that rdapConformance and notices are common to all RDAP responses.

{
   "rdapConformance" : [ "rdap_level_0" ],
   "notices" : [
      {
         "description" : [
            "This is the APNIC WHOIS Database query service. The objects are in RDAP format.",
            "This information has been partially mirrored by APNIC from IDNIC."
         ],
         "links" : [
            {
               "href" : "http://www.apnic.net/db/dbcopyright.html",
               "rel" : "terms-of-service",
               "type" : "text/html",
               "value" : "https://idnic.rdap.apnic.net/autnum/64297"
            }
         ],
         "title" : "Terms and Conditions"
      }
   ],
   "objectClassName" : "autnum",
   "handle" : "AS64297",
   "startAutnum" : 64297,
   "endAutnum" : 64297,
   "name" : "GLOBALMANDIRI-AS-ID",
   "country" : "ID",
   "status" : [
      "active"
   ],
   "entities" : [
      {
         "handle" : "MYH18-AP",
         "objectClassName" : "entity",
         "roles" : [
            "administrative",
            "technical"
         ],
         "events" : [
            { "eventAction" : "registration", "eventDate" : "2019-08-20T06:25:43Z" },
            { "eventAction" : "last changed", "eventDate" : "2016-10-26T03:33:39Z" }
         ],
         "links" : [
            {
               "href" : "https://idnic.rdap.apnic.net/entity/MYH18-AP",
               "rel" : "self",
               "type" : "application/rdap+json",
               "value" : "https://idnic.rdap.apnic.net/autnum/64297"
            }
         ],
         "vcardArray" : [
            "vcard",
            [
               [ "version", {}, "text", "4.0" ],
               [ "fn", {}, "text", "M Yusuf Hamid" ],
               [ "kind", {}, "text", "individual" ],
               [ "adr",
                  {
                     "label" : "Jl. Muhammadiyah Lr.139 B/24\nMelayu, Wajo\nSulawesi Selatan 90144"
                  },
                  "text",
                  [ "", "", "", "", "", "", "" ]
               ],
               [ "email", {}, "text", "noc@globalmandiri.co.id" ]
            ]
         ]
      },
   ],
   "events" : [
      { "eventAction" : "registration", "eventDate" : "2019-08-20T06:30:32Z" },
      { "eventAction" : "last changed", "eventDate" : "2023-05-03T06:00:56Z" }
   ],
   "links" : [
      {
         "href" : "https://idnic.rdap.apnic.net/autnum/64297",
         "rel" : "self",
         "type" : "application/rdap+json",
         "value" : "https://idnic.rdap.apnic.net/autnum/64297"
      }
   ],
   "remarks" : [
      {
         "description" : [
            "Send Spam & Abuse reports to: xchange@globallink.net.id"
         ]
      }
   ]
}

Entity Children

As noted above, all objects can have a entities value that is an array of entities, including an entity. This means that entities can be nested, which is useful when showing the relationship between entities.

{
  // ...
  "entities" : [
    {
      "objectClassName" : "entity",
      "handle" : "big-company-1",
      "roles" : [ "registrant" ],
      // ...
      "entities" : [
        {
          "objectClassName" : "entity",
          "handle" : "employee-1",
          "roles" : [ "technical" ]
          // ...
        }
      ]
    }  
  ]
}

IP Network Children

Entities may have multiple IP network children. This is used to allow RIR members to enumerate the number of networks they hold.

{
  "objectClassName" : "entity",
  "networks" : [
    {
      "objectClassName" : "ip network",
      "handle" : "net1"
      // ...
    },
    {
      "objectClassName" : "ip network",
      "handle" : "net2"
      // ...
    }  
  ]

  // ...
}

Autnum Children

Similarly, entities may also have autnum children. Again, this is used to allow RIR members to enumerate the number of autnum registrations they hold.

{
  "objectClassName" : "entity",
  "autnums" : [
    {
      "objectClassName" : "autnum",
      "handle" : "asn-1-1"
      // ...
    },
    {
      "objectClassName" : "autnum",
      "handle" : "asn-2-1"
      // ...
    }  
  ]

  // ...
}

jCard and vCard

RDAP does not define contact data, instead it re-uses a specification called jCard, which is a programmatic representation of vCard… and why it looks so different than the rest of RDAP. When RDAP was going through the specification process, it was believed that using jCard would allow RDAP to benefit from a multitude of jCard implementations. Those jCard implementations never materialized and every RDAP server and client must directly implement jCard.

The use of jCard in RDAP is considered to be the biggest mistake in the development of the protocol, and now there are current efforts in the REGEXT to find a replacement, though there is controversy around this as well for the same reason… this time the adoption of JSContact which also has no known production implementations.

Properties

The individual items of vCard and jCard, such as phone numbers, email addresses, postal addresses, etc…, are called properties. Properties are represented in an array, and each has a name, parameters, a type, and a value or values which occupy a specific position in the array.

[
  "fn",   // property name
  {},     // object containing property parameters
  "text", // type of the value(s)
  "Bob"   // the value (could be more than one)
]

Each property is put into an array, which is the second element of an outer array.

[
  "vcard",
  [
    ["version", {}, "text", "4.0"],
    ["fn", {}, "text", "Alice Allison"],
    ["email", {}, "text", "alice@example.com"]
  ]
]

These nested arrays mimic the vCard structure but serve no purpose other than to be a source of interoperability problems.

Another unfortunate issue is that RFC 9083 does not restrict the types of properties that may be used, leaving RDAP client implementers to guess which parts of jCard/vCard to implement. As jCard can support properties such as wedding anniversaries, photos, sounds, and arbitrary blobs of XML, this can be another source of interoperability issues.

In practice, registries only use a subset and clients can limit their implementations to the following:

With the exception of the version property, these properties may be repeated more than once and may have pref parameter.

[
  "vcard",
  [
    [ "version", {}, "text", "4.0"],
    [ "fn", {}, "text", "Alice Allison"],
    [ 
      "email", 
      { "pref": "1" },       // note: "1" is a string, not an integer
      "text", 
      "alice@example.com"
    ],
    [ 
      "email", 
      { "pref": "2" },       // note: "2" is a string, not an integer
      "text", 
      "theboss@example.org"
    ]
  ]
]

Though pref is an integer between 1 and 100 according to the vCard specification, it is represented as a string in jCard. This is also another source of interoperability problems.

adr Property

The adr property represents a postal address. This property is the most complicated and is a source of many interoperability issues. Its complications arise from its dual nature of supporting both unstructured and structured postal addresses. The following is the difference between them:

  • An unstructured address does not have any categorized items such as city name or postal code. It is simply a series of lines of text as would be found on a postal envelope.
  • A structured address defines the parts of the address that are separate items, such as city name and postal code.

The following is an example of an unstructured postal address:

[
  "adr",
  {
    "label":"Mail Stop 3\nSuite 3000\n123 Maple Ave\nQuebec\nQC\nG1V 2M2\nCanada\n"
  },
  "text",
  [
    "", "", "", "", "", "", ""
  ]
],

Note that the unstructured address must have a 7 element array of empty strings as the value to conform to the vCard serialization format.

This is an example of the same address in structured form:

[
  "adr",
  {},
  "text",
  [
    "Mail Stop 3",
    "Suite 3000",
    "123 Maple Ave",
    "Quebec",
    "QC",
    "G1V 2M2",
    "Canada"
  ]
],

The value array for a structured address must be 7 elements exactly, though some may be empty. Each position in the array has a specific meaning.

[
  "adr",
  {},
  "text",
  [
    "Mail Stop 3",   // post office box (not recommended for use)
    "Suite 3000",    // apartment or suite (not recommended for use)
    "123 Maple Ave", // street address
    "Quebec",        // locality or city name
    "QC",            // region (can be either a code or full name)
    "G1V 2M2",       // postal code
    "Canada"         // full country name
  ]
],

There is still one more wrinkle with structured addresses: the street address component (item 3, 0-index 2) can either be a string or an array of strings. Here the an example:

[
  "adr", {}, "text",
  [
    "", 
    "",
    [                   // street is an array of strings
      "Country Road 8", 
      "Mile 29"
    ],
    "Waycross",
    "Georgia",
    "31501",
    "United States"
  ]
],

adr Property - cc Paramter

Using a country code instead of the full country name is a common mistake seen with structured addresses, though in practice there is no real harm. However, the cc parameter is meant to convey the country code.

gTLD server implementers should take note that the ICANN profile requires that the cc parameter be used and the country name is to be empty.

[
  "adr",
  {
    "cc": "CA"  // defined in RFC 8605 as a 2 character code
  },
  "text",
  [
    "Mail Stop 3",   
    "Suite 3000",    
    "123 Maple Ave", 
    "Quebec",        
    "QC",            
    "G1V 2M2",       
    ""         // EMPTY STRING
  ]
],

adr Property - type Paramater

The adr property may also have a type parameter which can be either “home” or “work”. This parameter applies to both structured and unstructured addresses.

[
  "adr",
  {
    "type": "work",  // allowed values are "home" and "work"
    "label":"Mail Stop 3\nSuite 3000\n123 Maple Ave\nQuebec\nQC\nG1V 2M2\nCanada\n"
  },
  "text",
  [
    "", "", "", "", "", "", ""
  ]
],

contact-uri Property

The contact-uri property is defined in RFC 8605 and represents an alternate means of contact either via a web-form or an email address. This property is purposely defined for use in RDAP.

[
  "contact-uri"
  {},
  "uri",
  "https://example.com/contact-form"
]

This may be either an http, https, or mailto URI.

[ 
  "contact-uri"
  {},
  "uri",
  "mailto:contact@example.com"
]

email Property

The email property has a text value that is an email address.

[ 
  "email"
  {},
  "text",
  "contact@example.com"
]

email Property - type Parameter

Like the adr property, the email property may also have a type parameter than can be either “work” or “home”.

[ 
  "email"
  { "type": "work" },   // can be either "work" or "home"
  "text",
  "contact@example.com"
]

fn Property

The fn property represents a persons “full name”. Unlike most other properties, this is property is required in jCard because, theoretically, jCard/vCard processors use this information as an index in a contact database.

[ 
  "fn"
  {},
  "text",
  "Alice Allison"
]

Some servers are required to redact or omit a person’s full name for various, legitmate policy reasons. In those cases, the value of the fn property should be an empty string.

[ 
  "fn"
  {},
  "text",
  ""      // EMPTY STRING
]

kind Property

The kind property signifies the type of contact, such as an organization or individual. There can be many values, but in practice it is either “individual”, “org”, or “group”.

[ 
  "kind"
  {},
  "text",
  "individual"  // "org", "individual", or "group"
]

No more than one of these properties is required by jCard/vCard. However, when present it cannot have an empty value.

lang Property

The lang property specifies the language of the contact.

[ 
  "lang"
  {},
  "language-tag",
  "fr" 
]

org Property

The org property represents the name of the organization to which an individual belongs.

[ 
  "org"
  {},
  "text",
  "Acme Rockets, LTD" 
]

role Property

The role property represents the role of an individual within an organization or group.

[ 
  "role"
  {},
  "text",
  "Coffee Fetcher" 
]

This should not be confused with the role array on the entity. This role relates an individual or group to the organization, while the other relates the entity to the resource (i.e. domain, IP network).

tel Property

The tel property represents a telephone number, and its value can be either free-form text expressing the telephone number or a tel URI.

[ 
  "tel"
  {},
  "text",             // note: type of "text"
  "1 (800) 555-1212" 
]
[ 
  "tel"
  {},
  "uri",             // note: type of "uri"
  "tel:+18005551212" // must follow tel URI format
]

The tel URI format is defined in RFC 3966, which fall into two basic categories: global numbers and local numbers. In summary, global numbers are signified by a starting + character and part of the E.123 / E.164 specification (e.g. “+18005551212”) of international phone numbers; local numbers are part of a private numbering plan and must be tagged with a phone context (e.g. “123;phone-context=example.com”).

tel Property - type Parameter

The tel property can have a type parameter, but unlike the email and other properties the set of values describing the capabilities of the phone in addition to the values “work” and “home”.

  • text - capable of text messages
  • voice - traditional telephone
  • fax - facsimile machine
  • cell - mobile phone
  • video - has video/audio capabilities
  • pager - old-style pager
  • textphone - for those with hearing and speach challenges
[ 
  "tel"
  {
    "type" : "voice"
  },
  "text",             
  "1 (703) 555-8888" 
]

When multiple types are needed, then an array of strings is used:

[ 
  "tel"
  {
    "type" : [ "voice", "text", "work" ]
  },
  "text",             
  "1 (703) 555-8888" 
]

title Property

Similar to the role property, the title property signifies the title or person, such as “Vice President of Sales”. So a person may have a role of “Project Leader” but their title may be “Software Engineer”. There really is no good reason for a contact in a domain or IP network registration database to have either of these types of meta-data about a person, but some registries/registrars do collect this information.

[ 
  "title"
  {},
  "text",             
  "Sanitation Engineer" 
]

url property

The url property specifies a URL associated with the jCard. RFC 6350 does not define these in detail, but does note:

Examples for individuals include personal web sites, blogs, and social networking site identifiers.

While the url property can have a media type parameter, one is seldom provided.

This property should not be confused with a link, which are often used to indicate additional processing by an RDAP client. The url property is useful should the jCard be extracted and passed on to other applications.

[ "url", 
  { "type":"home" },
  "uri", 
  "https://example.org"
]

version Property

The version property is required in all jCards, there must only be one, its value is always “4.0” and it must always be the first element in the “vCard” array.

[ 
  "version"
  {},
  "text",             
  "4.0" 
]

Unfortunately, RFC 9083 does not restrict the jCard/vCard version to “4.0”, but in the unlikely event a new version of jCard/vCard were to be standardized it would almost certainly be ignored as most RDAP server and client implementations of jCard are hard-coded.

Search Responses

Responses to RDAP searches use a named array that matches the object class found in the array.

Array NameObject Class
domainSearchResultsdomain
nameserverSearchResultsnameserver
entitySearchResultsentity

Note that each search result is required to have a rdapConformance array and may have a notices array.

Domain Search Results

Domain search results are the proper response to a domain search query:

{
  "rdapConformance": [ "rdap_level_0" ],
  "domainSearchResults" : [  
    {
      "objectClassName" : "domain",
      "handle" : "result_1",
      "ldhName" : "1.com"
      // ...
    },
    {
      "objectClassName" : "domain",
      "handle" : "result_2",
      "ldhName" : "2.com"
      // ...
    }
  ]
}

Nameserver Search Results

Nameserver search results are the proper response to a nameserver search query:

{
  "rdapConformance": [ "rdap_level_0" ],
  "nameserverSearchResults" : [  
    {
      "objectClassName" : "nameserver",
      "handle" : "result_1",
      "ldhName" : "ns1.foo.com"
      // ...
    },
    {
      "objectClassName" : "nameserver",
      "handle" : "result_2",
      "ldhName" : "ns2.foo.com"
      // ...
    }
  ]
}

Entity Search Results

Entity search results are the proper response to an entity search query:

{
  "rdapConformance": [ "rdap_level_0" ],
  "entitySearchResults" : [  
    {
      "objectClassName" : "entity",
      "handle" : "entity_1",
      // ...
    },
    {
      "objectClassName" : "entity",
      "handle" : "entity_2",
      // ...
    }
  ]
}

Other Common Data Structures in Search Results

RFC 9083 is a bit light on the details of search results and there are a few of the common data structures that make sense to be included in a search result in addition to the rdapConformance. Specifically, those would be links, notices, and events.

{
  "rdapConformance": [ "rdap_level_0" ],
  "nameserverSearchResults" : [  
    {
      "objectClassName" : "nameserver",
      "handle" : "result_1",
      "ldhName" : "ns1.foo.com"
      // ...
    },
    {
      "objectClassName" : "nameserver",
      "handle" : "result_2",
      "ldhName" : "ns2.foo.com"
      // ...
    }
  ],
  "notices" : 
  [
    {
      "title" : "Terms of Service",
      "description" :
      [
        "This data is covered under some terms."
      ]
    }
  ],
  "events" :
  [
    {
      "eventAction" : "last update of RDAP database", 
      "eventActor" : "A_REGISTRY",
      "eventDate" : "1990-12-31T23:59:59Z",
    }
  ]
}

Error Responses

When a query results in an error, an RDAP server is not required to send an RDAP error response but doing so is considered good practice.

Responses to errors in RDAP mirror the HTTP status code. Like all other RDAP responses, these are to have the content-type: application/rdap+json header and the rdapConformance array. The following is a very simple example:

{
  "rdapConformance" : [ "rdap_level_0" ],
  "errorCode": 420,
  "title": "Enhance Your Calm",
  "description":
  [
    "Chill out!",
    "Srsly, dude."
  ]
}

The response can have the following JSON data structures, including the common response structures of rdapConformance and notices array.

NameValue
rdapConformance(REQUIRED) a common type defined here
noticesa common type defined here
errorCode(REQUIRED) an integer matching the HTTP status code
titlea string specifying the title of the error
descriptionan array of strings describing the error
langa lang sting

Though rarely used, the error response may also have a notices array. The following is a complete example from RFC 9083:

{
  "rdapConformance" :
  [
    "rdap_level_0"
  ],
  "notices" :
  [
    {
      "title" : "Beverage Policy",
      "description" :
      [
        "Beverages with caffeine for keeping horses awake."
      ],
      "links" :
      [
        {
          "value" : "https://example.net/ip/192.0.2.0/24",
          "rel" : "alternate",
          "type" : "text/html",
          "href" : "https://www.example.com/redaction_policy.html"
        }
      ]
    }
  ],
  "lang" : "en",
  "errorCode": 418,
  "title": "Your beverage choice is not available",
  "description":
  [
    "I know coffee has more ummppphhh.",
    "Sorry, dude!"
  ]
}

Server Help

The /help query is a psuedo-lookup for server help. It contains nothing more than a rdapConformance array and a notices array.

The following is an example from RFC 9083:

{
  "rdapConformance" :
  [
    "rdap_level_0"
  ],
  "notices" :
  [
    {
      "title" : "Authentication Policy",
      "description" :
      [
        "Access to sensitive data for users with proper credentials."
      ],
      "links" :
      [
        {
          "value" : "https://example.net/help",
          "rel" : "alternate",
          "type" : "text/html",
          "href" : "https://www.example.com/auth_policy.html"
        }
      ]
    }
  ]
}

Extensions

RDAP has an extension mechanism in which each extension is signaled by an extension identifier. These identifiers must start with an alphabetic character and may contain any combination of alphabetic characters, numeric characters (digits), and the underscore (“_”) character.

These extension identifiers are:

  1. Prepended to the names of JSON values.
  2. Precede path segments in URLs.
  3. Placed in the RDAP conformance array.

As simple as this sounds, some of these rules have been bent over the years causing some ambiguity. The IETF is currently working to correct some of these issues.

JSON

RFC 9083 gives an example of how these extension identifiers are used in JSON.

{
  "handle" : "ABC123",
  "objectClassName" : "entity"
  "lunarNIC_beforeOneSmallStep" : "TRUE THAT!",    // simple string
  "remarks" :
  [
    {
      "description" :
      [
        "She sells sea shells down by the sea shore.",
        "Originally written by Terry Sullivan."
      ]
    }
  ],
  "lunarNIC_harshMistressNotes" : // an array
  [
    "In space,",
    "nobody can hear you scream."
  ]
}

Left unsaid by the RFC, this is an example of the extension defining JSON that augments JSON defined by the core of RDAP. See the example below for the definition of a new object class by the extension.

In essence, the extension identifier prepends any JSON the extension defines.


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  extension identifier
  lunarNIC_beforeOneSmallStep
  defined by extension
  
    
    
    
  
  
    
    
    
  

The rule of thumb for clients laid out in RFC 9083 is to ignore any JSON the client is prepared to process.

URLs

RFC 9082 defines how extensions are to be used in URLs. Here, the extension identifier is used to prepend URL paths.


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  extension identifier
  https://rdap.lunar/lunarNIC_crater/alpha92
  extension defined query
  lookup of crater alpha92
  
    
    
    
  
  
    
    
    
  
  
    
    
    
  

To round out this example, the URL https://rdap.lunar/lunarNIC_crater/alph92 might yield the following response:

{
  "rdapConformance" :
  [
    "rdap_level_0",
    "lunarNIC"
  ],
  "objectClassName" : "lunarNIC_crater",
  "lunarNIC_handle" : "alpha92",
  "lunarNIC_coordinates" : {
    "quadrant_id": "b0",
    "surveyed" : false
  }
}

RFC 9082 does not define the use of extension identifiers in URL query parameters or as the only part of the path segment. As mentioned above, fixes to this are in active discussions in the IETF.

RDAP Conformance Array

The RDAP conformance array is a data structure that is a property of the JSON object returned as an RDAP response. It does not appear anywhere but as a direct child property of this JSON object (i.e. “top-most”).

The extension identifier gets listed in this array:

"rdapConformance" :
[
  "rdap_level_0",
  "lunarNIC"       // lunarNic extension identifier
]

The following is the example from RFC 9083 modified to show the RDAP conformance array.

{
  "rdapConformance" :
  [
    "rdap_level_0",
    "lunarNIC"       // lunarNic extension identifier
  ],
  "handle" : "ABC123",

  // simple string defined by the lunarNIC extension
  "lunarNIC_beforeOneSmallStep" : "TRUE THAT!",   

  "remarks" :
  [
    {
      "description" :
      [
        "She sells sea shells down by the sea shore.",
        "Originally written by Terry Sullivan."
      ]
    }
  ],

  // an array defined by the lunarNIC extension
  "lunarNIC_harshMistressNotes" : 
  [
    "In space,",
    "nobody can hear you scream."
  ]
}

Finding Servers

RDAP servers exist for various types of Internet registration services:

  1. top-level domain registries
  2. second-level and below domain registries
  3. domain registrars
  4. regional internet registries
  5. national internet registries
  6. local internet registries
  7. the IANA

The method to find the appropriate server to query depends on the type of service being targeted. There are three basic mechanisms to find a server:

  1. “Bootstrapping” - This is the process defined by RFC 9224 and RFC 7480.
  2. Redirects - HTTP redirects by another RDAP server as defined by RFC 7480.
  3. Referrals - Links from one RDAP server to another using a link.

The process of getting to redirects or referrals always begins with “bootstrapping” in some form.

RDAP Bootstrapping

“Bootstrapping” is, according to WikiPedia:

In general, bootstrapping usually refers to a self-starting process that is supposed to continue or grow without external input.

In RDAP, it is the first process to finding an RDAP server, and the last when the RDAP server being sought is that for either a TLD (ccTLD or gTLD) or the IANA. This process is defined by RFC 9224, which a client may execute explicitly or via a redirect server as described in RFC 7480.


There is no official list of RDAP bootstrap services, however two of the most popular are the ones run by ARIN and RDAP.ORG, the latter of which reports 10 million query redirects daily.


The title of RFC 9224, “Finding the Authoritative Registration Data Access Protocol (RDAP) Service” is misleading in that the RFC only describes the discovery of RDAP sources registered with IANA. Important as those sources may be, they are not “authoritative” for second and third level domain registries (e.g. co.uk), IP addresses and Autonomous System Numbers transferred between RIRs, number resources of NIRs and LIRs, and domain contacts of “thin” TLDs where the information resides solely at a domain registrar.

The Bootstrap Files

Bootstrapping starts with one of 5 IANA files, depending on the information being sought.

For all but Object Tags, the files are structured as illustrated in RFC 9224:

{
  "version": "1.0",
  "publication": "YYYY-MM-DDTHH:MM:SSZ",
  "description": "Some text",
  "services": [
    [
      ["entry1", "entry2", "entry3"],
      [
        "https://registry.example.com/myrdap/",
        "http://registry.example.com/myrdap/"
      ]
    ],
    [
      ["entry4"],
      [
        "https://example.org/"
      ]
    ]
  ]
}

The entries are either domain names (e.g. “.com”, “.xyz”), IP address CIDR blocks (either v6 or v4), or Autonomous System Number (ASN) ranges, and the arrays are the RDAP Base URLs of the services for those resources.

Each entry type as a specific matching strategy:

TypeExample EntriesEvaluation
DNS["net", "com"]Longest Label-wise match
IPv4["198.51.100.0/24", "192.0.0.0/8"]Most specific match
IPv6["2001:db8:4000::/36", "2001:db8:ffff::/48"]Most specific match
Object Tag["YYYY", "XXXX"]Exact match

The IANA is the Root

IANA is represented as an empty string (“”) in the dns.json file. Though IANA’s base URLs are only represented in the dns.json file, this should not be misconstrued to mean IANA’s RDAP services only contain TLD information.


As of this writing, IANA has not placed their RDAP URLs into the RDAP dns.json bootstrap file as root (“”), though there is an entry for “.int”.


Object Tags

Object Tags were introduced as a mechanism to provide bootstrapping to things in RDAP that had no natural bootstrapping process, mostly RDAP entities. That is, RFC 8521 defines how tags can be applied to objects which can also be used to find the servers where those objects are defined.

In more simple terms, this means identifying a suffix on a string is an object tag and then querying the server for it. For example, an entity with a handle of “FOO-ARIN” can be found in the ARIN RDAP server because the handle name is suffixed by “-ARIN”.

Object tags can also be used to direct clients at RDAP services using “short names”. Neither usage is in widespread use.

Redirects

An HTTP redirect is a type of response a client receives from a server when the server wishes the client to send the query elsewhere.


  
  
    
      
    
    
      
    
    
      
    
    
      
    
    
      
    
  
  
  
  Client
  
  Server
  GET /ip/101.100.49.1
  HTTP/1.1 301 MOVED PERMANENTLY
  location: https://rdap.apnic.net/ip/101.100.49.1
  
    
    
  
  
    
    
  

This is used widely among the RIRs to supplement the normal bootstrapping process to accommodate Internet number resources that have been transferred from on RIR to another (IANA does not record these transfers).

In the following example, a client uses bootstrapping to query LACNIC for 21.1.1.1, however that resource has been transferred to ARIN therefore LACNIC issues a redirect.

sequenceDiagram
    Client->>LACNIC: GET /ip/21.1.1.1
    LACNIC->>Client: HTTP/1.1 301 MOVED PERMANENTLY 
    Client->>ARIN: GET /ip/21.1.1.1
    ARIN->>Client: HTTP/1.1 200 OK

The following example is from Appendix C of RFC 7480. However, that example also shows a redirector (an RDAP server performing redirects for clients) and is more fully described as follows:

sequenceDiagram
    Client->>Redirector: GET /ip/21.1.1.1
    Redirector->>Client: HTTP/1.1 301 MOVED PERMANENTLY 
    Client->>LACNIC: GET /ip/21.1.1.1
    LACNIC->>Client: HTTP/1.1 301 MOVED PERMANENTLY 
    Client->>ARIN: GET /ip/21.1.1.1
    ARIN->>Client: HTTP/1.1 200 OK

Referrals

Referrals are not a formal mechanism in RDAP but are often used to link a resource in one RDAP server to another. They are in wide-spread use within the gTLD services to allow a gTLD registry to point a client at a domain name in a gTLD registrar.

Referrals work using the links data structure when the type attribute of the link is set to the RDAP media type “application/rdap+json”.

{
  "value" : "https://registry.example/domain/foo.example",
  "rel"   : "related",
  "type"  : "application/rdap+json",
  "href"  : "https://registrar.example/domain/foo.example"
}

The ICANN Response Profile specifies that these referrals be made using the related relationship type.

The soon-to-be RIR Search will define referrals for “up”, “down”, “top”, “bottom”.

Client Implementations

This section lists known, publicly available client implementations. Most are open source. As there is evidence that most RDAP queries are due to automation, it is unknown how many proprietary RDAP clients exist.

Client implementations are broken down as follows:

  1. Web Applications - those clients running inside a web browser.
  2. Mobile Applications - clients on mobile devices such as phones.
  3. CLI Applications - command line interface (CLI) clients.
  4. Client Libraries - software libraries incorporated into other clients.

Web Applications

Services

APNIC RDAP Web

https://rdap-web.apnic.net/

ARIN Whois/RDAP

https://search.arin.net/rdap/

Client.RDAP.Org

https://client.rdap.org/

ICANN Lookup

https://lookup.icann.org/en

LACNIC RDAP Web Client

https://rdap-web.lacnic.net/

RDAP.Dev

https://rdap.dev/

Software

RDAP Lookup Client

This repository contains an example of Domain Name Registration Data Lookup using RDAP protocol. The example is implemented as a Single Page Application (SPA) using Angular. The application gives you the ability to look up publicly available contact and other information related to a domain name.

RDAP Explorer

RDAP Explorer provides a basic frontend for querying, formatting and navigating RDAP information using:

  • IPWhois by Philip Hane.
  • pycountry by Christian Theune
  • JSONFormatter by Mohsen Azimi.

RDAP Web Client

RDAP WebSpa

Mobile Applications

Android

RDAP Browser

This application provides registration information for domain names, IP addresses and autonomous system numbers, by reaching the autoritative RDAP servers and displaying the results. Displayed information includes registrant, expiration, registrar, registry, DNS servers and DNSSEC details, as well as contact information when available. As RDAP is being deployed by top-level domain registries, not all domain names may return data. RDAP is a replacement of Whois.

iOS

RDAP Browser

Search domain names, IP addresses and Autonomous System Numbers and find the registration status, owner, registrar, nameservers and various contacts using RDAP.

CLI Applications

Command-Line Interface (CLI) clients have a heritage that goes back to original WHOIS, which was accessed via clients run on Unix systems.

ICANN RDAP CLI

From the GitHub Repository:

This is a command-line interface (CLI) client for the Registration Data Access Protocol (RDAP) written and sponsored by the Internet Corporation for Assigned Names and Numbers (ICANN). RDAP is standard of the IETF, and extensions to RDAP are a current work activity of the IETF’s REGEXT working group. More information on ICANN’s role in RDAP can be found here.

ICANN RDAP CLI

IPWhois

ipwhois_cli.py and ipwhois_utils_cli.py are command line interfaces for the ipwhois library. When using pip to install ipwhois, the CLI scripts are installed to your Python environment Scripts directory.

  • ipwhois_cli.py has full ipwhois.py functionality.
  • ipwhois_utils_cli.py has full utils.py functionality.
  • The others (net.py, rdap.py, whois.py, nir.py, asn.py) will be included in a future release.

jrdap

jrdap is a command-line RDAP client written in JavaScript. It has no dependencies beyond node.js.

NicInfo

From the GitHub Repository:

NicInfo is a general purpose, command line Registry Data Access Protocol (RDAP) client released under an open source, ISC derivative BSD style license. RDAP is an HTTP-based RESTful protocol defined by the IETF as a replacement for Whois.

  • License: ISC
  • Repository: https://github.com/arineng/nicinfo
  • Language: Ruby
  • Operating Systems: MacOS, Linux, Windows
  • Features:
    • Query type detection: it will attempt to determine what type of query is needed based on the supplied query value.
    • Plain text output: default output is a text version of the RDAP results.
    • JSON output: the RDAP JSON can be passed directly to a calling program for intergration with scripts with the ability to select specific JSON values.
    • Multiple output controls: the amount of text detail and process execution can be varied and sent to different files.
    • A Built-in cache: RDAP queries are cached.
    • Bootstrapping using the IANA bootstrap files or by using a bootstrap server.
    • Demonstration queries: a set of built-in queries and results are provided for demonstration purposes.

NicInfo Querying 1.1.1.1

OpenRDAP

From OpenRDAP.org:

OpenRDAP is a command line client for the Registration Data Access Protocol, written in Go.

RDAP is a replacement for WHOIS, which provides domain name & IP address registration information in JSON format over HTTP.

  • License: MIT
  • Repository: https://github.com/openrdap/rdap
  • Language: Go
  • Operating Systems: MacOS, Linux, Windows
  • Features:
    • Output formats: text, JSON, WHOIS style
    • Query types supported:
      • ip
      • domain
      • autnum
      • nameserver
      • entity
      • help
      • url
      • domain-search
      • domain-search-by-nameserver
      • domain-search-by-nameserver-ip
      • nameserver-search
      • nameserver-search-by-ip
      • entity-search
      • entity-search-by-handle
    • Automatic server detection for ip/domain/autnum/entities
    • Object tags support
    • Bootstrap cache (optional, uses ~/.openrdap by default)
    • X.509 client authentication

OpenRDAP Querying Google.com

20c RDAP

usage: rdap [-h] [--debug] [--home HOME] [--verbose] [--quiet] [--version] [--output-format OUTPUT_FORMAT] [--show-requests] [--parse] [--rir] [--write-bootstrap-data] query [query ...]

rdap

positional arguments:
  query

options:
  -h, --help            show this help message and exit
  --debug               enable extra debug output
  --home HOME           specify the home directory, by default will check in order: $RDAP_HOME, ./.rdap, /home/grizz/.rdap, /home/grizz/.config/rdap
  --verbose             enable more verbose output
  --quiet               no output at all
  --version             show program's version number and exit
  --output-format OUTPUT_FORMAT
                        output format (yaml, json, text)
  --show-requests       show all requests
  --parse               parse data into object before display
  --rir                 display rir
  --write-bootstrap-data
                        write bootstrap data for type (as query)  

RDAP Cli

This program is in charge of collecting all the relevant information related to a domain such as domain expiration date, nameservers, registration entity, domain registration date, if it is available to register or not.

RDAP Explorer

Program focused on retrieving and parsing RDAP data and Geolocation for IPv4 addresses.

RDAP Check

A simple library and command-line tool to check domain name availability in bulk using the RDAP protocol, a simple protocol meant to replace WHOIS.

RDAP Check

rdapper

rdapper is a simple RDAP client. It uses Net::RDAP to retrieve data about internet resources (domain names, IP addresses, and autonymous systems) and outputs the information in a human-readable format. If you want to consume this data in your own program you should use Net::RDAP directly.

rdapper was originally conceived as a full RDAP client (back when the RDAP specification was still in draft form) but is now just a very thin front-end to Net::RDAP.

Libraries

Client libraries can be embedded into other programs to give them the ability to query RDAP. These libraries are categorized by programming language.

GO

RegistroBR

Who-Go

Java

rdap-client

rdap-java

Other

Prometheus

adamdecaf rdap_exporter

hsn723 rdap_exporter

Rapid7

Splunkbase

Perl

Net::RDAP

Net::RDAP provides an interface to the Registration Data Access Protocol (RDAP).

RDAP is replacing Whois as the preferred way of obtainining information about Internet resources (IP addresses, autonymous system numbers, and domain names). As of writing, RDAP is fully supported by Regional Internet Registries (who are responsible for the allocation of IP addresses and AS numbers) and generic TLD operators (e.g. .com, .org, .xyz) but is still being rolled out among country-code registries.

Net::RDAP does all the hard work of determining the correct server to query (Net::RDAP::Registry is an interface to the IANA registry of RDAP services), querying the server (Net::RDAP::UA is an RDAP HTTP user agent), and parsing the response (Net::RDAP::Object and its submodules provide access to the data returned by the server). As such, it provides a single unified interface to information about all unique Internet identifiers.

PHP

Array Access RDAP Client

Meta Registrar RDAP Client

RDAP Whois Proxy

A bridge from WHOIS to RDAP

Python

IPWhois

Whodap

whodap | Simple RDAP Utility for Python

Support for asyncio HTTP requests (httpx) Leverages the SimpleNamespace type for cleaner RDAP Response traversal Keeps the familiar look of WHOIS via the to_whois_dict method for DNS lookups

Whoisit

A Python client to RDAP WHOIS-like services for internet resources (IPs, ASNs, domains, etc.). whoisit is a simple library that makes requests to the “new” RDAP (Registration Data Access Protocol) query services for internet resource information. These services started to appear in 2017 and have become more widespread since 2020.

whoisit is designed to abstract over RDAP. While RDAP is a basic HTTP and JSON based protocol which can be implemented in a single line of Python with requests the bootstrapping (which RDAP service to query for what item) and extracting useful information from the RDAP responses is extensive enough that a library like this is useful.

Ruby

RDAP

A minimal Ruby client to query RDAP APIs though a bootstrap server. No dependencies, no caching or bootstrap file (the query is routed through a bootstrap server first).

Rust

ICANN RDAP Client Library

This is a command-line interface (CLI) client for the Registration Data Access Protocol (RDAP) written and sponsored by the Internet Corporation for Assigned Names and Numbers (ICANN). RDAP is standard of the IETF, and extensions to RDAP are a current work activity of the IETF’s REGEXT working group. More information on ICANN’s role in RDAP can be found here.

rdap_client

Async and fast RDAP client and parser for Rust.

  • Package Information: https://crates.io/crates/rdap_client
  • Repository: https://github.com/JakubOnderka/rdap_client
  • Documentation: https://docs.rs/rdap_client/0.2.0
  • License: BSD 2-Clause
  • Features:
    • Supported Standards:
      • RFC 7480: HTTP Usage in the Registration Data Access Protocol (RDAP)
      • RFC 7482: Registration Data Access Protocol (RDAP) Query Format
      • RFC 7483: JSON Responses for the Registration Data Access Protocol (RDAP)
      • RFC 8056: Extensible Provisioning Protocol (EPP) and Registration Data Access Protocol (RDAP) Status Mapping
      • RFC 8521: Registration Data Access Protocol (RDAP) Object Tagging
      • RDAP JSON Values
    • Supported Extensions
      • fred
      • cidr0
      • arin_originas0
      • rdap_objectTag (RFC 8521)

test_friendly_rdap_client

This is essentially a version of the original rdap_client with a few extra sprinkles to make it a bit easier for me to wire up rdap_client in integration tests.

I initially attempted to keep the code as close to upstream as possible but, unfortunately, crates.io either did not like the way the Cargo.toml was set up or (more likely) I was doing something stupid.

Typescript

RDAP Check

A simple library and command-line tool to check domain name availability in bulk using the RDAP protocol, a simple protocol meant to replace WHOIS.

Server Implementations

RDAP servers come in two basic flavors, authoritative server and redirect servers. Authoritative servers contain the information for domain names, IP addresses and ASNs, whereas redirect servers issue HTTP level redirects to clients to assist them to get to the right authoritative server. Sometime, as in the case of the RIRs, servers can be both authoritative for their own information and issue redirects for other information.

Listed under server implementations are conformance tools, which are actually clients developed to make sure servers conform to standards. They are listed here because they are of little use to the general-public and typically only used by server operators.

Authoritative Servers

CNNIC RDAP Proxy43

CoCCA RDAP

https://cocca.org.nz/srs/rdap.html

  • License: Unknown
  • Repository: Unknown
  • Language: Java

DNSBelgium RDAP

This java library makes it very easy to build an RDAP server that talks with your registry back-end.

Domain Cocoon

https://domaincocoon.com/products/whois-server-installation-configuration-jwhoisserver

  • License: Unknown
  • Repository: Unknown
  • Language: Java

ICANN RDAP Server

This server was created to aid in the development of the ICANN RDAP Command Line Interface client. It can be used as a library or as a server started within its own process. It currently has in-memory storage, though its storage layer is architected to accommodate a PostgreSQL backend if that is needed in the future.

Namingo Registry

Namingo is a state-of-the-art open-source domain registry platform, diligently crafted to serve ccTLD, gTLD, brand and private domain registries. Written from scratch in 2023/2024, it adheres to the latest standards, ensuring a cutting-edge experience.

Namingo Registrar Platform

Namingo Registrar Platform, built atop FOSSBilling, transforms the system into a comprehensive and open-source ICANN accredited registrar management system. It provides a powerful and flexible solution for managing domain names as an ICANN accredited registrar, adhering to the stringent standards set by ICANN.

Nomulus

Nomulus is an open source, scalable, cloud-based service for operating top-level domains (TLDs). It is the authoritative source for the TLDs that it runs, meaning that it is responsible for tracking domain name ownership and handling registrations, renewals, availability checks, and WHOIS requests. End-user registrants (i.e. people or companies that want to register a domain name) use an intermediate domain name registrar acting on their behalf to interact with the registry.

RDAPd

rdapd takes historical data imported from the RIPE database last and history tables and exposes an RDAP API for current state, as well as RDAP-like responses for historical state.

Red Dog

Red Dog is an Open Source RDAP (Registration Data Access Protocol) Server implementation built with Java, funded and developed by NIC Mexico.

The server is a RESTful service expected to provide HTTP content in accordance with:

Beside the RFCs accordance, Red Dog has the following features:

  • Response render can be customized by implementing a set of interfaces; e.g. beside JSON responses, a TEXT/HTML/XML or any other response type can be returned if the implementer wishes to.
  • Reference database and data access implementation to ease Red Dog’s use.
  • A set of Java interfaces to implement any kind of data access according to the implementer needs (e.g. data can be obtained from the implementer data repository).
  • Optional Basic Authentication and the possibility to implement/customize the authentication type if needed.
  • Response data privacy using general settings (e.g. everybody can see X data, nobody can see Y data, etc.) or specific settings (e.g. only the owner can see X data, certain custom user roles can see Y data).

Redirect Servers

Redirect servers use the IANA bootstrapping files to redirect clients to an RDAP server. See RDAP Bootstrapping and Redirects.

Services

ARIN RDAP Bootstrap Server

RDAP.Net

Root.RDAP.Org

Software

APNIC rdap-ingressd

rdap-ingressd is a proxy and redirection server for the RDAP protocol. It receives RDAP queries from clients and routes the requests to the appropriate RDAP service by either:

  1. HTTP 301 redirect; or
  2. Proxying the request to another RDAP service and returning the result.

ICANN RDAP Server

RDAP Bootstrap Server

From the GitHub Repository:

The Registration Data Access Protocol (RDAP) defines a bootstrapping process in RFC 7484. A bootstrap server aids clients by reading the bootstrapping information published by IANA and using it to send HTTP redirects to RDAP queries. Clients utilizing a bootstrap server will not need to conduct their own bootstrapping.

RDAP.Org

From the GitHub Repository:

This repository contains the RDAP.org Bootstrap Server, which is implemented in PHP using Openswoole.

You will also find a Dockerfile for building Docker container images, and a TOML file for deploying on Fly.io.

Conformance Tools

Conformance tools or validators evaluate the RDAP servers against RFCs and extensions.

Services

RDAP.Org

  • Service: https://validator.rdap.org/
  • Related: Software
  • Validations:
    • Vanilla (IETF STD 95)
    • gTLD registry (February 2024 gTLD RDAP profile)
    • gTLD registrar (February 2024 gTLD RDAP profile)
    • RIR (January 2021 NRO RDAP Profile)

WebRDAPct

Software

APNIC RDAP Conformance

Tests an RDAP server for conformance with the published standards. See RFC7480 and http://datatracker.ietf.org/wg/weirds.

CentralNIC RDAP Conformance

A script to validate the conformance of an RDAP server.

ICANN RDAP Conformance Tool

The RDAP Conformance Tool is a stand-alone tool acting like a test suite that verifies the conformity of an RDAP server against the specifications developed by the IETF (RFC7481, RFC7482, RFC7483, RFC7484) and the ICANN gTLD RDAP profile https://www.icann.org/gtld-rdap-profile. It only tests RDAP servers related to domains. Apart from generic RDAP tests, there are no specific tests for IP addresses and AS Numbers RDAP servers.

  • License: Apache License, Version 2.0
  • Repository: https://github.com/icann/rdap-conformance-tool
  • Features:
    • Command-line module
    • RDAP validation library
  • Validations:
    • Standard IETF RFCs
    • gTLD Registry (thin or thick)
    • gTLD Registrar
    • ICANN gTLD Profile February 2019

Validator.RDAP.Org

This repository contains:

  • JavaScript library which implements an RDAP validator;
  • CLI tool that uses the library;
  • single-page web application which provides a web frontend.
  • License: Unknown Open Source
  • Repository: https://github.com/rdap-org/validator.rdap.org
  • Related: Service
  • Validations:
    • Vanilla (IETF STD 95)
    • gTLD registry (February 2024 gTLD RDAP profile)
    • gTLD registrar (February 2024 gTLD RDAP profile)
    • RIR (January 2021 NRO RDAP Profile)

Specifications

This section lists the RDAP specifications and useful information related to the RDAP standards.

  • RFCs lists the IETF RFCs for RDAP and related specifications.
  • ICANN describes the ICANN RDAP extensions specifications.
  • NRO describes the NRO RDAP extension specifications.
  • IANA lists the various IANA protocol registries relevant to RDAP.

RFCs

RFCs from the WEIRDS Working Group

RFCTitleKnown As
RFC 7480HTTP Usage in the Registration Data Access Protocol (RDAP)
RFC 7481Security Services for the Registration Data Access Protocol (RDAP)
RFC 7482Registration Data Access Protocol (RDAP) Query Format
RFC 7483JSON Responses for the Registration Data Access Protocol (RDAP)
RFC 7484Finding the Authoritative Registration Data (RDAP) Servicebootstrapping
RFC 7485Inventory and Analysis of WHOIS Registration Objects

RFCs from the REGEXT Working Group

RFCTitleKnown As
RFC 8056Extensible Provisioning Protocol (EPP) and Registration Data Access Protocol (RDAP) Status Mapping
RFC 8521Registration Data Access Protocol (RDAP) Object Taggingobject tagging
RFC 8977Registration Data Access Protocol (RDAP) Query Parameters for Result Sorting and Pagingsorting
RFC 8982Registration Data Access Protocol (RDAP) Partial Responsesubsetting
RFC 9082Registration Data Access Protocol (RDAP) Query Format
RFC 9083JSON Responses for the Registration Data Access Protocol (RDAP)
RFC 9224Finding the Authoritative Registration Data Access Protocol (RDAP) Servicebootstrapping
RFC 9536Registration Data Access Protocol (RDAP) Reverse Searchreverse search
RFC 9537Redacted Fields in the Registration Data Access Protocol (RDAP) Responseredaction
RFC 9560Federated Authentication for the Registration Data Access Protocol (RDAP) Using OpenID Connectopen ID

Relevant vCard and jCard RFCs

RFCTitleKnown As
RFC 6350vCard Format SpecificationvCard
RFC 7095jCard: The JSON Format for vCardjCard
RFC 8605vCard Format Extensions: ICANN Extensions for the Registration Data Access Protocol (RDAP)contact-uri, cc

ICANN

The Internet Corporation for Names and Numbers (ICANN) has a set of requirements for gTLD registries and registrars running RDAP. These requirements are broken into two parts: 1) the RDAP Technical Implementation Guide which defines the implementation and operation of RDAP, and 2) the RDAP Response Profile which defines how gTLD registries and registrars are to respond to RDAP queries.

The latest versions of these documents were published in February 2024 for implementation by August 2024:

Previous to the 2024 requirements, ICANN had the 2019 requirements:

NRO

The Number Resource Organization is an umbrella coordination group for the RIRs.

The NRO has a number of RDAP extensions specific to RIRs all specified in one document:

  • NRO RDAP Profile v0
  • NRO RDAP Profile ASN Flat v0
  • NRO RDAP Profile ASN Hierarchical V0

In addition, the NRO defines an extension for expressing IP address CIDR blocks in RDAP called cidr0.

Finally, there is an extension specific to ARIN for representing the originating autonomous system number of an IP network: arin_originas0.

IANA Registries

RDAP JSON Values Registry

This IANA registry contains the values found in various RDAP strings, as denoted by the type column.

https://www.iana.org/assignments/rdap-json-values/rdap-json-values.xhtml

RDAP Extensions Registry

This registry holds the list of RDAP extensions and their identifiers, which are found in the rdapConformance array.

Registering an extension requires that it be published somewhere, though not necessarily as an IETF RFC.

https://www.iana.org/assignments/rdap-extensions/rdap-extensions.xhtml

RDAP Bootstrap Registries

RDAP bootstrapping starts with these IANA registries:

HTTP Status Codes

This IANA registry holds the HTTP status codes, which are used by RDAP, and used as the errorCode value in error responses.

https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml

vCard/jCard Elements

Values for the various parameter names, property names, etc… for vCard/jCard can be found here:

https://www.iana.org/assignments/vcard-elements/vcard-elements.xhtml

The values in the rel JSON property of link objects can be found here:

https://www.iana.org/assignments/link-relations/link-relations.xhtml

Media Types

The values in the type JSON property of link objects can be found here:

https://www.iana.org/assignments/media-types/media-types.xhtml

Other Documents

Research Papers

Implementation and Utilities of RDAP for Wider Usability among Internet Stakeholders

WHOIS Right? An Analysis of WHOIS and RDAP Consistency

WHOIS sunset? A primer in Registration Data Access Protocol (RDAP) performance

Blog Posts

Is RDAP ready to replace whois?

Glossary

ccTLD

This stands for Country Code Top-Level Domain, which are TLDs operating on behalf of countries and consist of domains such as .uk but also the IDN variants. [WikiPedia]

DNR

A Domain Name Registry is an organization responsible for the production of an authoritative DNS zone file in the public DNS. These are typically organizations running gTLDs and ccTLDs but may also be registries below a TLD.

EPP

The Extensible Provisioning Protocol is an IETF standard used by domain registrars to register domain names into domain registries. EPP is the required means of provisioning domains in gTLDs and is used in some ccTLDs. EPP is used by a few INRs but none of the RIRs. [WikiPedia]

gTLD

This stands for Generic Top-Level Domain, which is a type of TLD operating under contract with ICANN. [WikiPedia]

IANA

The Internet Assigned Numbers Authority is responsible for the allocation of Autonomous System Numbers and IP addresses to the RIRs from the pools of these resources created by the IETF, managing the root DNS zones, and managing the registries of protocol elements for the IETF and other organizations.

ICANN

The Internet Corporation for Assigned Names and Numbers a multi-stakeholder coordination body for ccTLDs, gTLDs, and RIRs.

IETF

The Internet Engineering Task Force, or IETF, is one of the main standards setting organizations for Internet standards and is the Standards Developing Organization (SDO) which defined RDAP.

INR (disambiguation)

Internet Number Resource

An Internet Number Resource is either an IP network (bounded by a start and end IP address and sometimes expressed using CIDR) or an Autonomous System Number (ASN).

Internet Number Registry

“Internet Number Registry”, see Internet Number Resource Registry.

INRR

An Internet Number Resource Registry is a registry assigning IP addresses and Autonomous System numbers (ASNs) to other organizations within a defined service area. INRRs are composed of RIRs but also Local Internet Registries (LIRs) and National Internet Registries (NIRs).

jCard

jCard is the JSON version of the vCard standard, which defines the details of a contact. It is standardized in RFC 7095.

LIR

A “Local Internet Regitry”, sometimes known as an Internet Service Provider (ISP), receives number resources from another INR for re-allocation to customers.

NIR

A “National Internet Registry” is an INR that receives Internet number resources from an RIR for redistribution in a specific country or economy.

NRO

The Number Resource Organization is a coordination group for the RIRs.

RDAP

The Registration Data Access Protocol is the name of the set of specifications for accessing data from Internet resource registries.

REGEXT

REGEXT, or the Registration Protocols Extensions, working group is a long-running activity of the IETF chartered with standardizing extensions to the Extensible Provisioning Protocol (EPP), RDAP, and other data formats necessary for handling data between Internet resource registries (e.g. RIRs, domain registries) and their clients.

RIR

Regional Internet Registries are the organizations receiving IP addresses and Autonomous System numbers (ASNs), collectively called Internet number resources, from IANA and distributed to others in their respective regions. RIRs are described in RFC 7020. [WikiPedia]

TLD

A Top Level Domain is a DNS domain just below the root of the DNS, such as .com or .uk. [WikiPedia]

WEIRDS

The Web Extensibility Internet Registry Data Service (WEIRDS) working group was chartered by the IETF to standardize RDAP. This working group completed all of its originally chartered goals and was shutdown, as is standard practice in the IETF.

vCard

vCard is a MIME-encoded standard for exchanging contact information, such as virtual business cards. It is specified in RFC 6530.

Contributing

Contributions to this book are welcome. If you have a GitHub account, click the “edit” icon above. Otherwise:

  1. To request the addition of an implementation or service, please open a GitHub issue here.
  2. For minor text changes, either:
    1. Open an issue, or
    2. Create a pull request.
  3. For major modification or changes, create a pull request. Before spending any significant effort, contributors are advised to open an issue to ask if the contribution would be accepted.