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
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
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:
- A Bash Shell Example: Finding IP Networks - finding the start, end addresses, and CIDR blocks of public IP networks.
- A Python Example: Finding Protected Domains - list domains that are not protected.
- A Rust Example: Networks of Nameservers - get the networks of the nameservers of a list of domain names.
Whois is also used for other purposes, but these are the ones that generate most traffic and have the highest uses.
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:
- The
-s
suppresses progress output so only JSON is passed tojq
. - The
accept
header is set to the RDAP media type. - The target is a bootstrap server that redirects queries to the appropriate authoritative server.
- The
-L
instructscurl
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:
- “startAddress” and “endAddress” are defined in RFC 9083
- “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.
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:
Path | Search |
---|---|
/domains | Search for domains by name, nameserver name, or nameserver IP. |
/nameservers | Search for nameserver by name or IP. |
/entities | Search for entities (aka contacts) by name or handle. |
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.
- 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.
- Clients and servers should abort a handshake when there is no agreed upon protocol in the ALPN.
- Servers should use key sizes no smaller than the following:
- DH - 2048 bits
- ECDH - 224 bits
- 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:
- Either the client is to fully validate DNSSEC records or is to have a secure channel to a DNS resolver which does so.
- There may be multiple TLSA records, so each record must be evaluated until one is found to work.
- 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.
Not Found
If a client queries for a registration that the server cannot provide, the response code is 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.
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)
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:
Path | Returned Object Class |
---|---|
/ip | IP Network |
/autnum | Autnum |
/domain | Domain |
/nameserver | Nameserver |
/entity | Entity |
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:
Lookup | Example |
---|---|
Single IP Address | https://example.com/rdap/ip/192.0.2.0 |
CIDR notation | https://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:
Lookup | Example |
---|---|
Fully Qualified ASCII | https://example.com/domain/blah.example.com |
Fully Qualified IDN | https://example.com/domain/日本語.example.com |
IPv4 Reverse DNS | https://example.com/rdap/domain/2.0.192.in-addr.arpa |
IPv6 Reverse DNS | https://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
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:
Name | Value |
---|---|
objectClassName | (REQUIRED) must be “entity”. See objectClassName |
handle | a registry-unique string identifier. See handle . |
vcardArray | see jCard/vCard |
roles | an 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. |
publicIds | a common type defined here |
entities | an array of objects as defined by this object class. See entity children. |
remarks | a common type defined here |
links | a common type defined here |
events | a common type defined here |
asEventActor | an array of events without the eventActor JSON member. These are meant to define the entity as being the event actor. This is seldom used. |
status | a common type defined here |
port43 | a common type defined here |
networks | an array of IP networks. See IP network children. |
autnums | an 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:
Name | Value |
---|---|
objectClassName | (REQUIRED) must be “domain”. See objectClassName . |
handle | a registry-unique string identifier. See handle . |
ldhName | a letters-digits-hyphens (ldh, aka ASCII-only) domain name. |
unicodeName | the U-label version of an Internationalized Domain Name (IDN). |
variants | set of variant IDNs for this domain. See variants . |
nameservers | an array of nameserver objects. See nameserver children. |
secureDNS | DNSSEC information. See DNSSEC data. |
publicIds | a common type defined here |
entities | an array of entity objects. See entity children. |
remarks | a common type defined here |
links | a common type defined here |
events | a common type defined here |
status | a common type defined here |
port43 | a common type defined here |
network | a 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:
Name | Value |
---|---|
relation | array of strings, each a “domain variant relation” from the RDAP JSON Values IANA Registry. |
idnTable | the name of the IDN table. |
variantNames | array 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
.
Name | Value |
---|---|
zoneSigned | true if the domain’s zone is signed, otherwise false . |
delegationSigned | true if the domain’s parent zone has signed the delegation to this domain, otherwise false . |
dsData | an array of objects describing Delegation Signer objects. See below. |
keyData | an array of objects describing DNS Key objects. See below. |
dsData
Name | Value |
---|---|
keyTag | the integer of the key tag field of a DS record. |
algorithm | the integer of the algorithm field of a DS record. |
digest | string containing the hexadecimal digest of the DS record. |
digestType | the integer of the digest type of DS record. |
links | a common type defined here |
events | a common type defined here |
keyData
Name | Value |
---|---|
flag | the integer of the flag field of a DNSKEY record. |
protocol | the integer of the protocol field of a DNSKEY record. |
publicKey | string containing the hexadecimal digest of a DNSKEY record public key. |
algorithm | the integer of the algorithm field of a DNSKEY record. |
links | a common type defined here |
events | a 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:
Name | Value |
---|---|
objectClassName | (REQUIRED) must be “nameserver”. See objectClassName . |
handle | a registry-unique string identifier. See handle . |
ldhName | a letters-digits-hyphens (ldh, aka ASCII-only) fully-qualified domain name of the nameserver. |
unicodeName | the U-label version of Internationalized Domain Name (IDN) of the nameserver. |
ipAddresses | an array of objects, each with a v4 and v6 string array containing the IP addresses of the nameserver. |
entities | an array of entity objects. See entity children. |
remarks | a common type defined here |
links | a common type defined here |
events | a common type defined here |
status | a common type defined here |
port43 | a 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:
Name | Value |
---|---|
objectClassName | (REQUIRED) must be “ip network”. See objectClassName . |
handle | a registry-unique string identifier. See handle . |
startAddress | a string containing the start IP address. |
endAddress | a string containing the end IP address. |
ipVersion | a string of either “v4” or “v6” denoting the IP address family version. |
name | a name for the registration usually given by the registration holder. |
type | a string containing an RIR classification of the registration. |
country | a string with the ISO 3166-2 Alpha2 country code where the network originates traffic. |
parentHandle | the handle of the parent network. |
entities | an array of entity objects. See entity children. |
remarks | a common type defined here |
links | a common type defined here |
events | a common type defined here |
status | a common type defined here |
port43 | a 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:
Name | Value |
---|---|
objectClassName | (REQUIRED) must be “autnum”. See objectClassName . |
handle | a registry-unique string identifier. See handle . |
startNum | a string containing the starting ASN. |
endAddress | a string containing the ending ASN. |
name | a name for the registration usually given by the registration holder. |
type | a string containing an RIR classification of the registration. |
country | a string with the ISO 3166-2 Alpha2 country code where the network originates traffic. |
entities | an array of entity objects. See entity children. |
remarks | a common type defined here |
links | a common type defined here |
events | a common type defined here |
status | a common type defined here |
port43 | a 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 Name | Object Class |
---|---|
domainSearchResults | domain |
nameserverSearchResults | nameserver |
entitySearchResults | entity |
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.
Name | Value |
---|---|
rdapConformance | (REQUIRED) a common type defined here |
notices | a common type defined here |
errorCode | (REQUIRED) an integer matching the HTTP status code |
title | a string specifying the title of the error |
description | an array of strings describing the error |
lang | a 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:
- Prepended to the names of JSON values.
- Precede path segments in URLs.
- 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.
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.
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:
- top-level domain registries
- second-level and below domain registries
- domain registrars
- regional internet registries
- national internet registries
- local internet registries
- 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:
- “Bootstrapping” - This is the process defined by RFC 9224 and RFC 7480.
- Redirects - HTTP redirects by another RDAP server as defined by RFC 7480.
- 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.
Type | Link |
---|---|
Forward DNS | https://data.iana.org/rdap/dns.json |
IPv4 Addresses | https://data.iana.org/rdap/ipv4.json |
IPv6 Addresses | https://data.iana.org/rdap/ipv6.json |
Autonomous System Numbers | https://data.iana.org/rdap/asn.json |
Object Tags | https://data.iana.org/rdap/object-tags.json |
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:
Type | Example Entries | Evaluation |
---|---|---|
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.
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:
- Web Applications - those clients running inside a web browser.
- Mobile Applications - clients on mobile devices such as phones.
- CLI Applications - command line interface (CLI) clients.
- Client Libraries - software libraries incorporated into other clients.
Web Applications
Services
APNIC RDAP Web
ARIN Whois/RDAP
Client.RDAP.Org
- Related: Web Application Software
ICANN Lookup
LACNIC RDAP Web Client
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.
- Repository: https://github.com/icann/rdap-lookup-client
- Language: Typescript
- License: Unknown Open Source
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.
- Repository: https://github.com/cdubz/rdap-explorer
- Language: Python
- License: MIT
RDAP Web Client
- Repository: https://github.com/rdap-org/client.rdap.org
- Language: Javascript
- License: Unknown Open Source
- Related: Web Application Service
RDAP WebSpa
- Repository: https://github.com/arineng/rdap_webspa
- Language: Javascript
- License: ISC
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.
- Application Information: https://play.google.com/store/apps/details?id=ca.viagenie.rdapclient&hl=en_US
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.
- Application Information:
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.
- License: MIT, Apache License 2.0
- Repository: https://github.com/icann/icann-rdap
- Language: Rust
- Operating Systems: MacOS, Linux, Windows
- Related: Client Library, Authoritative Server, Redirect Server
- Features:
- Caching
- Bootstrapping
- Output Paging
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.
- License: BSD 2-Clause
- Repository: https://github.com/secynic/ipwhois
- Language: Python
- Operating Systems: MacOS, Linux, Windows Related: Client Library
jrdap
jrdap is a command-line RDAP client written in JavaScript. It has no dependencies beyond node.js.
- License: BSD 3-Clause
- Repository: https://github.com/gbxyz/jrdap
- Language: Javascript
- Operating Systems: MacOs, Linux, Windows
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.
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
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)
- Package Information: https://pypi.org/project/rdap/
- Repository: https://github.com/20c/rdap
- License: Apache 2.0
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.
- Package Information: https://pypi.org/project/rdap-cli/
- Repository: https://github.com/alexeipopov95/rdap-cli
- License: GPL 3.0
RDAP Explorer
Program focused on retrieving and parsing RDAP data and Geolocation for IPv4 addresses.
- Repository: https://github.com/stifferdoroskevich/rdap_explorer
- License: Unknown
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.
- Package Information: https://deno.land/x/rdapcheck@v0.1.1
- Repository: https://github.com/Gadiguibou/rdapcheck
- Documentation: https://deno.land/x/rdapcheck@v0.1.1?doc
- License: AGPL-3.0
- Related: Client Library
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.
- Package Information: https://metacpan.org/pod/App::rdapper
- Repository: https://github.com/gbxyz/rdapper
- Documentation: https://metacpan.org/pod/App::rdapper
- License: Unknown Open Source
- Related: Client Library
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
- Package Information: https://pkg.go.dev/github.com/registrobr/rdap/protocol
- Repository: https://github.com/registrobr/rdap
- Documentation: https://pkg.go.dev/github.com/registrobr/rdap/protocol#section-documentation
- License: Unknown Open Source
Who-Go
- Package Information: https://pkg.go.dev/github.com/darkqiank/whois
- Repository: <github.com/darkqiank/whois>
- Documentation: https://pkg.go.dev/github.com/darkqiank/whois#section-documentation
- License: Apache 2.0
Java
rdap-client
- Repository: https://github.com/dzh/rdap-client
- License: Apache 2.0
rdap-java
- Package Information: https://central.sonatype.com/artifact/cc.maria.rdap-java/rdap-java
- Repository: https://github.com/MariaMerkel/rdap-java
- License: Apache 2.0
Other
Prometheus
adamdecaf rdap_exporter
- Package Information: https://pkg.go.dev/github.com/adamdecaf/rdap_exporter
- Repository: https://github.com/adamdecaf/rdap_exporter
- Documentation: https://pkg.go.dev/github.com/adamdecaf/rdap_exporter#section-documentation
- License: MIT
hsn723 rdap_exporter
- Package Information: https://pkg.go.dev/github.com/hsn723/rdap-exporter
- Repository: <github.com/hsn723/rdap-exporter>
- Documentation: https://pkg.go.dev/github.com/hsn723/rdap-exporter#section-documentation
- License: MIT
Rapid7
- Package Information: https://extensions.rapid7.com/extension/rdap
- Repository: https://github.com/rapid7/insightconnect-plugins
- Documentation: https://extensions.rapid7.com/extension/rdap#Documentation-Setup
- License: MIT
Splunkbase
- Package Information: https://splunkbase.splunk.com/app/5945
- Repository: https://github.com/splunk-soar-connectors/whoisrdap
- Documentation: https://splunkbase.splunk.com/app/5945
- License: Splunk General Terms
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.
- Package Information: https://metacpan.org/pod/Net%3A%3ARDAP
- Repository: https://github.com/gbxyz/perl-net-rdap
- Documentation: https://metacpan.org/pod/Net%3A%3ARDAP
- License: Unknown Open Source
- Related: CLI Application
PHP
Array Access RDAP Client
- Repository: https://github.com/ArrayAccess/RDAP-Client
- License: GPL 3.0
Meta Registrar RDAP Client
- Repository: https://github.com/metaregistrar/rdap-client
- License: GPL 2.0
RDAP Whois Proxy
A bridge from WHOIS to RDAP
- Repository: https://github.com/hiqdev/rdap-whois-proxy
- License: BSD 3-Clause
Python
IPWhois
- Package Information: https://pypi.org/project/ipwhois/
- Repository: https://github.com/secynic/ipwhois
- Documentation: https://ipwhois.readthedocs.io/en/latest
- License: BSD 2-Clause
- Related: CLI Application
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
- Package Information: https://pypi.org/project/whodap/
- Repository: https://github.com/pogzyb/whodap
- Documentation: https://pypi.org/project/whodap/
- License: MIT
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 withrequests
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.
- Package Information: https://pypi.org/project/whoisit/
- Repository: https://github.com/meeb/whoisit
- Documentation: https://pypi.org/project/whoisit/
- License: BSD 3-Clause
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).
- Package Information: https://rubygems.org/gems/rdap
- Repository: https://github.com/jarthod/rdap
- Documentation: https://www.rubydoc.info/gems/rdap/0.1.5
- License: Unspecified
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.
- Package Information: https://crates.io/crates/icann-rdap-client/0.0.16
- Repository: https://github.com/icann/icann-rdap
- Documentation: https://docs.rs/icann-rdap-client/latest/icann_rdap_client/
- License: MIT, Apache License 2.0
- Related: CLI Application, Authoritative Server, Redirect Server
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)
- Supported Standards:
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.
- Package Information: https://crates.io/crates/test_friendly_rdap_client
- Repository: https://github.com/rorymckinley/test_friendly_rdap_client.git
- Documentation: https://docs.rs/test_friendly_rdap_client/0.1.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)
- Supported Standards:
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.
- Package Information: https://deno.land/x/rdapcheck@v0.1.1
- Repository: https://github.com/Gadiguibou/rdapcheck
- Documentation: https://deno.land/x/rdapcheck@v0.1.1?doc
- License: AGPL-3.0
- Related: CLI Application
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
- License: Unspecified
- Language: Java
- Repository: https://github.com/cnnic/rdap
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.
- License: Apache 2.0
- Repository: https://github.com/DNSBelgium/rdap
- Language: Java
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.
- License: MIT, Apache License 2.0
- Repository: https://github.com/icann/icann-rdap
- Language: Rust
- Related: Client Library, CLI Application, Redirect Server
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.
- License: MIT
- Repository: https://github.com/getnamingo/registry
- Language: PHP
- Related: Authoritative Server
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.
- License: MIT
- Repository: https://github.com/getnamingo/registrar
- Language: PHP
- Related: Authoritative Server
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.
- License: Apache 2.0
- Repository: https://github.com/google/nomulus
- Language: Java
RDAPd
rdapd takes historical data imported from the RIPE database
last
andhistory
tables and exposes an RDAP API for current state, as well as RDAP-like responses for historical state.
- License: BSD
- Repository: https://github.com/APNIC-net/rdapd
- Language: Java
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:
- RFC 7480 - HTTP Usage in the Registration Data Access Protocol (RDAP)
- RFC 7481 - Security Services for 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).
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).
- License: Apache 2.0
- Repository: https://github.com/NICMx/rdap-server
- Language: Java
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
- Base RDAP URL: https://rdap-bootstrap.arin/net/bootstrap
- More Information: https://www.arin.net/resources/registry/whois/rdap/
- Related: Software
RDAP.Net
- Base RDAP URL: https://www.rdap.net
- More Information: https://www.openrdap.org/api
- Related: Software
Root.RDAP.Org
- Base RDAP URL: https://root.rdap.org
- Additional services: http://registrars.rdap.org/entity/{NNNN}-iana where NNNN is the numeric IANA ID.
- More information: https://about.rdap.org/
- Related: Software
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:
- HTTP 301 redirect; or
- Proxying the request to another RDAP service and returning the result.
- License: BSD
- Repository: https://github.com/APNIC-net/rdap-ingressd
- Language: Java
ICANN RDAP Server
- License: MIT, Apache License 2.0
- Repository: https://github.com/icann/icann-rdap
- Language: Rust
- Related: Client Library, CLI Application, Authoritative 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.
- License: ISC License
- Repository: https://github.com/arineng/rdap_bootstrap_server
- Language: Java
- Related: Service
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.
- License: Unknown Open Source
- Repository: https://github.com/rdap-org/rdap.org
- Language: PHP
- Related: Service
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
- Service: https://webrdapct.icann.org
- Related: Software
- Validations:
- Standard IETF RFCs
- gTLD Registry (thin or thick)
- gTLD Registrar
- ICANN gTLD Profile February 2019
Software
APNIC RDAP Conformance
Tests an RDAP server for conformance with the published standards. See RFC7480 and http://datatracker.ietf.org/wg/weirds.
- License: BSD
- Repository: https://github.com/APNIC-net/rdap-conformance
CentralNIC RDAP Conformance
A script to validate the conformance of an RDAP server.
- License: Unknown
- Repository: https://gitlab.centralnic.com/centralnic/rdap-conformance
- Archived
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
RFC | Title | Known As |
---|---|---|
RFC 7480 | HTTP Usage in the Registration Data Access Protocol (RDAP) | |
RFC 7481 | Security Services for 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 7484 | Finding the Authoritative Registration Data (RDAP) Service | bootstrapping |
RFC 7485 | Inventory and Analysis of WHOIS Registration Objects |
RFCs from the REGEXT Working Group
RFC | Title | Known As |
---|---|---|
RFC 8056 | Extensible Provisioning Protocol (EPP) and Registration Data Access Protocol (RDAP) Status Mapping | |
RFC 8521 | Registration Data Access Protocol (RDAP) Object Tagging | object tagging |
RFC 8977 | Registration Data Access Protocol (RDAP) Query Parameters for Result Sorting and Paging | sorting |
RFC 8982 | Registration Data Access Protocol (RDAP) Partial Response | subsetting |
RFC 9082 | Registration Data Access Protocol (RDAP) Query Format | |
RFC 9083 | JSON Responses for the Registration Data Access Protocol (RDAP) | |
RFC 9224 | Finding the Authoritative Registration Data Access Protocol (RDAP) Service | bootstrapping |
RFC 9536 | Registration Data Access Protocol (RDAP) Reverse Search | reverse search |
RFC 9537 | Redacted Fields in the Registration Data Access Protocol (RDAP) Response | redaction |
RFC 9560 | Federated Authentication for the Registration Data Access Protocol (RDAP) Using OpenID Connect | open ID |
Relevant vCard and jCard RFCs
RFC | Title | Known As |
---|---|---|
RFC 6350 | vCard Format Specification | vCard |
RFC 7095 | jCard: The JSON Format for vCard | jCard |
RFC 8605 | vCard 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:
Type | Link |
---|---|
Forward DNS | https://data.iana.org/rdap/dns.json |
IPv4 Addresses | https://data.iana.org/rdap/ipv4.json |
IPv6 Addresses | https://data.iana.org/rdap/ipv6.json |
Autonomous System Numbers | https://data.iana.org/rdap/asn.json |
Object Tags | https://data.iana.org/rdap/object-tags.json |
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
Link Relations
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
- Prof. TS. Dr. Miss Laiha Binti Mat Kiah, Ali Hussain, Mahi Uddin
- University of Malaya, Faculty of Computer Science & Information Technology, Jalan Universiti, 50603, Wilayah Persekutuan Kuala Lumpur, Malaysia
- https://apnic.foundation/projects/implementation-and-utilites-of-rdap-for-wider-usability-among-internet-stakeholders/technicalreport/
WHOIS Right? An Analysis of WHOIS and RDAP Consistency
- Simon Fernandez, Olivier Hureau, Andrzej Duda, and Maciej Korczynski
- Univ. Grenoble Alpes, Grenoble INP, LIG
- https://pam2024.cs.northwestern.edu/pdfs/paper-89.pdf
WHOIS sunset? A primer in Registration Data Access Protocol (RDAP) performance
- Carlos H. Gañán
- Internet Corporation for Assigned Names and Numbers (ICANN)
- https://dl.ifip.org/db/conf/tma/tma2021/tma2021-paper16.pdf
Blog Posts
Is RDAP ready to replace whois?
- George Michaelson
- APNIC
- https://blog.apnic.net/2021/04/02/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:
- To request the addition of an implementation or service, please open a GitHub issue here.
- For minor text changes, either:
- Open an issue, or
- Create a pull request.
- 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.