1 /*
2 * Copyright 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
17 #include "interface.h"
18
19 #include "netlink.h"
20
21 #include <errno.h>
22 #include <linux/if.h>
23 #include <linux/if_ether.h>
24 #include <linux/route.h>
25 #include <linux/rtnetlink.h>
26 #include <string.h>
27 #include <unistd.h>
28
broadcastFromNetmask(in_addr_t address,in_addr_t netmask)29 in_addr_t broadcastFromNetmask(in_addr_t address, in_addr_t netmask) {
30 // The broadcast address is the address with the bits excluded in the
31 // netmask set to 1. For example if address = 10.0.2.15 and netmask is
32 // 255.255.255.0 then the broadcast is 10.0.2.255. If instead netmask was
33 // 255.0.0.0.0 then the broadcast would be 10.255.255.255
34 //
35 // Simply set all the lower bits to 1 and that should do it.
36 return address | (~netmask);
37 }
38
Interface()39 Interface::Interface() : mSocketFd(-1) {
40 }
41
~Interface()42 Interface::~Interface() {
43 if (mSocketFd != -1) {
44 close(mSocketFd);
45 mSocketFd = -1;
46 }
47 }
48
init(const char * interfaceName)49 Result Interface::init(const char* interfaceName) {
50 mInterfaceName = interfaceName;
51
52 if (mSocketFd != -1) {
53 return Result::error("Interface initialized more than once");
54 }
55
56 mSocketFd = ::socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
57 if (mSocketFd == -1) {
58 return Result::error("Failed to create interface socket for '%s': %s",
59 interfaceName, strerror(errno));
60 }
61
62 Result res = populateIndex();
63 if (!res) {
64 return res;
65 }
66
67 res = populateMacAddress();
68 if (!res) {
69 return res;
70 }
71
72 res = bringUp();
73 if (!res) {
74 return res;
75 }
76
77 res = setAddress(0, 0);
78 if (!res) {
79 return res;
80 }
81
82 return Result::success();
83 }
84
bringUp()85 Result Interface::bringUp() {
86 return setInterfaceUp(true);
87 }
88
bringDown()89 Result Interface::bringDown() {
90 return setInterfaceUp(false);
91 }
92
setMtu(uint16_t mtu)93 Result Interface::setMtu(uint16_t mtu) {
94 struct ifreq request = createRequest();
95
96 strncpy(request.ifr_name, mInterfaceName.c_str(), sizeof(request.ifr_name));
97 request.ifr_mtu = mtu;
98 int status = ::ioctl(mSocketFd, SIOCSIFMTU, &request);
99 if (status != 0) {
100 return Result::error("Failed to set interface MTU %u for '%s': %s",
101 static_cast<unsigned int>(mtu),
102 mInterfaceName.c_str(),
103 strerror(errno));
104 }
105
106 return Result::success();
107 }
108
setAddress(in_addr_t address,in_addr_t subnetMask)109 Result Interface::setAddress(in_addr_t address, in_addr_t subnetMask) {
110 struct Request {
111 struct nlmsghdr hdr;
112 struct ifaddrmsg msg;
113 char buf[256];
114 } request;
115
116 memset(&request, 0, sizeof(request));
117
118 request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.msg));
119 request.hdr.nlmsg_type = RTM_NEWADDR;
120 request.hdr.nlmsg_flags = NLM_F_REQUEST |
121 NLM_F_ACK |
122 NLM_F_CREATE |
123 NLM_F_REPLACE;
124
125 request.msg.ifa_family = AF_INET;
126 // Count the number of bits in the subnet mask, this is the length.
127 request.msg.ifa_prefixlen = __builtin_popcount(subnetMask);
128 request.msg.ifa_index = mIndex;
129
130 addRouterAttribute(request, IFA_ADDRESS, &address, sizeof(address));
131 addRouterAttribute(request, IFA_LOCAL, &address, sizeof(address));
132 in_addr_t broadcast = broadcastFromNetmask(address, subnetMask);
133 addRouterAttribute(request, IFA_BROADCAST, &broadcast, sizeof(broadcast));
134
135 struct sockaddr_nl nlAddr;
136 memset(&nlAddr, 0, sizeof(nlAddr));
137 nlAddr.nl_family = AF_NETLINK;
138
139 int status = ::sendto(mSocketFd, &request, request.hdr.nlmsg_len, 0,
140 reinterpret_cast<sockaddr*>(&nlAddr),
141 sizeof(nlAddr));
142 if (status == -1) {
143 return Result::error("Unable to set interface address: %s",
144 strerror(errno));
145 }
146 char buffer[8192];
147 status = ::recv(mSocketFd, buffer, sizeof(buffer), 0);
148 if (status < 0) {
149 return Result::error("Unable to read netlink response: %s",
150 strerror(errno));
151 }
152 size_t responseSize = static_cast<size_t>(status);
153 if (responseSize < sizeof(nlmsghdr)) {
154 return Result::error("Received incomplete response from netlink");
155 }
156 auto response = reinterpret_cast<const nlmsghdr*>(buffer);
157 if (response->nlmsg_type == NLMSG_ERROR) {
158 if (responseSize < NLMSG_HDRLEN + sizeof(nlmsgerr)) {
159 return Result::error("Recieved an error from netlink but the "
160 "response was incomplete");
161 }
162 auto err = reinterpret_cast<const nlmsgerr*>(NLMSG_DATA(response));
163 if (err->error) {
164 return Result::error("Could not set interface address: %s",
165 strerror(-err->error));
166 }
167 }
168 return Result::success();
169 }
170
createRequest() const171 struct ifreq Interface::createRequest() const {
172 struct ifreq request;
173 memset(&request, 0, sizeof(request));
174 strncpy(request.ifr_name, mInterfaceName.c_str(), sizeof(request.ifr_name));
175 request.ifr_name[sizeof(request.ifr_name) - 1] = '\0';
176
177 return request;
178 }
179
populateIndex()180 Result Interface::populateIndex() {
181 struct ifreq request = createRequest();
182
183 int status = ::ioctl(mSocketFd, SIOCGIFINDEX, &request);
184 if (status != 0) {
185 return Result::error("Failed to get interface index for '%s': %s",
186 mInterfaceName.c_str(), strerror(errno));
187 }
188 mIndex = request.ifr_ifindex;
189 return Result::success();
190 }
191
populateMacAddress()192 Result Interface::populateMacAddress() {
193 struct ifreq request = createRequest();
194
195 int status = ::ioctl(mSocketFd, SIOCGIFHWADDR, &request);
196 if (status != 0) {
197 return Result::error("Failed to get MAC address for '%s': %s",
198 mInterfaceName.c_str(), strerror(errno));
199 }
200 memcpy(mMacAddress, &request.ifr_hwaddr.sa_data, ETH_ALEN);
201 return Result::success();
202 }
203
setInterfaceUp(bool shouldBeUp)204 Result Interface::setInterfaceUp(bool shouldBeUp) {
205 struct ifreq request = createRequest();
206
207 int status = ::ioctl(mSocketFd, SIOCGIFFLAGS, &request);
208 if (status != 0) {
209 return Result::error("Failed to get interface flags for '%s': %s",
210 mInterfaceName.c_str(), strerror(errno));
211 }
212
213 bool isUp = (request.ifr_flags & IFF_UP) != 0;
214 if (isUp != shouldBeUp) {
215 // Toggle the up flag
216 request.ifr_flags ^= IFF_UP;
217 } else {
218 // Interface is already in desired state, do nothing
219 return Result::success();
220 }
221
222 status = ::ioctl(mSocketFd, SIOCSIFFLAGS, &request);
223 if (status != 0) {
224 return Result::error("Failed to set interface flags for '%s': %s",
225 mInterfaceName.c_str(), strerror(errno));
226 }
227
228 return Result::success();
229 }
230
231