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