/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "namespace.h" #include #include #include #include #include #include #include #include #include "log.h" static const char kNetNsDir[] = "/data/vendor/var/run/netns"; // Set the current namespace to that of the /proc//ns/net provided in // |path|. This may be a link or mount point for that same file, anything that // when opened will be an fd usable by setns is fine. static bool setNamespaceFromPath(const char* path) { int nsFd = open(path, O_RDONLY | O_CLOEXEC); if (nsFd == -1) { loge("Cannot open network namespace at '%s': %s\n", path, strerror(errno)); return false; } if (setns(nsFd, CLONE_NEWNET) == -1) { loge("Cannot set network namespace at '%s': %s\n", path, strerror(errno)); close(nsFd); return false; } close(nsFd); return true; } bool setNetworkNamespace(const char* ns) { // There is a file in the net namespace dir (usually /var/run/netns) with // the same name as the namespace. This file is bound to /proc//ns/net // by the 'ip' command when the namespace is created. This allows us to // access the file of a process running in that network namespace without // knowing its pid, knowing the namespace name is enough. // // We are going to call setns which requires a file descriptor to that proc // file in /proc//net. The process has to already be running in that // namespace. Since the file in the net namespace dir has been bound to // such a file already we just have to open /var/run/netns/ and // we have the required file descriptor. char nsPath[PATH_MAX]; snprintf(nsPath, sizeof(nsPath), "%s/%s", kNetNsDir, ns); return setNamespaceFromPath(nsPath); } bool setNetworkNamespace(pid_t pid) { // If we know the pid we can create the path to the /proc file right away // and use that when we call setns. char nsPath[PATH_MAX]; static_assert(sizeof(pid_t) <= sizeof(unsigned long long), "Cast requires sizeof(pid_t) <= sizeof(unsigned long long)"); snprintf(nsPath, sizeof(nsPath), "/proc/%llu/ns/net/", static_cast(pid)); return setNamespaceFromPath(nsPath); }