Home | History | Annotate | Download | only in ipv6proxy
      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