]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_user_nic.c
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #define _GNU_SOURCE /* See feature_test_macros(7) */
24 #include <sys/types.h>
33 #include <sys/socket.h>
37 #include <sys/ioctl.h>
38 #include <linux/netlink.h>
39 #include <arpa/inet.h>
41 #include <net/if_arp.h>
42 #include <netinet/in.h>
43 #include <linux/if_bridge.h>
44 #include <linux/netlink.h>
45 #include <linux/rtnetlink.h>
46 #include <linux/sockios.h>
47 #include <sys/param.h>
53 #define CONF_FILE "/tmp/lxc-usernet"
54 #define DB_FILE "/tmp/nics"
56 #define CONF_FILE LXC_USERNIC_CONF
57 #define DB_FILE LXC_USERNIC_DB
63 # define IFLA_LINKMODE 17
67 # define IFLA_LINKINFO 18
70 #ifndef IFLA_NET_NS_PID
71 # define IFLA_NET_NS_PID 19
74 #ifndef IFLA_INFO_KIND
75 # define IFLA_INFO_KIND 1
79 # define IFLA_VLAN_ID 1
82 #ifndef IFLA_INFO_DATA
83 # define IFLA_INFO_DATA 2
86 #ifndef VETH_INFO_PEER
87 # define VETH_INFO_PEER 1
90 #ifndef IFLA_MACVLAN_MODE
91 # define IFLA_MACVLAN_MODE 1
94 void usage(char *me
, bool fail
)
96 fprintf(stderr
, "Usage: %s pid type bridge nicname\n", me
);
97 fprintf(stderr
, " nicname is the name to use inside the container\n");
101 static int open_and_lock(char *path
)
106 fd
= open(path
, O_RDWR
|O_CREAT
, S_IWUSR
| S_IRUSR
);
108 fprintf(stderr
, "Failed to open %s: %s\n",
109 path
, strerror(errno
));
114 lk
.l_whence
= SEEK_SET
;
117 if (fcntl(fd
, F_SETLKW
, &lk
) < 0) {
118 fprintf(stderr
, "Failed to lock %s: %s\n",
119 path
, strerror(errno
));
127 static char *get_username(void)
129 struct passwd
*pwd
= getpwuid(getuid());
139 /* The configuration file consists of lines of the form:
141 * user type bridge count
143 * Return the count entry for the calling user if there is one. Else
146 static int get_alloted(char *me
, char *intype
, char *link
)
148 FILE *fin
= fopen(CONF_FILE
, "r");
150 char user
[100], type
[100], br
[100];
155 fprintf(stderr
, "Failed to open %s: %s\n", CONF_FILE
,
160 while ((getline(&line
, &len
, fin
)) != -1) {
161 ret
= sscanf(line
, "%99[^ \t] %99[^ \t] %99[^ \t] %d", user
, type
, br
, &n
);
165 if (strcmp(user
, me
) != 0)
167 if (strcmp(type
, intype
) != 0)
169 if (strcmp(link
, br
) != 0)
181 static char *get_eol(char *s
)
183 while (*s
&& *s
!= '\n')
188 static char *get_eow(char *s
)
190 while (*s
&& !isblank(*s
) && *s
!= '\n')
195 static char *find_line(char *p
, char *e
, char *u
, char *t
, char *l
)
199 while (p
< e
&& (p1
= get_eol(p
)) < e
) {
203 while (isblank(*p
)) p
++;
205 if (!p2
|| p2
-p
!= strlen(u
) || strncmp(p
, u
, strlen(u
)) != 0)
208 while (isblank(*p
)) p
++;
210 if (!p2
|| p2
-p
!= strlen(t
) || strncmp(p
, t
, strlen(t
)) != 0)
213 while (isblank(*p
)) p
++;
215 if (!p2
|| p2
-p
!= strlen(l
) || strncmp(p
, l
, strlen(l
)) != 0)
225 static bool nic_exists(char *nic
)
227 char path
[MAXPATHLEN
];
232 ret
= snprintf(path
, MAXPATHLEN
, "/tmp/lxcnettest/%s", nic
);
234 ret
= snprintf(path
, MAXPATHLEN
, "/sys/class/net/%s", nic
);
236 if (ret
< 0 || ret
>= MAXPATHLEN
) // should never happen!
238 ret
= stat(path
, &sb
);
246 struct ifinfomsg ifinfomsg
;
251 static int lxc_veth_create(const char *name1
, const char *name2
)
253 struct nl_handler nlh
;
254 struct nlmsg
*nlmsg
= NULL
, *answer
= NULL
;
255 struct link_req
*link_req
;
256 struct rtattr
*nest1
, *nest2
, *nest3
;
259 err
= netlink_open(&nlh
, NETLINK_ROUTE
);
265 if (len
== 1 || len
>= IFNAMSIZ
)
269 if (len
== 1 || len
>= IFNAMSIZ
)
273 nlmsg
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
277 answer
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
281 link_req
= (struct link_req
*)nlmsg
;
282 link_req
->ifinfomsg
.ifi_family
= AF_UNSPEC
;
283 nlmsg
->nlmsghdr
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
284 nlmsg
->nlmsghdr
.nlmsg_flags
=
285 NLM_F_REQUEST
|NLM_F_CREATE
|NLM_F_EXCL
|NLM_F_ACK
;
286 nlmsg
->nlmsghdr
.nlmsg_type
= RTM_NEWLINK
;
289 nest1
= nla_begin_nested(nlmsg
, IFLA_LINKINFO
);
293 if (nla_put_string(nlmsg
, IFLA_INFO_KIND
, "veth"))
296 nest2
= nla_begin_nested(nlmsg
, IFLA_INFO_DATA
);
300 nest3
= nla_begin_nested(nlmsg
, VETH_INFO_PEER
);
304 nlmsg
->nlmsghdr
.nlmsg_len
+= sizeof(struct ifinfomsg
);
306 if (nla_put_string(nlmsg
, IFLA_IFNAME
, name2
))
309 nla_end_nested(nlmsg
, nest3
);
311 nla_end_nested(nlmsg
, nest2
);
313 nla_end_nested(nlmsg
, nest1
);
315 if (nla_put_string(nlmsg
, IFLA_IFNAME
, name1
))
318 err
= netlink_transaction(&nlh
, nlmsg
, answer
);
326 static int lxc_netdev_move(char *ifname
, pid_t pid
)
328 struct nl_handler nlh
;
329 struct nlmsg
*nlmsg
= NULL
;
330 struct link_req
*link_req
;
333 index
= if_nametoindex(ifname
);
337 err
= netlink_open(&nlh
, NETLINK_ROUTE
);
342 nlmsg
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
346 link_req
= (struct link_req
*)nlmsg
;
347 link_req
->ifinfomsg
.ifi_family
= AF_UNSPEC
;
348 link_req
->ifinfomsg
.ifi_index
= index
;
349 nlmsg
->nlmsghdr
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
350 nlmsg
->nlmsghdr
.nlmsg_flags
= NLM_F_REQUEST
|NLM_F_ACK
;
351 nlmsg
->nlmsghdr
.nlmsg_type
= RTM_NEWLINK
;
353 if (nla_put_u32(nlmsg
, IFLA_NET_NS_PID
, pid
))
356 err
= netlink_transaction(&nlh
, nlmsg
, nlmsg
);
363 static int setup_private_host_hw_addr(char *veth1
)
369 sockfd
= socket(AF_INET
, SOCK_DGRAM
, 0);
373 snprintf((char *)ifr
.ifr_name
, IFNAMSIZ
, "%s", veth1
);
374 err
= ioctl(sockfd
, SIOCGIFHWADDR
, &ifr
);
380 ifr
.ifr_hwaddr
.sa_data
[0] = 0xfe;
381 err
= ioctl(sockfd
, SIOCSIFHWADDR
, &ifr
);
389 static int netdev_set_flag(const char *name
, int flag
)
391 struct nl_handler nlh
;
392 struct nlmsg
*nlmsg
= NULL
, *answer
= NULL
;
393 struct link_req
*link_req
;
396 err
= netlink_open(&nlh
, NETLINK_ROUTE
);
402 if (len
== 1 || len
>= IFNAMSIZ
)
406 nlmsg
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
410 answer
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
415 index
= if_nametoindex(name
);
419 link_req
= (struct link_req
*)nlmsg
;
420 link_req
->ifinfomsg
.ifi_family
= AF_UNSPEC
;
421 link_req
->ifinfomsg
.ifi_index
= index
;
422 link_req
->ifinfomsg
.ifi_change
|= IFF_UP
;
423 link_req
->ifinfomsg
.ifi_flags
|= flag
;
424 nlmsg
->nlmsghdr
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
425 nlmsg
->nlmsghdr
.nlmsg_flags
= NLM_F_REQUEST
|NLM_F_ACK
;
426 nlmsg
->nlmsghdr
.nlmsg_type
= RTM_NEWLINK
;
428 err
= netlink_transaction(&nlh
, nlmsg
, answer
);
436 static int instanciate_veth(char *n1
, char **n2
)
440 err
= snprintf(*n2
, IFNAMSIZ
, "%sp", n1
);
441 if (err
< 0 || err
>= IFNAMSIZ
) {
442 fprintf(stderr
, "nic name too long\n");
446 err
= lxc_veth_create(n1
, *n2
);
448 fprintf(stderr
, "failed to create %s-%s : %s\n", n1
, *n2
,
453 /* changing the high byte of the mac address to 0xfe, the bridge interface
454 * will always keep the host's mac address and not take the mac address
456 err
= setup_private_host_hw_addr(n1
);
458 fprintf(stderr
, "failed to change mac address of host interface '%s' : %s",
462 return netdev_set_flag(n1
, IFF_UP
);
465 static int lxc_bridge_attach(const char *bridge
, const char *ifname
)
470 if (strlen(ifname
) >= IFNAMSIZ
)
473 index
= if_nametoindex(ifname
);
477 fd
= socket(AF_INET
, SOCK_STREAM
, 0);
481 strncpy(ifr
.ifr_name
, bridge
, IFNAMSIZ
-1);
482 ifr
.ifr_name
[IFNAMSIZ
-1] = '\0';
483 ifr
.ifr_ifindex
= index
;
484 err
= ioctl(fd
, SIOCBRADDIF
, &ifr
);
492 static int lxc_netdev_delete_by_index(int ifindex
)
494 struct nl_handler nlh
;
495 struct nlmsg
*nlmsg
= NULL
, *answer
= NULL
;
496 struct link_req
*link_req
;
499 err
= netlink_open(&nlh
, NETLINK_ROUTE
);
504 nlmsg
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
508 answer
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
512 link_req
= (struct link_req
*)nlmsg
;
513 link_req
->ifinfomsg
.ifi_family
= AF_UNSPEC
;
514 link_req
->ifinfomsg
.ifi_index
= ifindex
;
515 nlmsg
->nlmsghdr
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
516 nlmsg
->nlmsghdr
.nlmsg_flags
= NLM_F_ACK
|NLM_F_REQUEST
;
517 nlmsg
->nlmsghdr
.nlmsg_type
= RTM_DELLINK
;
519 err
= netlink_transaction(&nlh
, nlmsg
, answer
);
527 static int lxc_netdev_delete_by_name(const char *name
)
531 index
= if_nametoindex(name
);
535 return lxc_netdev_delete_by_index(index
);
538 static int lxc_netdev_delete_by_name(const char *name
)
541 sprintf(path
, "/tmp/lxcnettest/%s", name
);
547 static bool create_nic(char *nic
, char *br
, int pid
, char **cnic
)
551 sprintf(path
, "/tmp/lxcnettest/%s", nic
);
552 int fd
= open(path
, O_RDWR
|O_CREAT
, S_IWUSR
| S_IRUSR
);
558 char *veth1buf
, *veth2buf
;
559 veth1buf
= alloca(IFNAMSIZ
);
560 veth2buf
= alloca(IFNAMSIZ
);
563 ret
= snprintf(veth1buf
, IFNAMSIZ
, "%s", nic
);
564 if (ret
< 0 || ret
>= IFNAMSIZ
) {
565 fprintf(stderr
, "host nic name too long\n");
569 /* create the nics */
570 if (instanciate_veth(veth1buf
, &veth2buf
) < 0) {
571 fprintf(stderr
, "Error creating veth tunnel\n");
575 /* attach veth1 to bridge */
576 if (lxc_bridge_attach(br
, veth1buf
) < 0) {
577 fprintf(stderr
, "Error attaching %s to %s\n", veth1buf
, br
);
581 /* pass veth2 to target netns */
582 ret
= lxc_netdev_move(veth2buf
, pid
);
584 fprintf(stderr
, "Error moving %s to netns %d\n", veth2buf
, pid
);
587 *cnic
= strdup(veth2buf
);
591 lxc_netdev_delete_by_name(veth1buf
);
598 * *dest will container the name (lxcuser-%d) which is attached
599 * on the host to the lxc bridge
601 static void get_new_nicname(char **dest
, char *br
, int pid
, char **cnic
)
604 // TODO - speed this up. For large installations we won't
605 // want n stats for every nth container startup.
607 sprintf(*dest
, "lxcuser-%d", i
);
608 if (!nic_exists(*dest
) && create_nic(*dest
, br
, pid
, cnic
))
614 static bool get_nic_from_line(char *p
, char **nic
)
616 char user
[100], type
[100], br
[100];
619 ret
= sscanf(p
, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user
, type
, br
, *nic
);
625 static bool cull_entries(int fd
, char *me
, char *t
, char *br
)
628 char *buf
, *p
, *e
, *nic
;
637 buf
= mmap(NULL
, len
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
638 if (buf
== MAP_FAILED
) {
639 fprintf(stderr
, "Failed to create mapping: %s\n", strerror(errno
));
645 while ((p
= find_line(p
, e
, me
, t
, br
)) != NULL
) {
646 if (!get_nic_from_line(p
, &nic
))
648 if (nic
&& !nic_exists(nic
)) {
649 // copy from eol(p)+1..e to p
650 char *src
= get_eol(p
) + 1, *dest
= p
;
653 *(dest
++) = *(src
)++;
660 munmap(buf
, sb
.st_size
);
661 if (ftruncate(fd
, e
-buf
))
662 fprintf(stderr
, "Failed to set new file size\n");
666 static int count_entries(char *buf
, off_t len
, char *me
, char *t
, char *br
)
670 while ((buf
= find_line(buf
, e
, me
, t
, br
)) != NULL
) {
672 buf
= get_eol(buf
)+1;
681 * The dbfile has lines of the format:
682 * user type bridge nicname
684 static bool get_nic_if_avail(int fd
, char *me
, int pid
, char *intype
, char *br
, int allowed
, char **nicname
, char **cnic
)
688 char *buf
= NULL
, *newline
;
691 cull_entries(fd
, me
, intype
, br
);
696 buf
= mmap(NULL
, len
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
697 if (buf
== MAP_FAILED
) {
698 fprintf(stderr
, "Failed to create mapping\n");
702 count
= count_entries(buf
, len
, me
, intype
, br
);
703 if (count
>= allowed
)
708 get_new_nicname(nicname
, br
, pid
, cnic
);
709 /* me ' ' intype ' ' br ' ' *nicname + '\n' + '\0' */
710 slen
= strlen(me
) + strlen(intype
) + strlen(br
) + strlen(*nicname
) + 5;
711 newline
= alloca(slen
);
712 ret
= snprintf(newline
, slen
, "%s %s %s %s\n", me
, intype
, br
, *nicname
);
713 if (ret
< 0 || ret
>= slen
) {
714 if (lxc_netdev_delete_by_name(*nicname
) != 0)
715 fprintf(stderr
, "Error unlinking %s!\n", *nicname
);
720 if (ftruncate(fd
, len
+ slen
))
721 fprintf(stderr
, "Failed to set new file size\n");
722 buf
= mmap(NULL
, len
+ slen
, PROT_READ
|PROT_WRITE
, MAP_SHARED
, fd
, 0);
723 if (buf
== MAP_FAILED
) {
724 fprintf(stderr
, "Failed to create mapping after extending: %s\n", strerror(errno
));
725 if (lxc_netdev_delete_by_name(*nicname
) != 0)
726 fprintf(stderr
, "Error unlinking %s!\n", *nicname
);
729 strcpy(buf
+len
, newline
);
730 munmap(buf
, len
+slen
);
734 static bool create_db_dir(char *fnam
)
736 char *p
= alloca(strlen(fnam
)+1);
742 while (*p
&& *p
!= '/') p
++;
746 if (mkdir(fnam
, 0755) && errno
!= EEXIST
) {
747 fprintf(stderr
, "failed to create %s\n", fnam
);
755 static int lxc_netdev_rename_by_index(int ifindex
, const char *newname
)
757 struct nl_handler nlh
;
758 struct nlmsg
*nlmsg
= NULL
, *answer
= NULL
;
759 struct link_req
*link_req
;
762 err
= netlink_open(&nlh
, NETLINK_ROUTE
);
766 len
= strlen(newname
);
767 if (len
== 1 || len
>= IFNAMSIZ
)
771 nlmsg
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
775 answer
= nlmsg_alloc(NLMSG_GOOD_SIZE
);
779 link_req
= (struct link_req
*)nlmsg
;
780 link_req
->ifinfomsg
.ifi_family
= AF_UNSPEC
;
781 link_req
->ifinfomsg
.ifi_index
= ifindex
;
782 nlmsg
->nlmsghdr
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct ifinfomsg
));
783 nlmsg
->nlmsghdr
.nlmsg_flags
= NLM_F_ACK
|NLM_F_REQUEST
;
784 nlmsg
->nlmsghdr
.nlmsg_type
= RTM_NEWLINK
;
786 if (nla_put_string(nlmsg
, IFLA_IFNAME
, newname
))
789 err
= netlink_transaction(&nlh
, nlmsg
, answer
);
797 static int lxc_netdev_rename_by_name(const char *oldname
, const char *newname
)
801 len
= strlen(oldname
);
802 if (len
== 1 || len
>= IFNAMSIZ
)
805 index
= if_nametoindex(oldname
);
807 fprintf(stderr
, "Error getting ifindex for %s\n", oldname
);
811 return lxc_netdev_rename_by_index(index
, newname
);
814 static int rename_in_ns(int pid
, char *oldname
, char *newname
)
816 char nspath
[MAXPATHLEN
];
817 int fd
= -1, ofd
= -1, ret
;
819 ret
= snprintf(nspath
, MAXPATHLEN
, "/proc/%d/ns/net", getpid());
820 if (ret
< 0 || ret
>= MAXPATHLEN
)
822 if ((ofd
= open(nspath
, O_RDONLY
)) < 0) {
823 fprintf(stderr
, "Opening %s\n", nspath
);
826 ret
= snprintf(nspath
, MAXPATHLEN
, "/proc/%d/ns/net", pid
);
827 if (ret
< 0 || ret
>= MAXPATHLEN
)
830 if ((fd
= open(nspath
, O_RDONLY
)) < 0) {
831 fprintf(stderr
, "Opening %s\n", nspath
);
834 if (setns(fd
, 0) < 0) {
835 fprintf(stderr
, "setns to container network namespace\n");
839 if ((ret
= lxc_netdev_rename_by_name(oldname
, newname
)) < 0) {
840 fprintf(stderr
, "Error %d renaming netdev %s to %s in container\n", ret
, oldname
, newname
);
843 if (setns(ofd
, 0) < 0) {
844 fprintf(stderr
, "Error returning to original netns\n");
855 if (setns(ofd
, 0) < 0)
856 fprintf(stderr
, "Error returning to original network namespace\n");
863 * If the caller (real uid, not effective uid) may read the
864 * /proc/pid/net/ns, then it is either the caller's netns or one
867 static bool may_access_netns(int pid
)
871 uid_t ruid
, suid
, euid
;
872 bool may_access
= false;
874 ret
= getresuid(&ruid
, &euid
, &suid
);
876 fprintf(stderr
, "Failed to get my uids: %s\n", strerror(errno
));
879 ret
= setresuid(ruid
, ruid
, euid
);
881 fprintf(stderr
, "Failed to set temp uids to (%d,%d,%d): %s\n",
882 (int)ruid
, (int)ruid
, (int)euid
, strerror(errno
));
885 ret
= snprintf(s
, 200, "/proc/%d/ns/net", pid
);
886 if (ret
< 0 || ret
>= 200) // can't happen
888 ret
= access(s
, R_OK
);
890 fprintf(stderr
, "Uid %d may not access %s: %s\n",
891 (int)ruid
, s
, strerror(errno
));
893 may_access
= ret
== 0;
894 ret
= setresuid(ruid
, euid
, suid
);
896 fprintf(stderr
, "Failed to restore uids to (%d,%d,%d): %s\n",
897 (int)ruid
, (int)euid
, (int)suid
, strerror(errno
));
903 int main(int argc
, char *argv
[])
908 char *nicname
= alloca(40);
909 char *cnic
= NULL
; // created nic name in container is returned here.
913 if ((me
= get_username()) == NULL
) {
914 fprintf(stderr
, "Failed to get username\n");
919 usage(argv
[0], true);
926 pid
= (int) strtol(argv
[1], NULL
, 10);
928 fprintf(stderr
, "Could not read pid: %s\n", argv
[1]);
932 if (!create_db_dir(DB_FILE
)) {
933 fprintf(stderr
, "Failed to create directory for db file\n");
937 if ((fd
= open_and_lock(DB_FILE
)) < 0) {
938 fprintf(stderr
, "Failed to lock %s\n", DB_FILE
);
942 if (!may_access_netns(pid
)) {
943 fprintf(stderr
, "User %s may not modify netns for pid %d\n",
948 n
= get_alloted(me
, argv
[2], argv
[3]);
950 gotone
= get_nic_if_avail(fd
, me
, pid
, argv
[2], argv
[3], n
, &nicname
, &cnic
);
953 fprintf(stderr
, "Quota reached\n");
957 // Now rename the link
958 if (rename_in_ns(pid
, cnic
, vethname
) < 0) {
959 fprintf(stderr
, "Failed to rename the link\n");