Rust: Domain Name Validation
Tags: rust, beginners, domain, validation
Published: 2021-05-18 07:55:35

Recently, as I work my way through learning bits of **rust**, I have been thinking that I should in corporate some form of **input validation** for **domains**.

Today I will look at two **crates**.

Initially I thought I would make validation part of the *decon-spf* crate. Though I think I would prefer to keep the crate simple and clean. To this end I have decided that validation is not the role of the crate itself. The reality is this crate is an experiment and is intended to *parse* and *deconstruct* existing **SPF** records.

## Crates

### publicsuffix

I am using version 1.5.4 which can be found on [crates.io](https://crates.io/crates/publicsuffix/1.5.4).

#### Example
```rust
use publicsuffix::List;

fn main() {
    let list = List::fetch().unwrap();
    let case1 = "_i-am-not-so-very-long.example.com";
    let items = case1.split(".");
    println!("Case1:");
    for i in items.into_iter() {
        println!("label Name: {}", i);
        println!("label Len : {}", i.len());
    }
    let domain = list.parse_dns_name(case1);
    match domain {
        Err(_) => println!("Invalid Domain"),
        Ok(result) => {
            println!("test: {}", result);
        }
    }
    let case2 = "_i-am-a-very-long-long-string-of-text-that-should-not-be-allowed.example.com";
    let items = case2.split(".");
    println!("Case2:");
    for i in items.into_iter() {
        println!("label Name: {}", i);
        println!("label Len : {}", i.len());
    }
    let domain = list.parse_dns_name(case2);
    match domain {
        Err(_) => println!("Invalid Domain"),
        Ok(result) => {
            println!("test: {}", result);
        }
    }
}
```
#### Output

```zsh
Case1:
label Name: _i-am-not-so-very-long
label Len : 22
label Name: example
label Len : 7
label Name: com
label Len : 3
test: _i-am-not-so-very-long.example.com
Case2:
label Name: _i-am-a-very-long-long-string-of-text-that-should-not-be-allowed
label Len : 64
label Name: example
label Len : 7
label Name: com
label Len : 3
Invalid Domain
```

### addr

I am using version 0.14.0 which can be found on [crates.io](https://crates.io/crates/addr).

Please also note that I am using `parse_dns_name` and **not** `parse_domain_name`. The difference being `parse_domain_name` does not allow for addictional characters per [RFC1034](https://datatracker.ietf.org/doc/html/rfc1034) which covers **host** and **domain** records. There is more flexibity allowed when specifying **resource** type records. See [StackOverFlow](https://stackoverflow.com/questions/2180465/can-domain-name-subdomains-have-an-underscore-in-it).

#### Example

```rust
use addr::parser::DnsName;
use addr::psl::List;

fn main() {
    let domain1 = List.parse_dns_name("_spf.example.com").unwrap();
    println!("Domain1 Valid: {}", domain1);
    let domain2 = "_i-am-a-very-long-long-string-of-text-that-should-not-be-allowed.example.com";
    let validity = List.parse_dns_name(domain2);
    match validity {
        Err(_) => {
            let mut c = 1;
            println!("Invalid Domain");
            let labels = domain2.split(".").into_iter();
            for label in labels {
                if label.len() > 63 {
                    println!("Label exceeds max length of 63!");
                }
                println!("label{}: len {} Str {}", c, label.len(), label);
                c += 1;
            }
        }
        Ok(domain) => println!("valid Domain: {}", domain),
    }
}
```

#### Output

```zsh
Domain1 Valid: _spf.example.com
Invalid Domain
Label exceeds max length of 63!
label1: len 64 Str _i-am-a-very-long-long-string-of-text-that-should-not-be-allowed
label2: len 7 Str example
label3: len 3 Str com
```

## Closing

I hope this information is useful. If anyone has some other suggestions or references. I would be interested to hear from you.
Thanks