1 /*
2 * Copyright (C) 2017 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 #include "common/libs/net/network_interface_manager.h"
17
18 #include <arpa/inet.h>
19 #include <linux/if_addr.h>
20 #include <linux/if_link.h>
21 #include <linux/netlink.h>
22 #include <linux/rtnetlink.h>
23 #include <net/if.h>
24
25 #include <memory>
26
27 #include "common/libs/glog/logging.h"
28 #include "common/libs/net/network_interface.h"
29
30 namespace cvd {
31 namespace {
BuildLinkRequest(const NetworkInterface & interface)32 NetlinkRequest BuildLinkRequest(
33 const NetworkInterface& interface) {
34 NetlinkRequest request(RTM_SETLINK, 0);
35 request.AddIfInfo(interface.Index(), interface.IsOperational());
36 if (!interface.Name().empty()) {
37 request.AddString(IFLA_IFNAME, interface.Name());
38 }
39
40 return request;
41 }
42
BuildAddrRequest(const NetworkInterface & interface)43 NetlinkRequest BuildAddrRequest(
44 const NetworkInterface& interface) {
45 NetlinkRequest request(RTM_NEWADDR, 0);
46 request.AddAddrInfo(interface.Index(), interface.PrefixLength());
47 in_addr_t address{inet_addr(interface.Address().c_str())};
48 request.AddInt(IFA_LOCAL, address);
49 request.AddInt(IFA_ADDRESS, address);
50 request.AddInt(IFA_BROADCAST,
51 inet_addr(interface.BroadcastAddress().c_str()));
52
53 return request;
54 }
55 } // namespace
56
New(NetlinkClientFactory * nl_factory)57 std::unique_ptr<NetworkInterfaceManager> NetworkInterfaceManager::New(
58 NetlinkClientFactory* nl_factory) {
59 std::unique_ptr<NetworkInterfaceManager> mgr;
60
61 if (nl_factory == NULL) {
62 nl_factory = NetlinkClientFactory::Default();
63 }
64
65 auto client = nl_factory->New(NETLINK_ROUTE);
66 if (client) {
67 mgr.reset(new NetworkInterfaceManager(std::move(client)));
68 }
69
70 return mgr;
71 }
72
NetworkInterfaceManager(std::unique_ptr<NetlinkClient> nl_client)73 NetworkInterfaceManager::NetworkInterfaceManager(
74 std::unique_ptr<NetlinkClient> nl_client)
75 : nl_client_(std::move(nl_client)) {}
76
Open(const std::string & if_name,const std::string & if_name_alt)77 std::unique_ptr<NetworkInterface> NetworkInterfaceManager::Open(
78 const std::string& if_name, const std::string& if_name_alt) {
79 std::unique_ptr<NetworkInterface> iface;
80 // NOTE: do not replace this code with an IOCTL call.
81 // On SELinux enabled Androids, RILD is not permitted to execute an IOCTL
82 // and this call will fail.
83 int32_t index = if_nametoindex(if_name.c_str());
84 if (index == 0) {
85 // Try the alternate name. This will be renamed to our preferred name
86 // by the kernel, because we specify IFLA_IFNAME, but open by index.
87 LOG(ERROR) << "Failed to get interface (" << if_name << ") index, "
88 << "trying alternate.";
89 index = if_nametoindex(if_name_alt.c_str());
90 if (index == 0) {
91 LOG(ERROR) << "Failed to get interface (" << if_name_alt << ") index.";
92 return iface;
93 }
94 }
95
96 iface.reset(new NetworkInterface(index));
97 return iface;
98 }
99
ApplyChanges(const NetworkInterface & iface)100 bool NetworkInterfaceManager::ApplyChanges(const NetworkInterface& iface) {
101 if (!nl_client_->Send(BuildLinkRequest(iface))) return false;
102 // Terminate immediately if interface is down.
103 if (!iface.IsOperational()) return true;
104 return nl_client_->Send(BuildAddrRequest(iface));
105 }
106
107 } // namespace cvd
108