blob: f282ab056a8ce7bd042ba4a7ec8b90aadb66536b [file] [log] [blame]
Maciej Żenczykowskib70da762019-01-28 15:20:48 -08001/*
2 * Copyright (C) 2019 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#include "ClatUtils.h"
18
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080019#include <errno.h>
20#include <linux/if.h>
Maciej Żenczykowski7330b022019-01-28 17:30:24 -080021#include <linux/netlink.h>
Maciej Żenczykowskiff3308d2019-02-12 19:10:55 -080022#include <linux/pkt_sched.h>
23#include <linux/rtnetlink.h>
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080024#include <sys/ioctl.h>
25#include <sys/socket.h>
26#include <sys/types.h>
27#include <unistd.h>
28
Maciej Żenczykowskib70da762019-01-28 15:20:48 -080029#define LOG_TAG "ClatUtils"
30#include <log/log.h>
31
Maciej Żenczykowski7330b022019-01-28 17:30:24 -080032#include "NetlinkCommands.h"
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080033#include "android-base/unique_fd.h"
Maciej Żenczykowski88d28ff2019-03-25 11:54:32 -070034#include "bpf/BpfUtils.h"
35#include "netdbpf/bpf_shared.h"
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080036
Maciej Żenczykowskib70da762019-01-28 15:20:48 -080037namespace android {
38namespace net {
39
Maciej Żenczykowski0a7dce82019-01-28 15:31:55 -080040int hardwareAddressType(const std::string& interface) {
41 base::unique_fd ufd(socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0));
42
43 if (ufd < 0) {
44 const int err = errno;
45 ALOGE("socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)");
46 return -err;
47 };
48
49 struct ifreq ifr = {};
50 // We use strncpy() instead of strlcpy() since kernel has to be able
51 // to handle non-zero terminated junk passed in by userspace anyway,
52 // and this way too long interface names (more than IFNAMSIZ-1 = 15
53 // characters plus terminating NULL) will not get truncated to 15
54 // characters and zero-terminated and thus potentially erroneously
55 // match a truncated interface if one were to exist.
56 strncpy(ifr.ifr_name, interface.c_str(), sizeof(ifr.ifr_name));
57
58 if (ioctl(ufd, SIOCGIFHWADDR, &ifr, sizeof(ifr))) return -errno;
59
60 return ifr.ifr_hwaddr.sa_family;
61}
62
Maciej Żenczykowski88d28ff2019-03-25 11:54:32 -070063int getClatMapFd(void) {
64 const int fd = bpf::bpfFdGet(CLAT_MAP_PATH, 0);
65 return (fd == -1) ? -errno : fd;
66}
67
Maciej Żenczykowski949d84a2019-01-28 17:22:30 -080068int getClatProgFd(bool with_ethernet_header) {
69 const int fd =
70 bpf::bpfFdGet(with_ethernet_header ? CLAT_PROG_ETHER_PATH : CLAT_PROG_RAWIP_PATH, 0);
71 return (fd == -1) ? -errno : fd;
72}
73
Maciej Żenczykowski7330b022019-01-28 17:30:24 -080074// TODO: use //system/netd/server/NetlinkCommands.cpp:openNetlinkSocket(protocol)
75int openNetlinkSocket(void) {
76 base::unique_fd fd(socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE));
77 if (fd == -1) {
78 const int err = errno;
79 ALOGE("socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE)");
80 return -err;
81 }
82
83 int rv;
84
85 const int on = 1;
86 rv = setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, &on, sizeof(on));
87 if (rv) ALOGE("setsockopt(fd, SOL_NETLINK, NETLINK_CAP_ACK, %d)", on);
88
89 // this is needed to get sane strace netlink parsing, it allocates the pid
90 rv = bind(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR));
91 if (rv) {
92 const int err = errno;
93 ALOGE("bind(fd, {AF_NETLINK, 0, 0})");
94 return -err;
95 }
96
97 // we do not want to receive messages from anyone besides the kernel
98 rv = connect(fd, (const struct sockaddr*)&KERNEL_NLADDR, sizeof(KERNEL_NLADDR));
99 if (rv) {
100 const int err = errno;
101 ALOGE("connect(fd, {AF_NETLINK, 0, 0})");
102 return -err;
103 }
104
105 return fd.release();
106}
107
Maciej Żenczykowski992a51d2019-02-11 18:06:56 -0800108// TODO: merge with //system/netd/server/SockDiag.cpp:checkError(fd)
109int processNetlinkResponse(int fd) {
110 struct {
111 nlmsghdr h;
112 nlmsgerr e;
113 char buf[256];
114 } resp = {};
115
116 const int rv = recv(fd, &resp, sizeof(resp), MSG_TRUNC);
117
118 if (rv == -1) {
119 const int err = errno;
120 ALOGE("recv() failed");
121 return -err;
122 }
123
124 if (rv < (int)NLMSG_SPACE(sizeof(struct nlmsgerr))) {
125 ALOGE("recv() returned short packet: %d", rv);
126 return -EMSGSIZE;
127 }
128
129 if (resp.h.nlmsg_len != (unsigned)rv) {
130 ALOGE("recv() returned invalid header length: %d != %d", resp.h.nlmsg_len, rv);
131 return -EBADMSG;
132 }
133
134 if (resp.h.nlmsg_type != NLMSG_ERROR) {
135 ALOGE("recv() did not return NLMSG_ERROR message: %d", resp.h.nlmsg_type);
136 return -EBADMSG;
137 }
138
139 return resp.e.error; // returns 0 on success
140}
141
Maciej Żenczykowskiff3308d2019-02-12 19:10:55 -0800142// ADD: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_EXCL|NLM_F_CREATE
143// REPLACE: nlMsgType=RTM_NEWQDISC nlMsgFlags=NLM_F_CREATE|NLM_F_REPLACE
144// DEL: nlMsgType=RTM_DELQDISC nlMsgFlags=0
145int doTcQdiscClsact(int fd, int ifIndex, __u16 nlMsgType, __u16 nlMsgFlags) {
146 // This is the name of the qdisc we are attaching.
147 // Some hoop jumping to make this compile time constant with known size,
148 // so that the structure declaration is well defined at compile time.
149#define CLSACT "clsact"
150 static const char clsact[] = CLSACT;
151 // sizeof() includes the terminating NULL
152#define ASCIIZ_LEN_CLSACT sizeof(clsact)
153
154 const struct {
155 nlmsghdr n;
156 tcmsg t;
157 struct {
158 nlattr attr;
159 char str[NLMSG_ALIGN(ASCIIZ_LEN_CLSACT)];
160 } kind;
161 } req = {
162 .n =
163 {
164 .nlmsg_len = sizeof(req),
165 .nlmsg_type = nlMsgType,
166 .nlmsg_flags = static_cast<__u16>(NETLINK_REQUEST_FLAGS | nlMsgFlags),
167 },
168 .t =
169 {
170 .tcm_family = AF_UNSPEC,
171 .tcm_ifindex = ifIndex,
172 .tcm_handle = TC_H_MAKE(TC_H_CLSACT, 0),
173 .tcm_parent = TC_H_CLSACT,
174 },
175 .kind =
176 {
177 .attr =
178 {
179 .nla_len = NLA_HDRLEN + ASCIIZ_LEN_CLSACT,
180 .nla_type = TCA_KIND,
181 },
182 .str = CLSACT,
183 },
184 };
185#undef ASCIIZ_LEN_CLSACT
186#undef CLSACT
187
188 const int rv = send(fd, &req, sizeof(req), 0);
189 if (rv == -1) return -errno;
190 if (rv != sizeof(req)) return -EMSGSIZE;
191
192 return processNetlinkResponse(fd);
193}
194
195int tcQdiscAddDevClsact(int fd, int ifIndex) {
196 return doTcQdiscClsact(fd, ifIndex, RTM_NEWQDISC, NLM_F_EXCL | NLM_F_CREATE);
197}
198
199int tcQdiscReplaceDevClsact(int fd, int ifIndex) {
200 return doTcQdiscClsact(fd, ifIndex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE);
201}
202
203int tcQdiscDelDevClsact(int fd, int ifIndex) {
204 return doTcQdiscClsact(fd, ifIndex, RTM_DELQDISC, 0);
205}
206
Maciej Żenczykowskib70da762019-01-28 15:20:48 -0800207} // namespace net
208} // namespace android