libnet: setupDNS: don't overwrite user-modified resolv.conf

Call resolvconf.UserModified() in sandbox.setupDNS() to check if
resolv.conf was manually modified before regenerating it during
container restart for non-host network modes.

Signed-off-by: zhangguanzhang <zhangguanzhang@qq.com>
Signed-off-by: Albin Kerouanton <albin.kerouanton@docker.com>
This commit is contained in:
zhangguanzhang
2025-11-13 11:31:23 +08:00
parent eb18b398d4
commit 7639e193ff
3 changed files with 111 additions and 2 deletions

View File

@@ -264,8 +264,17 @@ func (sb *Sandbox) loadResolvConf(path string) (*resolvconf.ResolvConf, error) {
// be a copy of the host's file, with overrides for nameservers, options and search
// domains applied.
func (sb *Sandbox) setupDNS() error {
// Make sure the directory exists.
sb.restoreResolvConfPath()
// When the container is restarted, a new Sandbox is created but the same resolv.conf is re-used. If it was
// user-modified, do not attempt to overwrite it.
if !sb.config.useDefaultSandBox {
if mod, err := resolvconf.UserModified(sb.config.resolvConfPath, sb.config.resolvConfHashFile); err != nil || mod {
return err
}
}
// Make sure the directory exists.
dir, _ := filepath.Split(sb.config.resolvConfPath)
if err := createBasePath(dir); err != nil {
return err

View File

@@ -14,12 +14,17 @@ import (
is "gotest.tools/v3/assert/cmp"
)
func getResolvConfOptions(t *testing.T, rcPath string) []string {
func getResolvConf(t *testing.T, rcPath string) resolvconf.ResolvConf {
t.Helper()
resolv, err := os.ReadFile(rcPath)
assert.NilError(t, err)
rc, err := resolvconf.Parse(bytes.NewBuffer(resolv), "")
assert.NilError(t, err)
return rc
}
func getResolvConfOptions(t *testing.T, rcPath string) []string {
rc := getResolvConf(t, rcPath)
return rc.Options()
}
@@ -90,3 +95,60 @@ func TestDNSOptions(t *testing.T) {
dnsOptionsList = getResolvConfOptions(t, sb2.config.resolvConfPath)
assert.Check(t, is.DeepEqual([]string{"ndots:0"}, dnsOptionsList))
}
func TestNonHostNetDNSRestart(t *testing.T) {
c, err := New(context.Background(), config.OptionDataDir(t.TempDir()))
assert.NilError(t, err)
// Step 1: Create initial sandbox (simulating first container start)
sb, err := c.NewSandbox(context.Background(), "cnt1")
assert.NilError(t, err)
defer func() {
_ = sb.Delete(context.Background())
}()
sb.startResolver(false)
err = sb.setupDNS()
assert.NilError(t, err)
err = sb.rebuildDNS()
assert.NilError(t, err)
// Step 2: Simulate user manually overwriting the container's resolv.conf
resolvConfPath := sb.config.resolvConfPath
modifiedContent := []byte(`nameserver 1.1.1.1`)
err = os.WriteFile(resolvConfPath, modifiedContent, 0644)
assert.NilError(t, err)
// Step 3: Delete the sandbox (simulating container stop)
err = sb.Delete(context.Background())
assert.NilError(t, err)
// Step 4: Create a new sandbox (simulating container restart)
sbRestart, err := c.NewSandbox(context.Background(), "cnt1",
OptionResolvConfPath(resolvConfPath),
)
assert.NilError(t, err)
defer func() {
if err := sbRestart.Delete(context.Background()); err != nil {
t.Error(err)
}
}()
sbRestart.startResolver(false)
// Step 5: Call setupDNS on restart - should preserve user modifications
err = sbRestart.setupDNS()
assert.NilError(t, err)
rc := getResolvConf(t, sbRestart.config.resolvConfPath)
assert.Check(t, is.Equal("1.1.1.1", rc.NameServers()[0].String()))
// Step 6: Call rebuildDNS on restart - should preserve user modifications
err = sbRestart.rebuildDNS()
assert.NilError(t, err)
rc = getResolvConf(t, sbRestart.config.resolvConfPath)
assert.Check(t, is.Equal("1.1.1.1", rc.NameServers()[0].String()))
}