iproute2/ip/ipnetns.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2#define _ATFILE_SOURCE
   3#include <sys/file.h>
   4#include <sys/types.h>
   5#include <sys/stat.h>
   6#include <sys/wait.h>
   7#include <sys/inotify.h>
   8#include <sys/mount.h>
   9#include <sys/syscall.h>
  10#include <stdio.h>
  11#include <string.h>
  12#include <sched.h>
  13#include <fcntl.h>
  14#include <dirent.h>
  15#include <errno.h>
  16#include <unistd.h>
  17#include <ctype.h>
  18#include <linux/limits.h>
  19
  20#include <linux/net_namespace.h>
  21
  22#include "utils.h"
  23#include "list.h"
  24#include "ip_common.h"
  25#include "namespace.h"
  26#include "json_print.h"
  27
  28static int usage(void)
  29{
  30        fprintf(stderr,
  31                "Usage: ip netns list\n"
  32                "       ip netns add NAME\n"
  33                "       ip netns attach NAME PID\n"
  34                "       ip netns set NAME NETNSID\n"
  35                "       ip [-all] netns delete [NAME]\n"
  36                "       ip netns identify [PID]\n"
  37                "       ip netns pids NAME\n"
  38                "       ip [-all] netns exec [NAME] cmd ...\n"
  39                "       ip netns monitor\n"
  40                "       ip netns list-id [target-nsid POSITIVE-INT] [nsid POSITIVE-INT]\n"
  41                "NETNSID := auto | POSITIVE-INT\n");
  42        exit(-1);
  43}
  44
  45/* This socket is used to get nsid */
  46static struct rtnl_handle rtnsh = { .fd = -1 };
  47
  48static int have_rtnl_getnsid = -1;
  49static int saved_netns = -1;
  50static struct link_filter filter;
  51
  52static int ipnetns_accept_msg(struct rtnl_ctrl_data *ctrl,
  53                              struct nlmsghdr *n, void *arg)
  54{
  55        struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(n);
  56
  57        if (n->nlmsg_type == NLMSG_ERROR &&
  58            (err->error == -EOPNOTSUPP || err->error == -EINVAL))
  59                have_rtnl_getnsid = 0;
  60        else
  61                have_rtnl_getnsid = 1;
  62        return -1;
  63}
  64
  65static int ipnetns_have_nsid(void)
  66{
  67        struct {
  68                struct nlmsghdr n;
  69                struct rtgenmsg g;
  70                char            buf[1024];
  71        } req = {
  72                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
  73                .n.nlmsg_flags = NLM_F_REQUEST,
  74                .n.nlmsg_type = RTM_GETNSID,
  75                .g.rtgen_family = AF_UNSPEC,
  76        };
  77        int fd;
  78
  79        if (have_rtnl_getnsid >= 0) {
  80                fd = open("/proc/self/ns/net", O_RDONLY);
  81                if (fd < 0) {
  82                        fprintf(stderr,
  83                                "/proc/self/ns/net: %s. Continuing anyway.\n",
  84                                strerror(errno));
  85                        have_rtnl_getnsid = 0;
  86                        return 0;
  87                }
  88
  89                addattr32(&req.n, 1024, NETNSA_FD, fd);
  90
  91                if (rtnl_send(&rth, &req.n, req.n.nlmsg_len) < 0) {
  92                        fprintf(stderr,
  93                                "rtnl_send(RTM_GETNSID): %s. Continuing anyway.\n",
  94                                strerror(errno));
  95                        have_rtnl_getnsid = 0;
  96                        close(fd);
  97                        return 0;
  98                }
  99                rtnl_listen(&rth, ipnetns_accept_msg, NULL);
 100                close(fd);
 101        }
 102
 103        return have_rtnl_getnsid;
 104}
 105
 106int get_netnsid_from_name(const char *name)
 107{
 108        struct {
 109                struct nlmsghdr n;
 110                struct rtgenmsg g;
 111                char            buf[1024];
 112        } req = {
 113                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
 114                .n.nlmsg_flags = NLM_F_REQUEST,
 115                .n.nlmsg_type = RTM_GETNSID,
 116                .g.rtgen_family = AF_UNSPEC,
 117        };
 118        struct nlmsghdr *answer;
 119        struct rtattr *tb[NETNSA_MAX + 1];
 120        struct rtgenmsg *rthdr;
 121        int len, fd, ret = -1;
 122
 123        netns_nsid_socket_init();
 124
 125        fd = netns_get_fd(name);
 126        if (fd < 0)
 127                return fd;
 128
 129        addattr32(&req.n, 1024, NETNSA_FD, fd);
 130        if (rtnl_talk(&rtnsh, &req.n, &answer) < 0) {
 131                close(fd);
 132                return -2;
 133        }
 134        close(fd);
 135
 136        /* Validate message and parse attributes */
 137        if (answer->nlmsg_type == NLMSG_ERROR)
 138                goto out;
 139
 140        rthdr = NLMSG_DATA(answer);
 141        len = answer->nlmsg_len - NLMSG_SPACE(sizeof(*rthdr));
 142        if (len < 0)
 143                goto out;
 144
 145        parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
 146
 147        if (tb[NETNSA_NSID]) {
 148                ret = rta_getattr_s32(tb[NETNSA_NSID]);
 149        }
 150
 151out:
 152        free(answer);
 153        return ret;
 154}
 155
 156struct nsid_cache {
 157        struct hlist_node       nsid_hash;
 158        struct hlist_node       name_hash;
 159        int                     nsid;
 160        char                    name[0];
 161};
 162
 163#define NSIDMAP_SIZE            128
 164#define NSID_HASH_NSID(nsid)    (nsid & (NSIDMAP_SIZE - 1))
 165#define NSID_HASH_NAME(name)    (namehash(name) & (NSIDMAP_SIZE - 1))
 166
 167static struct hlist_head        nsid_head[NSIDMAP_SIZE];
 168static struct hlist_head        name_head[NSIDMAP_SIZE];
 169
 170static struct nsid_cache *netns_map_get_by_nsid(int nsid)
 171{
 172        struct hlist_node *n;
 173        uint32_t h;
 174
 175        if (nsid < 0)
 176                return NULL;
 177
 178        h = NSID_HASH_NSID(nsid);
 179        hlist_for_each(n, &nsid_head[h]) {
 180                struct nsid_cache *c = container_of(n, struct nsid_cache,
 181                                                    nsid_hash);
 182                if (c->nsid == nsid)
 183                        return c;
 184        }
 185
 186        return NULL;
 187}
 188
 189char *get_name_from_nsid(int nsid)
 190{
 191        struct nsid_cache *c;
 192
 193        if (nsid < 0)
 194                return NULL;
 195
 196        netns_nsid_socket_init();
 197        netns_map_init();
 198
 199        c = netns_map_get_by_nsid(nsid);
 200        if (c)
 201                return c->name;
 202
 203        return NULL;
 204}
 205
 206static int netns_map_add(int nsid, const char *name)
 207{
 208        struct nsid_cache *c;
 209        uint32_t h;
 210
 211        if (netns_map_get_by_nsid(nsid) != NULL)
 212                return -EEXIST;
 213
 214        c = malloc(sizeof(*c) + strlen(name) + 1);
 215        if (c == NULL) {
 216                perror("malloc");
 217                return -ENOMEM;
 218        }
 219        c->nsid = nsid;
 220        strcpy(c->name, name);
 221
 222        h = NSID_HASH_NSID(nsid);
 223        hlist_add_head(&c->nsid_hash, &nsid_head[h]);
 224
 225        h = NSID_HASH_NAME(name);
 226        hlist_add_head(&c->name_hash, &name_head[h]);
 227
 228        return 0;
 229}
 230
 231static void netns_map_del(struct nsid_cache *c)
 232{
 233        hlist_del(&c->name_hash);
 234        hlist_del(&c->nsid_hash);
 235        free(c);
 236}
 237
 238void netns_nsid_socket_init(void)
 239{
 240        if (rtnsh.fd > -1 || !ipnetns_have_nsid())
 241                return;
 242
 243        if (rtnl_open(&rtnsh, 0) < 0) {
 244                fprintf(stderr, "Cannot open rtnetlink\n");
 245                exit(1);
 246        }
 247
 248}
 249
 250void netns_map_init(void)
 251{
 252        static int initialized;
 253        struct dirent *entry;
 254        DIR *dir;
 255        int nsid;
 256
 257        if (initialized || !ipnetns_have_nsid())
 258                return;
 259
 260        dir = opendir(NETNS_RUN_DIR);
 261        if (!dir)
 262                return;
 263
 264        while ((entry = readdir(dir)) != NULL) {
 265                if (strcmp(entry->d_name, ".") == 0)
 266                        continue;
 267                if (strcmp(entry->d_name, "..") == 0)
 268                        continue;
 269                nsid = get_netnsid_from_name(entry->d_name);
 270
 271                if (nsid >= 0)
 272                        netns_map_add(nsid, entry->d_name);
 273        }
 274        closedir(dir);
 275        initialized = 1;
 276}
 277
 278static int netns_get_name(int nsid, char *name)
 279{
 280        struct dirent *entry;
 281        DIR *dir;
 282        int id;
 283
 284        if (nsid < 0)
 285                return -EINVAL;
 286
 287        dir = opendir(NETNS_RUN_DIR);
 288        if (!dir)
 289                return -ENOENT;
 290
 291        while ((entry = readdir(dir)) != NULL) {
 292                if (strcmp(entry->d_name, ".") == 0)
 293                        continue;
 294                if (strcmp(entry->d_name, "..") == 0)
 295                        continue;
 296                id = get_netnsid_from_name(entry->d_name);
 297
 298                if (id >= 0 && nsid == id) {
 299                        strcpy(name, entry->d_name);
 300                        closedir(dir);
 301                        return 0;
 302                }
 303        }
 304        closedir(dir);
 305        return -ENOENT;
 306}
 307
 308int print_nsid(struct nlmsghdr *n, void *arg)
 309{
 310        struct rtgenmsg *rthdr = NLMSG_DATA(n);
 311        struct rtattr *tb[NETNSA_MAX+1];
 312        int len = n->nlmsg_len;
 313        FILE *fp = (FILE *)arg;
 314        struct nsid_cache *c;
 315        char name[NAME_MAX];
 316        int nsid, current;
 317
 318        if (n->nlmsg_type != RTM_NEWNSID && n->nlmsg_type != RTM_DELNSID)
 319                return 0;
 320
 321        len -= NLMSG_SPACE(sizeof(*rthdr));
 322        if (len < 0) {
 323                fprintf(stderr, "BUG: wrong nlmsg len %d in %s\n", len,
 324                        __func__);
 325                return -1;
 326        }
 327
 328        parse_rtattr(tb, NETNSA_MAX, NETNS_RTA(rthdr), len);
 329        if (tb[NETNSA_NSID] == NULL) {
 330                fprintf(stderr, "BUG: NETNSA_NSID is missing %s\n", __func__);
 331                return -1;
 332        }
 333
 334        open_json_object(NULL);
 335        if (n->nlmsg_type == RTM_DELNSID)
 336                print_bool(PRINT_ANY, "deleted", "Deleted ", true);
 337
 338        nsid = rta_getattr_s32(tb[NETNSA_NSID]);
 339        if (nsid < 0)
 340                print_string(PRINT_FP, NULL, "nsid unassigned ", NULL);
 341        else
 342                print_int(PRINT_ANY, "nsid", "nsid %d ", nsid);
 343
 344        if (tb[NETNSA_CURRENT_NSID]) {
 345                current = rta_getattr_s32(tb[NETNSA_CURRENT_NSID]);
 346                if (current < 0)
 347                        print_string(PRINT_FP, NULL,
 348                                     "current-nsid unassigned ", NULL);
 349                else
 350                        print_int(PRINT_ANY, "current-nsid",
 351                                  "current-nsid %d ", current);
 352        }
 353
 354        c = netns_map_get_by_nsid(tb[NETNSA_CURRENT_NSID] ? current : nsid);
 355        if (c != NULL) {
 356                print_string(PRINT_ANY, "name",
 357                             "(iproute2 netns name: %s)", c->name);
 358                netns_map_del(c);
 359        }
 360
 361        /* nsid might not be in cache */
 362        if (c == NULL && n->nlmsg_type == RTM_NEWNSID)
 363                if (netns_get_name(nsid, name) == 0) {
 364                        print_string(PRINT_ANY, "name",
 365                                     "(iproute2 netns name: %s)", name);
 366                        netns_map_add(nsid, name);
 367                }
 368
 369        print_string(PRINT_FP, NULL, "\n", NULL);
 370        close_json_object();
 371        fflush(fp);
 372        return 0;
 373}
 374
 375static int get_netnsid_from_netnsid(int nsid)
 376{
 377        struct {
 378                struct nlmsghdr n;
 379                struct rtgenmsg g;
 380                char            buf[1024];
 381        } req = {
 382                .n.nlmsg_len = NLMSG_LENGTH(NLMSG_ALIGN(sizeof(struct rtgenmsg))),
 383                .n.nlmsg_flags = NLM_F_REQUEST,
 384                .n.nlmsg_type = RTM_GETNSID,
 385                .g.rtgen_family = AF_UNSPEC,
 386        };
 387        struct nlmsghdr *answer;
 388        int err;
 389
 390        netns_nsid_socket_init();
 391
 392        err = addattr32(&req.n, sizeof(req), NETNSA_NSID, nsid);
 393        if (err)
 394                return err;
 395
 396        if (filter.target_nsid >= 0) {
 397                err = addattr32(&req.n, sizeof(req), NETNSA_TARGET_NSID,
 398                                filter.target_nsid);
 399                if (err)
 400                        return err;
 401        }
 402
 403        if (rtnl_talk(&rtnsh, &req.n, &answer) < 0)
 404                return -2;
 405
 406        /* Validate message and parse attributes */
 407        if (answer->nlmsg_type == NLMSG_ERROR)
 408                goto err_out;
 409
 410        new_json_obj(json);
 411        err = print_nsid(answer, stdout);
 412        delete_json_obj();
 413err_out:
 414        free(answer);
 415        return err;
 416}
 417
 418static int netns_filter_req(struct nlmsghdr *nlh, int reqlen)
 419{
 420        int err;
 421
 422        if (filter.target_nsid >= 0) {
 423                err = addattr32(nlh, reqlen, NETNSA_TARGET_NSID,
 424                                filter.target_nsid);
 425                if (err)
 426                        return err;
 427        }
 428
 429        return 0;
 430}
 431
 432static int netns_list_id(int argc, char **argv)
 433{
 434        int nsid = -1;
 435
 436        if (!ipnetns_have_nsid()) {
 437                fprintf(stderr,
 438                        "RTM_GETNSID is not supported by the kernel.\n");
 439                return -ENOTSUP;
 440        }
 441
 442        filter.target_nsid = -1;
 443        while (argc > 0) {
 444                if (strcmp(*argv, "target-nsid") == 0) {
 445                        if (filter.target_nsid >= 0)
 446                                duparg("target-nsid", *argv);
 447                        NEXT_ARG();
 448
 449                        if (get_integer(&filter.target_nsid, *argv, 0))
 450                                invarg("\"target-nsid\" value is invalid",
 451                                       *argv);
 452                        else if (filter.target_nsid < 0)
 453                                invarg("\"target-nsid\" value should be >= 0",
 454                                       argv[1]);
 455                } else if (strcmp(*argv, "nsid") == 0) {
 456                        if (nsid >= 0)
 457                                duparg("nsid", *argv);
 458                        NEXT_ARG();
 459
 460                        if (get_integer(&nsid, *argv, 0))
 461                                invarg("\"nsid\" value is invalid", *argv);
 462                        else if (nsid < 0)
 463                                invarg("\"nsid\" value should be >= 0",
 464                                       argv[1]);
 465                } else
 466                        usage();
 467                argc--; argv++;
 468        }
 469
 470        if (nsid >= 0)
 471                return get_netnsid_from_netnsid(nsid);
 472
 473        if (rtnl_nsiddump_req_filter_fn(&rth, AF_UNSPEC,
 474                                        netns_filter_req) < 0) {
 475                perror("Cannot send dump request");
 476                exit(1);
 477        }
 478
 479        new_json_obj(json);
 480        if (rtnl_dump_filter(&rth, print_nsid, stdout) < 0) {
 481                delete_json_obj();
 482                fprintf(stderr, "Dump terminated\n");
 483                exit(1);
 484        }
 485        delete_json_obj();
 486        return 0;
 487}
 488
 489static int netns_list(int argc, char **argv)
 490{
 491        struct dirent *entry;
 492        DIR *dir;
 493        int id;
 494
 495        dir = opendir(NETNS_RUN_DIR);
 496        if (!dir)
 497                return 0;
 498
 499        new_json_obj(json);
 500        while ((entry = readdir(dir)) != NULL) {
 501                if (strcmp(entry->d_name, ".") == 0)
 502                        continue;
 503                if (strcmp(entry->d_name, "..") == 0)
 504                        continue;
 505
 506                open_json_object(NULL);
 507                print_string(PRINT_ANY, "name",
 508                             "%s", entry->d_name);
 509                if (ipnetns_have_nsid()) {
 510                        id = get_netnsid_from_name(entry->d_name);
 511                        if (id >= 0)
 512                                print_int(PRINT_ANY, "id", " (id: %d)", id);
 513                }
 514                print_string(PRINT_FP, NULL, "\n", NULL);
 515                close_json_object();
 516        }
 517        closedir(dir);
 518        delete_json_obj();
 519        return 0;
 520}
 521
 522static int do_switch(void *arg)
 523{
 524        char *netns = arg;
 525
 526        /* we just changed namespaces. clear any vrf association
 527         * with prior namespace before exec'ing command
 528         */
 529        vrf_reset();
 530
 531        return netns_switch(netns);
 532}
 533
 534static int on_netns_exec(char *nsname, void *arg)
 535{
 536        char **argv = arg;
 537
 538        printf("\nnetns: %s\n", nsname);
 539        cmd_exec(argv[0], argv, true, do_switch, nsname);
 540        return 0;
 541}
 542
 543static int netns_exec(int argc, char **argv)
 544{
 545        /* Setup the proper environment for apps that are not netns
 546         * aware, and execute a program in that environment.
 547         */
 548        if (argc < 1 && !do_all) {
 549                fprintf(stderr, "No netns name specified\n");
 550                return -1;
 551        }
 552        if ((argc < 2 && !do_all) || (argc < 1 && do_all)) {
 553                fprintf(stderr, "No command specified\n");
 554                return -1;
 555        }
 556
 557        if (do_all)
 558                return netns_foreach(on_netns_exec, argv);
 559
 560        /* ip must return the status of the child,
 561         * but do_cmd() will add a minus to this,
 562         * so let's add another one here to cancel it.
 563         */
 564        return -cmd_exec(argv[1], argv + 1, !!batch_mode, do_switch, argv[0]);
 565}
 566
 567static int is_pid(const char *str)
 568{
 569        int ch;
 570
 571        for (; (ch = *str); str++) {
 572                if (!isdigit(ch))
 573                        return 0;
 574        }
 575        return 1;
 576}
 577
 578static int netns_pids(int argc, char **argv)
 579{
 580        const char *name;
 581        char net_path[PATH_MAX];
 582        int netns;
 583        struct stat netst;
 584        DIR *dir;
 585        struct dirent *entry;
 586
 587        if (argc < 1) {
 588                fprintf(stderr, "No netns name specified\n");
 589                return -1;
 590        }
 591        if (argc > 1) {
 592                fprintf(stderr, "extra arguments specified\n");
 593                return -1;
 594        }
 595
 596        name = argv[0];
 597        snprintf(net_path, sizeof(net_path), "%s/%s", NETNS_RUN_DIR, name);
 598        netns = open(net_path, O_RDONLY);
 599        if (netns < 0) {
 600                fprintf(stderr, "Cannot open network namespace: %s\n",
 601                        strerror(errno));
 602                return -1;
 603        }
 604        if (fstat(netns, &netst) < 0) {
 605                fprintf(stderr, "Stat of netns failed: %s\n",
 606                        strerror(errno));
 607                return -1;
 608        }
 609        dir = opendir("/proc/");
 610        if (!dir) {
 611                fprintf(stderr, "Open of /proc failed: %s\n",
 612                        strerror(errno));
 613                return -1;
 614        }
 615        while ((entry = readdir(dir))) {
 616                char pid_net_path[PATH_MAX];
 617                struct stat st;
 618
 619                if (!is_pid(entry->d_name))
 620                        continue;
 621                snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%s/ns/net",
 622                        entry->d_name);
 623                if (stat(pid_net_path, &st) != 0)
 624                        continue;
 625                if ((st.st_dev == netst.st_dev) &&
 626                    (st.st_ino == netst.st_ino)) {
 627                        printf("%s\n", entry->d_name);
 628                }
 629        }
 630        closedir(dir);
 631        return 0;
 632
 633}
 634
 635int netns_identify_pid(const char *pidstr, char *name, int len)
 636{
 637        char net_path[PATH_MAX];
 638        int netns;
 639        struct stat netst;
 640        DIR *dir;
 641        struct dirent *entry;
 642
 643        name[0] = '\0';
 644
 645        snprintf(net_path, sizeof(net_path), "/proc/%s/ns/net", pidstr);
 646        netns = open(net_path, O_RDONLY);
 647        if (netns < 0) {
 648                fprintf(stderr, "Cannot open network namespace: %s\n",
 649                        strerror(errno));
 650                return -1;
 651        }
 652        if (fstat(netns, &netst) < 0) {
 653                fprintf(stderr, "Stat of netns failed: %s\n",
 654                        strerror(errno));
 655                return -1;
 656        }
 657        dir = opendir(NETNS_RUN_DIR);
 658        if (!dir) {
 659                /* Succeed treat a missing directory as an empty directory */
 660                if (errno == ENOENT)
 661                        return 0;
 662
 663                fprintf(stderr, "Failed to open directory %s:%s\n",
 664                        NETNS_RUN_DIR, strerror(errno));
 665                return -1;
 666        }
 667
 668        while ((entry = readdir(dir))) {
 669                char name_path[PATH_MAX];
 670                struct stat st;
 671
 672                if (strcmp(entry->d_name, ".") == 0)
 673                        continue;
 674                if (strcmp(entry->d_name, "..") == 0)
 675                        continue;
 676
 677                snprintf(name_path, sizeof(name_path), "%s/%s", NETNS_RUN_DIR,
 678                        entry->d_name);
 679
 680                if (stat(name_path, &st) != 0)
 681                        continue;
 682
 683                if ((st.st_dev == netst.st_dev) &&
 684                    (st.st_ino == netst.st_ino)) {
 685                        strlcpy(name, entry->d_name, len);
 686                }
 687        }
 688        closedir(dir);
 689        return 0;
 690
 691}
 692
 693static int netns_identify(int argc, char **argv)
 694{
 695        const char *pidstr;
 696        char name[256];
 697        int rc;
 698
 699        if (argc < 1) {
 700                pidstr = "self";
 701        } else if (argc > 1) {
 702                fprintf(stderr, "extra arguments specified\n");
 703                return -1;
 704        } else {
 705                pidstr = argv[0];
 706                if (!is_pid(pidstr)) {
 707                        fprintf(stderr, "Specified string '%s' is not a pid\n",
 708                                        pidstr);
 709                        return -1;
 710                }
 711        }
 712
 713        rc = netns_identify_pid(pidstr, name, sizeof(name));
 714        if (!rc)
 715                printf("%s\n", name);
 716
 717        return rc;
 718}
 719
 720static int on_netns_del(char *nsname, void *arg)
 721{
 722        char netns_path[PATH_MAX];
 723
 724        snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, nsname);
 725        umount2(netns_path, MNT_DETACH);
 726        if (unlink(netns_path) < 0) {
 727                fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
 728                        netns_path, strerror(errno));
 729                return -1;
 730        }
 731        return 0;
 732}
 733
 734static int netns_delete(int argc, char **argv)
 735{
 736        if (argc < 1 && !do_all) {
 737                fprintf(stderr, "No netns name specified\n");
 738                return -1;
 739        }
 740
 741        if (do_all)
 742                return netns_foreach(on_netns_del, NULL);
 743
 744        return on_netns_del(argv[0], NULL);
 745}
 746
 747static int create_netns_dir(void)
 748{
 749        /* Create the base netns directory if it doesn't exist */
 750        if (mkdir(NETNS_RUN_DIR, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH)) {
 751                if (errno != EEXIST) {
 752                        fprintf(stderr, "mkdir %s failed: %s\n",
 753                                NETNS_RUN_DIR, strerror(errno));
 754                        return -1;
 755                }
 756        }
 757
 758        return 0;
 759}
 760
 761/* Obtain a FD for the current namespace, so we can reenter it later */
 762static void netns_save(void)
 763{
 764        if (saved_netns != -1)
 765                return;
 766
 767        saved_netns = open("/proc/self/ns/net", O_RDONLY | O_CLOEXEC);
 768        if (saved_netns == -1) {
 769                perror("Cannot open init namespace");
 770                exit(1);
 771        }
 772}
 773
 774static void netns_restore(void)
 775{
 776        if (saved_netns == -1)
 777                return;
 778
 779        if (setns(saved_netns, CLONE_NEWNET)) {
 780                perror("setns");
 781                exit(1);
 782        }
 783
 784        close(saved_netns);
 785        saved_netns = -1;
 786}
 787
 788static int netns_add(int argc, char **argv, bool create)
 789{
 790        /* This function creates a new network namespace and
 791         * a new mount namespace and bind them into a well known
 792         * location in the filesystem based on the name provided.
 793         *
 794         * If create is true, a new namespace will be created,
 795         * otherwise an existing one will be attached to the file.
 796         *
 797         * The mount namespace is created so that any necessary
 798         * userspace tweaks like remounting /sys, or bind mounting
 799         * a new /etc/resolv.conf can be shared between users.
 800         */
 801        char netns_path[PATH_MAX], proc_path[PATH_MAX];
 802        const char *name;
 803        pid_t pid;
 804        int fd;
 805        int lock;
 806        int made_netns_run_dir_mount = 0;
 807
 808        if (create) {
 809                if (argc < 1) {
 810                        fprintf(stderr, "No netns name specified\n");
 811                        return -1;
 812                }
 813        } else {
 814                if (argc < 2) {
 815                        fprintf(stderr, "No netns name and PID specified\n");
 816                        return -1;
 817                }
 818
 819                if (get_s32(&pid, argv[1], 0) || !pid) {
 820                        fprintf(stderr, "Invalid PID: %s\n", argv[1]);
 821                        return -1;
 822                }
 823        }
 824        name = argv[0];
 825
 826        snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
 827
 828        if (create_netns_dir())
 829                return -1;
 830
 831        /* Make it possible for network namespace mounts to propagate between
 832         * mount namespaces.  This makes it likely that a unmounting a network
 833         * namespace file in one namespace will unmount the network namespace
 834         * file in all namespaces allowing the network namespace to be freed
 835         * sooner.
 836         * These setup steps need to happen only once, as if multiple ip processes
 837         * try to attempt the same operation at the same time, the mountpoints will
 838         * be recursively created multiple times, eventually causing the system
 839         * to lock up. For example, this has been observed when multiple netns
 840         * namespaces are created in parallel at boot. See:
 841         * https://bugs.debian.org/949235
 842         * Try to take an exclusive file lock on the top level directory to ensure
 843         * this cannot happen, but proceed nonetheless if it cannot happen for any
 844         * reason.
 845         */
 846        lock = open(NETNS_RUN_DIR, O_RDONLY|O_DIRECTORY, 0);
 847        if (lock < 0) {
 848                fprintf(stderr, "Cannot open netns runtime directory \"%s\": %s\n",
 849                        NETNS_RUN_DIR, strerror(errno));
 850                return -1;
 851        }
 852        if (flock(lock, LOCK_EX) < 0) {
 853                fprintf(stderr, "Warning: could not flock netns runtime directory \"%s\": %s\n",
 854                        NETNS_RUN_DIR, strerror(errno));
 855                close(lock);
 856                lock = -1;
 857        }
 858        while (mount("", NETNS_RUN_DIR, "none", MS_SHARED | MS_REC, NULL)) {
 859                /* Fail unless we need to make the mount point */
 860                if (errno != EINVAL || made_netns_run_dir_mount) {
 861                        fprintf(stderr, "mount --make-shared %s failed: %s\n",
 862                                NETNS_RUN_DIR, strerror(errno));
 863                        if (lock != -1) {
 864                                flock(lock, LOCK_UN);
 865                                close(lock);
 866                        }
 867                        return -1;
 868                }
 869
 870                /* Upgrade NETNS_RUN_DIR to a mount point */
 871                if (mount(NETNS_RUN_DIR, NETNS_RUN_DIR, "none", MS_BIND | MS_REC, NULL)) {
 872                        fprintf(stderr, "mount --bind %s %s failed: %s\n",
 873                                NETNS_RUN_DIR, NETNS_RUN_DIR, strerror(errno));
 874                        if (lock != -1) {
 875                                flock(lock, LOCK_UN);
 876                                close(lock);
 877                        }
 878                        return -1;
 879                }
 880                made_netns_run_dir_mount = 1;
 881        }
 882        if (lock != -1) {
 883                flock(lock, LOCK_UN);
 884                close(lock);
 885        }
 886
 887        /* Create the filesystem state */
 888        fd = open(netns_path, O_RDONLY|O_CREAT|O_EXCL, 0);
 889        if (fd < 0) {
 890                fprintf(stderr, "Cannot create namespace file \"%s\": %s\n",
 891                        netns_path, strerror(errno));
 892                return -1;
 893        }
 894        close(fd);
 895
 896        if (create) {
 897                netns_save();
 898                if (unshare(CLONE_NEWNET) < 0) {
 899                        fprintf(stderr, "Failed to create a new network namespace \"%s\": %s\n",
 900                                name, strerror(errno));
 901                        goto out_delete;
 902                }
 903
 904                strcpy(proc_path, "/proc/self/ns/net");
 905        } else {
 906                snprintf(proc_path, sizeof(proc_path), "/proc/%d/ns/net", pid);
 907        }
 908
 909        /* Bind the netns last so I can watch for it */
 910        if (mount(proc_path, netns_path, "none", MS_BIND, NULL) < 0) {
 911                fprintf(stderr, "Bind %s -> %s failed: %s\n",
 912                        proc_path, netns_path, strerror(errno));
 913                goto out_delete;
 914        }
 915        netns_restore();
 916
 917        return 0;
 918out_delete:
 919        if (create) {
 920                netns_restore();
 921                netns_delete(argc, argv);
 922        } else if (unlink(netns_path) < 0) {
 923                fprintf(stderr, "Cannot remove namespace file \"%s\": %s\n",
 924                        netns_path, strerror(errno));
 925        }
 926        return -1;
 927}
 928
 929int set_netnsid_from_name(const char *name, int nsid)
 930{
 931        struct {
 932                struct nlmsghdr n;
 933                struct rtgenmsg g;
 934                char            buf[1024];
 935        } req = {
 936                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtgenmsg)),
 937                .n.nlmsg_flags = NLM_F_REQUEST,
 938                .n.nlmsg_type = RTM_NEWNSID,
 939                .g.rtgen_family = AF_UNSPEC,
 940        };
 941        int fd, err = 0;
 942
 943        netns_nsid_socket_init();
 944
 945        fd = netns_get_fd(name);
 946        if (fd < 0)
 947                return fd;
 948
 949        addattr32(&req.n, 1024, NETNSA_FD, fd);
 950        addattr32(&req.n, 1024, NETNSA_NSID, nsid);
 951        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 952                err = -2;
 953
 954        close(fd);
 955        return err;
 956}
 957
 958static int netns_set(int argc, char **argv)
 959{
 960        char netns_path[PATH_MAX];
 961        const char *name;
 962        int netns, nsid;
 963
 964        if (argc < 1) {
 965                fprintf(stderr, "No netns name specified\n");
 966                return -1;
 967        }
 968        if (argc < 2) {
 969                fprintf(stderr, "No nsid specified\n");
 970                return -1;
 971        }
 972        name = argv[0];
 973        /* If a negative nsid is specified the kernel will select the nsid. */
 974        if (strcmp(argv[1], "auto") == 0)
 975                nsid = -1;
 976        else if (get_integer(&nsid, argv[1], 0))
 977                invarg("Invalid \"netnsid\" value", argv[1]);
 978        else if (nsid < 0)
 979                invarg("\"netnsid\" value should be >= 0", argv[1]);
 980
 981        snprintf(netns_path, sizeof(netns_path), "%s/%s", NETNS_RUN_DIR, name);
 982        netns = open(netns_path, O_RDONLY | O_CLOEXEC);
 983        if (netns < 0) {
 984                fprintf(stderr, "Cannot open network namespace \"%s\": %s\n",
 985                        name, strerror(errno));
 986                return -1;
 987        }
 988
 989        return set_netnsid_from_name(name, nsid);
 990}
 991
 992static int netns_monitor(int argc, char **argv)
 993{
 994        char buf[4096];
 995        struct inotify_event *event;
 996        int fd;
 997
 998        fd = inotify_init();
 999        if (fd < 0) {
1000                fprintf(stderr, "inotify_init failed: %s\n",
1001                        strerror(errno));
1002                return -1;
1003        }
1004
1005        if (create_netns_dir())
1006                return -1;
1007
1008        if (inotify_add_watch(fd, NETNS_RUN_DIR, IN_CREATE | IN_DELETE) < 0) {
1009                fprintf(stderr, "inotify_add_watch failed: %s\n",
1010                        strerror(errno));
1011                return -1;
1012        }
1013        for (;;) {
1014                ssize_t len = read(fd, buf, sizeof(buf));
1015
1016                if (len < 0) {
1017                        fprintf(stderr, "read failed: %s\n",
1018                                strerror(errno));
1019                        return -1;
1020                }
1021                for (event = (struct inotify_event *)buf;
1022                     (char *)event < &buf[len];
1023                     event = (struct inotify_event *)((char *)event + sizeof(*event) + event->len)) {
1024                        if (event->mask & IN_CREATE)
1025                                printf("add %s\n", event->name);
1026                        if (event->mask & IN_DELETE)
1027                                printf("delete %s\n", event->name);
1028                }
1029        }
1030        return 0;
1031}
1032
1033static int invalid_name(const char *name)
1034{
1035        return !*name || strlen(name) > NAME_MAX ||
1036                strchr(name, '/') || !strcmp(name, ".") || !strcmp(name, "..");
1037}
1038
1039int do_netns(int argc, char **argv)
1040{
1041        netns_nsid_socket_init();
1042
1043        if (argc < 1) {
1044                netns_map_init();
1045                return netns_list(0, NULL);
1046        }
1047
1048        if (!do_all && argc > 1 && invalid_name(argv[1])) {
1049                fprintf(stderr, "Invalid netns name \"%s\"\n", argv[1]);
1050                exit(-1);
1051        }
1052
1053        if ((matches(*argv, "list") == 0) || (matches(*argv, "show") == 0) ||
1054            (matches(*argv, "lst") == 0)) {
1055                netns_map_init();
1056                return netns_list(argc-1, argv+1);
1057        }
1058
1059        if ((matches(*argv, "list-id") == 0)) {
1060                netns_map_init();
1061                return netns_list_id(argc-1, argv+1);
1062        }
1063
1064        if (matches(*argv, "help") == 0)
1065                return usage();
1066
1067        if (matches(*argv, "add") == 0)
1068                return netns_add(argc-1, argv+1, true);
1069
1070        if (matches(*argv, "set") == 0)
1071                return netns_set(argc-1, argv+1);
1072
1073        if (matches(*argv, "delete") == 0)
1074                return netns_delete(argc-1, argv+1);
1075
1076        if (matches(*argv, "identify") == 0)
1077                return netns_identify(argc-1, argv+1);
1078
1079        if (matches(*argv, "pids") == 0)
1080                return netns_pids(argc-1, argv+1);
1081
1082        if (matches(*argv, "exec") == 0)
1083                return netns_exec(argc-1, argv+1);
1084
1085        if (matches(*argv, "monitor") == 0)
1086                return netns_monitor(argc-1, argv+1);
1087
1088        if (matches(*argv, "attach") == 0)
1089                return netns_add(argc-1, argv+1, false);
1090
1091        fprintf(stderr, "Command \"%s\" is unknown, try \"ip netns help\".\n", *argv);
1092        exit(-1);
1093}
1094