@@ -792,6 +792,25 @@ fn redact_token(token: &str) -> String {
792792 }
793793}
794794
795+ fn validate_zt_domain ( domain : & str ) -> Result < ( ) > {
796+ if domain. is_empty ( ) || domain. len ( ) > 253 || !domain. is_ascii ( ) {
797+ bail ! ( "domain must be a non-empty ASCII DNS name of at most 253 bytes" ) ;
798+ }
799+ for label in domain. split ( '.' ) {
800+ if label. is_empty ( )
801+ || label. len ( ) > 63
802+ || label. starts_with ( '-' )
803+ || label. ends_with ( '-' )
804+ || !label
805+ . bytes ( )
806+ . all ( |byte| byte. is_ascii_alphanumeric ( ) || byte == b'-' )
807+ {
808+ bail ! ( "domain contains an invalid DNS label" ) ;
809+ }
810+ }
811+ Ok ( ( ) )
812+ }
813+
795814/// Convert proto ZtDomainConfig to internal ZtDomainConfig
796815fn proto_to_zt_domain_config (
797816 proto : & ProtoZtDomainConfig ,
@@ -817,6 +836,10 @@ fn proto_to_zt_domain_config(
817836 . strip_prefix ( "*." )
818837 . unwrap_or ( & proto. domain )
819838 . to_string ( ) ;
839+ validate_zt_domain ( & domain) ?;
840+ if proto. port == 0 {
841+ bail ! ( "port must be between 1 and 65535" ) ;
842+ }
820843
821844 Ok ( ZtDomainConfig {
822845 domain,
@@ -856,3 +879,29 @@ fn zt_domain_to_proto(
856879 cert_status,
857880 }
858881}
882+
883+ #[ cfg( test) ]
884+ mod zt_domain_tests {
885+ use super :: validate_zt_domain;
886+
887+ #[ test]
888+ fn accepts_a_dns_domain ( ) {
889+ validate_zt_domain ( "service.example.com" ) . unwrap ( ) ;
890+ }
891+
892+ #[ test]
893+ fn rejects_empty_and_invalid_dns_domains ( ) {
894+ for domain in [
895+ "" ,
896+ ".example.com" ,
897+ "example..com" ,
898+ "-bad.example" ,
899+ "bad-.example" ,
900+ ] {
901+ assert ! (
902+ validate_zt_domain( domain) . is_err( ) ,
903+ "{domain} should be rejected"
904+ ) ;
905+ }
906+ }
907+ }
0 commit comments