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