1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "namespace.h" 18 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <linux/limits.h> 22 #include <sched.h> 23 #include <stdio.h> 24 #include <string.h> 25 #include <sys/stat.h> 26 #include <unistd.h> 27 28 #include "log.h" 29 30 static const char kNetNsDir[] = "/data/vendor/var/run/netns"; 31 32 // Set the current namespace to that of the /proc/<pid>/ns/net provided in 33 // |path|. This may be a link or mount point for that same file, anything that 34 // when opened will be an fd usable by setns is fine. 35 static bool setNamespaceFromPath(const char* path) { 36 int nsFd = open(path, O_RDONLY | O_CLOEXEC); 37 if (nsFd == -1) { 38 loge("Cannot open network namespace at '%s': %s\n", 39 path, strerror(errno)); 40 return false; 41 } 42 43 if (setns(nsFd, CLONE_NEWNET) == -1) { 44 loge("Cannot set network namespace at '%s': %s\n", 45 path, strerror(errno)); 46 close(nsFd); 47 return false; 48 } 49 close(nsFd); 50 return true; 51 } 52 53 bool setNetworkNamespace(const char* ns) { 54 // There is a file in the net namespace dir (usually /var/run/netns) with 55 // the same name as the namespace. This file is bound to /proc/<pid>/ns/net 56 // by the 'ip' command when the namespace is created. This allows us to 57 // access the file of a process running in that network namespace without 58 // knowing its pid, knowing the namespace name is enough. 59 // 60 // We are going to call setns which requires a file descriptor to that proc 61 // file in /proc/<pid>/net. The process has to already be running in that 62 // namespace. Since the file in the net namespace dir has been bound to 63 // such a file already we just have to open /var/run/netns/<namespace> and 64 // we have the required file descriptor. 65 char nsPath[PATH_MAX]; 66 snprintf(nsPath, sizeof(nsPath), "%s/%s", kNetNsDir, ns); 67 return setNamespaceFromPath(nsPath); 68 } 69 70 bool setNetworkNamespace(pid_t pid) { 71 // If we know the pid we can create the path to the /proc file right away 72 // and use that when we call setns. 73 char nsPath[PATH_MAX]; 74 static_assert(sizeof(pid_t) <= sizeof(unsigned long long), 75 "Cast requires sizeof(pid_t) <= sizeof(unsigned long long)"); 76 snprintf(nsPath, sizeof(nsPath), "/proc/%llu/ns/net/", 77 static_cast<unsigned long long>(pid)); 78 return setNamespaceFromPath(nsPath); 79 } 80 81