@ -38,11 +38,31 @@ func (m *resolvdManager) SetDNS(config OSConfig) error {
m . ifName ,
m . ifName ,
}
}
origResolv , err := m . readAndCopy ( resolvConf , backupConf , 0644 )
// first, read in the resolvConf
origResolv , err := m . fs . ReadFile ( resolvConf )
if err != nil {
if err != nil {
return err
return err
}
}
newResolvConf := removeSearchLines ( origResolv )
// search for our sentinel in resolvConf, if it's not present
// it's our first call to SetDNS, and we should make backupConf
resolvConfOwned := bytes . Contains ( origResolv , [ ] byte ( "generated by tailscale" ) )
if ! resolvConfOwned {
_ , err = m . fs . Stat ( backupConf )
if err != nil && os . IsNotExist ( err ) {
_ , err = m . readAndCopy ( resolvConf , backupConf , 0644 )
if err != nil {
return err
}
}
}
// remove resolvd nameservers and search lines
origResolv = removeSearchLines ( origResolv )
origResolv = removeResolvdNameserverLines ( origResolv )
// and clean up whitespace
removeBlanks := regexp . MustCompile ( ` (?m)^\s*\n ` )
origResolv = removeBlanks . ReplaceAll ( origResolv , [ ] byte ( "" ) )
for _ , ns := range config . Nameservers {
for _ , ns := range config . Nameservers {
args = append ( args , ns . String ( ) )
args = append ( args , ns . String ( ) )
@ -55,6 +75,15 @@ func (m *resolvdManager) SetDNS(config OSConfig) error {
newSearch = append ( newSearch , s . WithoutTrailingDot ( ) )
newSearch = append ( newSearch , s . WithoutTrailingDot ( ) )
}
}
var resolvConfHeader = [ ] byte ( "" )
if ! resolvConfOwned {
// if we don't have a header, insert one
resolvConfHeader = [ ] byte (
"# resolv.conf(5) file generated by tailscale\n" +
"# For more info, see https://tailscale.com/s/resolvconf-overwrite\n" +
"# DO NOT EDIT THIS FILE BY HAND -- CHANGES WILL BE OVERWRITTEN\n\n" )
}
newResolvConf := append ( resolvConfHeader , origResolv ... )
if len ( newSearch ) > 1 {
if len ( newSearch ) > 1 {
newResolvConf = append ( newResolvConf , [ ] byte ( strings . Join ( newSearch , " " ) ) ... )
newResolvConf = append ( newResolvConf , [ ] byte ( strings . Join ( newSearch , " " ) ) ... )
newResolvConf = append ( newResolvConf , '\n' )
newResolvConf = append ( newResolvConf , '\n' )
@ -123,6 +152,11 @@ func (m resolvdManager) readResolvConf() (config OSConfig, err error) {
} , nil
} , nil
}
}
func removeResolvdNameserverLines ( orig [ ] byte ) [ ] byte {
re := regexp . MustCompile ( ` (?m)^nameserver\s+[^\s]+\s+#\s+resolvd:.*$ ` )
return re . ReplaceAll ( orig , [ ] byte ( "" ) )
}
func removeSearchLines ( orig [ ] byte ) [ ] byte {
func removeSearchLines ( orig [ ] byte ) [ ] byte {
re := regexp . MustCompile ( ` (?ms)^search\s+.+$ ` )
re := regexp . MustCompile ( ` (?ms)^search\s+.+$ ` )
return re . ReplaceAll ( orig , [ ] byte ( "" ) )
return re . ReplaceAll ( orig , [ ] byte ( "" ) )