@@ -10,8 +10,10 @@ pub fn parse_and_validate_server_name(data: &mut Root, server_name: &str) {
1010 return ;
1111 }
1212
13+ let is_bracketed = server_name. starts_with ( '[' ) ;
14+
1315 // Split hostname and port, handling IPv6 literals in brackets: [addr] or [addr]:port
14- let ( hostname, port_str) : ( & str , & str ) = if server_name . starts_with ( '[' ) {
16+ let ( hostname, port_str) : ( & str , & str ) = if is_bracketed {
1517 match server_name. find ( ']' ) {
1618 Some ( end) => {
1719 let inner = & server_name[ 1 ..end] ;
@@ -50,7 +52,19 @@ pub fn parse_and_validate_server_name(data: &mut Root, server_name: &str) {
5052 return ;
5153 }
5254
53- if hostname. parse :: < std:: net:: IpAddr > ( ) . is_ok ( ) {
55+ // Pre-filter before the expensive IpAddr::from_str (which attempts both IPv4 and IPv6):
56+ // - Bracketed form: inner could be IPv4 or IPv6 → hex digits, ':', '.'
57+ // - Non-bracketed: only IPv4 is valid per Matrix spec (IPv6 requires brackets) → digits, '.'
58+ // Anything outside these sets can't be a valid IP, so skip the parse entirely.
59+ let might_be_ip = if is_bracketed {
60+ hostname
61+ . bytes ( )
62+ . all ( |b| b. is_ascii_hexdigit ( ) || matches ! ( b, b':' | b'.' ) )
63+ } else {
64+ hostname. bytes ( ) . all ( |b| b. is_ascii_digit ( ) || b == b'.' )
65+ } ;
66+
67+ if might_be_ip && hostname. parse :: < std:: net:: IpAddr > ( ) . is_ok ( ) {
5468 // Valid IP literal; validate port if present
5569 if !port_str. is_empty ( ) && port_str. parse :: < u16 > ( ) . is_err ( ) {
5670 data. error = Some ( Error {
@@ -64,24 +78,41 @@ pub fn parse_and_validate_server_name(data: &mut Root, server_name: &str) {
6478 }
6579
6680 // Not an IP literal — validate as DNS name
67- if !hostname. is_ascii ( ) || hostname. len ( ) > 255 || hostname . contains ( ".." ) {
81+ if !hostname. is_ascii ( ) || hostname. len ( ) > 255 {
6882 data. error = Some ( Error {
6983 error : format ! ( "Invalid server name: {server_name} (Not a valid DNS name)" , ) ,
7084 error_code : ErrorCode :: InvalidServerName ( InvalidServerNameErrorCode :: NotValidDNS ) ,
7185 } ) ;
7286 return ;
7387 }
7488
75- // Check for invalid characters in the hostname
76- for c in hostname. chars ( ) {
77- if !c. is_ascii_alphanumeric ( ) && c != '-' && c != '.' {
78- data. error = Some ( Error {
79- error : format ! ( "Invalid server name: {server_name} (Invalid character '{c}')" , ) ,
80- error_code : ErrorCode :: InvalidServerName (
81- InvalidServerNameErrorCode :: InvalidCharacter ,
82- ) ,
83- } ) ;
84- return ;
89+ // Single-pass over bytes: detect invalid characters and ".." simultaneously.
90+ // Since is_ascii() passed above, iterating bytes is equivalent to iterating chars.
91+ let mut prev_was_dot = false ;
92+ for b in hostname. bytes ( ) {
93+ if b == b'.' {
94+ if prev_was_dot {
95+ data. error = Some ( Error {
96+ error : format ! ( "Invalid server name: {server_name} (Not a valid DNS name)" , ) ,
97+ error_code : ErrorCode :: InvalidServerName (
98+ InvalidServerNameErrorCode :: NotValidDNS ,
99+ ) ,
100+ } ) ;
101+ return ;
102+ }
103+ prev_was_dot = true ;
104+ } else {
105+ prev_was_dot = false ;
106+ if !b. is_ascii_alphanumeric ( ) && b != b'-' {
107+ let c = b as char ;
108+ data. error = Some ( Error {
109+ error : format ! ( "Invalid server name: {server_name} (Invalid character '{c}')" , ) ,
110+ error_code : ErrorCode :: InvalidServerName (
111+ InvalidServerNameErrorCode :: InvalidCharacter ,
112+ ) ,
113+ } ) ;
114+ return ;
115+ }
85116 }
86117 }
87118}
0 commit comments