1 /*
2 * Copyright 2018, 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 "monitor.h"
18
19 #include "log.h"
20
21 #include <arpa/inet.h>
22 #include <errno.h>
23 #include <linux/rtnetlink.h>
24 #include <net/if.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
Monitor()31 Monitor::Monitor() : mSocketFd(-1) {
32
33 }
34
~Monitor()35 Monitor::~Monitor() {
36 closeSocket();
37 }
38
init()39 Result Monitor::init() {
40 Result res = openSocket();
41 if (!res) {
42 return res;
43 }
44 return requestInterfaces();
45 }
46
setOnInterfaceState(OnInterfaceStateCallback callback)47 void Monitor::setOnInterfaceState(OnInterfaceStateCallback callback) {
48 mOnInterfaceStateCallback = callback;
49 }
50
onReadAvailable(int,int *)51 bool Monitor::onReadAvailable(int /*fd*/, int* /*status*/) {
52 char buffer[32768];
53 struct sockaddr_storage storage;
54
55 while (true) {
56 socklen_t addrSize = sizeof(storage);
57 int status = ::recvfrom(mSocketFd,
58 buffer,
59 sizeof(buffer),
60 MSG_DONTWAIT,
61 reinterpret_cast<struct sockaddr*>(&storage),
62 &addrSize);
63 if (status < 0) {
64 if (errno == EAGAIN || errno == EWOULDBLOCK) {
65 // Nothing to receive, everything is fine
66 return true;
67 } else if (errno == EINTR) {
68 continue;
69 }
70 LOGE("Monitor receive failed: %s", strerror(errno));
71 // An error occurred but let's keep trying
72 return true;
73 } else if (addrSize < 0 ||
74 static_cast<size_t>(addrSize) != sizeof(struct sockaddr_nl)) {
75 LOGE("Monitor received invalid address size");
76 // It's an error but no need to exit, let's keep polling
77 return true;
78 }
79
80 size_t length = static_cast<size_t>(status);
81
82 auto hdr = reinterpret_cast<struct nlmsghdr*>(buffer);
83 while (NLMSG_OK(hdr, length) && hdr->nlmsg_type != NLMSG_DONE) {
84 switch (hdr->nlmsg_type) {
85 case RTM_NEWLINK:
86 handleNewLink(hdr);
87 break;
88 default:
89 break;
90 }
91 hdr = NLMSG_NEXT(hdr, length);
92 }
93 }
94 }
95
onClose(int,int * status)96 bool Monitor::onClose(int /*fd*/, int* status) {
97 // Socket was closed from the other end, close it from our end and re-open
98 closeSocket();
99 Result res = openSocket();
100 if (!res) {
101 LOGE("%s", res.c_str());
102 *status = 1;
103 return false;
104 }
105 return true;
106 }
107
onTimeout(int *)108 bool Monitor::onTimeout(int* /*status*/) {
109 return true;
110 }
111
getPollData(std::vector<pollfd> * fds) const112 void Monitor::getPollData(std::vector<pollfd>* fds) const {
113 if (mSocketFd != -1) {
114 fds->push_back(pollfd{mSocketFd, POLLIN, 0});
115 }
116 }
117
getTimeout() const118 Pollable::Timestamp Monitor::getTimeout() const {
119 return Pollable::Timestamp::max();
120 }
121
openSocket()122 Result Monitor::openSocket() {
123 if (mSocketFd != -1) {
124 return Result::error("Monitor already initialized");
125 }
126
127 mSocketFd = ::socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
128 if (mSocketFd == -1) {
129 return Result::error("Monitor failed to open socket: %s",
130 strerror(errno));
131 }
132
133 struct sockaddr_nl addr;
134 memset(&addr, 0, sizeof(addr));
135 addr.nl_family = AF_NETLINK;
136 addr.nl_groups = RTNLGRP_LINK | RTNLGRP_IPV4_IFADDR | RTNLGRP_IPV6_IFADDR;
137
138 struct sockaddr* sa = reinterpret_cast<struct sockaddr*>(&addr);
139 if (::bind(mSocketFd, sa, sizeof(addr)) != 0) {
140 return Result::error("Monitor failed to bind socket: %s",
141 strerror(errno));
142 }
143
144 return Result::success();
145 }
146
requestInterfaces()147 Result Monitor::requestInterfaces() {
148 if (mSocketFd == -1) {
149 return Result::error("Monitor not initialized yet");
150 }
151
152 struct {
153 struct nlmsghdr hdr;
154 struct rtgenmsg gen;
155 } request;
156
157 memset(&request, 0, sizeof(request));
158
159 request.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(request.gen));
160 request.hdr.nlmsg_type = RTM_GETLINK;
161 request.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
162 request.hdr.nlmsg_seq = 1;
163 request.hdr.nlmsg_pid = getpid();
164 request.gen.rtgen_family = AF_PACKET;
165
166 ssize_t result = TEMP_FAILURE_RETRY(::send(mSocketFd,
167 &request,
168 request.hdr.nlmsg_len,
169 0));
170 if (result < 0) {
171 return Result::error("Failed to request interfaces: %s",
172 strerror(errno));
173 }
174 return Result::success();
175 }
176
closeSocket()177 void Monitor::closeSocket() {
178 if (mSocketFd != -1) {
179 ::close(mSocketFd);
180 mSocketFd = -1;
181 }
182 }
183
handleNewLink(const struct nlmsghdr * hdr)184 void Monitor::handleNewLink(const struct nlmsghdr* hdr) {
185 if (!mOnInterfaceStateCallback) {
186 return;
187 }
188
189 auto msg = reinterpret_cast<const struct ifinfomsg*>(NLMSG_DATA(hdr));
190
191 char name[IF_NAMESIZE + 1] = { 0 };
192 const unsigned int ifIndex = msg->ifi_index;
193 if (if_indextoname(ifIndex, name) == nullptr) {
194 LOGE("Unable to get interface name for interface index %u", ifIndex);
195 }
196
197 bool isUp = !!(msg->ifi_flags & IFF_UP);
198 auto iterator = mUpInterfaces.find(ifIndex);
199
200 if (iterator == mUpInterfaces.end() && isUp) {
201 // The interface was not known to be up but is up, known state changed
202 mUpInterfaces.insert(ifIndex);
203 mOnInterfaceStateCallback(ifIndex, name, InterfaceState::Up);
204 } else if (iterator != mUpInterfaces.end() && !isUp) {
205 // The interface was known to be up, now it's not, known state changed
206 mUpInterfaces.erase(iterator);
207 mOnInterfaceStateCallback(ifIndex, name, InterfaceState::Down);
208 }
209 }
210
211