Skip to content

Commit

Permalink
basic search functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
gbxyz committed Oct 14, 2024
1 parent afab739 commit 6b01202
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 26 deletions.
75 changes: 50 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# NAME

App::rdapper - a simple console-based RDAP client.
App::rdapper - a simple console-based [RDAP](https://about.rdap.org) client.

# INSTALLATION

Expand All @@ -21,19 +21,28 @@ Alternatively, you can pull the [image from Docker Hub](https://hub.docker.com/r

# SYNOPSIS

General form:

rdapper [OPTIONS] OBJECT

# DESCRIPTION
Examples:

rdapper example.com

rdapper --type=tld foo

`rdapper` is a simple RDAP client. It uses [Net::RDAP](https://metacpan.org/pod/Net%3A%3ARDAP) to retrieve
data about internet resources (domain names, IP addresses, and
autonymous systems) and outputs the information in a human-readable
format. If you want to consume this data in your own program you
should use [Net::RDAP](https://metacpan.org/pod/Net%3A%3ARDAP) directly.
rdapper 192.168.0.1

`rdapper` was originally conceived as a full RDAP client (back
when the RDAP specification was still in draft form) but is now
just a very thin front-end to [Net::RDAP](https://metacpan.org/pod/Net%3A%3ARDAP).
rdapper https://rdap.org/domain/example.com

rdapper --search "exampl*.com"

# DESCRIPTION

`rdapper` is a simple RDAP client. It uses [Net::RDAP](https://metacpan.org/pod/Net%3A%3ARDAP) to retrieve data about
internet resources (domain names, IP addresses, and autonymous systems) and
outputs the information in a human-readable format. If you want to consume this
data in your own program you should use [Net::RDAP](https://metacpan.org/pod/Net%3A%3ARDAP) directly.

# OPTIONS

Expand All @@ -42,21 +51,20 @@ You can pass any internet resource as an argument; this may be:
- a "forward" domain name such as `example.com`;
- a top-level domain such as `com`;
- a "reverse" domain name such as `168.192.in-addr.arpa`;
- a IPv4 or IPv6 address or CIDR prefix, such as `192.168.0.1`
or `2001:DB8::/32`;
- a IPv4 or IPv6 address or CIDR prefix, such as `192.168.0.1` or
`2001:DB8::/32`;
- an Autonymous System Number such as `AS65536`.
- the URL of an RDAP resource such as
`https://example.com/rdap/domain/example.com`.
- the "tagged" handle of an entity, such as an LIR, registrar,
or domain admin/tech contact. Because these handles are difficult
to distinguish from domain names, you must use the `--type` argument
to explicitly tell `rdapper` that you want to perform an entity query,
.e.g `rdapper --type=entity ABC123-EXAMPLE`.
- the "tagged" handle of an entity, such as an LIR, registrar, or domain
admin/tech contact. Because these handles are difficult to distinguish from
domain names, you must use the `--type` argument to explicitly tell `rdapper`
that you want to perform an entity query, .e.g `rdapper --type=entity
ABC123-EXAMPLE`.

`rdapper` also implements limited support for in-bailiwick nameservers,
but you must use the `--type=nameserver` argument to disambiguate
from domain names. The RDAP server of the parent domain's registry will
be queried.
`rdapper` also implements limited support for in-bailiwick nameservers, but you
must use the `--type=nameserver` argument to disambiguate from domain names. The
RDAP server of the parent domain's registry will be queried.

- `--registrar` - follow referral to the registrar's RDAP record (if any)
which will be displayed instead of the registry record.
Expand All @@ -81,11 +89,28 @@ explicitly setting the `--type` argument to one of : `ip`, `autnum`,
- `--raw` - print the raw JSON rather than parsing it.
- `--short` - omit remarks, notices, links and redactions.
- `--bypass-cache` - disable local cache of RDAP objects.
- `--auth=USER:PASS` - HTTP Basic Authentication credentials
to be used when accessing the specified resource. This option
**SHOULD NOT** be used unless you explicitly specify a URL, otherwise
your credentials may be sent to servers you aren't expecting them to.
- `--auth=USER:PASS` - HTTP Basic Authentication credentials to be used
when accessing the specified resource. This option **SHOULD NOT** be used unless
you explicitly specify a URL, otherwise your credentials may be sent to servers
you aren't expecting them to.
- `--nocolor` - disable ANSI colors in the formatted output.
- `--search` - perform a search.

# RDAP Search

Some RDAP servers support the ability to perform simple substring searches.
You can use the `--search` option to enable this functionality.

When the `--search` option is used, `OBJECT` will be used as a search term. If
it contains no dots (e.g. `exampl*`), then `rdapper` will send a search query
for `exampl*` to _all_ known RDAP servers. If it contains one or more dots
(e.g. `exampl*.com`), it will send the search query to the RDAP server for the
specified TLD (if any).

Any errors observed will be printed to `STDERR`; any search results will be
printed to `STDOUT`.

As of writing, search is only available for domain names.

# COPYRIGHT & LICENSE

Expand Down
92 changes: 91 additions & 1 deletion lib/App/rdapper.pm
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ $VERSION = '1.04';
# global arg variables (note: nopager is now ignored)
#
my ($type, $object, $help, $short, $bypass, $auth, $nopager, $raw, $both,
$registrar, $nocolor, $reverse, $version);
$registrar, $nocolor, $reverse, $version, $search);

#
# options spec for Getopt::Long
Expand All @@ -51,6 +51,7 @@ my %opts = (
'nocolor' => \$nocolor,
'reverse' => \$reverse,
'version' => \$version,
'search' => \$search,
);

my %funcs = (
Expand Down Expand Up @@ -152,6 +153,11 @@ sub main {
my %args;
($args{'user'}, $args{'pass'}) = split(/:/, $auth, 2) if ($auth);

if ($search) {
$package->search($rdap, $object, $type, %args);
return;
}

my $response;
if ('ip' eq $type) {
my $ip = Net::IP->new($object);
Expand Down Expand Up @@ -223,6 +229,58 @@ sub show_version {
exit;
}

sub search {
my ($package, $rdap, $object, $type, %args) = @_;

if ('domain' eq $type) {
$package->domain_search($rdap, $object, %args);

} else {
$package->error('Current unable to do searches for %s objects.', $type);
}
}

sub domain_search {
my ($package, $rdap, $query, %args) = @_;

my @labels = grep { length > 0 } split(/\./, lc($query), 2);

my $prefix = shift(@labels);
my $suffix = shift(@labels) || '*';

my $servers = {};
my $zones = {};

foreach my $service (Net::RDAP::Registry->load_registry(Net::RDAP::Registry::DNS_URL)->services) {
foreach my $zone ($service->registries) {
my $url = Net::RDAP::Registry->get_best_url($service->urls);

if (!exists($servers->{$url->as_string})) {
$servers->{$url->as_string} = Net::RDAP::Service->new($url);
}

$zones->{lc($zone)} = $url->as_string;
}
}

my @zones = sort(keys(%{$zones}));
@zones = grep { lc($suffix) eq $_ || $suffix =~ /\.$_/i } @zones if ($suffix ne '*');

foreach my $zone (@zones) {
my $server = $servers->{$zones->{$zone}};
my $result = $server->domains(name => $prefix);

if ($result->isa('Net::RDAP::Error')) {
$err->print(sprintf("%s.%s: %s %s\n", $prefix, $zone, $result->errorCode, $result->title));

} elsif ($result->isa('Net::RDAP::SearchResult')) {
foreach my $domain ($result->domains) {
$out->print(sprintf("%s\n", $domain->name->name));
}
}
}
}

sub display {
my ($package, $object, $indent, $nofatal) = @_;

Expand Down Expand Up @@ -669,8 +727,22 @@ Alternatively, you can pull the L<image from Docker Hub|https://hub.docker.com/r
=head1 SYNOPSIS
General form:
rdapper [OPTIONS] OBJECT
Examples:
rdapper example.com
rdapper --type=tld foo
rdapper 192.168.0.1
rdapper https://rdap.org/domain/example.com
rdapper --search "exampl*.com"
=head1 DESCRIPTION
C<rdapper> is a simple RDAP client. It uses L<Net::RDAP> to retrieve data about
Expand Down Expand Up @@ -757,8 +829,26 @@ you aren't expecting them to.
=item * C<--nocolor> - disable ANSI colors in the formatted output.
=item * C<--search> - perform a search.
=back
=head1 RDAP Search
Some RDAP servers support the ability to perform simple substring searches.
You can use the C<--search> option to enable this functionality.
When the C<--search> option is used, C<OBJECT> will be used as a search term. If
it contains no dots (e.g. C<exampl*>), then C<rdapper> will send a search query
for C<exampl*> to I<all> known RDAP servers. If it contains one or more dots
(e.g. C<exampl*.com>), it will send the search query to the RDAP server for the
specified TLD (if any).
Any errors observed will be printed to C<STDERR>; any search results will be
printed to C<STDOUT>.
As of writing, search is only available for domain names.
=head1 COPYRIGHT & LICENSE
Copyright (c) 2012-2023 CentralNic Ltd.
Expand Down

0 comments on commit 6b01202

Please sign in to comment.