Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

example(outline-cli): configure system DNS when resolv.conf does not exist #203

Merged
merged 12 commits into from
May 30, 2024

Conversation

zeslava
Copy link
Contributor

@zeslava zeslava commented Mar 23, 2024

It's ok if no original resolv.conf file found

It's ok if no original resolv.conf file found
@fortuna fortuna requested a review from jyyi1 March 25, 2024 18:01
Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution!

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution.

But this logic might not work when there is resolv.head.conf, but not resolv.conf. Previously, only resolv.conf.outlinecli.backup will be created and only resolv.conf will be changed; but now both resolv.head.conf and resolv.conf will be changed.

We might need to add a special logic to setSystemDNSServer to handle the situation that neither resolv.head.conf nor resolv.conf exist in the system. In that case, we just need to create a new resolv.conf with Outline's setting, and when we restoreSystemDNSServer, we need to delete the newly created resolv.conf (because no backups are available).

@jyyi1 jyyi1 changed the title Update dns_linux.go example(outline-cli): configure system DNS when resolv.conf does not exist Apr 1, 2024
Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the update! I believe we can even simplify the logic by introducing a global backups variable here. So we don't need to have any restoration callback functions, which is a little bit harder to understand.

@@ -27,30 +28,58 @@ const (
resolvConfHeadBackupFile = "/etc/resolv.head.outlinecli.backup"
)

