Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ https://www.openrdap.org - homepage
https://www.openrdap.org/demo - live demo

## Features

* Command line RDAP client
* Output formats: text, JSON, WHOIS style
* Query types supported:
Expand All @@ -27,7 +28,7 @@ https://www.openrdap.org/demo - live demo
* entity-search-by-handle
* Automatic server detection for ip/domain/autnum/entities
* Object tags support
* Bootstrap cache (optional, uses ~/.openrdap by default)
* Bootstrap cache (optional, uses $XDG_CACHE_HOME/openrdap by default, falling back to ~/.cache/openrdap)
* X.509 client authentication

## Installation
Expand All @@ -44,17 +45,18 @@ This will install the "rdap" binary in your $GOPATH/go/bin directory. Try runnin

## Usage

| Query type | Usage |
| ------------------------- | ------------------------------------------------------------------------ |
| Domain (.com) | rdap -v example.com |
| IPv4 Address | rdap -v 192.0.2.0 |
| IPv6 Address | rdap -v 2001:db8:: |
| Autonomous System (ASN) | rdap -v AS15169 |
| Entity (with object tag) | rdap -v OPS4-RIPE |
| Query type | Usage |
|--------------------------|---------------------|
| Domain (.com) | rdap -v example.com |
| IPv4 Address | rdap -v 192.0.2.0 |
| IPv6 Address | rdap -v 2001:db8:: |
| Autonomous System (ASN) | rdap -v AS15169 |
| Entity (with object tag) | rdap -v OPS4-RIPE |

## Advanced usage (server must be specified using -s; not all servers support all query types)

| Query type | Usage |
| ------------------------- | ------------------------------------------------------------------------ |
|---------------------------|--------------------------------------------------------------------------|
| Nameserver | rdap -v -t nameserver -s https://rdap.verisign.com/com/v1 ns1.google.com |
| Help | rdap -v -t help -s https://rdap.verisign.com/com/v1 |
| Domain Search | rdap -v -t domain-search -s $SERVER_URL example*.gtld |
Expand Down Expand Up @@ -724,12 +726,15 @@ Click the examples to see the output:
</details>

## Go docs

