Quick Answer
WHOIS and RDAP are protocols for accessing domain registration data, but they differ fundamentally in design and capabilities. WHOIS is the legacy protocol from 1982 using plain text over port 43 with inconsistent formatting. RDAP (Registration Data Access Protocol) is the modern replacement using RESTful HTTPS APIs with standardized JSON responses. As of January 28, 2025, RDAP became the official standard for gTLDs, offering superior security, internationalization, access control, and GDPR compliance. While WHOIS continues operating for backward compatibility, all new development and features now use RDAP exclusively.
Table of Contents
- Introduction: Why This Comparison Matters
- Historical Context
- Core Protocol Differences
- Data Format Comparison
- Security Architecture
- Access Control and Privacy
- Internationalization Support
- Error Handling and Standards
- Performance and Scalability
- Implementation Requirements
- Migration Timeline and Strategy
- Developer Perspective
- Use Case Analysis
- Cost and Resource Implications
- Future Outlook
- Best Practices
- Frequently Asked Questions
- Key Takeaways
- Next Steps
- Research Sources
Introduction: Why This Comparison Matters
The transition from WHOIS to RDAP represents one of the most significant infrastructure changes in domain name system history. For over 40 years, WHOIS served as the primary method for accessing domain registration data. Now, RDAP has officially replaced it.
Who Needs to Understand This Transition?
Developers: If you're building applications that query domain data, you need to migrate from WHOIS to RDAP APIs to ensure reliability and compliance.
Domain Professionals: Registrars, registries, resellers, and domain investors must understand how RDAP changes data access, privacy controls, and operational workflows.
Security Teams: Cybersecurity professionals rely on registration data for threat intelligence, incident response, and abuse investigations. RDAP's enhanced features provide better tools for security operations.
Legal and Compliance: GDPR and other privacy regulations require sophisticated data access controls that only RDAP can properly implement.
What You'll Learn
This comprehensive comparison goes beyond surface-level differences. You'll understand:
- Technical architecture: How each protocol works at the transport, data, and application layers
- Practical implications: Real-world impact on your tools, workflows, and systems
- Migration strategies: Concrete steps for transitioning from WHOIS to RDAP
- Future-proofing: How to build systems that remain compliant and functional as the ecosystem evolves
Whether you're maintaining legacy WHOIS code, planning an RDAP implementation, or simply curious about why this change happened, this guide provides the depth and context you need.
Historical Context
The Birth of WHOIS (1982)
WHOIS emerged in 1982 when the internet consisted of a few hundred computers. Ken Harrenstien and Vic White at SRI International created WHOIS to maintain a directory of network users and resources.
Original Design Goals:
- Simple directory service for network administrators
- Quick lookups of contact information
- Minimal protocol overhead for slow connections
- Plain text for easy human readability
The Internet in 1982:
- Approximately 500 hosts total
- Single centralized directory (NIC.DDN.MIL)
- Everyone knew everyone else
- No commercial activity
- No privacy concerns
WHOIS Evolution and Growing Pains
As the internet commercialized in the 1990s, WHOIS faced increasing challenges:
1993-1998: Commercialization Network Solutions (NSI) operated the .com, .net, and .org registries. WHOIS data was public and unregulated. Spammers harvested email addresses. No privacy protections existed.
1998-2008: Competition and Fragmentation ICANN introduced competition among registrars. Each registrar implemented WHOIS differently. No standard format emerged. Thick vs thin WHOIS models created confusion.
2008-2018: Privacy Regulations GDPR and other privacy laws conflicted with WHOIS's all-or-nothing model. Emergency redaction measures were inconsistent. Legal uncertainty paralyzed the industry.
2018-2025: The Breaking Point GDPR enforcement (May 2018) revealed WHOIS's fundamental limitations. Registrars redacted data differently. Access requests had no standardized process. The protocol couldn't distinguish between legitimate and illegitimate requesters.
The RDAP Initiative
Recognizing WHOIS's insurmountable problems, the IETF began developing RDAP in 2012.
Key Development Milestones:
| Year | Milestone |
|---|---|
| 2012 | IETF WEIRDS working group formed |
| 2015 | RFC 7480-7484 published (core RDAP specs) |
| 2019 | RFC 8521 published (registration data policy) |
| 2020 | ICANN begins piloting RDAP |
| 2023 | ICANN mandates RDAP implementation |
| 2025 | RDAP becomes official standard, WHOIS sunset |
Design Philosophy Shift:
WHOIS was designed for a trusted, small network. RDAP was designed for an adversarial, global internet with privacy requirements and legal complexity.
Core Protocol Differences
Transport Layer
WHOIS:
Protocol: TCP Port 43
Encryption: None (plain text)
Connection: Short-lived, single query per connection
Query Format: Plain text string
Response Format: Free-form text
Connection Reuse: Not supported
RDAP:
Protocol: HTTPS (TCP Port 443)
Encryption: TLS 1.2+ required
Connection: HTTP/1.1 or HTTP/2 with keep-alive
Query Format: RESTful URL paths
Response Format: Structured JSON
Connection Reuse: Supported via HTTP keep-alive
Protocol Architecture
WHOIS Architecture:
┌─────────────┐ ┌─────────────┐
│ Client │ │ WHOIS Server│
│ │ Port 43 │ │
│ TCP Connect ├─────────►│ │
│ │ │ │
│ Send Query ├─────────►│ Process │
│ │ │ │
│ Receive Text◄──────────┤ Send Text │
│ │ │ │
│ Close Conn │ │ Close Conn │
└─────────────┘ └─────────────┘
RDAP Architecture:
┌──────────────┐ ┌──────────────┐
│ Client │ │ RDAP Server │
│ │ HTTPS │ │
│ GET Request ├────────►│ Authenticate │
│ │ │ │
│ │ │ Process │
│ │ │ │
│ │ │ Apply ACL │
│ │ │ │
│ JSON Response◄─────────┤ Send JSON │
│ │ │ │
│ Keep-Alive │◄───────►│ Persistent │
└──────────────┘ └──────────────┘
Query Syntax
WHOIS Query Examples:
# Simple domain query
whois example.com
# IP address query
whois 8.8.8.8
# Server-specific query
whois -h whois.verisign-grs.com example.com
# Recursive query disabled
whois +norecurse example.com
Challenges:
- No standard query syntax
- Each server interprets queries differently
- No way to specify desired fields
- No structured search capabilities
- Query options vary by server
RDAP Query Examples:
# Domain query
https://rdap.verisign.com/com/v1/domain/example.com
# IP address query
https://rdap.arin.net/registry/ip/8.8.8.8
# Nameserver query
https://rdap.verisign.com/com/v1/nameserver/ns1.example.com
# ASN query
https://rdap.arin.net/registry/autnum/64496
# Entity query
https://rdap.verisign.com/com/v1/entity/123456
Advantages:
- Standard RESTful URL structure
- Predictable query format across servers
- Support for searches (where implemented)
- Clear resource type identification
- URL parameters for additional options
Service Discovery
WHOIS Service Discovery:
No standard mechanism exists. You must:
- Know which WHOIS server handles the TLD
- Manually configure the correct server
- Handle referrals when thin WHOIS requires querying both registry and registrar
- Maintain updated server lists manually
Example Complexity:
Query: example.com
Step 1: Query whois.verisign-grs.com (registry)
Result: "Registrar WHOIS Server: whois.registrar.com"
Step 2: Query whois.registrar.com (registrar)
Result: Full registration data
Two separate connections to different servers required.
RDAP Service Discovery:
IANA maintains the RDAP Bootstrap Service Registry:
- Bootstrap File: https://data.iana.org/rdap/dns.json
- Auto-discovery: Clients automatically find correct server
- Single query: No referrals needed
- Centralized updates: IANA maintains mappings
Bootstrap File Structure:
{
"version": "1.0",
"publication": "2025-01-28T10:00:00Z",
"services": [
[
["com", "net"],
["https://rdap.verisign.com/com/v1/", "https://rdap.verisign.com/net/v1/"]
],
[
["org"],
["https://rdap.publicinterestregistry.org/rdap/"]
]
]
}
Universal Resolver:
RDAP.org provides automatic server routing:
curl https://rdap.org/domain/example.com
# Automatically routes to correct RDAP server
Data Format Comparison
WHOIS Data Format
WHOIS responses are unstructured plain text with no standard format.
Example 1: Verisign Format (.com)
Domain Name: EXAMPLE.COM
Registry Domain ID: 2336799_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.registrar.com
Registrar URL: http://www.registrar.com
Updated Date: 2024-08-14T07:01:44Z
Creation Date: 1995-08-14T04:00:00Z
Registry Expiry Date: 2025-08-13T04:00:00Z
Registrar: Example Registrar, Inc.
Registrar IANA ID: 376
Registrar Abuse Contact Email: [email protected]
Registrar Abuse Contact Phone: +1.1234567890
Domain Status: clientDeleteProhibited https://icann.org/epp#clientDeleteProhibited
Domain Status: clientTransferProhibited https://icann.org/epp#clientTransferProhibited
Name Server: A.IANA-SERVERS.NET
Name Server: B.IANA-SERVERS.NET
DNSSEC: unsigned
Example 2: Different Registrar Format
domain: example.org
status: active
registrant: REDACTED FOR PRIVACY
admin-c: REDACTED FOR PRIVACY
tech-c: REDACTED FOR PRIVACY
billing-c: REDACTED FOR PRIVACY
nserver: ns1.example.org
nserver: ns2.example.org
created: 1997-08-14
modified: 2024-08-14
expires: 2025-08-14
Parsing Challenges:
// Pseudo-code showing WHOIS parsing complexity
function parseWHOIS(text) {
const result = {};
// Different registries use different field names
const domainPatterns = [
/Domain Name:\s*(.+)/i,
/domain:\s*(.+)/i,
/Domain:\s*(.+)/i,
/\[Domain Name\]\s*(.+)/i
];
// Different date formats
const datePatterns = [
/Creation Date:\s*(.+)/i,
/created:\s*(.+)/i,
/Created on:\s*(.+)/i,
/\[Created on\]\s*(.+)/i
];
// Must handle all variations
// Still fragile when format changes
}
RDAP Data Format
RDAP responses use standardized JSON defined in RFC 7483.
Standard RDAP Response:
{
"objectClassName": "domain",
"handle": "2336799_DOMAIN_COM-VRSN",
"ldhName": "example.com",
"status": [
"client delete prohibited",
"client transfer prohibited"
],
"events": [
{
"eventAction": "registration",
"eventDate": "1995-08-14T04:00:00Z"
},
{
"eventAction": "expiration",
"eventDate": "2025-08-13T04:00:00Z"
},
{
"eventAction": "last changed",
"eventDate": "2024-08-14T07:01:44Z"
},
{
"eventAction": "last update of RDAP database",
"eventDate": "2025-12-01T12:30:00Z"
}
],
"nameservers": [
{
"objectClassName": "nameserver",
"ldhName": "a.iana-servers.net"
},
{
"objectClassName": "nameserver",
"ldhName": "b.iana-servers.net"
}
],
"secureDNS": {
"delegationSigned": false
},
"entities": [
{
"objectClassName": "entity",
"handle": "376",
"roles": ["registrar"],
"publicIds": [
{
"type": "IANA Registrar ID",
"identifier": "376"
}
],
"vcardArray": [
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "Example Registrar, Inc."],
["email", {}, "text", "[email protected]"],
["tel", {}, "uri", "tel:+1.1234567890"]
]
],
"entities": [
{
"objectClassName": "entity",
"roles": ["abuse"],
"vcardArray": [
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "Abuse Department"],
["email", {}, "text", "[email protected]"]
]
]
}
]
}
],
"notices": [
{
"title": "Terms of Use",
"description": [
"Service subject to Terms of Use."
],
"links": [
{
"href": "https://www.verisign.com/domain-names/registration-data-access-protocol/terms-service/index.xhtml",
"type": "text/html"
}
]
}
],
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
]
}
Parsing Simplicity:
// RDAP parsing is straightforward
async function parseRDAP(domain) {
const response = await fetch(
`https://rdap.verisign.com/com/v1/domain/${domain}`
);
const data = await response.json();
return {
domain: data.ldhName,
status: data.status,
registered: data.events.find(e => e.eventAction === 'registration')?.eventDate,
expires: data.events.find(e => e.eventAction === 'expiration')?.eventDate,
updated: data.events.find(e => e.eventAction === 'last changed')?.eventDate,
nameservers: data.nameservers?.map(ns => ns.ldhName) || [],
registrar: data.entities?.find(e => e.roles?.includes('registrar'))
?.vcardArray?.[1]?.find(v => v[0] === 'fn')?.[3]
};
}
Field Mapping
| Data Element | WHOIS Field (varies) | RDAP Location |
|---|---|---|
| Domain Name | "Domain Name:", "domain:", "Domain:" | ldhName |
| Creation Date | "Creation Date:", "created:", "Created on:" | events[eventAction=registration].eventDate |
| Expiry Date | "Registry Expiry Date:", "expires:", "Expiration Date:" | events[eventAction=expiration].eventDate |
| Status Codes | "Domain Status:", "status:" | status[] |
| Nameservers | "Name Server:", "nserver:" | nameservers[].ldhName |
| Registrar | "Registrar:", "registrar:" | entities[roles=registrar].vcardArray |
Security Architecture
WHOIS Security Limitations
1. No Encryption
All data transmitted in plain text over port 43:
┌────────┐ ┌──────────┐
│ Client │ ──────Port 43───►│ Server │
│ │ Plain Text │ │
│ │◄──────────────────│ │
└────────┘ example.com... └──────────┘
ANYONE can intercept
Vulnerabilities:
- Man-in-the-middle attacks trivial
- Query patterns expose research interests
- Response spoofing possible
- No integrity verification
- Credentials (if used) transmitted in clear
2. No Authentication
WHOIS has no mechanism to verify:
- Who is making the request
- Whether the requestor has legitimate interest
- Whether responses come from authorized servers
3. No Authorization
Cannot implement access controls:
- Everyone sees the same data (or nothing if privacy-protected)
- No differentiated access levels
- Cannot provide more data to law enforcement
- Cannot enforce acceptable use policies programmatically
4. DDoS Vulnerability
Simple protocol makes abuse easy:
- No rate limiting standards
- Difficult to distinguish legitimate from malicious queries
- Amplification attacks possible
- Resource exhaustion attacks simple
RDAP Security Features
1. Mandatory Encryption
All RDAP communication uses HTTPS with TLS 1.2+:
┌────────┐ ┌──────────┐
│ Client │ ─────HTTPS/TLS────►│ Server │
│ │ Encrypted JSON │ │
│ │◄───────────────────│ │
└────────┘ [encrypted] └──────────┘
Confidentiality + Integrity
Benefits:
- Query and response confidentiality
- Server authentication via TLS certificates
- Data integrity verification
- Protection against interception and tampering
2. Authentication Support
RDAP supports multiple authentication methods:
HTTP Basic Authentication:
GET /domain/example.com HTTP/1.1
Host: rdap.example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
OAuth 2.0:
GET /domain/example.com HTTP/1.1
Host: rdap.example.com
Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
API Keys:
GET /domain/example.com HTTP/1.1
Host: rdap.example.com
X-API-Key: a1b2c3d4-e5f6-7890-abcd-ef1234567890
Client Certificates (mTLS):
Client presents certificate during TLS handshake
Server validates certificate against trusted CA
Access granted based on certificate attributes
3. Differentiated Access Control
RDAP can provide different data based on authentication:
// Anonymous query
{
"ldhName": "example.com",
"status": ["active"],
"events": [...],
"nameservers": [...],
"entities": [
{
"roles": ["registrar"],
"vcardArray": [...] // Registrar info only
}
]
}
// Authenticated law enforcement query
{
"ldhName": "example.com",
"status": ["active"],
"events": [...],
"nameservers": [...],
"entities": [
{
"roles": ["registrant"],
"vcardArray": [...] // Full registrant details
},
{
"roles": ["technical"],
"vcardArray": [...] // Technical contact
},
{
"roles": ["registrar"],
"vcardArray": [...]
}
]
}
4. Rate Limiting and Abuse Prevention
RDAP uses standard HTTP mechanisms:
HTTP/1.1 429 Too Many Requests
Retry-After: 3600
X-Rate-Limit-Limit: 100
X-Rate-Limit-Remaining: 0
X-Rate-Limit-Reset: 1733068800
{
"errorCode": 429,
"title": "Too Many Requests",
"description": ["Rate limit exceeded. Try again in 1 hour."]
}
5. Security Headers
RDAP responses include modern security headers:
HTTP/2 200 OK
Strict-Transport-Security: max-age=31536000; includeSubDomains
Content-Security-Policy: default-src 'none'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: no-referrer
Access Control and Privacy
WHOIS Privacy Challenges
The All-or-Nothing Problem:
WHOIS was designed when privacy wasn't a concern. The protocol has only two modes:
- Show everything: Expose all registrant contact information publicly
- Show nothing: Use privacy service to hide all details
No middle ground exists for:
- Legitimate researchers needing partial access
- Law enforcement requiring full data
- Trademark holders investigating infringement
- Security researchers tracking abuse
Pre-GDPR WHOIS:
Domain Name: example.com
Registrant Name: John Smith
Registrant Organization: Smith Consulting LLC
Registrant Street: 123 Main Street
Registrant City: Anytown
Registrant State/Province: CA
Registrant Postal Code: 90210
Registrant Country: US
Registrant Phone: +1.3105551234
Registrant Email: [email protected]
Admin Name: John Smith
Admin Email: [email protected]
Tech Name: John Smith
Tech Email: [email protected]
Problems:
- Personal information publicly available
- Email addresses harvested for spam
- Physical addresses exposed
- Phone numbers collected
- Identity theft risk
Post-GDPR WHOIS:
Domain Name: example.com
Registry Domain ID: 123456_DOMAIN_COM-VRSN
Registrar WHOIS Server: whois.registrar.com
Registrar URL: http://www.registrar.com
Updated Date: 2024-12-01T00:00:00Z
Creation Date: 2020-01-01T00:00:00Z
Registry Expiry Date: 2025-01-01T00:00:00Z
Registrar: Example Registrar Inc.
Registrar IANA ID: 1234
Registrar Abuse Contact Email: [email protected]
Registrar Abuse Contact Phone: +1.2025551234
Domain Status: ok https://icann.org/epp#ok
Name Server: NS1.EXAMPLE.COM
Name Server: NS2.EXAMPLE.COM
DNSSEC: unsigned
Registrant Name: REDACTED FOR PRIVACY
Registrant Organization: REDACTED FOR PRIVACY
Registrant Street: REDACTED FOR PRIVACY
Registrant City: REDACTED FOR PRIVACY
Registrant State/Province: REDACTED FOR PRIVACY
Registrant Postal Code: REDACTED FOR PRIVACY
Registrant Country: REDACTED FOR PRIVACY
Registrant Phone: REDACTED FOR PRIVACY
Registrant Email: Please query the RDDS service of the Registrar
Admin Name: REDACTED FOR PRIVACY
Admin Email: Please query the RDDS service of the Registrar
Tech Name: REDACTED FOR PRIVACY
Tech Email: Please query the RDDS service of the Registrar
New Problems:
- Useful data completely hidden
- Security research hindered
- Abuse investigation complicated
- No standardized access request process
- Registrar-specific policies create inconsistency
RDAP Privacy Solutions
Differentiated Access Levels:
RDAP implements a tiered access model:
Level 1: Anonymous/Public Access
{
"ldhName": "example.com",
"status": ["active"],
"events": [
{"eventAction": "registration", "eventDate": "2020-01-01T00:00:00Z"},
{"eventAction": "expiration", "eventDate": "2025-01-01T00:00:00Z"}
],
"nameservers": [
{"ldhName": "ns1.example.com"},
{"ldhName": "ns2.example.com"}
],
"entities": [
{
"roles": ["registrar"],
"vcardArray": [
"vcard",
[
["fn", {}, "text", "Example Registrar Inc."],
["email", {}, "text", "[email protected]"]
]
]
}
],
"remarks": [
{
"title": "REDACTED FOR PRIVACY",
"description": [
"Registrant contact information redacted per GDPR.",
"To request access, visit: https://registrar.com/data-access"
]
}
]
}
Level 2: Authenticated User Access
{
"ldhName": "example.com",
// ... public fields ...
"entities": [
{
"roles": ["registrant"],
"vcardArray": [
"vcard",
[
["fn", {}, "text", "Smith Consulting LLC"], // Organization shown
["email", {}, "text", "[email protected]"] // Privacy service email
]
]
}
],
"remarks": [
{
"title": "PARTIAL ACCESS",
"description": [
"Additional contact information available to verified requesters.",
"Submit access request with justification."
]
}
]
}
Level 3: Authorized Access (Law Enforcement)
{
"ldhName": "example.com",
// ... all public fields ...
"entities": [
{
"roles": ["registrant"],
"vcardArray": [
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "John Smith"],
["org", {}, "text", "Smith Consulting LLC"],
["adr", {}, "text", [
"", "", "123 Main Street", "Anytown", "CA", "90210", "US"
]],
["tel", {}, "uri", "tel:+1.3105551234"],
["email", {}, "text", "[email protected]"]
]
]
},
{
"roles": ["administrative"],
// ... full admin contact ...
},
{
"roles": ["technical"],
// ... full tech contact ...
}
],
"notices": [
{
"title": "LAW ENFORCEMENT ACCESS",
"description": [
"Full registration data provided pursuant to official request.",
"Disclosure authorized under applicable law.",
"Case reference: LE-2025-12345"
]
}
]
}
Standardized Access Request Process:
RDAP includes structured information about requesting access:
{
"notices": [
{
"title": "Data Access Policy",
"description": [
"Redacted data may be available to authorized parties."
],
"links": [
{
"rel": "alternate",
"href": "https://registrar.com/data-access-policy",
"type": "text/html",
"title": "Data Access Request Form"
}
]
}
]
}
Redaction Transparency:
RDAP responses clearly indicate what has been redacted and why:
{
"entities": [
{
"roles": ["registrant"],
"vcardArray": [
"vcard",
[
["fn", {}, "text", "REDACTED"],
["email", {}, "text", "REDACTED"]
]
],
"remarks": [
{
"title": "PRIVACY NOTICE",
"description": [
"Personal data redacted pursuant to GDPR Article 6(1)(f).",
"Registrar: Example Registrar Inc.",
"Privacy Policy: https://registrar.com/privacy",
"Data Access Requests: [email protected]"
]
}
]
}
]
}
Internationalization Support
WHOIS ASCII Limitation
WHOIS was designed for ASCII text only (7-bit encoding).
Problems with Non-ASCII Domains:
# Chinese domain
Domain Name: 例え.com
WHOIS query result:
Domain Name: xn--r8jz45g.com # Punycode only
Registrant Name: ??? (garbled or absent)
# Arabic domain
Domain Name: مثال.com
WHOIS query result:
Domain Name: xn--mgbh0fb.com # Punycode only
Registrant Organization: ????? (cannot display)
Contact Information Issues:
# Japanese registrant
Registrant Name: ??? (cannot display)
Registrant Street: ?????? (cannot display)
Registrant City: ??? (cannot display)
# Russian technical contact
Tech Name: ??? (mojibake)
Tech Organization: ??? (lost in translation)
Encoding Inconsistencies:
Different servers attempted different solutions:
- Some used Latin transliteration (lossy)
- Others used UTF-8 (broke WHOIS parsers)
- Many simply omitted non-ASCII text
- No standard approach existed
RDAP Unicode Support
RDAP fully supports Unicode (UTF-8 encoding).
Internationalized Domain Names (IDNs):
{
"objectClassName": "domain",
"ldhName": "xn--r8jz45g.com", // ASCII-compatible form
"unicodeName": "例え.com", // Unicode form
"status": ["active"],
"events": [...],
"lang": "ja" // Language tag
}
Multilingual Contact Information:
{
"entities": [
{
"roles": ["registrant"],
"vcardArray": [
"vcard",
[
["version", {}, "text", "4.0"],
["fn", {}, "text", "田中太郎"], // Japanese name in original script
["fn", {"language": "en"}, "text", "Taro Tanaka"], // English version
["org", {}, "text", "株式会社サンプル"], // Japanese company name
["org", {"language": "en"}, "text", "Sample Corporation"], // English
["adr", {}, "text", [
"",
"",
"千代田区霞が関1-1-1", // Japanese address
"東京都",
"",
"100-0013",
"JP"
]],
["adr", {"language": "en"}, "text", [
"",
"",
"1-1-1 Kasumigaseki, Chiyoda-ku", // Romanized address
"Tokyo",
"",
"100-0013",
"JP"
]]
]
]
}
]
}
Language Tags:
RDAP uses standard IETF language tags (RFC 5646):
{
"lang": "ja", // Primary language: Japanese
"entities": [
{
"vcardArray": [
"vcard",
[
["fn", {"language": "ja"}, "text", "山田花子"],
["fn", {"language": "en"}, "text", "Hanako Yamada"],
["fn", {"language": "ja-Kana"}, "text", "ヤマダハナコ"], // Katakana
["fn", {"language": "ja-Hira"}, "text", "やまだはなこ"] // Hiragana
]
]
}
]
}
Script and Direction Support:
{
"entities": [
{
"roles": ["registrant"],
"vcardArray": [
"vcard",
[
["fn", {"language": "ar"}, "text", "محمد أحمد"], // Arabic (RTL)
["fn", {"language": "ar-Latn"}, "text", "Muhammad Ahmad"], // Romanized
["fn", {"language": "he"}, "text", "דוד כהן"], // Hebrew (RTL)
["fn", {"language": "he-Latn"}, "text", "David Cohen"] // Romanized
]
]
}
]
}
Benefits:
- Original scripts preserved
- Multiple language representations supported
- Client can choose appropriate version
- No information loss
- Proper cultural representation
Error Handling and Standards
WHOIS Error Handling
WHOIS has no standardized error responses.
Different servers, different errors:
Server 1:
% No match for "NONEXISTENT.COM".
Server 2:
No Data Found
Server 3:
NOT FOUND
Server 4:
This domain is not registered.
Server 5:
ERROR: Domain not found in registry
Parsing Nightmare:
function checkDomainAvailable(whoisText) {
// Must check dozens of possible error messages
const notFoundPatterns = [
/No match/i,
/NOT FOUND/i,
/No Data Found/i,
/not registered/i,
/No entries found/i,
/Status: free/i,
/Domain not found/i,
// ... 50+ more patterns ...
];
// Still fragile - new servers break code
return notFoundPatterns.some(pattern => pattern.test(whoisText));
}
Rate Limiting:
No standard. Some close connection, others return:
% Your query limit exceeded
or
ERROR: Rate limit
or disconnect without message.
RDAP Error Handling
RDAP uses standard HTTP status codes and structured JSON errors.
Standard HTTP Status Codes:
| Code | Meaning | RDAP Usage |
|---|---|---|
| 200 | OK | Successful query, data returned |
| 400 | Bad Request | Malformed query syntax |
| 401 | Unauthorized | Authentication required |
| 403 | Forbidden | Authenticated but not authorized |
| 404 | Not Found | Domain/object does not exist |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server-side problem |
| 501 | Not Implemented | Query type not supported |
| 503 | Service Unavailable | Temporary server unavailability |
Structured Error Responses:
// 404 Not Found - Domain Available
{
"errorCode": 404,
"title": "Not Found",
"description": [
"The requested domain does not exist in the registry."
]
}
// 400 Bad Request - Invalid Query
{
"errorCode": 400,
"title": "Bad Request",
"description": [
"Invalid domain name format.",
"Domain names must contain only alphanumeric characters and hyphens."
]
}
// 429 Too Many Requests - Rate Limited
{
"errorCode": 429,
"title": "Too Many Requests",
"description": [
"Rate limit of 10 requests per minute exceeded.",
"Retry after 60 seconds."
],
"notices": [
{
"title": "Rate Limit Policy",
"description": [
"Anonymous users: 10 queries/minute",
"Authenticated users: 100 queries/minute",
"Sign up for API access: https://rdap.example.com/signup"
]
}
]
}
// 503 Service Unavailable - Maintenance
{
"errorCode": 503,
"title": "Service Temporarily Unavailable",
"description": [
"Scheduled maintenance in progress.",
"Service expected to resume at 2025-12-01T14:00:00Z"
],
"notices": [
{
"title": "Maintenance Window",
"description": [
"Maintenance schedule: https://status.rdap.example.com"
]
}
]
}
Client-Friendly Error Handling:
async function queryRDAP(domain) {
try {
const response = await fetch(
`https://rdap.verisign.com/com/v1/domain/${domain}`
);
if (response.ok) {
return await response.json();
}
// Structured error handling
switch (response.status) {
case 404:
return { available: true };
case 429:
const retryAfter = response.headers.get('Retry-After');
throw new Error(`Rate limited. Retry after ${retryAfter} seconds`);
case 400:
const error = await response.json();
throw new Error(`Invalid query: ${error.description.join(' ')}`);
case 500:
case 503:
throw new Error('Server temporarily unavailable');
default:
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
} catch (error) {
console.error('RDAP query failed:', error);
throw error;
}
}
Performance and Scalability
WHOIS Performance Characteristics
Connection Overhead:
Each query requires:
1. TCP handshake (1 RTT)
2. Send query (1 RTT)
3. Receive response (1+ RTT)
4. Close connection
Total: ~3-4 RTTs per query
No Connection Reuse:
WHOIS typically uses one connection per query. For 100 queries:
- 100 TCP connections
- 300-400 round trips
- Significant overhead
No Caching Mechanisms:
WHOIS protocol provides no cache control:
- Clients don't know how long to cache
- Servers can't indicate freshness
- No conditional requests ("If-Modified-Since")
- Forces full queries even for unchanged data
Text Parsing Overhead:
// Parsing unstructured text is CPU-intensive
function parseWHOIS(text) {
// Regex parsing thousands of lines
// String matching and extraction
// Date parsing with format detection
// Encoding detection and conversion
// Takes 10-50ms per response
}
Benchmark - WHOIS:
Sequential 100 domain queries:
- Connection time: 5-10 seconds
- Query processing: 2-5 seconds
- Response parsing: 1-2 seconds
Total: 8-17 seconds (5-12 queries/second)
RDAP Performance Advantages
HTTP/2 and Connection Reuse:
Single connection for multiple queries:
1. Initial TLS handshake (2 RTTs)
2. Query 1 (1 RTT)
3. Query 2 (1 RTT) - reuses connection
4. Query 3 (1 RTT) - reuses connection
...
100 queries: ~102 RTTs vs 300-400 for WHOIS
HTTP/2 Multiplexing:
Multiple concurrent requests over one connection:
- No head-of-line blocking
- Request pipelining
- Stream prioritization
Enables parallel queries without connection overhead
Cache Control:
HTTP/2 200 OK
Cache-Control: public, max-age=3600
ETag: "a1b2c3d4e5f6"
Last-Modified: Wed, 01 Dec 2025 12:00:00 GMT
{
"ldhName": "example.com",
// ... response data ...
}
Conditional Requests:
GET /domain/example.com HTTP/2
Host: rdap.verisign.com
If-None-Match: "a1b2c3d4e5f6"
HTTP/2 304 Not Modified
Cache-Control: public, max-age=3600
Saves bandwidth and processing when data hasn't changed.
JSON Parsing Performance:
// Native JSON parsing is very fast
const data = JSON.parse(response); // 1-2ms
// No regex needed
// No format detection
// Direct object access
Benchmark - RDAP:
Sequential 100 domain queries (HTTP/2):
- Initial connection: 0.2 seconds
- Query processing: 2-5 seconds
- JSON parsing: 0.1-0.2 seconds
Total: 2.3-5.4 seconds (18-43 queries/second)
3-5x faster than WHOIS
Concurrent Queries:
// RDAP enables efficient parallel queries
const domains = ['example1.com', 'example2.com', /* ... 100 domains */];
const results = await Promise.all(
domains.map(domain => queryRDAP(domain))
);
// With HTTP/2 multiplexing over single connection
// 100 queries complete in ~3-5 seconds
// Effective rate: 20-33 queries/second
Scalability Considerations
WHOIS Scalability Limits:
- Connection overhead limits query rate
- Text parsing consumes significant CPU
- No standard caching reduces efficiency
- Difficult to implement CDN/proxy caching
- Rate limiting forces slow query rates
RDAP Scalability Features:
- HTTP/2 reduces connection overhead
- JSON parsing is highly efficient
- Standard caching enables CDN deployment
- Structured data enables database optimization
- Clear rate limit signals enable backoff strategies
Implementation Requirements
WHOIS Server Requirements
Minimal Specification:
- TCP socket on port 43
- Accept incoming connections
- Read query string (terminated by CRLF)
- Return plain text response
- Close connection
No Standards For:
- Response format
- Character encoding
- Error messages
- Rate limiting
- Access control
- Logging format
- Security features
Example Minimal WHOIS Server (Python):
import socket
def whois_server():
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(('0.0.0.0', 43))
server.listen(5)
while True:
client, addr = server.accept()
query = client.recv(1024).decode().strip()
# Process query (implementation-specific)
response = process_query(query)
# Send response as plain text
client.send(response.encode())
client.close()
def process_query(query):
# No standard format - implement however you want
return f"Domain: {query}\nStatus: active\n..."
Challenges:
- No guidance on proper implementation
- Each implementer invents their own format
- Inconsistencies proliferate
- Security often overlooked
RDAP Server Requirements
Comprehensive Specification:
Required RFCs:
- RFC 7480: HTTP Usage in RDAP
- RFC 7481: Security Services for RDAP
- RFC 7482: Query Format
- RFC 7483: JSON Responses
- RFC 7484: Finding the Right RDAP Server
ICANN Additional Requirements:
- ICANN RDAP Profile
- ICANN RDAP Technical Implementation Guide
- gTLD Registration Data Services
Server Implementation Checklist:
Transport:
- HTTPS on port 443
- TLS 1.2 or higher
- Valid TLS certificate
- HTTP/2 support recommended
Query Support:
- Domain lookup: /domain/{domain}
- Nameserver lookup: /nameserver/{nameserver}
- Entity lookup: /entity/{handle}
- IP lookup: /ip/{ip}
- ASN lookup: /autnum/{asn}
Response Format:
- JSON with proper content-type
- UTF-8 encoding
- Proper RDAP conformance tags
- Standard object classes
Security:
- Authentication support (optional but recommended)
- Authorization framework
- Rate limiting
- Abuse prevention
- Security headers
Privacy:
- Differentiated access control
- GDPR compliance
- Redaction mechanisms
- Access request process
Operational:
- Service status page
- Contact information
- Terms of service
- Privacy policy
- Logging and monitoring
Example RDAP Server Structure (Node.js/Express):
const express = require('express');
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');
const app = express();
// Security middleware
app.use(helmet());
app.use(express.json());
// Rate limiting
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 10, // 10 requests per minute
message: {
errorCode: 429,
title: "Too Many Requests",
description: ["Rate limit exceeded. Try again later."]
}
});
app.use('/rdap', limiter);
// Domain lookup endpoint
app.get('/rdap/domain/:domain', async (req, res) => {
try {
const { domain } = req.params;
// Validate domain format
if (!isValidDomain(domain)) {
return res.status(400).json({
errorCode: 400,
title: "Bad Request",
description: ["Invalid domain name format"]
});
}
// Query database
const data = await lookupDomain(domain);
if (!data) {
return res.status(404).json({
errorCode: 404,
title: "Not Found",
description: ["Domain not found in registry"]
});
}
// Apply access control
const accessLevel = determineAccessLevel(req);
const filteredData = applyPrivacyFilters(data, accessLevel);
// Return standard RDAP response
res.json(filteredData);
} catch (error) {
console.error('RDAP query error:', error);
res.status(500).json({
errorCode: 500,
title: "Internal Server Error",
description: ["An error occurred processing your request"]
});
}
});
// Standard error handler
app.use((err, req, res, next) => {
res.status(err.status || 500).json({
errorCode: err.status || 500,
title: err.title || "Internal Server Error",
description: [err.message]
});
});
// Start server
app.listen(443, () => {
console.log('RDAP server listening on port 443');
});
Testing and Validation:
ICANN provides:
- RDAP validation tools
- Test suite for compliance
- Reference implementations
- Interoperability testing
Migration Timeline and Strategy
Official Sunset Schedule
January 28, 2025: ICANN officially sunset WHOIS for gTLDs and mandated RDAP.
What This Means:
- RDAP is now the required protocol for gTLD registration data access
- All ICANN-accredited registries must provide RDAP services
- WHOIS is no longer the official standard
- New features and capabilities will be RDAP-only
What This Doesn't Mean:
- WHOIS servers haven't been shut off
- Many registries continue operating WHOIS for backward compatibility
- No specific date announced for WHOIS decommissioning
- Transition period continues while ecosystem adapts
Registry Implementation Status
Already Implemented (100%):
All major gTLD registries have RDAP:
- Verisign (.com, .net, .name, .cc, .tv)
- Public Interest Registry (.org)
- Donuts (portfolio of new gTLDs)
- Google Registry (.dev, .app, .page, etc.)
- Identity Digital (Afilias)
ccTLD Implementation (Varies):
Country-code TLDs are not under ICANN mandate:
- ✅ .uk - RDAP available
- ✅ .de - RDAP available
- ✅ .nl - RDAP available
- ✅ .ca - RDAP available
- ⚠️ .cn - Limited RDAP
- ❌ Many smaller ccTLDs - WHOIS only
Client Migration Strategy
Phase 1: Add RDAP Support (Completed for Most)
// Support both protocols during transition
async function lookupDomain(domain) {
try {
// Try RDAP first
return await queryRDAP(domain);
} catch (error) {
console.warn('RDAP failed, falling back to WHOIS:', error);
// Fallback to WHOIS
return await queryWHOIS(domain);
}
}
Phase 2: Prefer RDAP, Keep WHOIS Fallback (Current)
// Most tools now here
async function lookupDomain(domain) {
const tld = domain.split('.').pop();
// Check if TLD supports RDAP
if (await hasRDAPSupport(tld)) {
try {
return await queryRDAP(domain);
} catch (error) {
if (error.code === 'RDAP_UNAVAILABLE') {
console.warn('RDAP temporarily unavailable, trying WHOIS');
return await queryWHOIS(domain);
}
throw error;
}
}
// Use WHOIS for TLDs without RDAP
return await queryWHOIS(domain);
}
Phase 3: RDAP-Only (Future)
// Future state - RDAP only
async function lookupDomain(domain) {
return await queryRDAP(domain);
// No WHOIS fallback
}
Migration Checklist for Developers
Immediate Actions:
- Audit codebase for WHOIS usage
- Identify all domain lookup implementations
- Test RDAP support for your TLDs
- Update error handling for RDAP responses
- Implement proper JSON parsing
Short-term (3-6 months):
- Implement RDAP as primary lookup method
- Keep WHOIS fallback for ccTLDs
- Update documentation and API specs
- Add support for authentication (if needed)
- Implement rate limiting and retry logic
Medium-term (6-12 months):
- Remove WHOIS code for gTLDs
- Optimize RDAP query patterns
- Implement response caching
- Add monitoring and alerting
- Update UI to handle RDAP-specific features
Long-term (12+ months):
- Remove all WHOIS code
- Full RDAP feature utilization
- Implement differentiated access (if applicable)
- Leverage RDAP-only capabilities
- Archive WHOIS parsing libraries
Developer Perspective
Migration Code Examples
Before: WHOIS Implementation
// Legacy WHOIS client (Node.js)
const net = require('net');
function queryWHOIS(domain) {
return new Promise((resolve, reject) => {
const client = new net.Socket();
let data = '';
// Connect to WHOIS server on port 43
client.connect(43, 'whois.verisign-grs.com', () => {
client.write(domain + '\r\n');
});
// Accumulate response
client.on('data', (chunk) => {
data += chunk.toString();
});
// Connection closed, parse response
client.on('close', () => {
try {
const parsed = parseWHOIS(data);
resolve(parsed);
} catch (error) {
reject(error);
}
});
client.on('error', reject);
// Timeout after 10 seconds
client.setTimeout(10000);
client.on('timeout', () => {
client.destroy();
reject(new Error('WHOIS query timeout'));
});
});
}
// Fragile text parsing
function parseWHOIS(text) {
const result = {};
// Try multiple patterns for each field
const domainMatch = text.match(/Domain Name:\s*(.+)/i);
result.domain = domainMatch ? domainMatch[1].trim() : null;
const createdMatch = text.match(/Creation Date:\s*(.+)/i) ||
text.match(/created:\s*(.+)/i);
result.created = createdMatch ? new Date(createdMatch[1].trim()) : null;
const expiresMatch = text.match(/Registry Expiry Date:\s*(.+)/i) ||
text.match(/expires:\s*(.+)/i);
result.expires = expiresMatch ? new Date(expiresMatch[1].trim()) : null;
// Extract nameservers
const nsMatches = text.match(/Name Server:\s*(.+)/gi);
result.nameservers = nsMatches
? nsMatches.map(ns => ns.replace(/Name Server:\s*/i, '').trim())
: [];
return result;
}
// Usage
queryWHOIS('example.com')
.then(data => console.log(data))
.catch(error => console.error(error));
After: RDAP Implementation
// Modern RDAP client (Node.js)
const fetch = require('node-fetch');
// Bootstrap data could be cached
const BOOTSTRAP_URL = 'https://data.iana.org/rdap/dns.json';
async function queryRDAP(domain) {
// Find correct RDAP server for domain
const rdapUrl = await getRDAPServer(domain);
const response = await fetch(`${rdapUrl}/domain/${domain}`, {
headers: {
'Accept': 'application/rdap+json'
}
});
if (!response.ok) {
if (response.status === 404) {
return { available: true };
}
throw new Error(`RDAP query failed: ${response.status}`);
}
const data = await response.json();
return parseRDAP(data);
}
// Cache bootstrap data
let bootstrapCache = null;
async function getRDAPServer(domain) {
const tld = domain.split('.').pop().toLowerCase();
if (!bootstrapCache) {
const response = await fetch(BOOTSTRAP_URL);
bootstrapCache = await response.json();
}
// Find service for this TLD
for (const service of bootstrapCache.services) {
if (service[0].includes(tld)) {
return service[1][0]; // First URL
}
}
throw new Error(`No RDAP server found for TLD: ${tld}`);
}
// Simple, reliable parsing
function parseRDAP(data) {
return {
domain: data.ldhName || data.unicodeName,
status: data.status || [],
created: data.events?.find(e => e.eventAction === 'registration')?.eventDate,
expires: data.events?.find(e => e.eventAction === 'expiration')?.eventDate,
updated: data.events?.find(e => e.eventAction === 'last changed')?.eventDate,
nameservers: data.nameservers?.map(ns => ns.ldhName) || [],
registrar: extractRegistrar(data.entities),
dnssec: data.secureDNS?.delegationSigned || false
};
}
function extractRegistrar(entities = []) {
const registrar = entities.find(e => e.roles?.includes('registrar'));
if (!registrar) return null;
const vcard = registrar.vcardArray?.[1] || [];
const name = vcard.find(v => v[0] === 'fn')?.[3];
const email = vcard.find(v => v[0] === 'email')?.[3];
return { name, email };
}
// Usage
queryRDAP('example.com')
.then(data => console.log(data))
.catch(error => console.error(error));
Comparison:
| Aspect | WHOIS Code | RDAP Code |
|---|---|---|
| Lines of Code | ~80 | ~60 |
| Complexity | High (parsing) | Low (JSON) |
| Reliability | Fragile | Robust |
| Maintainability | Difficult | Easy |
| Performance | Slower | Faster |
| Error Handling | Custom | Standard HTTP |
Testing RDAP Implementation
// Unit tests for RDAP client
const assert = require('assert');
describe('RDAP Client', () => {
describe('queryRDAP', () => {
it('should return domain data for registered domain', async () => {
const data = await queryRDAP('google.com');
assert(data.domain === 'google.com');
assert(data.status.includes('client transfer prohibited'));
assert(data.created);
assert(data.expires);
assert(data.nameservers.length > 0);
});
it('should return available=true for unregistered domain', async () => {
const data = await queryRDAP('thisisnotarealdomain123456789.com');
assert(data.available === true);
});
it('should handle internationalized domains', async () => {
const data = await queryRDAP('例え.com');
assert(data.domain === '例え.com' || data.domain === 'xn--r8jz45g.com');
});
it('should handle rate limiting gracefully', async () => {
// Make many rapid requests
const promises = [];
for (let i = 0; i < 100; i++) {
promises.push(queryRDAP(`test${i}.com`).catch(e => e));
}
const results = await Promise.all(promises);
const rateLimited = results.filter(r => r.message?.includes('429'));
assert(rateLimited.length > 0, 'Should receive rate limit errors');
});
});
describe('parseRDAP', () => {
it('should extract all standard fields', () => {
const mockResponse = {
ldhName: 'example.com',
status: ['active'],
events: [
{ eventAction: 'registration', eventDate: '2020-01-01T00:00:00Z' },
{ eventAction: 'expiration', eventDate: '2025-01-01T00:00:00Z' }
],
nameservers: [
{ ldhName: 'ns1.example.com' },
{ ldhName: 'ns2.example.com' }
]
};
const parsed = parseRDAP(mockResponse);
assert(parsed.domain === 'example.com');
assert(parsed.status.includes('active'));
assert(parsed.created === '2020-01-01T00:00:00Z');
assert(parsed.expires === '2025-01-01T00:00:00Z');
assert(parsed.nameservers.length === 2);
});
});
});
Use Case Analysis
Domain Availability Checking
WHOIS Approach:
async function isDomainAvailable(domain) {
try {
const whoisData = await queryWHOIS(domain);
// Must check for various "not found" patterns
const notFoundIndicators = [
'No match for',
'NOT FOUND',
'No Data Found',
'not registered',
'No entries found',
'Status: free'
];
return notFoundIndicators.some(indicator =>
whoisData.toLowerCase().includes(indicator.toLowerCase())
);
} catch (error) {
// Connection errors might mean available OR server down
// No way to distinguish
throw error;
}
}
Challenges:
- Unreliable pattern matching
- False positives/negatives
- Different messages per server
- Error handling ambiguous
RDAP Approach:
async function isDomainAvailable(domain) {
const response = await fetch(
`https://rdap.org/domain/${domain}`
);
// Clear, standardized status codes
if (response.status === 404) {
return true; // Domain available
}
if (response.status === 200) {
return false; // Domain registered
}
// Other statuses handled clearly
if (response.status === 429) {
throw new Error('Rate limited');
}
throw new Error(`Unexpected status: ${response.status}`);
}
Advantages:
- Reliable status codes
- No pattern matching
- Clear error semantics
- Works consistently across TLDs
Security Research and Threat Intelligence
WHOIS Limitations:
// Monitoring for domain changes (WHOIS)
async function monitorDomain(domain) {
// Must query periodically
const initialData = await queryWHOIS(domain);
setInterval(async () => {
const currentData = await queryWHOIS(domain);
// Fragile comparison of text data
if (initialData !== currentData) {
// But what changed? Must re-parse and compare fields
const changes = diffWHOIS(initialData, currentData);
alertOnChanges(changes);
}
}, 3600000); // Check hourly
}
Problems:
- No structured change detection
- Text comparison unreliable
- Resource-intensive polling
- No historical data access
RDAP Advantages:
// Monitoring for domain changes (RDAP)
async function monitorDomain(domain) {
let lastETag = null;
setInterval(async () => {
const response = await fetch(
`https://rdap.org/domain/${domain}`,
{
headers: lastETag ? {
'If-None-Match': lastETag
} : {}
}
);
if (response.status === 304) {
// No changes since last check
return;
}
if (response.status === 200) {
const currentData = await response.json();
lastETag = response.headers.get('ETag');
// Structured comparison
const changes = detectChanges(currentData);
if (changes.nameserversChanged) {
alert('Nameservers modified - potential hijacking');
}
if (changes.statusChanged) {
alert('Domain status changed - review immediately');
}
if (changes.registrarChanged) {
alert('Domain transferred to new registrar');
}
}
}, 3600000);
}
function detectChanges(newData) {
// Structured change detection
return {
nameserversChanged: /* compare arrays */,
statusChanged: /* compare status arrays */,
registrarChanged: /* compare registrar entity */,
expirationChanged: /* compare expiration event */
};
}
Benefits:
- Efficient conditional queries (ETags)
- Structured change detection
- Clear field-level monitoring
- Better historical tracking
Compliance and Legal Access
WHOIS Problems:
- No standard way to request access to redacted data
- Contact information inconsistent or missing
- No audit trail of who accessed what data
- Cannot prove data provenance
RDAP Solutions:
{
"ldhName": "example.com",
"entities": [
{
"roles": ["registrant"],
"vcardArray": ["vcard", [["fn", {}, "text", "REDACTED"]]],
"remarks": [
{
"title": "DATA ACCESS REQUEST",
"description": [
"To request access to redacted data, submit form at:",
"https://registrar.com/data-access"
],
"links": [
{
"rel": "alternate",
"href": "https://registrar.com/data-access",
"type": "text/html"
}
]
}
]
}
],
"notices": [
{
"title": "LEGAL ACCESS PROCESS",
"description": [
"Law enforcement and legal requests:",
"Email: [email protected]",
"Include: case number, jurisdiction, data requested",
"Response time: 3-5 business days"
]
}
]
}
Authenticated Access Example:
// Law enforcement access with credentials
async function getLegalAccess(domain, credentials) {
const response = await fetch(
`https://rdap.registrar.com/domain/${domain}`,
{
headers: {
'Authorization': `Bearer ${credentials.token}`,
'X-Case-Number': credentials.caseNumber,
'X-Jurisdiction': credentials.jurisdiction
}
}
);
const data = await response.json();
// Full contact details provided to authorized requester
return data;
}
Cost and Resource Implications
Infrastructure Costs
WHOIS Server Costs:
Hardware/VM: Basic server
CPU: Low (text processing)
RAM: Minimal (simple queries)
Storage: Moderate (text logs)
Bandwidth: Low (small responses)
TLS Certificates: None
Load Balancer: Optional
CDN: Not applicable
Estimated monthly cost: $50-200
RDAP Server Costs:
Hardware/VM: Modern server (HTTP/2 support)
CPU: Moderate (JSON processing, authentication)
RAM: Moderate (connection pooling, caching)
Storage: Higher (structured logs, authentication)
Bandwidth: Moderate (JSON overhead ~2-3x text)
TLS Certificates: Required (~$0-200/year)
Load Balancer: Recommended
CDN: Beneficial for global performance
Estimated monthly cost: $200-800
Cost Increase Factors:
- TLS infrastructure
- Authentication systems
- Database for access control
- Monitoring and logging
- Compliance features
Cost Reduction Opportunities:
- Caching reduces backend load
- HTTP/2 reduces connection overhead
- Structured data enables better optimization
- Automated compliance reduces manual review costs
Development Costs
Migration Effort:
| Task | Estimated Hours |
|---|---|
| Requirements analysis | 8-16 |
| Protocol implementation | 40-80 |
| Authentication/authorization | 20-40 |
| Privacy controls | 20-40 |
| Testing and validation | 40-80 |
| Documentation | 16-32 |
| Total | 144-288 hours |
Typical cost: $14,000 - $43,000 (at $100-150/hour)
Maintenance Costs:
RDAP ongoing maintenance is generally lower than WHOIS:
- Structured data easier to maintain
- Standard error handling
- Better monitoring and debugging
- Fewer format-related bugs
Operational Benefits
RDAP Reduces Costs For:
- Customer Support: Clearer error messages reduce support tickets
- Compliance: Automated access controls reduce manual review
- Development: Standard formats reduce custom parsing code
- Monitoring: Structured data enables better alerting
- Integration: RESTful API easier to integrate with other systems
ROI Timeline:
Initial investment: $15,000-45,000 (migration)
Annual savings: $5,000-15,000 (reduced support/maintenance)
Break-even: 1-3 years
Long-term benefit: Ongoing savings + better functionality
Future Outlook
WHOIS Phase-Out Timeline
Realistic Expectation:
2025: RDAP mandatory, WHOIS continues (current)
2026-2027: Major registries begin deprecating WHOIS
2028-2029: WHOIS becomes optional/unsupported
2030+: WHOIS largely decommissioned for gTLDs
Factors Affecting Timeline:
- Legacy client migration speed
- ccTLD adoption rates
- Industry stakeholder readiness
- Regulatory requirements
- Cost considerations
Warning Signs WHOIS Shutdown Is Near:
- Formal deprecation notices from major registries
- ICANN sunset timeline announcement
- Registrar agreements updated to remove WHOIS requirements
- Major tools (ICANN Lookup, registrar tools) remove WHOIS support
RDAP Evolution
Short-term Enhancements (1-2 years):
-
Search Functionality: Standardized domain search APIs
GET /domains?name=example* GET /domains?nsLdhName=ns1.example.com -
Enhanced Notifications: Server-side change alerts
{ "subscriptions": [ { "event": "domain changed", "callback": "https://monitor.example.com/webhook" } ] } -
Bulk Query APIs: Efficient multi-domain lookups
POST /domains/bulk ["domain1.com", "domain2.com", "domain3.com"]
Medium-term Development (3-5 years):
-
Historical Data Access: Query past registration states
GET /domain/example.com?date=2024-01-01 -
Advanced Filtering: Complex access control policies
-
Real-time Feeds: Streaming registration changes
-
Machine Learning Integration: Abuse pattern detection
Long-term Vision (5+ years):
- Fully automated privacy compliance
- Blockchain-based audit trails
- AI-powered threat detection
- Decentralized RDAP nodes
- Integration with DNS infrastructure
Industry Impact
Registries and Registrars:
- Must maintain RDAP infrastructure long-term
- Opportunity to differentiate with value-added RDAP features
- Compliance becomes easier with structured data
Security Companies:
- Better threat intelligence from structured data
- More reliable monitoring and alerting
- Improved abuse detection capabilities
Domain Investors:
- Better research tools and data access
- More reliable expiration monitoring
- Enhanced market intelligence
Legal and Compliance:
- Clearer data access procedures
- Better audit trails
- Improved GDPR compliance
Best Practices
For RDAP Implementers
1. Follow All Specifications:
// Implement complete RDAP conformance
{
"rdapConformance": [
"rdap_level_0",
"icann_rdap_response_profile_0",
"icann_rdap_technical_implementation_guide_0"
],
// ... response data ...
}
2. Implement Proper Security:
// Require TLS 1.2+
server.setSecureContext({
minVersion: 'TLSv1.2',
maxVersion: 'TLSv1.3'
});
// Set security headers
app.use(helmet({
hsts: {
maxAge: 31536000,
includeSubDomains: true,
preload: true
}
}));
3. Provide Clear Documentation:
{
"notices": [
{
"title": "RDAP Terms of Service",
"links": [
{
"href": "https://rdap.example.com/tos",
"type": "text/html"
}
]
},
{
"title": "Rate Limits",
"description": [
"Anonymous: 10 queries/minute",
"Authenticated: 100 queries/minute",
"Contact us for higher limits"
]
}
]
}
4. Handle Privacy Properly:
function applyPrivacyFilters(data, accessLevel) {
const filtered = { ...data };
switch (accessLevel) {
case 'public':
// Redact personal information
filtered.entities = redactPersonalData(data.entities);
addRedactionNotices(filtered);
break;
case 'authenticated':
// Provide organization but not personal
filtered.entities = redactIndividualData(data.entities);
break;
case 'authorized':
// Full data access
filtered.entities = data.entities;
addAccessNotices(filtered, 'Law enforcement access granted');
break;
}
return filtered;
}
For RDAP Clients
1. Implement Proper Error Handling:
async function robustRDAPQuery(domain) {
try {
const response = await fetch(
`https://rdap.org/domain/${domain}`,
{ timeout: 10000 }
);
switch (response.status) {
case 200:
return await response.json();
case 404:
return { available: true };
case 429:
const retryAfter = response.headers.get('Retry-After');
await sleep(retryAfter * 1000);
return robustRDAPQuery(domain); // Retry
case 503:
throw new Error('Service temporarily unavailable');
default:
const error = await response.json();
throw new Error(error.description?.[0] || `HTTP ${response.status}`);
}
} catch (error) {
console.error('RDAP query failed:', error);
throw error;
}
}
2. Respect Rate Limits:
class RDAPClient {
constructor(queriesPerMinute = 10) {
this.queue = [];
this.interval = (60 * 1000) / queriesPerMinute;
this.lastQuery = 0;
}
async query(domain) {
const now = Date.now();
const timeSinceLastQuery = now - this.lastQuery;
if (timeSinceLastQuery < this.interval) {
await sleep(this.interval - timeSinceLastQuery);
}
this.lastQuery = Date.now();
return await queryRDAP(domain);
}
}
3. Implement Caching:
class CachedRDAPClient {
constructor() {
this.cache = new Map();
}
async query(domain) {
// Check cache
const cached = this.cache.get(domain);
if (cached && cached.expires > Date.now()) {
return cached.data;
}
// Query RDAP
const response = await fetch(`https://rdap.org/domain/${domain}`);
const data = await response.json();
// Cache based on Cache-Control header
const cacheControl = response.headers.get('Cache-Control');
const maxAge = this.parseMaxAge(cacheControl) || 3600; // Default 1 hour
this.cache.set(domain, {
data,
expires: Date.now() + (maxAge * 1000)
});
return data;
}
parseMaxAge(cacheControl) {
const match = cacheControl?.match(/max-age=(\d+)/);
return match ? parseInt(match[1]) : null;
}
}
4. Handle Redirects and Bootstrap:
class SmartRDAPClient {
constructor() {
this.bootstrapCache = null;
}
async query(domain) {
const server = await this.findRDAPServer(domain);
return await this.queryServer(server, domain);
}
async findRDAPServer(domain) {
// Load bootstrap data
if (!this.bootstrapCache) {
const response = await fetch('https://data.iana.org/rdap/dns.json');
this.bootstrapCache = await response.json();
}
// Find appropriate server
const tld = domain.split('.').pop().toLowerCase();
for (const service of this.bootstrapCache.services) {
if (service[0].includes(tld)) {
return service[1][0];
}
}
throw new Error(`No RDAP server found for .${tld}`);
}
}
Frequently Asked Questions
Is WHOIS being shut down immediately?
No. As of January 28, 2025, RDAP became the official standard, but WHOIS servers continue operating for backward compatibility. There's no announced shutdown date yet. However, RDAP is now required for all gTLDs, and new features will only be added to RDAP. Expect WHOIS to gradually phase out over the next 3-5 years.
Do I need to update my WHOIS queries right now?
Yes, you should begin migrating to RDAP as soon as practical. While WHOIS still works, it's no longer the official standard and won't receive updates or improvements. RDAP provides better reliability, security, and features. Most major tools and services have already migrated or are in the process.
Can I use both WHOIS and RDAP simultaneously?
Yes, and this is recommended during the transition period. Implement RDAP as your primary method with WHOIS as a fallback for TLDs that haven't fully implemented RDAP or during temporary RDAP service disruptions. This hybrid approach ensures maximum reliability while you complete your migration.
Is RDAP slower than WHOIS because of JSON overhead?
No, RDAP is actually faster in most cases. While JSON responses are slightly larger than WHOIS text, RDAP benefits from HTTP/2 connection reuse, multiplexing, and proper caching mechanisms. In practice, RDAP queries are 3-5x faster than WHOIS, especially when making multiple queries.
Does RDAP cost more to implement than WHOIS?
Initial implementation costs are higher for RDAP (TLS infrastructure, authentication, structured data). However, long-term operational costs are lower due to better maintainability, automated compliance, clearer error handling, and reduced customer support needs. Most organizations see positive ROI within 1-3 years.
Will RDAP make more registration data public?
No, the opposite. RDAP was designed specifically to better handle privacy requirements like GDPR. RDAP enables differentiated access control—public users see limited data while law enforcement and authorized parties can access more information through proper channels. WHOIS had no mechanism for this nuanced approach.
Can I still use command-line tools for RDAP?
Yes. While there's no RDAP equivalent to the whois command built into most operating systems, you can query RDAP using curl and parse JSON with jq:
curl -s "https://rdap.verisign.com/com/v1/domain/example.com" | jq .
Several third-party RDAP command-line tools are also emerging.
How do I know which RDAP server to query?
Use the IANA RDAP Bootstrap Service at https://data.iana.org/rdap/dns.json which maps TLDs to their RDAP servers. Alternatively, use https://rdap.org which automatically routes queries to the correct server. Most RDAP client libraries handle this automatically.
Does RDAP work for IP addresses and ASNs?
Yes. RDAP supports:
- Domains:
/domain/{domain} - IP addresses:
/ip/{ip-address} - ASNs:
/autnum/{asn} - Nameservers:
/nameserver/{nameserver} - Entities:
/entity/{handle}
This makes RDAP a unified protocol for all registration data, not just domains.
What happens to privacy services with RDAP?
Privacy services (WHOIS protection) continue working with RDAP. In fact, RDAP better supports privacy services through standardized redaction mechanisms and clear notices about privacy protection. The main difference is that RDAP can provide more nuanced privacy (showing some data while protecting other fields) rather than WHOIS's all-or-nothing approach.
Key Takeaways
-
RDAP officially replaced WHOIS as of January 28, 2025, becoming the standard for gTLD registration data access
-
Technical superiority: RDAP uses modern RESTful HTTPS APIs with JSON responses, offering security, structure, and internationalization that WHOIS cannot provide
-
Better privacy compliance: RDAP enables differentiated access control, allowing compliance with GDPR and other regulations while still serving legitimate data access needs
-
Transition period continues: While RDAP is now required, WHOIS servers remain operational for backward compatibility with no announced shutdown date
-
Developers must migrate: Update your code to use RDAP as the primary method, maintaining WHOIS fallback only for ccTLDs or temporary issues
-
Improved performance: RDAP queries are typically 3-5x faster than WHOIS due to HTTP/2, connection reuse, and caching
-
Higher initial costs, lower long-term costs: RDAP implementation requires more upfront investment but reduces operational expenses over time
-
Standardized error handling: RDAP uses HTTP status codes and structured error responses, eliminating WHOIS's fragile text parsing
-
Future-proof: All new features and capabilities will be RDAP-only; WHOIS receives no further development
-
Ecosystem support: All major registries and registrars now support RDAP, with tools and libraries widely available
Next Steps
For Developers
- Audit your codebase: Identify all WHOIS usage in your applications
- Implement RDAP support: Use the code examples in this guide as starting points
- Test thoroughly: Validate RDAP implementation across multiple TLDs
- Deploy hybrid approach: RDAP primary with WHOIS fallback during transition
- Plan WHOIS removal: Set timeline for deprecating WHOIS code entirely
For Organizations
- Assess requirements: Determine if you need differentiated access or authentication
- Budget appropriately: Plan for initial implementation costs and long-term savings
- Train staff: Ensure your team understands RDAP capabilities and limitations
- Update documentation: Revise internal and customer-facing docs to reflect RDAP
- Monitor the transition: Track WHOIS sunset announcements and industry updates
For Registries and Registrars
- Complete RDAP implementation: Ensure full compliance with ICANN requirements
- Test access controls: Validate differentiated access and privacy redaction
- Document your API: Provide clear RDAP documentation and examples
- Plan WHOIS deprecation: Set internal timeline for WHOIS phase-out
- Communicate with customers: Announce RDAP availability and WHOIS timeline
Related Articles
- RDAP Explained: The Modern WHOIS Replacement
- How to Query RDAP Programmatically: Developer Guide
- WHOIS Privacy After GDPR: What Changed?
- Domain Privacy Protection: Complete Guide
Research Sources
This comprehensive comparison was researched using official specifications and authoritative sources:
- ICANN Announcement: Launching RDAP; Sunsetting WHOIS
- 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
- ICANN RDAP Profile
- ICANN gTLD RDAP Technical Implementation Guide
- IANA RDAP Bootstrap Service Registry
- RDAP.org - About RDAP