included all requirements to be tested and associated existing tests with the...

included all requirements to be tested and associated existing tests with the corresponding requirements. added --nameserver and --proxy arguments
parent 63062bad
#!/usr/bin/perl
# Copyright 2018 CentralNic Ltd. This program is free software, you can
# use it and/or modify it under the same terms as Perl itself.
use Devel::StackTrace;
use File::Basename qw(basename);
use Getopt::Long;
use HTTP::Request::Common;
......@@ -21,35 +22,29 @@ GetOptions(
'handle=s',
'type=s',
'debug',
'nameserver=s',
'proxy=s',
);
$opt->{'type'} ||= 'domain';
$opt->{'handle'} ||= basename($ARGV[0]);
pod2usage() if ($opt->{'help'});
pod2usage({'-verbose' => 99, '-sections' => 'USAGE|OPTIONS'}) unless ($ARGV[0] || $opt->{'type'} =~ /^(domain|entity|nameserver|help)$/);
$ENV{'NET_RDAP_UA_DEBUG'} = $opt->{'debug'};
printf(STDERR "Testing %s, type '%s'...\n", $ARGV[0], $opt->{'type'});
my $url = URI->new($ARGV[0]);
fail("URL must use HTTPS") unless ('https' eq $url->scheme);
warning('TLS best practices validation is not currently available');
my $rdap = Net::RDAP->new;
$opt->{'handle'} ||= ($url->path_segments)[-1];
$opt->{'type'} ||= ('help' eq $opt->{'handle'} ? 'help' : ($url->path_segments)[-2]);
my $response = $rdap->ua->request(HEAD($url));
my $msg = sprintf('HEAD request to %s returned %03d', $url->as_string, $response->code);
if (200 == $response->code) {
pass($msg);
printf(STDERR "Testing %s, type '%s'...\n", $ARGV[0], $opt->{'type'});
} else {
fail($msg);
my $rdap = Net::RDAP->new;
$ENV{'NET_RDAP_UA_DEBUG'} = $opt->{'debug'};
$rdap->ua->proxy([qw(http https)], $opt->{'proxy'}) if ($opt->{'proxy'});
}
my $resolver = Net::DNS::Resolver->new;
$resolver->debug($opt->{'debug'});
$resolver->dnssec(1);
$resolver->adflag(1);
$resolver->nameservers($opt->{'nameserver'});
my $response = $rdap->fetch($url);
......@@ -59,7 +54,7 @@ if ($response->isa('Net::RDAP::Error')) {
fail($response);
} else {
check_rdap_conformance($response);
check_rfc_conformance($response);
check_gtld_conformance($response);
if ('domain' eq $opt->{'type'}) {
......@@ -84,11 +79,61 @@ if ($response->isa('Net::RDAP::Error')) {
exit($errors);
}
sub check_rdap_conformance {
sub check_rfc_conformance {
my $response = shift;
# to get this far, Net::RDAP has already validated a lot of stuff, e.g. the media type, JSON well-formedness, etc.
#
# to get this far, Net::RDAP has already validated a lot of stuff, e.g. the media type, JSON well-formedness, etc,
# but there may be other RFC-specific things we need to check as well, which we'll do here.
#
}
sub check_gtld_conformance {
my $response = shift;
# Implementation Guide - RDAP Protocol - 1.2: The RDAP service MUST be provided over HTTPS only.
fail("URL must use HTTPS") unless ('https' eq $url->scheme);
# Implementation Guide - RDAP Protocol - 1.3: An RDAP server MUST use the best practices for secure use of TLS as described in​ ​RFC7525​ or its successors.
# TODO - inspect headers added by LWP to check ciphers/algorithms/key sizes, etc
warning('TLS best practices validation is not currently available');
# Implementation Guide - RDAP Protocol - 1.4: An RDAP client SHOULD be able to successfully validate the TLS certificate used for the RDAP service with a ​TLSA​ record from the DNS (​RFC6698​ and RFC7671​) published by the RDAP service provider. The certificate(s) for the RDAP service associated by DNS-Based Authentication of Named Entities (DANE) SHOULD satisfy the requirements of section 1.5.
my $host = $url->host.'.';
my $answer = $resolver->query(sprintf('_443._tcp.%s.', $url->host), 'TLSA');
if (!$answer) {
fail(sprintf('No answer to TLSA query for %s', uc($url->host)));
} elsif ('NOERROR' ne $answer->header->rcode) {
fail(sprintf('%s received in answer to TLSA query for %s', $answer->header->rcode, uc($url->host)));
} else {
my @rrs = grep { 'TLSA' eq $_->type } $answer->answer;
if (scalar(@rrs) < 1) {
fail(sprintf('No records found in answer TLSA query for %s', uc($url->host)));
} else {
pass('%d TLSA record(s) found for %s', scalar(@rrs), uc($url->host));
warning('TLSA record validation is not currently available');
}
}
# Implementation Guide - RDAP Protocol - 1.5: The TLS certificate used for the RDAP service SHOULD be issued by a Certificate Authority (CA) trusted by the major browsers and mobile operating systems such as the ones listed in the Mozilla Included CA Certificate List (​https://wiki.mozilla.org/CA:IncludedCAs​). The TLS certificate used for the RDAP service SHOULD be issued by a CA that follows the latest CAB Forum Baseline Requirements (​https://cabforum.org/baseline-requirements-documents​).
# TODO - Net::RDAP uses Mozilla::CA which *should* mean that a request sent to an invalid cert will have resulted in an error before we get to this point.
# Implementation Guide - RDAP Protocol - 1.6: The RDAP server MUST support both​ ​RFC7480​ GET and HEAD types of HTTP methods.
my $head = $rdap->ua->request(HEAD($url));
my $msg = sprintf('HEAD request to %s returned %03d', $url->as_string, $head->code);
if (200 == $head->code) {
pass($msg);
} else {
fail($msg);
}
# Implementation Guide - RDAP Protocol - 1.7: An ​rdapConformance​ object [​RFC7483​] MUST be present in the topmost object of every response, and it MUST contain the conformance level of the RDAP protocol and of any extensions, as specified in​ ​RFC7483​.
my @conformance = $response->conformance;
if (scalar(@conformance) < 1) {
fail('rdapConformance is missing or empty', [ "The 'rdapConformance' property must be an array of one or more strings"]);
......@@ -117,51 +162,61 @@ sub check_rdap_conformance {
}
}
}
}
sub check_gtld_conformance {
my $response = shift;
# Implementation Guide - RDAP Protocol - 1.8: RDAP services MUST be available over both IPv4 and IPv6 transport.
my $v4answer = $resolver->query($host, 'A');
my $v6answer = $resolver->query($host, 'AAAA');
my $v4count = scalar(grep { 'A' eq $_->type } $v4answer->answer);
my $v6count = scalar(grep { 'AAAA' eq $_->type } $v6answer->answer);
if ($v4count > 0 && $v6count > 0) {
pass('RDAP service is available over both IPv4 and IPv6');
my $host = $url->host.'.';
} else {
fail('RDAP service is not available over both IPv4 and IPv6');
my $resolver = Net::DNS::Resolver->new('debug' => $opt->{'debug'});
my $answer = $resolver->query(sprintf('_443._tcp.%s.', $url->host), 'TLSA');
if (!$answer) {
fail(sprintf('No answer to TLSA query for %s', uc($url->host)));
}
} elsif ('NOERROR' ne $answer->header->rcode) {
fail(sprintf('%s received in answer to TLSA query for %s', $answer->header->rcode, uc($url->host)));
# Implementation Guide - RDAP Protocol - 1.9.1: The resource records for the RDAP service MUST be signed with DNSSEC, and the DNSSEC chain of trust from the root trust anchor to the name of the RDAP server MUST be valid.
} else {
my @rrs = grep { 'TLSA' eq $_->type } $answer->answer;
if (scalar(@rrs) < 1) {
fail(sprintf('No records found in answer TLSA query for %s', uc($url->host)));
my $rrsig_answer = $resolver->query($host, 'RRSIG');
my @sigs = scalar(grep { 'RRSIG' eq $_->type } $rrsig_answer->answer);
if (scalar(@sigs) > 0) {
pass(sprintf('%s appears to be signed using DNSSEC', uc($url->host)));
} else {
pass('%d TLSA record(s) found for %s', scalar(@rrs), uc($url->host));
} else {
fail(sprintf('%s does not appear to be signed using DNSSEC', uc($url->host)));
warning('TLSA record validation is not currently available');
}
}
my $v4count = scalar(grep { 'A' eq $_->type } $resolver->query($host, 'A')->answer);
my $v6count = scalar(grep { 'AAAA' eq $_->type } $resolver->query($host, 'AAAA')->answer);
my @answers = ($v4answer, $v6answer); # $rrsig_answer is not included as responses to queries for DNSSEC records never have the AD flag set
my $ad = 0;
foreach my $answer (@answers) {
if ($answer->header->ad) {
$ad++;
pass(sprintf('AD bit set on answer to query for %s/%s', ($answer->question)[0]->name, ($answer->question)[0]->type));
pass('RDAP service is available over IPv4') if ($v4count > 0);
pass('RDAP service is available over IPv6') if ($v6count > 0);
fail('RDAP service is not available over both IPv4 and IPv6') unless ($v4count > 0 && $v6count > 0);
my @sigs = scalar(grep { 'RRSIG' eq $_->type } $resolver->query($host, 'RRSIG')->answer);
if (scalar(@sigs) > 0) {
pass(sprintf('%s appears to be signed using DNSSEC', uc($url->host)));
} else {
fail(sprintf('AD bit NOT set on answer to query for %s/%s', ($answer->question)[0]->name, ($answer->question)[0]->type));
warning('DNSSEC validation is not currently available');
}
}
if ($ad == scalar(@answers)) {
pass(sprintf('AD bit set on all answers needed to resolve %s', $host));
} else {
fail(sprintf('%s does not appear to be signed using DNSSEC', uc($url->host)));
fail(sprintf('AD bit NOT set on all answers needed to resolve %s', $host));
}
warning('Full DNSSEC chain-of-trust validation is not currently available');
# TODO:
# Implementation Guide - RDAP Protocol - 1.10: RDAP servers MUST only use fully qualified domain names in RDAP responses.
# Implementation Guide - RDAP Protocol - 1.11.2: When the RDAP service base URL needs to be changed, the previous URL and the new one MUST remain in operation until: 1) the IANA's Bootstrap Service registry for Domain Name Space is updated, and 2) the date and time in the Expires HTTP header of a HTTP/GET request performed on the IANA's Bootstrap registry for Domain Name Space (after the new URL has been published) has elapsed.
# Implementation Guide - Responses to RDAP queries - 2.1: The RDAP server MUST support Internationalized Domain Name (IDN) RDAP lookup queries using A-label and MAY support U-label format [​RFC5890​] for domain names and name server objects.
# Implementation Guide - Responses to RDAP queries - 2.2: An RDAP server that receives a query string with a mixture of A-labels and U-labels SHOULD reject the query.
# Implementation Guide - Responses to RDAP queries - 2.3: An RDAP response to a domain query MUST contain a links object as defined in [​RFC7483​] section 4.2., in the topmost JSON object of the response. The links object MUST contain the elements ​rel:related​ and ​href​ pointing to the Registrar's RDAP URL of the queried domain name object.
my @links = $response->links;
if (scalar(@links) < 1) {
fail('response must contain at least one link');
......@@ -178,6 +233,8 @@ sub check_gtld_conformance {
}
}
# Implementation Guide - Responses to RDAP queries - 2.4.1: The terms of service of the RDAP service MUST be specified in the notices​ object in the initial JSON object of the response.
# Implementation Guide - Responses to RDAP queries - 2.4.2: The ​notices​ object MUST contain a l​inks​ object [​RFC7483​] containing an URL of the RDAP service provider.
my @notices = $response->notices;
if (scalar(@notices) < 1) {
fail('At least one notice must be present, containing the Terms of Service');
......@@ -193,6 +250,13 @@ sub check_gtld_conformance {
}
}
# TODO:
# Implementation Guide - Responses to RDAP queries - 2.4.3: The RDAP service provider MUST provide a web page with the terms of service of the RDAP service at the URL contained in the links object (2.4.2) which MAY be the same as the terms or service in the notices object (2.4.1) or MAY expand upon them.
# Implementation Guide - Responses to RDAP queries - 2.5: RDAP Help queries [​RFC7482​] MUST be answered and include a ​links​ member with a URL to a document that provides usage information, policy and other explanatory material.
# Implementation Guide - Responses to RDAP queries - 2.6: Truncated RDAP responses MUST contain a ​notices​ member describing the reason for the truncation. The ​notices​ object type MUST be of the form “Response truncated due to {authorization|load|unexplainable reason}”.
# Implementation Guide - Responses to RDAP queries - 2.7: Truncated RDAP objects MUST contain a ​remarks​ member describing the reason for the truncation. The ​remarks​ object type MUST be of the form “Result set truncated due to {authorization|load|unexplainable reason}”.
# Implementation Guide - Responses to RDAP queries - 2.8: In the case where the RDAP service provider is querying its database directly, and therefore, using real-time data, the ​eventAction​ type ​last update of RDAP database​ MUST show the timestamp of the response to the query.
}
sub check_domain_conformance {
......@@ -201,6 +265,9 @@ sub check_domain_conformance {
my @segments = $url->path_segments;
my $domain = Net::DNS::Domain->new(pop(@segments));
#
# not explicitly stated but we should check that a domain query returns a domain response
#
if ('domain' eq $response->class) {
pass('domain lookup returned a domain response');
......@@ -209,54 +276,114 @@ sub check_domain_conformance {
}
#
# not explicitly stated but we should check that the name matches the queried name
#
if (lc($domain->name) == lc($response->name->name)) {
pass('domain name in response matches name in lookup');
pass('domain name in response matches (case-insensitive) name in lookup');
} else {
fail(sprintf("domain name in response ('%s') does not match name in lookup ('%s')", lc($domain->name), lc($domain->name->name)));
fail(sprintf("domain name in response ('%s') does not match (case-insensitive) name in lookup ('%s')", lc($domain->name), lc($domain->name->name)));
}
my @labels = $domain->label;
my $tld = pop(@labels);
fail(sprintf('%s not found in RDAP IANA registry', uc($tld))) if (!Net::RDAP::Registry->get_url($domain));
# TODO: 1.11.3. An IANA's Bootstrap registry for Domain Name Space entry MUST be populated with an HTTPS URL only.
# TODO: 2.1. The RDAP server MUST support Internationalized Domain Name (IDN) RDAP lookup queries using A-label and MAY support U-label format [RFC5890] for domain names and name server objects.
# TODO: 2.2. An RDAP server that receives a query string with a mixture of A-labels and U-labels SHOULD reject the query.
# TODO:
# Response Profile - Domain Queries - 1.2.1: RDAP extensions, if used, MUST be registered in the IANA's RDAP Extensions registry (​https://www.iana.org/assignments/rdap-extensions/rdap-extensions.xhtml ), as defined in​ ​RFC7480​.
# Response Profile - Domain Queries - 1.2.2: RDAP extensions MUST NOT add browser executable code (e.g., Javascript) to the response.
# Response Profile - Domain Queries - 2.1: Domain Name - The top-level domain object [​RFC7483​] in the RDAP response MUST contain the A-label format of the domain in the ​ldhName​ member [​RFC7483​].
# Response Profile - Domain Queries - 2.2: Registry Domain ID - The ​domain​ object ​handle​ in the RDAP response MUST contain the Repository Object Identifier (ROID of the domain object, <domain:roid>​ as defined in​ ​RFC5731​) for the domain name object.
# Response Profile - Domain Queries - 2.3.1: The domain object in the RDAP response MUST contain the following events:
# Response Profile - Domain Queries - 2.3.1.1: Event of ​eventAction​ type ​registration
# Response Profile - Domain Queries - 2.3.1.2: Event of ​eventAction​ type ​expiration
# Response Profile - Domain Queries - 2.3.1.3: Event of ​eventAction​ type ​last update of RDAP database​ with a value equal to the timestamp when the RDAP database was last updated
my $actions = {};
foreach my $event ($response->events) {
$actions->{$event->action}++;
}
foreach my $action ('registration', 'expiration', 'last update of RDAP database') {
if (defined($actions->{$action})) {
pass(sprintf("'%s' event present in response", $action));
# TODO: 3.1. If the domain name is an IDN, the top-level domain object in the RDAP response MUST contain the U-label format of the domain in the unicodeName member [RFC7483],
} else {
fail(sprintf("'%s' event not present in response", $action));
# TODO: 3.2. The status member [RFC7483] MUST be a valid status type per the IANA's RDAP JSON Values registry (https://www.iana.org/assignments/rdap-json-values/rdap-json-values.xhtml) of status type.
}
}
# TODO: 3.3. The status member of a domain object in the RDAP response MUST match the EPP Status codes in the SRS as of the updated date of the RDAP response.
# TODO:
# Response Profile - Domain Queries - 2.4.1: Registrar - The ​domain​ object in the RDAP response MUST contain an entity​ with the ​registrar​ role (called registrar entity in this section) and a valid ​fn​ member MUST be present.
# Response Profile - Domain Queries - 2.4.2: Registrar IANA ID - The ​handle​ of the ​entity​ MUST be equal to the IANA Registrar ID.
# Response Profile - Domain Queries - 2.4.3: Registrar IANA ID - The ​entity​ with the ​registrar​ role in the RDAP response MUST contain a ​publicIDs​ member [​RFC7483​] to identify the IANA Registrar ID from the IANA’s Registrar ID registry (​https://www.iana.org/assignments/registrar-ids/registrar-ids.xhtml​). The type value of the ​publicID​ object MUST be equal to IANA Registrar ID.
# Response Profile - Domain Queries - 2.4.5: Abuse Contact (email, phone) - An RDAP server MUST include an ​entity with the ​abuse​ role within the registrar e​ ntity​ which MUST include ​tel​ and email​ members, and MAY include other members.
# Response Profile - Domain Queries - 2.6.1: The top-level domain object in the RDAP response MUST contain at least one ​status​ member [​RFC7483​].
# Response Profile - Domain Queries - 2.6.2: The ​status​ member value MUST conform to the ​Extensible Provisioning Protocol (EPP) and Registration Data Access Protocol (RDAP) Status Mapping​ [​RFC8056​].
# Response Profile - Domain Queries - 2.6.3: ​A domain name RDAP response MUST contain a ​notices​ member with a title​ “EPP Status Codes”, a ​description​ containing the string “For more information on domain status codes, please visit https://icann.org/epp” and a ​links​ member with the​ ​https://icann.org/epp​ URL.
# Response Profile - Domain Queries - 2.7.4: Registrant, Administrative, Technical, Other - The domain object in the RDAP response MUST contain entities with the registrant, administrative and technical roles and MAY contain other entities with corresponding roles (such as billing) with a handle (ROID of the contact object, <contact:roid>, as defined in ​RFC5733​) and valid members fn, adr, tel, email (as specified in ​RFC6350​, the vCard Format Specification and its corresponding JSON mapping ​RFC7095​).
# Response Profile - Domain Queries - 2.7.4.1: The following RDDS fields used to generate the adr member of the contact entities are REQUIRED to be included in the RDAP response: Street, City, Country.
# Response Profile - Domain Queries - 2.7.4.2: The following RDDS fields MUST be included in the adr member of the contact entities if the data exists: Organization, State/Province, Postal Code, Phone Ext, Fax, Fax Ext. If no data exists, the fields SHOULD NOT be included in the adr member.
# Response Profile - Domain Queries - 2.7.5.1: Registrant - Where processing is subject to the GDPR, the following MUST be omitted unless consent to publish has been provided and where processing is not subject to the GDPR MAY be omitted – the handle, fn and tel members of the (registrant) contact entity and the Street, City, Postal Code, Phone Ext, Fax and Fax Ext fields of the adr member in the RDAP response.
# Response Profile - Domain Queries - 2.7.5.2: Administrative, Technical, Other - Where processing is subject to the GDPR, the following MUST be omitted unless consent to publish has been provided and where processing is not subject to the GDPR MAY be omitted – the handle, fn and tel members of the (administrative, technical, other) contact entity and the Organization, Street, City, State/Province, Postal Code, Country, Phone Ext, Fax and Fax Ext fields of the adr member in the RDAP response.
# Response Profile - Domain Queries - 2.7.5.3: In an RDAP response where elements of the contact entity have been omitted, the contact entity MUST include a remarks element containing a title member with a value “REDACTED FOR PRIVACY” and a description member with a value “Some of the data in this object has been removed.”
# Response Profile - Domain Queries - 2.7.6.1: Email (Registrar Only) - the value of the email member in the RDAP response MUST be an email address or link to a web form to facilitate email communication with the Registrant but MUST NOT identify the contact email address or the contact itself.
# Response Profile - Domain Queries - 2.7.6.2: Email (Registry Only) - the value of the email member in the RDAP response MUST be substantially similar to the following “Please query the RDDS service of the Registrar of Record identified in this output for information on how to contact the Registrant of the queried domain name.”
# Response Profile - Domain Queries - 2.8: Name Server(s) - The ​domain​ object in the RDAP response MUST contain the name servers of the domain in the ​nameservers​ member.
# Response Profile - Domain Queries - 2.8.1: RDAP servers MUST support ​nameserver​ lookup queries based on the name server’s name as specified in 3.1.4 of​ ​RFC7482​.
# Response Profile - Domain Queries - 2.8.2: RDAP servers operated by Registries MUST support ​nameserver​ lookup queries based on IP address as defined in ​RFC7482​ section 3.2.2.
# Response Profile - Domain Queries - 2.8.3: Each ​nameserver​ object MUST contain the following member: ​ldhName​.
# Response Profile - Domain Queries - 2.8.4: The following members are Optional: ​ipAddresses​ [​RFC7483​], unicodeName,​ ​handle​ [​RFC7483​] (ROID of the host object, ​<host:roid>​ as defined in​ ​RFC5732​), and ​status​.
# Response Profile - Domain Queries - 2.8.5: In the case of a TLD in which name servers are specified as domain attributes, the ​nameserver​ object MUST NOT contain the following members: ​handle​ and s​tatus.​
# Response Profile - Domain Queries - 2.9: DNSSEC - The ​domain​ object in the RDAP response MUST contain a secureDNS​ member [R​FC7483​] including at least a ​delegationSigned​ element. Other elements (e.g. ​dsData​) of the ​secureDNS​ member MUST be included, if the domain name is signed and the elements are stored in the Registry or Registrar database, as the case may be.
# Response Profile - Domain Queries - 2.10: RDDS Inaccuracy - A domain name RDAP response MUST contain a ​notices member with a ​title​ “RDDS Inaccuracy Complaint Form”, a ​description​ containing the string “URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf” and a ​links​ member with the https://www.icann.org/wicf​ URL.
# Response Profile - Domain Queries - 2.11.1: A Registrar MUST return an HTTP 404 response when the Registrar is not the Sponsoring Registrar for the domain name.
# Response Profile - Domain Queries - 2.11.2: The ​domain​ object h andle​ in the RDAP response MUST contain the Repository Object Identifier (ROID of the domain object, ​<domain:roid>​ as defined in​ ​RFC5731​) for the Domain Name object. For example, a Registrar could obtain the ROID from the Registry via EPP and cache the information locally after creating or gaining a domain name via a transfer.
# Response Profile - Domain Queries - 2.11.3: The ​entity​ ​handle​ in the RDAP response MUST contain the Repository Object Identifier (ROID of the contact object, ​<contact:roid>​, as defined in RFC5733​) for the Contact object. For example, a Registrar could obtain the ROID from the Registry via EPP and cache the information locally. The RAA 2013 defines that this information MUST be shown if available from the Registry. If this information is not available from the Registry (e.g., a "thin" Registry), the ​handle​ MUST contain the unique identifier within the Registrar.
# Response Profile - Domain Queries - 2.11.4: The ​eventAction​ type ​last changed​ MUST reflect the date and time of the latest successful update known to the Registrar. Registrars are not required to constantly refresh this date from the Registry.
# Response Profile - Domain Queries - 2.11.5: The ​status​ element MUST reflect the latest known set of EPP statuses in the Registry. Registrars are not required to constantly refresh the EPP statuses from the Registry.
# Implementation Guide - RDAP Protocol - 1.11.1: The base URL of RDAP services MUST be registered in the IANA's Bootstrap Service registry for Domain Name Space (​https://www.iana.org/assignments/rdap-dns/rdap-dns.xhtml​), as described in​ ​RFC7484​, through the IANA Root Zone Management system. A separate entry is required for each TLD.
my @labels = $domain->label;
my $tld = pop(@labels);
fail(sprintf('%s not found in RDAP IANA registry', uc($tld))) if (!Net::RDAP::Registry->get_url($domain));
# TODO: 3.4. Entities MUST use jCard [RFC7095, 3.3.1.3] structured addresses
# TODO:
# Implementation Guide - Domain Queries - 3.1: If the domain name is an IDN, the top-level domain object in the RDAP response MUST contain the U-label format of the domain in the ​unicodeName​ member [​RFC7483​]. If the domain name is not an IDN, the ​unicodeName​ member is optional.
# Implementation Guide - Domain Queries - 3.2: The ​status​ member [​RFC7483​] MUST be a valid status type per the IANA’s RDAP JSON Values registry (​https://www.iana.org/assignments/rdap-json-values/rdap-json-values.xhtml​) of status type.
# Implementation Guide - Domain Queries - 3.3: The ​status​ member of a domain object in the RDAP response MUST match the EPP status per [​RFC8056​] as of the updated date of the RDAP response.
# Implementation Guide - Domain Queries - 3.4: Entities​ MUST use jCard [​RFC7095​, 3.3.1.3] structured addresses. If a street address has more than one line, it should be structured as an array of strings. ... But if it has a single line or street address, it should be structured not as an array, but as a simple string.
# Implementation Guide - Domain Queries - 3.5: If the server policy supports roles which are not listed below, the server MUST provide a clear mapping of additional roles.
}
sub check_entity_conformance {
my $response = shift;
# TODO:
# Response Profile - Registrar Queries - 3.1: Registrar object lookup using an entity query on the ​fn​ element MUST be supported
# Response Profile - Registrar Queries - 3.2: Registrar (name, address, phone number, email) - ​ ​In response to registrar queries, the returned RDAP response MUST be an ​entity​ with ​registrar​ role, with a ​handle​ and valid elements ​fn​, ​adr​, t​el,​ ​email.​
# Response Profile - Registrar Queries - 3.2.1: Registrar (Street, City, Country) - The ​adr​ member in the RDAP response for a Registrar query MUST at least contain the following RDDS fields: Street, City, Country.
# Response Profile - Registrar Queries - 3.2.2: Registrar (State/Province, Postal Code, Fax Number) - the following fields are optional in the ​adr​ member of the RDAP response: State/Province, Postal Code, Fax Number.
# Response Profile - Registrar Queries - 3.3: Contacts (Admin, Technical) - The RDAP response SHOULD contain at least two entities​, with the ​administrative​ and ​technical​ roles respectively within the ​entity with the ​registrar​ role. The ​entities​ with the ​administrative​ and ​technical​ roles MUST contain a ​handle​ and valid ​fn​, ​tel​, e​mail​ members, and MAY contain a valid ​adr​ element.
# Response Profile - Registrar Queries - 3.4: The RDAP response to a Registrar query MUST include an ​eventAction​ type ​last update of RDAP database​ with a value equal to the timestamp when the RDAP database was last updated.
# Implementation Guide - Registrar Queries - 5.1: RDAP servers MUST support lookup for ​entities​ with the ​registrar​ role within other objects using the ​handle​ (as described in 3.1.5 of​ ​RFC7482​). The ​handle​ of the ​entity​ with the ​registrar​ role MUST be equal to IANA Registrar ID. The ​entity with the ​registrar​ role in the RDAP response MUST contain a ​publicIDs​ member to identify the IANA Registrar ID from the IANA’s Registrar ID registry. The type value of the ​publicID​ object MUST be equal to IANA Registrar ID.
# Implementation Guide - Contact queries - 6.1: In contact ​entities​ [​RFC7483​], phone numbers MUST be inserted as ​tel properties with a ​voice​ type parameter, as specified in​ ​RFC6350​, the vCard Format Specification and its corresponding JSON mapping​ ​RFC7095​.
# Implementation Guide - Contact queries - 6.2: In contact ​entities​, fax numbers if used, MUST be inserted as ​tel​ properties with a fax​ type parameter, as specified in​ ​RFC6350​, the vCard Format Specification and its corresponding JSON mapping​ ​RFC7095​.
warning('Entity (registrar) record validation is not currently available');
}
sub check_nameserver_conformance {
my $response = shift;
warning('Nameserver record validation is not currently available');
# TODO: 4.1. The draft-lozano-rdap-nameservers-sharing-name Internet Draft MAY be used to support multiple host objects for the same name server name.
# TODO: 4.2. RDAP servers MUST support nameserver lookup queries based on the name server's name as specified in 3.1.4 of RFC7482.
# TODO:
# Response Profile - Nameserver Queries - 4.1: Name Server (Name) - In response to Nameserver queries the returned RDAP response MUST include a ​nameserver​ object and contain a ​ldhName​ member.
# Response Profile - Nameserver Queries - 4.2: IP Address(es) - If the name server record includes IP addresses then the nameserver​ object MUST contain a ipAddresses member listing all IPv4 and IPv6 glue records for the Nameserver.
# Response Profile - Nameserver Queries - 4.3: Registrar (Name, IANA ID) - The Registrar RDDS field is Optional; if present in the response, it MUST be represented as an entity with the registrar role. The handle of the entity with the registrar role MUST be equal to the IANA Registrar ID. If the Registrar does not have an IANA ID then the handle of the entity with the registrar role MUST equal "not applicable". If the Registrar has an IANA ID, then the entity with the registrar role in the RDAP response MUST contain a publicIDs member with a type value equal to the IANA Registrar ID. If the Registrar does not have an IANA ID then the RDAP response MUST NOT contain a publicIDs member.
# Response Profile - Nameserver Queries - 4.4: The RDAP response to a Name Server query MUST include an ​eventAction​ type last update of RDAP database​ with a value equal to the timestamp when the RDAP database was last updated.
# Implementation Guide - Nameserver Queries - 4.1: The name server's name MUST be specified in the ​ldhName​ in A-label format.
# Implementation Guide - Nameserver Queries - 4.2: The ​unicodeName​ member MAY be present in the response to a ​nameserver lookup.
# Implementation Guide - Nameserver Queries - 4.3: ​In the case of a Registry in which name servers are specified as domain attributes, the existence of a name server used as an attribute for an allocated domain name MUST be treated as equivalent to the existence of a host object.
# TODO: 4.3. The name server's name MUST be specified in the ldhName in A-label format.
# TODO: 4.4. The unicodeName member MAY be present in the response to a nameserver lookup, if the name server has an IDN label.
# TODO: 4.5. In the case of a Registry in which name servers are specified as domain attributes, the existence of a name server used as an attribute for an allocated domain name MUST be treated as equivalent to the existence of a host object.
warning('Nameserver record validation is not currently available');
}
sub check_help_conformance {
......@@ -267,17 +394,17 @@ sub check_help_conformance {
sub pass {
my $fmt = shift;
printf(STDERR "%s (%04d): %s\n", colored('PASS', 'bold green'), (caller)[2], sprintf($fmt, @_));
printf(STDERR "%s (#%04d): %s\n", colored('PASS', 'bold green'), (caller)[2], sprintf($fmt, @_));
}
sub warning {
my $fmt = shift;
printf(STDERR "%s (%04d): %s\n", colored('WARN', 'bold yellow'), (caller)[2], sprintf($fmt, @_));
printf(STDERR "%s (#%04d): %s\n", colored('WARN', 'bold yellow'), (caller)[2], sprintf($fmt, @_));
}
sub fail {
my $error = shift;
$error = mkerror($error, @_) if (!$error->isa('Net::RDAP::Error'));
$error = mkerror((caller)[2], $error, @_) if (!$error->isa('Net::RDAP::Error'));
printf(STDERR "%s (#%04d): %s\n", colored('FAIL', 'bold red'), $error->errorCode, $error->title);
my @description = $error->description;
if (scalar(@description) > 0) {
......@@ -285,12 +412,14 @@ sub fail {
fill(" ", " ", join("\n", @description)).
"\n\n";
}
$errors++;
}
sub mkerror {
my ($title, $description) = @_;
my ($code, $title, $description) = @_;
return Net::RDAP::Error->new({
'errorCode' => 600 + (caller)[2],
'errorCode' => $code,
'title' => $title,
'description' => $description,
});
......@@ -319,14 +448,22 @@ an RDAP server against the requirements published by ICANN.
=over
=item * C<--handle=HANDLE> - explicitly specify handle. If not provided, this is
derived from the path segment of the URL.
derived from the last path segment of the URL.
=item * C<--type=TYPE> - specify response type, must be one of C<domain>,
C<entity>, C<nameserver>, or C<help>. If not provided, this is
derived from the last-but-one path segment of the URL.
=item * C<--nameserver=SERVE> - specify a nameserver to use. In order to perform
DNSSEC-related tests, the server SHOULD be a validating resolver.
=item * C<--type=TYPE> - specify response type, must be one of C<domain> (the default),
C<entity>, C<nameserver>, or C<help>.
=item * C<--proxy=URL> - specify proxy to be used. If L<LWP::Protocol::socks> is
installed you can use a SOCKS proxy by givin the URL the C<socks://> scheme.
=item * C<--debug> - enable debug mode (i.e. print the HTTP request and response)
=item * C<--debug> - enable debug mode (i.e. print HTTP and DNS requests and
responsees).
=item * C<--help> - show this help
=item * C<--help> - show this help.
=back
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment