blob: e30a5004c5c7dc71611713255b174cf1a6b42fa7 [file] [log] [blame]
Patrick Rohr776c40c2022-01-12 21:05:26 +01001/*
2 * Copyright (C) 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "TcUtils"
18
19#include "tcutils/tcutils.h"
20
Patrick Rohre7f26e22022-01-12 22:13:12 +010021#include "kernelversion.h"
Patrick Rohr776c40c2022-01-12 21:05:26 +010022#include "scopeguard.h"
23
24#include <android/log.h>
25#include <arpa/inet.h>
26#include <cerrno>
Patrick Rohr776c40c2022-01-12 21:05:26 +010027#include <cstring>
28#include <libgen.h>
29#include <linux/if_arp.h>
30#include <linux/if_ether.h>
31#include <linux/netlink.h>
32#include <linux/pkt_cls.h>
33#include <linux/pkt_sched.h>
34#include <linux/rtnetlink.h>
35#include <net/if.h>
36#include <stdarg.h>
37#include <sys/socket.h>
Patrick Rohr776c40c2022-01-12 21:05:26 +010038#include <unistd.h>
39#include <utility>
40
41#define BPF_FD_JUST_USE_INT
42#include <BpfSyscallWrappers.h>
43#undef BPF_FD_JUST_USE_INT
44
45// The maximum length of TCA_BPF_NAME. Sync from net/sched/cls_bpf.c.
46#define CLS_BPF_NAME_LEN 256
47
48// Classifier name. See cls_bpf_ops in net/sched/cls_bpf.c.
49#define CLS_BPF_KIND_NAME "bpf"
50
51namespace android {
52namespace {
53
54void logError(const char *fmt...) {
55 va_list args;
56 va_start(args, fmt);
57 __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, fmt, args);
58 va_end(args);
59}
60
61const sockaddr_nl KERNEL_NLADDR = {AF_NETLINK, 0, 0, 0};
62const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK;
63
64int sendAndProcessNetlinkResponse(const void *req, int len) {
65 // TODO: use unique_fd instead of ScopeGuard
66 int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
67 if (fd == -1) {
68 int error = errno;
69 logError("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE): %d",
70 error);
71 return -error;
72 }
73 auto scopeGuard = base::make_scope_guard([fd] { close(fd); });
74
75 static constexpr int on = 1;
76 if (setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on))) {
77 int error = errno;
78 logError("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, 1): %d", error);
79 return -error;
80 }
81
82 // this is needed to get valid strace netlink parsing, it allocates the pid
83 if (bind(fd, (const struct sockaddr *)&KERNEL_NLADDR,
84 sizeof(KERNEL_NLADDR))) {
85 int error = errno;
86 logError("bind(fd, {AF_NETLINK, 0, 0}: %d)", error);
87 return -error;
88 }
89
90 // we do not want to receive messages from anyone besides the kernel
91 if (connect(fd, (const struct sockaddr *)&KERNEL_NLADDR,
92 sizeof(KERNEL_NLADDR))) {
93 int error = errno;
94 logError("connect(fd, {AF_NETLINK, 0, 0}): %d", error);
95 return -error;
96 }
97
98 int rv = send(fd, req, len, 0);
99
100 if (rv == -1) {
101 int error = errno;
102 logError("send(fd, req, len, 0) failed: %d", error);
103 return -error;
104 }
105
106 if (rv != len) {
107 logError("send(fd, req, len = %d, 0) returned invalid message size %d", len,
108 rv);
109 return -EMSGSIZE;
110 }
111
112 struct {
113 nlmsghdr h;
114 nlmsgerr e;
115 char buf[256];
116 } resp = {};
117
118 rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC);
119
120 if (rv == -1) {
121 int error = errno;
122 logError("recv() failed: %d", error);
123 return -error;
124 }
125
126 if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) {
127 logError("recv() returned short packet: %d", rv);
128 return -EBADMSG;
129 }
130
131 if (resp.h.nlmsg_len != (unsigned)rv) {
132 logError("recv() returned invalid header length: %d != %d",
133 resp.h.nlmsg_len, rv);
134 return -EBADMSG;
135 }
136
137 if (resp.h.nlmsg_type != NLMSG_ERROR) {
138 logError("recv() did not return NLMSG_ERROR message: %d",
139 resp.h.nlmsg_type);
140 return -ENOMSG;
141 }
142
143 if (resp.e.error) {
144 logError("NLMSG_ERROR message return error: %d", resp.e.error);
145 }
146 return resp.e.error; // returns 0 on success
147}
148
149int hardwareAddressType(const char *interface) {
150 int fd = socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0);
151 if (fd < 0)
152 return -errno;
153 auto scopeGuard = base::make_scope_guard([fd] { close(fd); });
154
155 struct ifreq ifr = {};
156 // We use strncpy() instead of strlcpy() since kernel has to be able
157 // to handle non-zero terminated junk passed in by userspace anyway,
158 // and this way too long interface names (more than IFNAMSIZ-1 = 15
159 // characters plus terminating NULL) will not get truncated to 15
160 // characters and zero-terminated and thus potentially erroneously
161 // match a truncated interface if one were to exist.
162 strncpy(ifr.ifr_name, interface, sizeof(ifr.ifr_name));
163
164 if (ioctl(fd, SIOCGIFHWADDR, &ifr, sizeof(ifr))) {
165 return -errno;
166 }
167 return ifr.ifr_hwaddr.sa_family;
168}
169
Patrick Rohr776c40c2022-01-12 21:05:26 +0100170} // namespace
171
172int isEthernet(const char *iface, bool &isEthernet) {
173 int rv = hardwareAddressType(iface);
174 if (rv < 0) {
175 logError("Get hardware address type of interface %s failed: %s", iface,
176 strerror(-rv));
177 return -rv;
178 }
179
180 // Backwards compatibility with pre-GKI kernels that use various custom
181 // ARPHRD_* for their cellular interface
182 switch (rv) {
183 // ARPHRD_PUREIP on at least some Mediatek Android kernels
184 // example: wembley with 4.19 kernel
185 case 520:
186 // in Linux 4.14+ rmnet support was upstreamed and ARHRD_RAWIP became 519,
187 // but it is 530 on at least some Qualcomm Android 4.9 kernels with rmnet
188 // example: Pixel 3 family
189 case 530:
190 // >5.4 kernels are GKI2.0 and thus upstream compatible, however 5.10
191 // shipped with Android S, so (for safety) let's limit ourselves to
192 // >5.10, ie. 5.11+ as a guarantee we're on Android T+ and thus no
193 // longer need this non-upstream compatibility logic
194 static bool is_pre_5_11_kernel = !isAtLeastKernelVersion(5, 11, 0);
195 if (is_pre_5_11_kernel)
196 return false;
197 }
198
199 switch (rv) {
200 case ARPHRD_ETHER:
201 isEthernet = true;
202 return 0;
203 case ARPHRD_NONE:
204 case ARPHRD_PPP:
205 case ARPHRD_RAWIP:
206 isEthernet = false;
207 return 0;
208 default:
209 logError("Unknown hardware address type %d on interface %s", rv, iface);
210 return -ENOENT;
211 }
212}
213
214// tc filter add dev .. in/egress prio 1 protocol ipv6/ip bpf object-pinned
215// /sys/fs/bpf/... direct-action
216int tcAddBpfFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto,
217 const char *bpfProgPath) {
218 const int bpfFd = bpf::retrieveProgram(bpfProgPath);
219 if (bpfFd == -1) {
220 logError("retrieveProgram failed: %d", errno);
221 return -errno;
222 }
223 auto scopeGuard = base::make_scope_guard([bpfFd] { close(bpfFd); });
224
225 struct {
226 nlmsghdr n;
227 tcmsg t;
228 struct {
229 nlattr attr;
230 // The maximum classifier name length is defined in
231 // tcf_proto_ops in include/net/sch_generic.h.
232 char str[NLMSG_ALIGN(sizeof(CLS_BPF_KIND_NAME))];
233 } kind;
234 struct {
235 nlattr attr;
236 struct {
237 nlattr attr;
238 __u32 u32;
239 } fd;
240 struct {
241 nlattr attr;
242 char str[NLMSG_ALIGN(CLS_BPF_NAME_LEN)];
243 } name;
244 struct {
245 nlattr attr;
246 __u32 u32;
247 } flags;
248 } options;
249 } req = {
250 .n =
251 {
252 .nlmsg_len = sizeof(req),
253 .nlmsg_type = RTM_NEWTFILTER,
254 .nlmsg_flags = NETLINK_REQUEST_FLAGS | NLM_F_EXCL | NLM_F_CREATE,
255 },
256 .t =
257 {
258 .tcm_family = AF_UNSPEC,
259 .tcm_ifindex = ifIndex,
260 .tcm_handle = TC_H_UNSPEC,
261 .tcm_parent = TC_H_MAKE(TC_H_CLSACT, ingress ? TC_H_MIN_INGRESS
262 : TC_H_MIN_EGRESS),
263 .tcm_info =
264 static_cast<__u32>((static_cast<uint16_t>(prio) << 16) |
265 htons(static_cast<uint16_t>(proto))),
266 },
267 .kind =
268 {
269 .attr =
270 {
271 .nla_len = sizeof(req.kind),
272 .nla_type = TCA_KIND,
273 },
274 .str = CLS_BPF_KIND_NAME,
275 },
276 .options =
277 {
278 .attr =
279 {
280 .nla_len = sizeof(req.options),
281 .nla_type = NLA_F_NESTED | TCA_OPTIONS,
282 },
283 .fd =
284 {
285 .attr =
286 {
287 .nla_len = sizeof(req.options.fd),
288 .nla_type = TCA_BPF_FD,
289 },
290 .u32 = static_cast<__u32>(bpfFd),
291 },
292 .name =
293 {
294 .attr =
295 {
296 .nla_len = sizeof(req.options.name),
297 .nla_type = TCA_BPF_NAME,
298 },
299 // Visible via 'tc filter show', but
300 // is overwritten by strncpy below
301 .str = "placeholder",
302 },
303 .flags =
304 {
305 .attr =
306 {
307 .nla_len = sizeof(req.options.flags),
308 .nla_type = TCA_BPF_FLAGS,
309 },
310 .u32 = TCA_BPF_FLAG_ACT_DIRECT,
311 },
312 },
313 };
314
315 snprintf(req.options.name.str, sizeof(req.options.name.str), "%s:[*fsobj]",
316 basename(bpfProgPath));
317
318 int error = sendAndProcessNetlinkResponse(&req, sizeof(req));
319 return error;
320}
321
322// tc filter del dev .. in/egress prio .. protocol ..
323int tcDeleteFilter(int ifIndex, bool ingress, uint16_t prio, uint16_t proto) {
324 const struct {
325 nlmsghdr n;
326 tcmsg t;
327 } req = {
328 .n =
329 {
330 .nlmsg_len = sizeof(req),
331 .nlmsg_type = RTM_DELTFILTER,
332 .nlmsg_flags = NETLINK_REQUEST_FLAGS,
333 },
334 .t =
335 {
336 .tcm_family = AF_UNSPEC,
337 .tcm_ifindex = ifIndex,
338 .tcm_handle = TC_H_UNSPEC,
339 .tcm_parent = TC_H_MAKE(TC_H_CLSACT, ingress ? TC_H_MIN_INGRESS
340 : TC_H_MIN_EGRESS),
341 .tcm_info =
342 static_cast<__u32>((static_cast<uint16_t>(prio) << 16) |
343 htons(static_cast<uint16_t>(proto))),
344 },
345 };
346
347 return sendAndProcessNetlinkResponse(&req, sizeof(req));
348}
349
350} // namespace android