1 /*
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 <libnetdevice/libnetdevice.h>
18
19 #include "common.h"
20 #include "ifreqs.h"
21
22 #include <android-base/logging.h>
23 #include <libnl++/MessageFactory.h>
24 #include <libnl++/Socket.h>
25
26 #include <arpa/inet.h>
27 #include <ifaddrs.h>
28 #include <linux/can.h>
29 #include <linux/rtnetlink.h>
30 #include <net/if.h>
31 #include <netdb.h>
32 #include <sys/ioctl.h>
33
34 #include <algorithm>
35 #include <iterator>
36 #include <sstream>
37
38 namespace android::netdevice {
39
useSocketDomain(int domain)40 void useSocketDomain(int domain) {
41 ifreqs::socketDomain = domain;
42 }
43
exists(std::string_view ifname)44 bool exists(std::string_view ifname) {
45 return nametoindex(ifname) != 0;
46 }
47
up(std::string_view ifname)48 bool up(std::string_view ifname) {
49 auto ifr = ifreqs::fromName(ifname);
50 if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
51 if (ifr.ifr_flags & IFF_UP) return true;
52 ifr.ifr_flags |= IFF_UP;
53 return ifreqs::send(SIOCSIFFLAGS, ifr);
54 }
55
down(std::string_view ifname)56 bool down(std::string_view ifname) {
57 auto ifr = ifreqs::fromName(ifname);
58 if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return false;
59 if (!(ifr.ifr_flags & IFF_UP)) return true;
60 ifr.ifr_flags &= ~IFF_UP;
61 return ifreqs::send(SIOCSIFFLAGS, ifr);
62 }
63
toString(const sockaddr * addr)64 static std::string toString(const sockaddr* addr) {
65 char host[NI_MAXHOST];
66 socklen_t addrlen = (addr->sa_family == AF_INET) ? sizeof(sockaddr_in) : sizeof(sockaddr_in6);
67 auto res = getnameinfo(addr, addrlen, host, sizeof(host), nullptr, 0, NI_NUMERICHOST);
68 CHECK(res == 0) << "getnameinfo failed: " << gai_strerror(res);
69 return host;
70 }
71
getifaddrs()72 static std::unique_ptr<ifaddrs, decltype(&freeifaddrs)> getifaddrs() {
73 ifaddrs* addrs = nullptr;
74 CHECK(getifaddrs(&addrs) == 0) << "getifaddrs failed: " << strerror(errno);
75 return {addrs, freeifaddrs};
76 }
77
getAllAddr4(std::string_view ifname)78 std::set<std::string> getAllAddr4(std::string_view ifname) {
79 std::set<std::string> addresses;
80 auto addrs = getifaddrs();
81 for (ifaddrs* addr = addrs.get(); addr != nullptr; addr = addr->ifa_next) {
82 if (ifname != addr->ifa_name) continue;
83 if (addr->ifa_addr == nullptr) continue;
84 if (addr->ifa_addr->sa_family != AF_INET) continue;
85 addresses.insert(toString(addr->ifa_addr));
86 }
87 return addresses;
88 }
89
inetAddr(std::string_view addr)90 static in_addr_t inetAddr(std::string_view addr) {
91 auto addrn = inet_addr(std::string(addr).c_str());
92 CHECK(addrn != INADDR_NONE) << "Invalid address " << addr;
93 return addrn;
94 }
95
prefixLengthToIpv4Netmask(uint8_t prefixlen)96 static in_addr_t prefixLengthToIpv4Netmask(uint8_t prefixlen) {
97 in_addr_t zero = 0;
98 return htonl(~zero << (32 - prefixlen));
99 }
100
setAddr4(std::string_view ifname,std::string_view addr,std::optional<uint8_t> prefixlen)101 bool setAddr4(std::string_view ifname, std::string_view addr, std::optional<uint8_t> prefixlen) {
102 auto ifr = ifreqs::fromName(ifname);
103 auto ifrAddr = reinterpret_cast<sockaddr_in*>(&ifr.ifr_addr);
104 ifrAddr->sin_family = AF_INET;
105 ifrAddr->sin_addr.s_addr = inetAddr(addr);
106 if (!ifreqs::send(SIOCSIFADDR, ifr)) return false;
107
108 if (prefixlen.has_value()) {
109 if (*prefixlen < 0 || *prefixlen > 32) {
110 LOG(ERROR) << "Invalid prefix length: " << *prefixlen;
111 return false;
112 }
113 ifr = ifreqs::fromName(ifname);
114 auto ifrNetmask = reinterpret_cast<sockaddr_in*>(&ifr.ifr_netmask);
115 ifrNetmask->sin_family = AF_INET;
116 ifrNetmask->sin_addr.s_addr = prefixLengthToIpv4Netmask(*prefixlen);
117 if (!ifreqs::send(SIOCSIFNETMASK, ifr)) return false;
118 }
119
120 return true;
121 }
122
addAddr4(std::string_view ifname,std::string_view addr,uint8_t prefixlen)123 bool addAddr4(std::string_view ifname, std::string_view addr, uint8_t prefixlen) {
124 nl::MessageFactory<ifaddrmsg> req(RTM_NEWADDR, nl::kCreateFlags);
125 req->ifa_family = AF_INET;
126 req->ifa_prefixlen = prefixlen;
127 req->ifa_flags = IFA_F_SECONDARY;
128 req->ifa_index = nametoindex(ifname);
129 if (req->ifa_index == 0) {
130 LOG(ERROR) << "Interface " << ifname << " doesn't exist";
131 return false;
132 }
133
134 auto addrn = inetAddr(addr);
135 req.add(IFLA_ADDRESS, addrn);
136 req.add(IFLA_BROADCAST, addrn);
137
138 nl::Socket sock(NETLINK_ROUTE);
139 return sock.send(req) && sock.receiveAck(req);
140 }
141
add(std::string_view dev,std::string_view type)142 bool add(std::string_view dev, std::string_view type) {
143 nl::MessageFactory<ifinfomsg> req(RTM_NEWLINK, nl::kCreateFlags);
144 req.add(IFLA_IFNAME, dev);
145
146 {
147 auto linkinfo = req.addNested(IFLA_LINKINFO);
148 req.add(IFLA_INFO_KIND, type);
149 }
150
151 nl::Socket sock(NETLINK_ROUTE);
152 return sock.send(req) && sock.receiveAck(req);
153 }
154
del(std::string_view dev)155 bool del(std::string_view dev) {
156 nl::MessageFactory<ifinfomsg> req(RTM_DELLINK);
157 req.add(IFLA_IFNAME, dev);
158
159 nl::Socket sock(NETLINK_ROUTE);
160 return sock.send(req) && sock.receiveAck(req);
161 }
162
rename(std::string_view from,std::string_view to)163 bool rename(std::string_view from, std::string_view to) {
164 if (!down(from)) return false;
165
166 nl::MessageFactory<ifinfomsg> req(RTM_SETLINK);
167 req.add(IFLA_IFNAME, to);
168
169 req->ifi_index = nametoindex(from);
170 if (req->ifi_index == 0) {
171 LOG(ERROR) << "Interface " << from << " doesn't exist";
172 return false;
173 }
174
175 nl::Socket sock(NETLINK_ROUTE);
176 return sock.send(req) && sock.receiveAck(req);
177 }
178
getHwAddr(std::string_view ifname)179 std::optional<hwaddr_t> getHwAddr(std::string_view ifname) {
180 auto ifr = ifreqs::fromName(ifname);
181 if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return std::nullopt;
182
183 hwaddr_t hwaddr;
184 memcpy(hwaddr.data(), ifr.ifr_hwaddr.sa_data, hwaddr.size());
185 return hwaddr;
186 }
187
setHwAddr(std::string_view ifname,hwaddr_t hwaddr)188 bool setHwAddr(std::string_view ifname, hwaddr_t hwaddr) {
189 auto ifr = ifreqs::fromName(ifname);
190
191 // fetch sa_family
192 if (!ifreqs::send(SIOCGIFHWADDR, ifr)) return false;
193
194 memcpy(ifr.ifr_hwaddr.sa_data, hwaddr.data(), hwaddr.size());
195 return ifreqs::send(SIOCSIFHWADDR, ifr);
196 }
197
isUp(std::string_view ifname)198 std::optional<bool> isUp(std::string_view ifname) {
199 auto ifr = ifreqs::fromName(ifname);
200 if (!ifreqs::send(SIOCGIFFLAGS, ifr)) return std::nullopt;
201 return ifr.ifr_flags & IFF_UP;
202 }
203
hasIpv4(std::string_view ifname)204 static bool hasIpv4(std::string_view ifname) {
205 auto ifr = ifreqs::fromName(ifname);
206 switch (ifreqs::trySend(SIOCGIFADDR, ifr)) {
207 case 0:
208 return true;
209 case EADDRNOTAVAIL:
210 case ENODEV:
211 return false;
212 default:
213 PLOG(WARNING) << "Failed checking IPv4 address";
214 return false;
215 }
216 }
217
218 struct WaitState {
219 bool present;
220 bool up;
221 bool hasIpv4Addr;
222
satisfiedandroid::netdevice::WaitState223 bool satisfied(WaitCondition cnd) const {
224 switch (cnd) {
225 case WaitCondition::PRESENT:
226 return present;
227 case WaitCondition::PRESENT_AND_UP:
228 return present && up;
229 case WaitCondition::PRESENT_AND_IPV4:
230 return present && up && hasIpv4Addr;
231 case WaitCondition::DOWN_OR_GONE:
232 return !present || !up;
233 }
234 }
235 };
236
toString(WaitCondition cnd)237 static std::string toString(WaitCondition cnd) {
238 switch (cnd) {
239 case WaitCondition::PRESENT:
240 return "become present";
241 case WaitCondition::PRESENT_AND_UP:
242 return "come up";
243 case WaitCondition::PRESENT_AND_IPV4:
244 return "get IPv4 address";
245 case WaitCondition::DOWN_OR_GONE:
246 return "go down";
247 }
248 }
249
toString(Quantifier quant)250 static std::string toString(Quantifier quant) {
251 switch (quant) {
252 case Quantifier::ALL_OF:
253 return "all of";
254 case Quantifier::ANY_OF:
255 return "any of";
256 }
257 }
258
toString(const std::set<std::string> & ifnames)259 static std::string toString(const std::set<std::string>& ifnames) {
260 std::stringstream ss;
261 std::copy(ifnames.begin(), ifnames.end(), std::ostream_iterator<std::string>(ss, ","));
262 auto str = ss.str();
263 str.pop_back();
264 return str;
265 }
266
waitFor(std::set<std::string> ifnames,WaitCondition cnd,Quantifier quant)267 std::optional<std::string> waitFor(std::set<std::string> ifnames, WaitCondition cnd,
268 Quantifier quant) {
269 nl::Socket sock(NETLINK_ROUTE, 0, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
270
271 using StatesMap = std::map<std::string, WaitState>;
272 StatesMap states = {};
273 for (const auto ifname : ifnames) {
274 const auto present = exists(ifname);
275 const auto up = present && isUp(ifname).value_or(false);
276 const auto hasIpv4Addr = present && hasIpv4(ifname);
277 states[ifname] = {present, up, hasIpv4Addr};
278 }
279
280 const auto mapConditionChecker = [cnd](const StatesMap::iterator::value_type& it) {
281 return it.second.satisfied(cnd);
282 };
283 const auto isFullySatisfied = [&states, quant,
284 mapConditionChecker]() -> std::optional<std::string> {
285 if (quant == Quantifier::ALL_OF) {
286 if (!std::all_of(states.begin(), states.end(), mapConditionChecker)) return {};
287 return states.begin()->first;
288 } else { // Quantifier::ANY_OF
289 const auto it = std::find_if(states.begin(), states.end(), mapConditionChecker);
290 if (it == states.end()) return {};
291 return it->first;
292 }
293 };
294
295 if (const auto iface = isFullySatisfied()) return iface;
296
297 LOG(DEBUG) << "Waiting for " << toString(quant) << " " << toString(ifnames) << " to "
298 << toString(cnd);
299 for (const auto rawMsg : sock) {
300 if (const auto msg = nl::Message<ifinfomsg>::parse(rawMsg, {RTM_NEWLINK, RTM_DELLINK});
301 msg.has_value()) {
302 // Interface added / removed
303 const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
304 if (ifnames.count(ifname) == 0) continue;
305
306 auto& state = states[ifname];
307 state.present = (msg->header.nlmsg_type != RTM_DELLINK);
308 state.up = state.present && (msg->data.ifi_flags & IFF_UP) != 0;
309 if (!state.present) state.hasIpv4Addr = false;
310
311 } else if (const auto msg =
312 nl::Message<ifaddrmsg>::parse(rawMsg, {RTM_NEWADDR, RTM_DELADDR});
313 msg.has_value()) {
314 // Address added / removed
315 const auto ifname = msg->attributes.get<std::string>(IFLA_IFNAME);
316 if (ifnames.count(ifname) == 0) continue;
317
318 if (msg->header.nlmsg_type == RTM_NEWADDR) {
319 states[ifname].hasIpv4Addr = true;
320 } else {
321 // instead of tracking which one got deleted, let's just ask
322 states[ifname].hasIpv4Addr = hasIpv4(ifname);
323 }
324 }
325
326 if (const auto iface = isFullySatisfied()) {
327 LOG(DEBUG) << "Finished waiting for " << toString(quant) << " " << toString(ifnames)
328 << " to " << toString(cnd);
329 return iface;
330 }
331 }
332 LOG(FATAL) << "Can't read Netlink socket";
333 return {};
334 }
335
336 } // namespace android::netdevice
337
operator ==(const android::netdevice::hwaddr_t lhs,const unsigned char rhs[ETH_ALEN])338 bool operator==(const android::netdevice::hwaddr_t lhs, const unsigned char rhs[ETH_ALEN]) {
339 static_assert(lhs.size() == ETH_ALEN);
340 return 0 == memcmp(lhs.data(), rhs, lhs.size());
341 }
342