whois-that: A Better whois client for rust
Whois that is a whois client that I created in rust because the current options are either hard to use or don’t have useful features for getting lots of whois data (internationalization and async)
The Start
I decided to start by doing a whois client that is based off of a whois client builder. The main reason that I wanted to do this is so that it would be easier to configure, and I could make the setup process have a lot of different options. One thing I noticed from my previous whois library whois-rust
was that it didn’t provide a default server list, and instead told users to download a custom one. I wanted to provide a default functionality while still allowing users to use a custom list in case my current one isn’t updated yet. This functionality is especially critical now with RDAP since certain domain providers (google) don’t provide whois servers anymore.
Whois servers
I chose three different ways to pass in whois server data depending on the use case: Path(PathBuf)
, Data(String)
, and Parsed(DashMap<String, Option<Arc<str>>>)
. The first two require the serde
feature which is enabled by default, but the last one allows users that don’t want to use serde a way to use this library. It also removes the ability to do a default list (since its defined as a file), but I think for environments that don’t want serde you probably don’t want the default list also. For the path enum variant, I decided that blocking io is fine since the file won’t be huge and ideally, you should only ever create one client at the start of your program. I used Arc<str>
instead of String
since they never change for the runtime of the Whois
client. It required a little overhead when parsing the dashmap, since you have to parse it as a String
then convert it, but other than that it was fine.
Issues with whois-rust
There were a couple of issues that I wanted to explicitly address when I created my whois client implementation
Lookup server before search
This is especially important so that I can fall back to RDAP if a whois call fails for a certain domain. In the whois-rust
library there is a lookup functionality, however, it is private. I made two different methods to get if a whois server exists. The first one uses a suffix which is the fastest option, and the second one takes in the whole domain, splitting it by each .
starting with the entire domain and removing one chunk every time until a match is found. This one has the added benefit of not having to load the kv pair if it can’t find a match for a suffix.
Parsing
I originally wanted to add parsing, but working with the random registrar data (as opposed to RDAP which is completely structured) simply isn’t worth the time because RDAP is so much better for that purpose.
Whois Encoding
From the whois RFC it says:
The WHOIS protocol has not been internationalised. The WHOIS protocol has no mechanism for indicating the character set in use. Originally, the predominant text encoding in use was US-ASCII. In practice, some WHOIS servers, particularly those outside the USA, might be using some other character set either for requests, replies, or both. This inability to predict or express text encoding has adversely impacted the interoperability (and, therefore, usefulness) of the WHOIS protocol.
So, using whois in an international context is sometimes pretty complicated. I decided to at least attempt to tackle this issue. Whereas whois-rust
will error when non-utf8 data is found, the client will either parse it lossy if the decode-global
feature is disabled or attempt WINDOWS_1252
encoding and return an error with the raw data if it has any issues. I think this strikes a good balance between supporting random encodings and literally making it impossible to use your client with non-utf8 data.
The Whois Standard
A big problem that I ran into is for certain whois providers cough cough verisign they make you enter in extra data to query whois on their server, in verisign’s case DOMAIN ${DOMAIN}\r\n
instead of ${DOMAIN}\r\n
. So, I had to modify my structure for the whois server map to support a detailed domain entry that includes extra data like the query and whether or not to convert the domains to punycode. I had to change the schema, but I was still able to put everything in Arc<str>
, so it should still have the same properties as before (at least after the list is parsed).
Result
Publishing was pretty simple, I just had to check and make sure everything worked then run
cargo publish
It is avaliable to download on crates.io