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