• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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