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