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

rootless netns: resolve all path components for resolv.conf #12524

Merged
merged 1 commit into from
Dec 7, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 40 additions & 7 deletions libpod/networking_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,29 +222,62 @@ func (r *RootlessNetNS) Do(toRun func() error) error {
// the link target will be available in the mount ns.
// see: https://github.com/containers/podman/issues/10855
resolvePath := "/etc/resolv.conf"
for i := 0; i < 255; i++ {
linkCount := 0
for i := 1; i < len(resolvePath); i++ {
// Do not use filepath.EvalSymlinks, we only want the first symlink under /run.
// If /etc/resolv.conf has more than one symlink under /run, e.g.
// -> /run/systemd/resolve/stub-resolv.conf -> /run/systemd/resolve/resolv.conf
// we would put the netns resolv.conf file to the last path. However this will
// break dns because the second link does not exists in the mount ns.
// see https://github.com/containers/podman/issues/11222
link, err := os.Readlink(resolvePath)
//
// We also need to resolve all path components not just the last file.
// see https://github.com/containers/podman/issues/12461

if resolvePath[i] != '/' {
Copy link
Member

Choose a reason for hiding this comment

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

Can't we strip any potential trailing / and then do a filepath.Dir()?

Copy link
Member Author

Choose a reason for hiding this comment

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

That would be the wrong order. You have to resolve from left to right.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe split the string on / to get an array of path components, and then iterate through them, adding each to the path and checking for a symlink?

Copy link
Member Author

Choose a reason for hiding this comment

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

I do not see how this would be better than what I am doing now. This would just complicate things because I now have to constantly use strings.Split() and strings.Join().

Copy link
Member

Choose a reason for hiding this comment

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

Fair - I just see the existing code as not exactly clear in what it's trying to do.

Copy link
Member Author

Choose a reason for hiding this comment

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

If I have more time after podman 4.0 I will spend some time to add a test for this and maybe rework this to make it more readable.

In theory we could drop this when we are full netavark without iptables backend. In this case we would not need to bind mount /run and /var/lib/cni because netavark does not need write access to those directories.

// if we are at the last char we need to inc i by one because there is no final slash
if i == len(resolvePath)-1 {
i++
} else {
// not the end of path, keep going
continue
}
}
path := resolvePath[:i]

fi, err := os.Lstat(path)
if err != nil {
// if there is no symlink exit
break
return errors.Wrap(err, "failed to stat resolv.conf path")
Luap99 marked this conversation as resolved.
Show resolved Hide resolved
}

// no link, just continue
if fi.Mode()&os.ModeSymlink == 0 {
continue
}

link, err := os.Readlink(path)
if err != nil {
return errors.Wrap(err, "failed to read resolv.conf symlink")
Luap99 marked this conversation as resolved.
Show resolved Hide resolved
}
linkCount++
if filepath.IsAbs(link) {
// link is as an absolute path
resolvePath = link
resolvePath = filepath.Join(link, resolvePath[i:])
} else {
// link is as a relative, join it with the previous path
resolvePath = filepath.Join(filepath.Dir(resolvePath), link)
base := filepath.Dir(path)
resolvePath = filepath.Join(base, link, resolvePath[i:])
}
// set i back to zero since we now have a new base path
i = 0

// we have to stop at the first path under /run because we will have an empty /run and will create the path anyway
// if we would continue we would need to recreate all links under /run
if strings.HasPrefix(resolvePath, "/run/") {
break
}
if i == 254 {
// make sure wo do not loop forever
if linkCount == 255 {
return errors.New("too many symlinks while resolving /etc/resolv.conf")
}
}
Expand Down