Skip to content

Commit 773c57f

Browse files
authored
Merge pull request #20 from Ziqi-Yang/stable-rust
refactor: use stable rust compiler
2 parents 6e2cca8 + 6b93b49 commit 773c57f

File tree

6 files changed

+82
-7
lines changed

6 files changed

+82
-7
lines changed

rust-toolchain.toml

Lines changed: 0 additions & 2 deletions
This file was deleted.

src/consts.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::usize;
2+
use lazy_static::lazy_static;
23

34
use regex::bytes::Regex;
45

src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,11 @@
153153
//!
154154
//! emval is licensed under the [MIT License](https://opensource.org/licenses/MIT). See the [LICENSE](https://github.com/bnkc/emval/blob/main/LICENSE) file for more details.
155155
156-
#![feature(ip)]
157-
#[macro_use]
158-
extern crate lazy_static;
159156
mod consts;
160157
pub mod errors;
161158
mod models;
162159
mod validators;
160+
pub(crate) mod util;
163161

164162
pub use crate::errors::ValidationError;
165163
pub use crate::models::{EmailValidator, ValidatedEmail};

src/util/ip_addr_ext.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/// IpAddr `is_global` implementation (for use with stable rust compiler)
2+
/// The code is copied from STD
3+
4+
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
5+
6+
pub trait IpAddrExt {
7+
fn is_global(&self) -> bool;
8+
}
9+
10+
impl IpAddrExt for IpAddr {
11+
fn is_global(&self) -> bool {
12+
match self {
13+
IpAddr::V4(ip) => IpAddrExt::is_global(ip),
14+
IpAddr::V6(ip) => IpAddrExt::is_global(ip),
15+
}
16+
}
17+
}
18+
19+
impl IpAddrExt for Ipv4Addr {
20+
fn is_global(&self) -> bool {
21+
!(self.octets()[0] == 0 // "This network"
22+
|| self.is_private()
23+
// NOTE, this line replaces `self.is_shared()`
24+
|| self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000)
25+
|| self.is_loopback()
26+
|| self.is_link_local()
27+
// addresses reserved for future protocols (`192.0.0.0/24`)
28+
// .9 and .10 are documented as globally reachable so they're excluded
29+
|| (
30+
self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0
31+
&& self.octets()[3] != 9 && self.octets()[3] != 10
32+
)
33+
|| self.is_documentation()
34+
// NOTE, this line replaces `self.is_benchmarking()`
35+
|| self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18
36+
// NOTE, this line replaces `self.is_reserved()`
37+
|| self.octets()[0] & 240 == 240 && !self.is_broadcast()
38+
|| self.is_broadcast())
39+
}
40+
}
41+
impl IpAddrExt for Ipv6Addr {
42+
fn is_global(&self) -> bool {
43+
!(self.is_unspecified()
44+
|| self.is_loopback()
45+
// IPv4-mapped Address (`::ffff:0:0/96`)
46+
|| matches!(self.segments(), [0, 0, 0, 0, 0, 0xffff, _, _])
47+
// IPv4-IPv6 Translat. (`64:ff9b:1::/48`)
48+
|| matches!(self.segments(), [0x64, 0xff9b, 1, _, _, _, _, _])
49+
// Discard-Only Address Block (`100::/64`)
50+
|| matches!(self.segments(), [0x100, 0, 0, 0, _, _, _, _])
51+
// IETF Protocol Assignments (`2001::/23`)
52+
|| (matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b < 0x200)
53+
&& !(
54+
// Port Control Protocol Anycast (`2001:1::1`)
55+
u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0001
56+
// Traversal Using Relays around NAT Anycast (`2001:1::2`)
57+
|| u128::from_be_bytes(self.octets()) == 0x2001_0001_0000_0000_0000_0000_0000_0002
58+
// AMT (`2001:3::/32`)
59+
|| matches!(self.segments(), [0x2001, 3, _, _, _, _, _, _])
60+
// AS112-v6 (`2001:4:112::/48`)
61+
|| matches!(self.segments(), [0x2001, 4, 0x112, _, _, _, _, _])
62+
// ORCHIDv2 (`2001:20::/28`)
63+
// Drone Remote ID Protocol Entity Tags (DETs) Prefix (`2001:30::/28`)`
64+
|| matches!(self.segments(), [0x2001, b, _, _, _, _, _, _] if b >= 0x20 && b <= 0x3F)
65+
))
66+
// 6to4 (`2002::/16`) – it's not explicitly documented as globally reachable,
67+
// IANA says N/A.
68+
|| matches!(self.segments(), [0x2002, _, _, _, _, _, _, _])
69+
// NOTE, this line replaces `self.is_documentation()`
70+
|| matches!(self.segments(), [0x2001, 0xdb8, ..] | [0x3fff, 0..=0x0fff, ..])
71+
// Segment Routing (SRv6) SIDs (`5f00::/16`)
72+
|| matches!(self.segments(), [0x5f00, ..])
73+
|| self.is_unique_local()
74+
|| self.is_unicast_link_local())
75+
}
76+
}

src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod ip_addr_ext;

src/validators/domain.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::net::IpAddr;
66
use std::str::FromStr;
77
use trust_dns_resolver::config::*;
88
use trust_dns_resolver::Resolver;
9+
use crate::util::ip_addr_ext::IpAddrExt;
910

1011
pub fn validate_domain(
1112
validator: &EmailValidator,
@@ -199,12 +200,12 @@ pub fn validate_deliverability(domain: &str) -> Result<(), ValidationError> {
199200

200201
// Fallback to A/AAAA records
201202
if let Ok(a_records) = resolver.ipv4_lookup(domain) {
202-
if a_records.iter().any(|ip| ip.is_global()) {
203+
if a_records.iter().any(|ip| IpAddrExt::is_global(&ip.0)) {
203204
return Ok(());
204205
}
205206
}
206207
if let Ok(aaaa_records) = resolver.ipv6_lookup(domain) {
207-
if aaaa_records.iter().any(|ip| ip.is_global()) {
208+
if aaaa_records.iter().any(|ip| IpAddrExt::is_global(&ip.0)) {
208209
return Ok(());
209210
}
210211
}

0 commit comments

Comments
 (0)