]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_user_nic.c
lxc_user_nic: initialize cnic to NULL to please compiler
[mirror_lxc.git] / src / lxc / lxc_user_nic.c
1 /*
2 *
3 * Copyright © 2013 Serge Hallyn <serge.hallyn@ubuntu.com>.
4 * Copyright © 2013 Canonical Ltd.
5 *
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.
9 *
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.
14 *
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.
18 */
19
20 #define _GNU_SOURCE /* See feature_test_macros(7) */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <sys/types.h>
25 #include <pwd.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 #include <sys/file.h>
29 #include <alloca.h>
30 #include <string.h>
31 #include <sched.h>
32 #include <sys/mman.h>
33 #include <sys/socket.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <sys/stat.h>
37 #include <sys/ioctl.h>
38 #include <linux/netlink.h>
39 #include <arpa/inet.h>
40 #include <net/if.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>
48 #include <sched.h>
49 #include "config.h"
50 #include "utils.h"
51
52 #if ISTEST
53 #define CONF_FILE "/tmp/lxc-usernet"
54 #define DB_FILE "/tmp/nics"
55 #else
56 #define CONF_FILE LXC_USERNIC_CONF
57 #define DB_FILE LXC_USERNIC_DB
58 #endif
59
60 #include "nl.h"
61
62 #ifndef IFLA_LINKMODE
63 # define IFLA_LINKMODE 17
64 #endif
65
66 #ifndef IFLA_LINKINFO
67 # define IFLA_LINKINFO 18
68 #endif
69
70 #ifndef IFLA_NET_NS_PID
71 # define IFLA_NET_NS_PID 19
72 #endif
73
74 #ifndef IFLA_INFO_KIND
75 # define IFLA_INFO_KIND 1
76 #endif
77
78 #ifndef IFLA_VLAN_ID
79 # define IFLA_VLAN_ID 1
80 #endif
81
82 #ifndef IFLA_INFO_DATA
83 # define IFLA_INFO_DATA 2
84 #endif
85
86 #ifndef VETH_INFO_PEER
87 # define VETH_INFO_PEER 1
88 #endif
89
90 #ifndef IFLA_MACVLAN_MODE
91 # define IFLA_MACVLAN_MODE 1
92 #endif
93
94 void usage(char *me, bool fail)
95 {
96 fprintf(stderr, "Usage: %s pid type bridge nicname\n", me);
97 fprintf(stderr, " nicname is the name to use inside the container\n");
98 exit(fail ? 1 : 0);
99 }
100
101 static int open_and_lock(char *path)
102 {
103 int fd;
104 struct flock lk;
105
106 fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
107 if (fd < 0) {
108 fprintf(stderr, "Failed to open %s: %s\n",
109 path, strerror(errno));
110 return(fd);
111 }
112
113 lk.l_type = F_WRLCK;
114 lk.l_whence = SEEK_SET;
115 lk.l_start = 0;
116 lk.l_len = 0;
117 if (fcntl(fd, F_SETLKW, &lk) < 0) {
118 fprintf(stderr, "Failed to lock %s: %s\n",
119 path, strerror(errno));
120 return -1;
121 }
122
123 return fd;
124 }
125
126
127 static char *get_username(void)
128 {
129 struct passwd *pwd = getpwuid(getuid());
130
131 if (pwd == NULL) {
132 perror("getpwuid");
133 return NULL;
134 }
135
136 return pwd->pw_name;
137 }
138
139 /* The configuration file consists of lines of the form:
140 *
141 * user type bridge count
142 *
143 * Return the count entry for the calling user if there is one. Else
144 * return -1.
145 */
146 static int get_alloted(char *me, char *intype, char *link)
147 {
148 FILE *fin = fopen(CONF_FILE, "r");
149 char *line = NULL;
150 char user[100], type[100], br[100];
151 size_t len = 0;
152 int n = -1, ret;
153
154 if (!fin) {
155 fprintf(stderr, "Failed to open %s: %s\n", CONF_FILE,
156 strerror(errno));
157 return -1;
158 }
159
160 while ((getline(&line, &len, fin)) != -1) {
161 ret = sscanf(line, "%99[^ \t] %99[^ \t] %99[^ \t] %d", user, type, br, &n);
162
163 if (ret != 4)
164 continue;
165 if (strcmp(user, me) != 0)
166 continue;
167 if (strcmp(type, intype) != 0)
168 continue;
169 if (strcmp(link, br) != 0)
170 continue;
171 free(line);
172 fclose(fin);
173 return n;
174 }
175 fclose(fin);
176 if (line)
177 free(line);
178 return -1;
179 }
180
181 static char *get_eol(char *s)
182 {
183 while (*s && *s != '\n')
184 s++;
185 return s;
186 }
187
188 static char *get_eow(char *s)
189 {
190 while (*s && !isblank(*s) && *s != '\n')
191 s++;
192 return s;
193 }
194
195 static char *find_line(char *p, char *e, char *u, char *t, char *l)
196 {
197 char *p1, *p2, *ret;
198
199 while (p < e && (p1 = get_eol(p)) < e) {
200 ret = p;
201 if (*p == '#')
202 goto next;
203 while (isblank(*p)) p++;
204 p2 = get_eow(p);
205 if (!p2 || p2-p != strlen(u) || strncmp(p, u, strlen(u)) != 0)
206 goto next;
207 p = p2+1;
208 while (isblank(*p)) p++;
209 p2 = get_eow(p);
210 if (!p2 || p2-p != strlen(t) || strncmp(p, t, strlen(t)) != 0)
211 goto next;
212 p = p2+1;
213 while (isblank(*p)) p++;
214 p2 = get_eow(p);
215 if (!p2 || p2-p != strlen(l) || strncmp(p, l, strlen(l)) != 0)
216 goto next;
217 return ret;
218 next:
219 p = p1 + 1;
220 }
221
222 return NULL;
223 }
224
225 static bool nic_exists(char *nic)
226 {
227 char path[MAXPATHLEN];
228 int ret;
229 struct stat sb;
230
231 #if ISTEST
232 ret = snprintf(path, MAXPATHLEN, "/tmp/lxcnettest/%s", nic);
233 #else
234 ret = snprintf(path, MAXPATHLEN, "/sys/class/net/%s", nic);
235 #endif
236 if (ret < 0 || ret >= MAXPATHLEN) // should never happen!
237 return true;
238 ret = stat(path, &sb);
239 if (ret != 0)
240 return false;
241 return true;
242 }
243
244 struct link_req {
245 struct nlmsg nlmsg;
246 struct ifinfomsg ifinfomsg;
247 };
248
249 #if ! ISTEST
250
251 static int lxc_veth_create(const char *name1, const char *name2)
252 {
253 struct nl_handler nlh;
254 struct nlmsg *nlmsg = NULL, *answer = NULL;
255 struct link_req *link_req;
256 struct rtattr *nest1, *nest2, *nest3;
257 int len, err;
258
259 err = netlink_open(&nlh, NETLINK_ROUTE);
260 if (err)
261 return err;
262
263 err = -EINVAL;
264 len = strlen(name1);
265 if (len == 1 || len >= IFNAMSIZ)
266 goto out;
267
268 len = strlen(name2);
269 if (len == 1 || len >= IFNAMSIZ)
270 goto out;
271
272 err = -ENOMEM;
273 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
274 if (!nlmsg)
275 goto out;
276
277 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
278 if (!answer)
279 goto out;
280
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;
287
288 err = -EINVAL;
289 nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO);
290 if (!nest1)
291 goto out;
292
293 if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth"))
294 goto out;
295
296 nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA);
297 if (!nest2)
298 goto out;
299
300 nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER);
301 if (!nest3)
302 goto out;
303
304 nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg);
305
306 if (nla_put_string(nlmsg, IFLA_IFNAME, name2))
307 goto out;
308
309 nla_end_nested(nlmsg, nest3);
310
311 nla_end_nested(nlmsg, nest2);
312
313 nla_end_nested(nlmsg, nest1);
314
315 if (nla_put_string(nlmsg, IFLA_IFNAME, name1))
316 goto out;
317
318 err = netlink_transaction(&nlh, nlmsg, answer);
319 out:
320 netlink_close(&nlh);
321 nlmsg_free(answer);
322 nlmsg_free(nlmsg);
323 return err;
324 }
325
326 static int lxc_netdev_move(char *ifname, pid_t pid)
327 {
328 struct nl_handler nlh;
329 struct nlmsg *nlmsg = NULL;
330 struct link_req *link_req;
331 int err, index;
332
333 index = if_nametoindex(ifname);
334 if (!ifname)
335 return -EINVAL;
336
337 err = netlink_open(&nlh, NETLINK_ROUTE);
338 if (err)
339 return err;
340
341 err = -ENOMEM;
342 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
343 if (!nlmsg)
344 goto out;
345
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;
352
353 if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid))
354 goto out;
355
356 err = netlink_transaction(&nlh, nlmsg, nlmsg);
357 out:
358 netlink_close(&nlh);
359 nlmsg_free(nlmsg);
360 return err;
361 }
362
363 static int setup_private_host_hw_addr(char *veth1)
364 {
365 struct ifreq ifr;
366 int err;
367 int sockfd;
368
369 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
370 if (sockfd < 0)
371 return -errno;
372
373 snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
374 err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
375 if (err < 0) {
376 close(sockfd);
377 return -errno;
378 }
379
380 ifr.ifr_hwaddr.sa_data[0] = 0xfe;
381 err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
382 close(sockfd);
383 if (err < 0)
384 return -errno;
385
386 return 0;
387 }
388
389 static int netdev_set_flag(const char *name, int flag)
390 {
391 struct nl_handler nlh;
392 struct nlmsg *nlmsg = NULL, *answer = NULL;
393 struct link_req *link_req;
394 int index, len, err;
395
396 err = netlink_open(&nlh, NETLINK_ROUTE);
397 if (err)
398 return err;
399
400 err = -EINVAL;
401 len = strlen(name);
402 if (len == 1 || len >= IFNAMSIZ)
403 goto out;
404
405 err = -ENOMEM;
406 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
407 if (!nlmsg)
408 goto out;
409
410 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
411 if (!answer)
412 goto out;
413
414 err = -EINVAL;
415 index = if_nametoindex(name);
416 if (!index)
417 goto out;
418
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;
427
428 err = netlink_transaction(&nlh, nlmsg, answer);
429 out:
430 netlink_close(&nlh);
431 nlmsg_free(nlmsg);
432 nlmsg_free(answer);
433 return err;
434 }
435
436 static int instanciate_veth(char *n1, char **n2)
437 {
438 int err;
439
440 err = snprintf(*n2, IFNAMSIZ, "%sp", n1);
441 if (err < 0 || err >= IFNAMSIZ) {
442 fprintf(stderr, "nic name too long\n");
443 return -1;
444 }
445
446 err = lxc_veth_create(n1, *n2);
447 if (err) {
448 fprintf(stderr, "failed to create %s-%s : %s\n", n1, *n2,
449 strerror(-err));
450 return -1;
451 }
452
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
455 * of a container */
456 err = setup_private_host_hw_addr(n1);
457 if (err) {
458 fprintf(stderr, "failed to change mac address of host interface '%s' : %s",
459 n1, strerror(-err));
460 }
461
462 return netdev_set_flag(n1, IFF_UP);
463 }
464
465 static int lxc_bridge_attach(const char *bridge, const char *ifname)
466 {
467 int fd, index, err;
468 struct ifreq ifr;
469
470 if (strlen(ifname) >= IFNAMSIZ)
471 return -EINVAL;
472
473 index = if_nametoindex(ifname);
474 if (!index)
475 return -EINVAL;
476
477 fd = socket(AF_INET, SOCK_STREAM, 0);
478 if (fd < 0)
479 return -errno;
480
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);
485 close(fd);
486 if (err)
487 err = -errno;
488
489 return err;
490 }
491
492 static int lxc_netdev_delete_by_index(int ifindex)
493 {
494 struct nl_handler nlh;
495 struct nlmsg *nlmsg = NULL, *answer = NULL;
496 struct link_req *link_req;
497 int err;
498
499 err = netlink_open(&nlh, NETLINK_ROUTE);
500 if (err)
501 return err;
502
503 err = -ENOMEM;
504 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
505 if (!nlmsg)
506 goto out;
507
508 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
509 if (!answer)
510 goto out;
511
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;
518
519 err = netlink_transaction(&nlh, nlmsg, answer);
520 out:
521 netlink_close(&nlh);
522 nlmsg_free(answer);
523 nlmsg_free(nlmsg);
524 return err;
525 }
526
527 static int lxc_netdev_delete_by_name(const char *name)
528 {
529 int index;
530
531 index = if_nametoindex(name);
532 if (!index)
533 return -EINVAL;
534
535 return lxc_netdev_delete_by_index(index);
536 }
537 #else
538 static int lxc_netdev_delete_by_name(const char *name)
539 {
540 char path[200];
541 sprintf(path, "/tmp/lxcnettest/%s", name);
542 return unlink(path);
543 }
544
545 #endif
546
547 static bool create_nic(char *nic, char *br, int pid, char **cnic)
548 {
549 #if ISTEST
550 char path[200];
551 sprintf(path, "/tmp/lxcnettest/%s", nic);
552 int fd = open(path, O_RDWR|O_CREAT, S_IWUSR | S_IRUSR);
553 if (fd < 0)
554 return false;
555 close(fd);
556 return true;
557 #else
558 char *veth1buf, *veth2buf;
559 veth1buf = alloca(IFNAMSIZ);
560 veth2buf = alloca(IFNAMSIZ);
561 int ret;
562
563 ret = snprintf(veth1buf, IFNAMSIZ, "%s", nic);
564 if (ret < 0 || ret >= IFNAMSIZ) {
565 fprintf(stderr, "host nic name too long\n");
566 return false;
567 }
568
569 /* create the nics */
570 if (instanciate_veth(veth1buf, &veth2buf) < 0) {
571 fprintf(stderr, "Error creating veth tunnel\n");
572 return false;
573 }
574
575 /* attach veth1 to bridge */
576 if (lxc_bridge_attach(br, veth1buf) < 0) {
577 fprintf(stderr, "Error attaching %s to %s\n", veth1buf, br);
578 goto out_del;
579 }
580
581 /* pass veth2 to target netns */
582 ret = lxc_netdev_move(veth2buf, pid);
583 if (ret < 0) {
584 fprintf(stderr, "Error moving %s to netns %d\n", veth2buf, pid);
585 goto out_del;
586 }
587 *cnic = strdup(veth2buf);
588 return true;
589
590 out_del:
591 lxc_netdev_delete_by_name(veth1buf);
592 return false;
593 #endif
594 }
595
596 /*
597 * Get a new nic.
598 * *dest will container the name (lxcuser-%d) which is attached
599 * on the host to the lxc bridge
600 */
601 static void get_new_nicname(char **dest, char *br, int pid, char **cnic)
602 {
603 int i = 0;
604 // TODO - speed this up. For large installations we won't
605 // want n stats for every nth container startup.
606 while (1) {
607 sprintf(*dest, "lxcuser-%d", i);
608 if (!nic_exists(*dest) && create_nic(*dest, br, pid, cnic))
609 return;
610 i++;
611 }
612 }
613
614 static bool get_nic_from_line(char *p, char **nic)
615 {
616 char user[100], type[100], br[100];
617 int ret;
618
619 ret = sscanf(p, "%99[^ \t\n] %99[^ \t\n] %99[^ \t\n] %99[^ \t\n]", user, type, br, *nic);
620 if (ret != 4)
621 return false;
622 return true;
623 }
624
625 static bool cull_entries(int fd, char *me, char *t, char *br)
626 {
627 struct stat sb;
628 char *buf, *p, *e, *nic;
629 off_t len;
630
631 nic = alloca(100);
632
633 fstat(fd, &sb);
634 len = sb.st_size;
635 if (len == 0)
636 return true;
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));
640 return false;
641 }
642
643 p = buf;
644 e = buf + len;
645 while ((p = find_line(p, e, me, t, br)) != NULL) {
646 if (!get_nic_from_line(p, &nic))
647 continue;
648 if (nic && !nic_exists(nic)) {
649 // copy from eol(p)+1..e to p
650 char *src = get_eol(p) + 1, *dest = p;
651 int diff = src - p;
652 while (src < e)
653 *(dest++) = *(src)++;
654 e -= diff;
655 } else
656 p = get_eol(p) + 1;
657 if (p >= e)
658 break;
659 }
660 munmap(buf, sb.st_size);
661 if (ftruncate(fd, e-buf))
662 fprintf(stderr, "Failed to set new file size\n");
663 return true;
664 }
665
666 static int count_entries(char *buf, off_t len, char *me, char *t, char *br)
667 {
668 char *e = &buf[len];
669 int count = 0;
670 while ((buf = find_line(buf, e, me, t, br)) != NULL) {
671 count++;
672 buf = get_eol(buf)+1;
673 if (buf >= e)
674 break;
675 }
676
677 return count;
678 }
679
680 /*
681 * The dbfile has lines of the format:
682 * user type bridge nicname
683 */
684 static bool get_nic_if_avail(int fd, char *me, int pid, char *intype, char *br, int allowed, char **nicname, char **cnic)
685 {
686 off_t len, slen;
687 struct stat sb;
688 char *buf = NULL, *newline;
689 int ret, count = 0;
690
691 cull_entries(fd, me, intype, br);
692
693 fstat(fd, &sb);
694 len = sb.st_size;
695 if (len != 0) {
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");
699 return false;
700 }
701
702 count = count_entries(buf, len, me, intype, br);
703 if (count >= allowed)
704 return false;
705 }
706
707
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);
716 return false;
717 }
718 if (len)
719 munmap(buf, len);
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);
727 return false;
728 }
729 strcpy(buf+len, newline);
730 munmap(buf, len+slen);
731 return true;
732 }
733
734 static bool create_db_dir(char *fnam)
735 {
736 char *p = alloca(strlen(fnam)+1);
737
738 strcpy(p, fnam);
739 fnam = p;
740 p = p + 1;
741 again:
742 while (*p && *p != '/') p++;
743 if (!*p)
744 return true;
745 *p = '\0';
746 if (mkdir(fnam, 0755) && errno != EEXIST) {
747 fprintf(stderr, "failed to create %s\n", fnam);
748 *p = '/';
749 return false;
750 }
751 *(p++) = '/';
752 goto again;
753 }
754
755 static int lxc_netdev_rename_by_index(int ifindex, const char *newname)
756 {
757 struct nl_handler nlh;
758 struct nlmsg *nlmsg = NULL, *answer = NULL;
759 struct link_req *link_req;
760 int len, err;
761
762 err = netlink_open(&nlh, NETLINK_ROUTE);
763 if (err)
764 return err;
765
766 len = strlen(newname);
767 if (len == 1 || len >= IFNAMSIZ)
768 goto out;
769
770 err = -ENOMEM;
771 nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
772 if (!nlmsg)
773 goto out;
774
775 answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
776 if (!answer)
777 goto out;
778
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;
785
786 if (nla_put_string(nlmsg, IFLA_IFNAME, newname))
787 goto out;
788
789 err = netlink_transaction(&nlh, nlmsg, answer);
790 out:
791 netlink_close(&nlh);
792 nlmsg_free(answer);
793 nlmsg_free(nlmsg);
794 return err;
795 }
796
797 static int lxc_netdev_rename_by_name(const char *oldname, const char *newname)
798 {
799 int len, index;
800
801 len = strlen(oldname);
802 if (len == 1 || len >= IFNAMSIZ)
803 return -EINVAL;
804
805 index = if_nametoindex(oldname);
806 if (!index) {
807 fprintf(stderr, "Error getting ifindex for %s\n", oldname);
808 return -EINVAL;
809 }
810
811 return lxc_netdev_rename_by_index(index, newname);
812 }
813
814 static int rename_in_ns(int pid, char *oldname, char *newname)
815 {
816 char nspath[MAXPATHLEN];
817 int fd = -1, ofd = -1, ret;
818
819 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", getpid());
820 if (ret < 0 || ret >= MAXPATHLEN)
821 return -1;
822 if ((ofd = open(nspath, O_RDONLY)) < 0) {
823 fprintf(stderr, "Opening %s\n", nspath);
824 return -1;
825 }
826 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/net", pid);
827 if (ret < 0 || ret >= MAXPATHLEN)
828 goto out_err;
829
830 if ((fd = open(nspath, O_RDONLY)) < 0) {
831 fprintf(stderr, "Opening %s\n", nspath);
832 goto out_err;
833 }
834 if (setns(fd, 0) < 0) {
835 fprintf(stderr, "setns to container network namespace\n");
836 goto out_err;
837 }
838 close(fd); fd = -1;
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);
841 goto out_err;
842 }
843 if (setns(ofd, 0) < 0) {
844 fprintf(stderr, "Error returning to original netns\n");
845 close(ofd);
846 return -1;
847 }
848 close(ofd);
849
850 return 0;
851
852 out_err:
853 if (ofd >= 0)
854 close(ofd);
855 if (setns(ofd, 0) < 0)
856 fprintf(stderr, "Error returning to original network namespace\n");
857 if (fd >= 0)
858 close(fd);
859 return -1;
860 }
861
862 /*
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
865 * which it created.
866 */
867 static bool may_access_netns(int pid)
868 {
869 int ret;
870 char s[200];
871 uid_t ruid, suid, euid;
872 bool may_access = false;
873
874 ret = getresuid(&ruid, &euid, &suid);
875 if (ret) {
876 fprintf(stderr, "Failed to get my uids: %s\n", strerror(errno));
877 return false;
878 }
879 ret = setresuid(ruid, ruid, euid);
880 if (ret) {
881 fprintf(stderr, "Failed to set temp uids to (%d,%d,%d): %s\n",
882 (int)ruid, (int)ruid, (int)euid, strerror(errno));
883 return false;
884 }
885 ret = snprintf(s, 200, "/proc/%d/ns/net", pid);
886 if (ret < 0 || ret >= 200) // can't happen
887 return false;
888 ret = access(s, R_OK);
889 if (ret) {
890 fprintf(stderr, "Uid %d may not access %s: %s\n",
891 (int)ruid, s, strerror(errno));
892 }
893 may_access = ret == 0;
894 ret = setresuid(ruid, euid, suid);
895 if (ret) {
896 fprintf(stderr, "Failed to restore uids to (%d,%d,%d): %s\n",
897 (int)ruid, (int)euid, (int)suid, strerror(errno));
898 may_access = false;
899 }
900 return may_access;
901 }
902
903 int main(int argc, char *argv[])
904 {
905 int n, fd;
906 bool gotone = false;
907 char *me;
908 char *nicname = alloca(40);
909 char *cnic = NULL; // created nic name in container is returned here.
910 char *vethname;
911 int pid;
912
913 if ((me = get_username()) == NULL) {
914 fprintf(stderr, "Failed to get username\n");
915 exit(1);
916 }
917
918 if (argc < 4)
919 usage(argv[0], true);
920 if (argc >= 5)
921 vethname = argv[4];
922 else
923 vethname = "eth0";
924
925 errno = 0;
926 pid = (int) strtol(argv[1], NULL, 10);
927 if (errno) {
928 fprintf(stderr, "Could not read pid: %s\n", argv[1]);
929 exit(1);
930 }
931
932 if (!create_db_dir(DB_FILE)) {
933 fprintf(stderr, "Failed to create directory for db file\n");
934 exit(1);
935 }
936
937 if ((fd = open_and_lock(DB_FILE)) < 0) {
938 fprintf(stderr, "Failed to lock %s\n", DB_FILE);
939 exit(1);
940 }
941
942 if (!may_access_netns(pid)) {
943 fprintf(stderr, "User %s may not modify netns for pid %d\n",
944 me, pid);
945 exit(1);
946 }
947
948 n = get_alloted(me, argv[2], argv[3]);
949 if (n > 0)
950 gotone = get_nic_if_avail(fd, me, pid, argv[2], argv[3], n, &nicname, &cnic);
951 close(fd);
952 if (!gotone) {
953 fprintf(stderr, "Quota reached\n");
954 exit(1);
955 }
956
957 // Now rename the link
958 if (rename_in_ns(pid, cnic, vethname) < 0) {
959 fprintf(stderr, "Failed to rename the link\n");
960 exit(1);
961 }
962
963 exit(0);
964 }