Skip to content

Commit

Permalink
example(outline-cli): configure system DNS when resolv.conf does no…
Browse files Browse the repository at this point in the history
…t exist (#203)

It's ok if no original resolv.conf file found
  • Loading branch information
zeslava authored May 30, 2024
1 parent 94731fb commit c99a7ce
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 21 deletions.
3 changes: 2 additions & 1 deletion x/examples/outline-cli/app_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ func (app App) Run() error {
logging.Info.Printf("OutlineDevice -> tun stopped: %v %v\n", written, err)
}()

if err := setSystemDNSServer(app.RoutingConfig.DNSServerIP); err != nil {
err = setSystemDNSServer(app.RoutingConfig.DNSServerIP)
if err != nil {
return fmt.Errorf("failed to configure system DNS: %w", err)
}
defer restoreSystemDNSServer()
Expand Down
73 changes: 55 additions & 18 deletions x/examples/outline-cli/dns_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package main

import (
"errors"
"fmt"
"os"
)
Expand All @@ -27,40 +28,76 @@ const (
resolvConfHeadBackupFile = "/etc/resolv.head.outlinecli.backup"
)

type systemDNSBackup struct {
original, backup string
}

var systemDNSBackups = make([]systemDNSBackup, 0, 2)

func setSystemDNSServer(serverHost string) error {
setting := []byte(`# Outline CLI DNS Setting
# The original file has been renamed as resolv[.head].outlinecli.backup
nameserver ` + serverHost + "\n")

if err := backupAndWriteFile(resolvConfFile, resolvConfBackupFile, setting); err != nil {
err := backupAndWriteFile(resolvConfFile, resolvConfBackupFile, setting)
if err != nil {
return err
}
return backupAndWriteFile(resolvConfHeadFile, resolvConfHeadBackupFile, setting)
}

func restoreSystemDNSServer() {
restoreFileIfExists(resolvConfBackupFile, resolvConfFile)
restoreFileIfExists(resolvConfHeadBackupFile, resolvConfHeadFile)
err = backupAndWriteFile(resolvConfHeadFile, resolvConfHeadBackupFile, setting)
if err != nil {
return err
}

return nil
}

func backupAndWriteFile(original, backup string, data []byte) error {
if err := os.Rename(original, backup); err != nil {
return fmt.Errorf("failed to backup DNS config file '%s' to '%s': %w", original, backup, err)
if _, err := os.Stat(original); err == nil {
// original file exist - move it into backup
if err := os.Rename(original, backup); err != nil {
return fmt.Errorf("failed to backup DNS config file '%s' to '%s': %w", original, backup, err)
}
} else if !errors.Is(err, os.ErrNotExist) { // if not exist - it's ok, just write to it
return fmt.Errorf("failed to check the existence of DNS config file '%s': %w", original, err)
}
if err := os.WriteFile(original, data, 0644); err != nil {

systemDNSBackups = append(systemDNSBackups, systemDNSBackup{
original: original,
backup: backup,
})

// save data to original
if err := os.WriteFile(original, data, 0o644); err != nil {
return fmt.Errorf("failed to write DNS config file '%s': %w", original, err)
}

return nil
}

func restoreFileIfExists(backup, original string) {
if _, err := os.Stat(backup); err != nil {
logging.Warn.Printf("no DNS config backup file '%s' presents: %v\n", backup, err)
return
}
if err := os.Rename(backup, original); err != nil {
logging.Err.Printf("failed to restore DNS config from backup '%s' to '%s': %v\n", backup, original, err)
return
func restoreSystemDNSServer() {
for _, backup := range systemDNSBackups {
if _, err := os.Stat(backup.backup); err == nil {
// backup exist - replace original with it
if err := os.Rename(backup.backup, backup.original); err != nil {
logging.Err.Printf(
"failed to restore DNS config from backup '%s' to '%s': %v\n",
backup.backup,
backup.original,
err,
)
continue
}
logging.Info.Printf("DNS config restored from '%s' to '%s'\n", backup.backup, backup.original)
} else if errors.Is(err, os.ErrNotExist) {
// backup not exist - just remove original, because it's created by ourselves
if err := os.Remove(backup.original); err != nil {
logging.Err.Printf("failed to remove Outline DNS config file '%s': %v\n", backup.original, err)
continue
}
logging.Info.Printf("Outline DNS config '%s' has been removed\n", backup.original)
} else {
logging.Err.Printf("failed to check the existence of DNS config backup file '%s': %v\n", backup.backup, err)
}
}
logging.Info.Printf("DNS config restored from '%s' to '%s'\n", backup, original)
}
2 changes: 1 addition & 1 deletion x/examples/outline-cli/ipv6_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func enableIPv6(enabled bool) (bool, error) {
} else {
disabledStr[0] = '1'
}
if err := os.WriteFile(disableIPv6ProcFile, disabledStr, 0644); err != nil {
if err := os.WriteFile(disableIPv6ProcFile, disabledStr, 0o644); err != nil {
return prevEnabled, fmt.Errorf("failed to write IPv6 config: %w", err)
}

Expand Down
1 change: 0 additions & 1 deletion x/examples/outline-cli/outline_packet_proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ func (proxy *outlinePacketProxy) testConnectivityAndRefresh(resolverAddr, domain
dialer := transport.PacketListenerDialer{Listener: proxy.remotePl}
dnsResolver := dns.NewUDPResolver(dialer, resolverAddr)
result, err := connectivity.TestConnectivityWithResolver(context.Background(), dnsResolver, domain)

if err != nil {
logging.Info.Printf("connectivity test failed. Refresh skipped. Error: %v\n", err)
return err
Expand Down

0 comments on commit c99a7ce

Please sign in to comment.