func setSystemDNSServer(serverHost string) error {
// restoreBackup restore backup file function
type restoreBackup func()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might not be needed (see comments below). In stead, we can have a global variable storing the updated resolv file paths:

Suggested change
type restoreBackup func()
type resolvBackup struct {
original, backup string
}
var backups []resolvBackup

Comment on lines 46 to 55
restoreOriginal, err := backupAndWriteFile(resolvConfFile, resolvConfBackupFile, setting)
restores = append(restores, restoreOriginal)
if err != nil {
return restore, err
}

restoreOriginalHead, err := backupAndWriteFile(resolvConfHeadFile, resolvConfHeadBackupFile, setting)
restores = append(restores, restoreOriginalHead)

return restore, err
Copy link
Contributor

@jyyi1 jyyi1 Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we only need to handle the os.ErrNotExist condition in backupAndWriteFile. So we don't need to change a lot of things in this function.

Comment on lines 59 to 62
restore := func() {
// by default restore original file from backup
restoreFileIfExists(backup, original)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, we can add file paths to the backups variable.

Suggested change
restore := func() {
// by default restore original file from backup
restoreFileIfExists(backup, original)
}

x/examples/outline-cli/dns_linux.go Show resolved Hide resolved
Comment on lines 65 to 74
if errors.Is(err, os.ErrNotExist) {
// original file does not exist, so just remove created file by ourselves
restore = func() {
if err := os.Remove(original); err != nil {
logging.Warn.Printf("failed to remove our file '%s': %v\n", original, err)
}
}
} else {
return func() {}, fmt.Errorf("failed to backup DNS config file '%s' to '%s': %w", original, backup, err)
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We just need to ignore os.ErrNotExist here. The paths will be appended to backups later.

Suggested change
if errors.Is(err, os.ErrNotExist) {
// original file does not exist, so just remove created file by ourselves
restore = func() {
if err := os.Remove(original); err != nil {
logging.Warn.Printf("failed to remove our file '%s': %v\n", original, err)
}
}
} else {
return func() {}, fmt.Errorf("failed to backup DNS config file '%s' to '%s': %w", original, backup, err)
}
if !errors.Is(err, os.ErrNotExist) {
return func() {}, fmt.Errorf("failed to backup DNS config file '%s' to '%s': %w", original, backup, err)
}

}

func backupAndWriteFile(original, backup string, data []byte) error {
func backupAndWriteFile(original, backup string, data []byte) (restoreBackup, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to return any restoration functions here.

Suggested change
func backupAndWriteFile(original, backup string, data []byte) (restoreBackup, error) {
func backupAndWriteFile(original, backup string, data []byte) error {

}
return nil

return restore, err
}

func restoreFileIfExists(backup, original string) {
Copy link
Contributor

@jyyi1 jyyi1 Apr 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And finally, you may simply loop though all entries in backups here (we don't need to take any backup or original parameters in this function any more):

// remember to remove restored entries from `backups` after this function is successfully run

for _, backup := range backups {
	if _, err := os.Stat(backup.backup); err != nil {
		// if err is notexist
		//   simplify remove file backup.original
		//   logging.Info.Printf("DNS config '%s' removed\n", backup.original)
		//   continue
		logging.Warn.Printf("filed to get info of DNS config backup file '%s': %v\n", backup, err)
		return
	}
	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)
		return
	}
	logging.Info.Printf("DNS config restored from '%s' to '%s'\n", backup.backup, backup.original)
}

@zeslava
Copy link
Contributor Author

zeslava commented Apr 30, 2024

@jyyi1 fixed

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code looks good to me, with a few minor comments. Please also exclude the unrelated style changes in this PR. Appreciated!

type tlsHandshakeRecordHeader []byte
// This file contains helper functions and constants for TLS Client Hello message.

type (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please revert these changes, they are not related to this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@@ -27,40 +28,77 @@ const (
resolvConfHeadBackupFile = "/etc/resolv.head.outlinecli.backup"
)

// systemDNSBackup info about systemdns backup
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't seem to be necessary.

Suggested change
// systemDNSBackup info about systemdns backup

return err
err := backupAndWriteFile(resolvConfFile, resolvConfBackupFile, setting)
if err != nil {
return fmt.Errorf("dns backup: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather simply return the error, because we have provided enough error details in backupAndWriteFile function.

Suggested change
return fmt.Errorf("dns backup: %w", err)
return err

restoreFileIfExists(resolvConfHeadBackupFile, resolvConfHeadFile)
err = backupAndWriteFile(resolvConfHeadFile, resolvConfHeadBackupFile, setting)
if err != nil {
return fmt.Errorf("dns head backup: %w", err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above.

Suggested change
return fmt.Errorf("dns head backup: %w", err)
return err

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also if we are simply returning the err here, we can just do return backupAndWriteFile(...) directly.

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 errors.New("check original file exists")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return errors.New("check original file exists")
return fmt.Errorf("failed to check the existence of DNS config file '%s': %w", original, err)

Comment on lines +70 to +75

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

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to put these lines before os.WriteFile. Because we have already backed up the original DNS config, even though we failed to write to the new file, we still need to copy the backup file back to original when we try to reset the DNS config.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}
logging.Info.Printf("DNS config removed '%s'\n", backup.original)
} else {
logging.Err.Printf("checking backup '%s': %v", backup.backup, err)
Copy link
Contributor

@jyyi1 jyyi1 May 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
logging.Err.Printf("checking backup '%s': %v", backup.backup, err)
logging.Err.Printf("failed to check the existence of DNS config backup file '%s': %v\n", backup.backup, err)

} 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("removing original DNS config file '%s': %v", backup.original, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
logging.Err.Printf("removing original DNS config file '%s': %v", backup.original, err)
logging.Err.Printf("failed to remove Outline DNS config file '%s': %v\n", backup.original, err)

logging.Err.Printf("removing original DNS config file '%s': %v", backup.original, err)
continue
}
logging.Info.Printf("DNS config removed '%s'\n", backup.original)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
logging.Info.Printf("DNS config removed '%s'\n", backup.original)
logging.Info.Printf("Outline DNS config '%s' has been removed\n", backup.original)

@@ -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 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍! Thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can keep this change. Though it's not related to DNS, but it's CLI.

Copy link
Contributor

@jyyi1 jyyi1 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @zeslava , the code looks good to me!

@jyyi1
Copy link
Contributor

jyyi1 commented May 30, 2024

Hi @zeslava , on last thing, could you fetch the latest main and merge it to this PR? It will unblock the failing CI so I can merge this PR. Thanks.

@jyyi1 jyyi1 merged commit c99a7ce into Jigsaw-Code:main May 30, 2024
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants