]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
30ae9dfd | 2 | |
dccca82b | 3 | #include <errno.h> |
634f0f98 | 4 | #include <fcntl.h> |
30ae9dfd | 5 | #include <linux/if_tun.h> |
634f0f98 | 6 | #include <net/if.h> |
e306723e | 7 | #include <netinet/if_ether.h> |
634f0f98 ZJS |
8 | #include <sys/ioctl.h> |
9 | #include <sys/stat.h> | |
10 | #include <sys/types.h> | |
30ae9dfd | 11 | |
b5efdb8a | 12 | #include "alloc-util.h" |
3ffd4af2 | 13 | #include "fd-util.h" |
441e9ae4 | 14 | #include "netdev/tuntap.h" |
b1d4f8e1 | 15 | #include "user-util.h" |
30ae9dfd SS |
16 | |
17 | #define TUN_DEV "/dev/net/tun" | |
18 | ||
30ae9dfd | 19 | static int netdev_fill_tuntap_message(NetDev *netdev, struct ifreq *ifr) { |
aa9f1140 | 20 | TunTap *t; |
30ae9dfd SS |
21 | |
22 | assert(netdev); | |
aa9f1140 | 23 | assert(netdev->ifname); |
30ae9dfd SS |
24 | assert(ifr); |
25 | ||
aa9f1140 TG |
26 | if (netdev->kind == NETDEV_KIND_TAP) { |
27 | t = TAP(netdev); | |
30ae9dfd | 28 | ifr->ifr_flags |= IFF_TAP; |
aa9f1140 TG |
29 | } else { |
30 | t = TUN(netdev); | |
63dadd90 | 31 | ifr->ifr_flags |= IFF_TUN; |
aa9f1140 | 32 | } |
63dadd90 | 33 | |
aa9f1140 | 34 | if (!t->packet_info) |
30ae9dfd SS |
35 | ifr->ifr_flags |= IFF_NO_PI; |
36 | ||
aa9f1140 | 37 | if (t->one_queue) |
30ae9dfd SS |
38 | ifr->ifr_flags |= IFF_ONE_QUEUE; |
39 | ||
aa9f1140 | 40 | if (t->multi_queue) |
30ae9dfd SS |
41 | ifr->ifr_flags |= IFF_MULTI_QUEUE; |
42 | ||
f5f07dbf SS |
43 | if (t->vnet_hdr) |
44 | ifr->ifr_flags |= IFF_VNET_HDR; | |
45 | ||
30ae9dfd SS |
46 | strncpy(ifr->ifr_name, netdev->ifname, IFNAMSIZ-1); |
47 | ||
48 | return 0; | |
49 | } | |
50 | ||
51 | static int netdev_tuntap_add(NetDev *netdev, struct ifreq *ifr) { | |
52 | _cleanup_close_ int fd; | |
aa9f1140 | 53 | TunTap *t = NULL; |
30ae9dfd SS |
54 | const char *user; |
55 | const char *group; | |
56 | uid_t uid; | |
57 | gid_t gid; | |
6f44acfb | 58 | int r; |
30ae9dfd | 59 | |
aa9f1140 TG |
60 | assert(netdev); |
61 | assert(ifr); | |
62 | ||
30ae9dfd | 63 | fd = open(TUN_DEV, O_RDWR); |
ce67afb0 SS |
64 | if (fd < 0) |
65 | return log_netdev_error_errno(netdev, -errno, "Failed to open tun dev: %m"); | |
30ae9dfd | 66 | |
ad16158c | 67 | if (ioctl(fd, TUNSETIFF, ifr) < 0) |
ce67afb0 | 68 | return log_netdev_error_errno(netdev, -errno, "TUNSETIFF failed on tun dev: %m"); |
30ae9dfd | 69 | |
aa9f1140 TG |
70 | if (netdev->kind == NETDEV_KIND_TAP) |
71 | t = TAP(netdev); | |
72 | else | |
73 | t = TUN(netdev); | |
74 | ||
75 | assert(t); | |
30ae9dfd | 76 | |
9ed794a3 | 77 | if (t->user_name) { |
aa9f1140 TG |
78 | |
79 | user = t->user_name; | |
30ae9dfd SS |
80 | |
81 | r = get_user_creds(&user, &uid, NULL, NULL, NULL); | |
ce67afb0 SS |
82 | if (r < 0) |
83 | return log_netdev_error_errno(netdev, r, "Cannot resolve user name %s: %m", t->user_name); | |
30ae9dfd | 84 | |
ad16158c | 85 | if (ioctl(fd, TUNSETOWNER, uid) < 0) |
ce67afb0 | 86 | return log_netdev_error_errno(netdev, -errno, "TUNSETOWNER failed on tun dev: %m"); |
30ae9dfd SS |
87 | } |
88 | ||
98b32556 | 89 | if (t->group_name) { |
30ae9dfd | 90 | |
aa9f1140 | 91 | group = t->group_name; |
30ae9dfd SS |
92 | |
93 | r = get_group_creds(&group, &gid); | |
ce67afb0 SS |
94 | if (r < 0) |
95 | return log_netdev_error_errno(netdev, r, "Cannot resolve group name %s: %m", t->group_name); | |
30ae9dfd | 96 | |
ad16158c | 97 | if (ioctl(fd, TUNSETGROUP, gid) < 0) |
ce67afb0 | 98 | return log_netdev_error_errno(netdev, -errno, "TUNSETGROUP failed on tun dev: %m"); |
30ae9dfd SS |
99 | |
100 | } | |
101 | ||
ad16158c | 102 | if (ioctl(fd, TUNSETPERSIST, 1) < 0) |
ce67afb0 | 103 | return log_netdev_error_errno(netdev, -errno, "TUNSETPERSIST failed on tun dev: %m"); |
30ae9dfd | 104 | |
6f44acfb | 105 | return 0; |
30ae9dfd SS |
106 | } |
107 | ||
3be1d7e0 | 108 | static int netdev_create_tuntap(NetDev *netdev) { |
aa9f1140 | 109 | struct ifreq ifr = {}; |
30ae9dfd SS |
110 | int r; |
111 | ||
30ae9dfd | 112 | r = netdev_fill_tuntap_message(netdev, &ifr); |
9ed794a3 | 113 | if (r < 0) |
30ae9dfd SS |
114 | return r; |
115 | ||
30ae9dfd SS |
116 | return netdev_tuntap_add(netdev, &ifr); |
117 | } | |
3be1d7e0 | 118 | |
aa9f1140 TG |
119 | static void tuntap_done(NetDev *netdev) { |
120 | TunTap *t = NULL; | |
121 | ||
122 | assert(netdev); | |
123 | ||
124 | if (netdev->kind == NETDEV_KIND_TUN) | |
125 | t = TUN(netdev); | |
126 | else | |
127 | t = TAP(netdev); | |
128 | ||
129 | assert(t); | |
130 | ||
a1e58e8e LP |
131 | t->user_name = mfree(t->user_name); |
132 | t->group_name = mfree(t->group_name); | |
aa9f1140 TG |
133 | } |
134 | ||
e0fbf1fc | 135 | static int tuntap_verify(NetDev *netdev, const char *filename) { |
e0fbf1fc TG |
136 | assert(netdev); |
137 | ||
4e964aa0 | 138 | if (netdev->mtu != 0) |
98b32556 | 139 | log_netdev_warning(netdev, "MTU configured for %s, ignoring", netdev_kind_to_string(netdev->kind)); |
e0fbf1fc | 140 | |
98b32556 LP |
141 | if (netdev->mac) |
142 | log_netdev_warning(netdev, "MAC configured for %s, ignoring", netdev_kind_to_string(netdev->kind)); | |
e0fbf1fc TG |
143 | |
144 | return 0; | |
145 | } | |
146 | ||
3be1d7e0 | 147 | const NetDevVTable tun_vtable = { |
aa9f1140 TG |
148 | .object_size = sizeof(TunTap), |
149 | .sections = "Match\0NetDev\0Tun\0", | |
e0fbf1fc | 150 | .config_verify = tuntap_verify, |
aa9f1140 | 151 | .done = tuntap_done, |
3be1d7e0 | 152 | .create = netdev_create_tuntap, |
aa9f1140 | 153 | .create_type = NETDEV_CREATE_INDEPENDENT, |
3be1d7e0 TG |
154 | }; |
155 | ||
156 | const NetDevVTable tap_vtable = { | |
aa9f1140 TG |
157 | .object_size = sizeof(TunTap), |
158 | .sections = "Match\0NetDev\0Tap\0", | |
e0fbf1fc | 159 | .config_verify = tuntap_verify, |
aa9f1140 | 160 | .done = tuntap_done, |
3be1d7e0 | 161 | .create = netdev_create_tuntap, |
aa9f1140 | 162 | .create_type = NETDEV_CREATE_INDEPENDENT, |
3be1d7e0 | 163 | }; |