[![godoc](https://godoc.org/github.com/openrdap/rdap?status.png)](https://godoc.org/github.com/openrdap/rdap)

## Uses

Go 1.20+

## Links

- Wikipedia - [Registration Data Access Protocol](https://en.wikipedia.org/wiki/Registration_Data_Access_Protocol)
- ICANN - [RDAP](https://www.icann.org/rdap)

Expand Down
60 changes: 32 additions & 28 deletions bootstrap/cache/disk_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@ import (
"path/filepath"
"time"

homedir "github.com/mitchellh/go-homedir"
"github.com/mitchellh/go-homedir"
)

const (
defaultCacheDirName = ".openrdap"
defaultCacheDirName = "openrdap"
)

// A DiskCache caches Service Registry files on disk.
//
// By default they're saved as $HOME/.openrdap/{asn,dns,ipv4,ipv6}.json. File
// mtimes are used to calculate cache expiry.
// By default they're saved as $XDG_CACHE_HOME/openrdap/{asn,dns,ipv4,ipv6}.json.
// File mtimes are used to calculate cache expiry.
//
// The cache directory is created automatically as needed.
type DiskCache struct {
Expand All @@ -32,7 +32,8 @@ type DiskCache struct {

// Directory to store cached files in.
//
// The default is $HOME/.openrdap.
// The default is $XDG_CACHE_HOME/openrdap (falling back to
// $HOME/.cache/openrdap).
Dir string

lastLoadedModTime map[string]time.Time
Expand All @@ -41,17 +42,23 @@ type DiskCache struct {
// NewDiskCache creates a new DiskCache.
func NewDiskCache() *DiskCache {
d := &DiskCache{
lastLoadedModTime: make(map[string]time.Time),
Timeout: time.Hour * 24,
lastLoadedModTime: make(map[string]time.Time),
}

dir, err := homedir.Dir()
// Honor $XDG_CACHE_HOME, falling back to $HOME/.cache. Relative values are
// ignored, per the XDG Base Directory spec.
cacheDir := os.Getenv("XDG_CACHE_HOME")
if !filepath.IsAbs(cacheDir) {
home, err := homedir.Dir()
if err != nil {
panic("Cannot determine home directory: HOME environment variable not set or inaccessible")
}

if err != nil {
panic("Can't determine your home directory")
cacheDir = filepath.Join(home, ".cache")
}

d.Dir = filepath.Join(dir, defaultCacheDirName)
d.Dir = filepath.Join(cacheDir, defaultCacheDirName)

return d
}
Expand All @@ -65,21 +72,20 @@ func (d *DiskCache) InitDir() (bool, error) {
if err == nil {
if fileInfo.IsDir() {
return false, nil
} else {
return false, errors.New("Cache dir is not a dir")
}

return false, errors.New("Cache dir is not a dir")
}

if os.IsNotExist(err) {
err := os.Mkdir(d.Dir, 0775)
if err == nil {
return true, nil
} else {
if err = os.MkdirAll(d.Dir, 0775); err != nil {
return false, err
}
} else {
return false, err

return true, nil
}

return false, err
}

// SetTimeout sets the duration each Service Registry file can be stored before
Expand All @@ -92,23 +98,21 @@ func (d *DiskCache) SetTimeout(timeout time.Duration) {
//
// The cache directory is created if necessary.
func (d *DiskCache) Save(filename string, data []byte) error {
_, err := d.InitDir()
if err != nil {
if _, err := d.InitDir(); err != nil {
return err
}

err = os.WriteFile(d.cacheDirPath(filename), data, 0664)
if err != nil {
if err := os.WriteFile(d.cacheDirPath(filename), data, 0664); err != nil {
return err
}

fileModTime, err := d.modTime(filename)
if err == nil {
d.lastLoadedModTime[filename] = fileModTime
} else {
if err != nil {
return fmt.Errorf("File %s failed to save correctly: %s", filename, err)
}

d.lastLoadedModTime[filename] = fileModTime

return nil
}

Expand All @@ -125,8 +129,8 @@ func (d *DiskCache) Load(filename string) ([]byte, error) {
}

var bytes []byte
bytes, err = os.ReadFile(d.cacheDirPath(filename))

bytes, err = os.ReadFile(d.cacheDirPath(filename))
if err != nil {
return nil, err
}
Expand All @@ -140,8 +144,8 @@ func (d *DiskCache) Load(filename string) ([]byte, error) {
//
// The returned state is one of: Absent, Good, ShouldReload, Expired.
func (d *DiskCache) State(filename string) FileState {
var expiry time.Time = time.Now().Add(-d.Timeout)
var state FileState = Absent
var expiry = time.Now().Add(-d.Timeout)
var state = Absent

fileModTime, err := d.modTime(filename)
if err == nil {
Expand Down
34 changes: 34 additions & 0 deletions bootstrap/cache/disk_cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,42 @@ import (
"path/filepath"
"testing"
"time"

"github.com/mitchellh/go-homedir"
)

func TestNewDiskCacheDir(t *testing.T) {
homedir.DisableCache = true
defer func() { homedir.DisableCache = false }()

home, err := os.MkdirTemp("", "home")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(home)

t.Setenv("HOME", home)

// XDG_CACHE_HOME set (absolute).
xdg := filepath.Join(home, "custom-cache")
t.Setenv("XDG_CACHE_HOME", xdg)
if got, want := NewDiskCache().Dir, filepath.Join(xdg, "openrdap"); got != want {
t.Errorf("with XDG_CACHE_HOME set: got %q, want %q", got, want)
}

// XDG_CACHE_HOME unset -> $HOME/.cache/openrdap.
t.Setenv("XDG_CACHE_HOME", "")
if got, want := NewDiskCache().Dir, filepath.Join(home, ".cache", "openrdap"); got != want {
t.Errorf("with XDG_CACHE_HOME unset: got %q, want %q", got, want)
}

// Relative XDG_CACHE_HOME is ignored per the XDG spec.
t.Setenv("XDG_CACHE_HOME", "relative/path")
if got, want := NewDiskCache().Dir, filepath.Join(home, ".cache", "openrdap"); got != want {
t.Errorf("with relative XDG_CACHE_HOME: got %q, want %q", got, want)
}
}

func TestDiskCache(t *testing.T) {
dir, err := os.MkdirTemp("", "test")
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion bootstrap/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
// By default, Service Registry files are cached in memory. bootstrap.Client
// also supports caching the Service Registry files on disk. The default cache
// location is
// $HOME/.openrdap/.
// $XDG_CACHE_HOME/openrdap/ (falling back to $HOME/.cache/openrdap/).
//
// Disk cache usage:
//
Expand Down
4 changes: 3 additions & 1 deletion cli.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,9 @@ Advanced options (query):
Advanced options (bootstrapping):
--cache-dir=DIR Bootstrap cache directory to use. Specify empty string
to disable bootstrap caching. The directory is created
automatically as needed. (default: $HOME/.openrdap).
automatically as needed.
(default: $XDG_CACHE_HOME/openrdap, falling back to
$HOME/.cache/openrdap).
--bs-url=URL Bootstrap service URL (default: https://data.iana.org/rdap)
--bs-ttl=SECS Bootstrap cache time in seconds (default: 3600)

Expand Down
2 changes: 1 addition & 1 deletion rdap.1
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Specify RDAP query type (e.g., domain, ip, autnum, nameserver, etc.).
.SH BOOTSTRAPPING OPTIONS
.TP
\fB--cache-dir\fR=\fIDIR\fR
Specify bootstrap cache directory (default: $HOME/.openrdap).
Specify bootstrap cache directory (default: $XDG_CACHE_HOME/openrdap, falling back to $HOME/.cache/openrdap).
.TP
\fB--bs-url\fR=\fIURL\fR
Set bootstrap service URL (default: https://data.iana.org/rdap).
Expand Down
Loading