2019-07-01 15:43:34 +00:00
use crate ::errors ::* ;
2020-03-07 15:57:47 +00:00
use crate ::ser ::text ::{ quoted , DnsTextContext } ;
2017-12-21 12:32:14 +00:00
2020-03-07 15:57:47 +00:00
use super ::{ DnsLabelRef , DnsName } ;
2017-12-26 21:23:51 +00:00
2018-02-10 10:32:25 +00:00
/// Parse text representation of a domain name
2020-03-07 15:57:47 +00:00
pub fn parse_name ( context : & DnsTextContext , value : & str ) -> Result < DnsName > {
2018-02-10 10:32:25 +00:00
let raw = value . as_bytes ( ) ;
let mut name = DnsName ::new_root ( ) ;
if raw = = b " . " {
return Ok ( name ) ;
} else if raw = = b " @ " {
match context . origin ( ) {
Some ( o ) = > return Ok ( o . clone ( ) ) ,
2019-07-01 15:43:34 +00:00
None = > failure ::bail! ( " @ invalid without $ORIGIN " ) ,
2018-02-10 10:32:25 +00:00
}
}
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! raw . is_empty ( ) , " invalid empty name " ) ;
2018-02-10 10:32:25 +00:00
let mut label = Vec ::new ( ) ;
let mut pos = 0 ;
while pos < raw . len ( ) {
if raw [ pos ] = = b '.' {
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! label . is_empty ( ) , " empty label in name: {:?} " , value ) ;
2017-12-21 12:32:14 +00:00
name . push_back ( DnsLabelRef ::new ( & label ) ? ) ? ;
2018-02-10 10:32:25 +00:00
label . clear ( ) ;
} else if raw [ pos ] = = b '\\' {
2020-03-07 15:57:47 +00:00
failure ::ensure! (
pos + 1 < raw . len ( ) ,
" unexpected end of name after backslash: {:?} " ,
value
) ;
if raw [ pos + 1 ] > = b '0' & & raw [ pos + 1 ] < = b '9' {
2018-02-10 10:32:25 +00:00
// \ddd escape
2020-03-07 15:57:47 +00:00
failure ::ensure! (
pos + 3 < raw . len ( ) ,
" unexpected end of name after backslash with digit: {:?} " ,
value
) ;
failure ::ensure! (
raw [ pos + 2 ] > = b '0'
& & raw [ pos + 2 ] < = b '9' & & raw [ pos + 3 ] > = b '0'
& & raw [ pos + 3 ] < = b '9' ,
" expected three digits after backslash in name: {:?} " ,
name
) ;
let d1 = ( raw [ pos + 1 ] - b '0' ) as u32 ;
let d2 = ( raw [ pos + 2 ] - b '0' ) as u32 ;
let d3 = ( raw [ pos + 3 ] - b '0' ) as u32 ;
2018-02-10 10:32:25 +00:00
let v = d1 * 100 + d2 * 10 + d3 ;
2019-07-01 15:43:34 +00:00
failure ::ensure! ( v < 256 , " invalid escape in name, {} > 255: {:?} " , v , name ) ;
2018-02-10 10:32:25 +00:00
label . push ( v as u8 ) ;
} else {
2019-07-01 15:43:34 +00:00
failure ::ensure! ( ! quoted ::is_ascii_whitespace ( raw [ pos + 1 ] ) , " whitespace cannot be escaped with backslash prefix; encode it as \\ {:03} in: {:?} " , raw [ pos + 1 ] , name ) ;
2020-03-07 15:57:47 +00:00
label . push ( raw [ pos + 1 ] ) ;
2017-12-26 21:23:51 +00:00
}
2018-02-10 10:32:25 +00:00
} else {
2020-03-07 15:57:47 +00:00
failure ::ensure! (
! quoted ::is_ascii_whitespace ( raw [ pos ] ) ,
" whitespace must be encoded as \\ {:03} in: {:?} " ,
raw [ pos ] ,
name
) ;
2018-02-10 10:32:25 +00:00
label . push ( raw [ pos ] ) ;
2017-12-21 12:32:14 +00:00
}
2018-02-10 10:32:25 +00:00
pos + = 1 ;
2017-12-21 12:32:14 +00:00
}
2018-02-10 10:32:25 +00:00
if ! label . is_empty ( ) {
// no trailing dot, relative name
2017-12-21 12:32:14 +00:00
2018-02-10 10:32:25 +00:00
// push last label
name . push_back ( DnsLabelRef ::new ( & label ) ? ) ? ;
2017-12-21 12:32:14 +00:00
2018-02-10 10:32:25 +00:00
match context . origin ( ) {
Some ( o ) = > {
2020-03-07 15:57:47 +00:00
for l in o {
name . push_back ( l ) ? ;
}
2018-02-10 10:32:25 +00:00
} ,
2019-07-01 15:43:34 +00:00
None = > failure ::bail! ( " missing trailing dot without $ORIGIN " ) ,
2018-02-10 10:32:25 +00:00
}
2017-12-21 12:32:14 +00:00
}
2017-12-27 17:38:02 +00:00
2018-02-10 10:32:25 +00:00
Ok ( name )
2017-12-27 17:38:02 +00:00
}