├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "hostname-validator" 3 | description = "Validate hostnames according to IETF RFC 1123" 4 | repository = "https://github.com/pop-os/hostname-validator" 5 | version = "1.1.1" 6 | keywords = ["ietf", "rfc", "1123", "hostname"] 7 | categories = ["no-std"] 8 | readme = "README.md" 9 | license = "MIT" 10 | 11 | [dependencies] 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 System76 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hostname-validator 2 | 3 | Rust crate for validating a hostname according to the [IETF RFC 1123](https://tools.ietf.org/html/rfc1123). 4 | 5 | ```rust 6 | extern crate hostname_validator; 7 | 8 | let valid = "VaLiD-HoStNaMe"; 9 | let invalid = "-invalid-name"; 10 | 11 | assert!(hostname_validator::is_valid(valid)); 12 | assert!(!hostname_validator::is_valid(invalid)); 13 | ``` 14 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | // Copyright 2018-2022 System76 2 | // SPDX-License-Identifier: MIT 3 | 4 | #![no_std] 5 | 6 | //! Validate a hostname according to the [IETF RFC 1123](https://tools.ietf.org/html/rfc1123). 7 | //! 8 | //! ```rust 9 | //! extern crate hostname_validator; 10 | //! 11 | //! let valid = "VaLiD-HoStNaMe"; 12 | //! let invalid = "-invalid-name"; 13 | //! 14 | //! assert!(hostname_validator::is_valid(valid)); 15 | //! assert!(!hostname_validator::is_valid(invalid)); 16 | //! ``` 17 | 18 | /// Validate a hostname according to [IETF RFC 1123](https://tools.ietf.org/html/rfc1123). 19 | /// 20 | /// A hostname is valid if the following condition are true: 21 | /// 22 | /// - It does not start or end with `-` or `.`. 23 | /// - It does not contain any characters outside of the alphanumeric range, except for `-` and `.`. 24 | /// - It is not empty. 25 | /// - It is 253 or fewer characters. 26 | /// - Its labels (characters separated by `.`) are not empty. 27 | /// - Its labels are 63 or fewer characters. 28 | /// - Its labels do not start or end with '-' or '.'. 29 | pub fn is_valid(hostname: &str) -> bool { 30 | fn is_valid_char(byte: u8) -> bool { 31 | (b'a'..=b'z').contains(&byte) 32 | || (b'A'..=b'Z').contains(&byte) 33 | || (b'0'..=b'9').contains(&byte) 34 | || byte == b'-' 35 | || byte == b'.' 36 | } 37 | 38 | !(hostname.bytes().any(|byte| !is_valid_char(byte)) 39 | || hostname.split('.').any(|label| { 40 | label.is_empty() || label.len() > 63 || label.starts_with('-') || label.ends_with('-') 41 | }) 42 | || hostname.is_empty() 43 | || hostname.len() > 253) 44 | } 45 | 46 | #[cfg(test)] 47 | mod tests { 48 | use super::*; 49 | 50 | #[test] 51 | fn valid_hostnames() { 52 | for hostname in &[ 53 | "VaLiD-HoStNaMe", 54 | "50-name", 55 | "235235", 56 | "example.com", 57 | "VaLid.HoStNaMe", 58 | "123.456", 59 | ] { 60 | assert!(is_valid(hostname), "{} is not valid", hostname); 61 | } 62 | } 63 | 64 | #[test] 65 | fn invalid_hostnames() { 66 | for hostname in &[ 67 | "-invalid-name", 68 | "also-invalid-", 69 | "asdf@fasd", 70 | "@asdfl", 71 | "asd f@", 72 | ".invalid", 73 | "invalid.name.", 74 | "foo.label-is-way-to-longgggggggggggggggggggggggggggggggggggggggggggg.org", 75 | "invalid.-starting.char", 76 | "invalid.ending-.char", 77 | "empty..label", 78 | ] { 79 | assert!(!is_valid(hostname), "{} should not be valid", hostname); 80 | } 81 | } 82 | } 83 | --------------------------------------------------------------------------------