• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2008 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 <stdarg.h>
18  #include <stdio.h>
19  #include <stdlib.h>
20  #include <string.h>
21  #include <errno.h>
22  
23  #define LOG_TAG "Netd"
24  
25  #include <cutils/log.h>
26  
27  #include <netutils/ifc.h>
28  #include <sysutils/NetlinkEvent.h>
29  #include "NetlinkHandler.h"
30  #include "NetlinkManager.h"
31  #include "ResponseCode.h"
32  #include "SockDiag.h"
33  #include "Controllers.h"
34  
35  static const char *kUpdated = "updated";
36  static const char *kRemoved = "removed";
37  
38  namespace android {
39  namespace net {
40  
NetlinkHandler(NetlinkManager * nm,int listenerSocket,int format)41  NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket,
42                                 int format) :
43                          NetlinkListener(listenerSocket, format) {
44      mNm = nm;
45  }
46  
~NetlinkHandler()47  NetlinkHandler::~NetlinkHandler() {
48  }
49  
start()50  int NetlinkHandler::start() {
51      return this->startListener();
52  }
53  
stop()54  int NetlinkHandler::stop() {
55      return this->stopListener();
56  }
57  
parseIfIndex(const char * ifIndex)58  static long parseIfIndex(const char* ifIndex) {
59      if (ifIndex == nullptr) {
60          return 0;
61      }
62      long ifaceIndex = strtol(ifIndex, NULL, 10);
63      // strtol returns 0 on error, which is fine because 0 is not a valid ifindex.
64      if (errno == ERANGE && (ifaceIndex == LONG_MAX || ifaceIndex == LONG_MIN)) {
65          return 0;
66      }
67      return ifaceIndex;
68  }
69  
onEvent(NetlinkEvent * evt)70  void NetlinkHandler::onEvent(NetlinkEvent *evt) {
71      const char *subsys = evt->getSubsystem();
72      if (!subsys) {
73          ALOGW("No subsystem found in netlink event");
74          return;
75      }
76  
77      if (!strcmp(subsys, "net")) {
78          NetlinkEvent::Action action = evt->getAction();
79          const char *iface = evt->findParam("INTERFACE");
80          if ((action == NetlinkEvent::Action::kAdd) ||
81              (action == NetlinkEvent::Action::kLinkUp) ||
82              (action == NetlinkEvent::Action::kLinkDown)) {
83              const char *ifIndex = evt->findParam("IFINDEX");
84              long ifaceIndex = parseIfIndex(ifIndex);
85              if (ifaceIndex) {
86                  gCtls->trafficCtrl.addInterface(iface, ifaceIndex);
87              } else {
88                  ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
89              }
90          }
91  
92          if (action == NetlinkEvent::Action::kAdd) {
93              notifyInterfaceAdded(iface);
94          } else if (action == NetlinkEvent::Action::kRemove) {
95              notifyInterfaceRemoved(iface);
96          } else if (action == NetlinkEvent::Action::kChange) {
97              evt->dump();
98              notifyInterfaceChanged("nana", true);
99          } else if (action == NetlinkEvent::Action::kLinkUp) {
100              notifyInterfaceLinkChanged(iface, true);
101          } else if (action == NetlinkEvent::Action::kLinkDown) {
102              notifyInterfaceLinkChanged(iface, false);
103          } else if (action == NetlinkEvent::Action::kAddressUpdated ||
104                     action == NetlinkEvent::Action::kAddressRemoved) {
105              const char *address = evt->findParam("ADDRESS");
106              const char *flags = evt->findParam("FLAGS");
107              const char *scope = evt->findParam("SCOPE");
108              const char *ifIndex = evt->findParam("IFINDEX");
109              char addrstr[INET6_ADDRSTRLEN + strlen("/128")];
110              strlcpy(addrstr, address, sizeof(addrstr));
111              char *slash = strchr(addrstr, '/');
112              if (slash) {
113                  *slash = '\0';
114              }
115  
116              long ifaceIndex = parseIfIndex(ifIndex);
117              if (!ifaceIndex) {
118                  ALOGE("invalid interface index: %s(%s)", iface, ifIndex);
119              }
120              if (action == NetlinkEvent::Action::kAddressUpdated) {
121                  gCtls->netCtrl.addInterfaceAddress(ifaceIndex, address);
122              } else {  // action == NetlinkEvent::Action::kAddressRemoved
123                  bool shouldDestroy = gCtls->netCtrl.removeInterfaceAddress(ifaceIndex, address);
124                  if (shouldDestroy) {
125                      SockDiag sd;
126                      if (sd.open()) {
127                          int ret = sd.destroySockets(addrstr);
128                          if (ret < 0) {
129                              ALOGE("Error destroying sockets: %s", strerror(-ret));
130                          }
131                      } else {
132                          ALOGE("Error opening NETLINK_SOCK_DIAG socket: %s", strerror(errno));
133                      }
134                  }
135              }
136              // Note: if this interface was deleted, iface is "" and we don't notify.
137              if (iface && iface[0] && address && flags && scope) {
138                  notifyAddressChanged(action, address, iface, flags, scope);
139              }
140          } else if (action == NetlinkEvent::Action::kRdnss) {
141              const char *lifetime = evt->findParam("LIFETIME");
142              const char *servers = evt->findParam("SERVERS");
143              if (lifetime && servers) {
144                  notifyInterfaceDnsServers(iface, lifetime, servers);
145              }
146          } else if (action == NetlinkEvent::Action::kRouteUpdated ||
147                     action == NetlinkEvent::Action::kRouteRemoved) {
148              const char *route = evt->findParam("ROUTE");
149              const char *gateway = evt->findParam("GATEWAY");
150              const char *iface = evt->findParam("INTERFACE");
151              if (route && (gateway || iface)) {
152                  notifyRouteChange(action, route, gateway, iface);
153              }
154          }
155  
156      } else if (!strcmp(subsys, "qlog") || !strcmp(subsys, "xt_quota2")) {
157          const char *alertName = evt->findParam("ALERT_NAME");
158          const char *iface = evt->findParam("INTERFACE");
159          notifyQuotaLimitReached(alertName, iface);
160  
161      } else if (!strcmp(subsys, "strict")) {
162          const char *uid = evt->findParam("UID");
163          const char *hex = evt->findParam("HEX");
164          notifyStrictCleartext(uid, hex);
165  
166      } else if (!strcmp(subsys, "xt_idletimer")) {
167          const char *label = evt->findParam("INTERFACE");
168          const char *state = evt->findParam("STATE");
169          const char *timestamp = evt->findParam("TIME_NS");
170          const char *uid = evt->findParam("UID");
171          if (state)
172              notifyInterfaceClassActivity(label, !strcmp("active", state),
173                                           timestamp, uid);
174  
175  #if !LOG_NDEBUG
176      } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) {
177          /* It is not a VSYNC or a backlight event */
178          ALOGV("unexpected event from subsystem %s", subsys);
179  #endif
180      }
181  }
182  
notify(int code,const char * format,...)183  void NetlinkHandler::notify(int code, const char *format, ...) {
184      char *msg;
185      va_list args;
186      va_start(args, format);
187      if (vasprintf(&msg, format, args) >= 0) {
188          mNm->getBroadcaster()->sendBroadcast(code, msg, false);
189          free(msg);
190      } else {
191          SLOGE("Failed to send notification: vasprintf: %s", strerror(errno));
192      }
193      va_end(args);
194  }
195  
notifyInterfaceAdded(const char * name)196  void NetlinkHandler::notifyInterfaceAdded(const char *name) {
197      notify(ResponseCode::InterfaceChange, "Iface added %s", name);
198  }
199  
notifyInterfaceRemoved(const char * name)200  void NetlinkHandler::notifyInterfaceRemoved(const char *name) {
201      notify(ResponseCode::InterfaceChange, "Iface removed %s", name);
202  }
203  
notifyInterfaceChanged(const char * name,bool isUp)204  void NetlinkHandler::notifyInterfaceChanged(const char *name, bool isUp) {
205      notify(ResponseCode::InterfaceChange,
206             "Iface changed %s %s", name, (isUp ? "up" : "down"));
207  }
208  
notifyInterfaceLinkChanged(const char * name,bool isUp)209  void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) {
210      notify(ResponseCode::InterfaceChange,
211             "Iface linkstate %s %s", name, (isUp ? "up" : "down"));
212  }
213  
notifyQuotaLimitReached(const char * name,const char * iface)214  void NetlinkHandler::notifyQuotaLimitReached(const char *name, const char *iface) {
215      notify(ResponseCode::BandwidthControl, "limit alert %s %s", name, iface);
216  }
217  
notifyInterfaceClassActivity(const char * name,bool isActive,const char * timestamp,const char * uid)218  void NetlinkHandler::notifyInterfaceClassActivity(const char *name,
219                                                    bool isActive,
220                                                    const char *timestamp,
221                                                    const char *uid) {
222      if (timestamp == NULL)
223          notify(ResponseCode::InterfaceClassActivity,
224             "IfaceClass %s %s", isActive ? "active" : "idle", name);
225      else if (uid != NULL && isActive)
226          notify(ResponseCode::InterfaceClassActivity,
227             "IfaceClass active %s %s %s", name, timestamp, uid);
228      else
229          notify(ResponseCode::InterfaceClassActivity,
230             "IfaceClass %s %s %s", isActive ? "active" : "idle", name, timestamp);
231  }
232  
notifyAddressChanged(NetlinkEvent::Action action,const char * addr,const char * iface,const char * flags,const char * scope)233  void NetlinkHandler::notifyAddressChanged(NetlinkEvent::Action action, const char *addr,
234                                            const char *iface, const char *flags,
235                                            const char *scope) {
236      notify(ResponseCode::InterfaceAddressChange,
237             "Address %s %s %s %s %s",
238             (action == NetlinkEvent::Action::kAddressUpdated) ? kUpdated : kRemoved,
239             addr, iface, flags, scope);
240  }
241  
notifyInterfaceDnsServers(const char * iface,const char * lifetime,const char * servers)242  void NetlinkHandler::notifyInterfaceDnsServers(const char *iface,
243                                                 const char *lifetime,
244                                                 const char *servers) {
245      notify(ResponseCode::InterfaceDnsInfo, "DnsInfo servers %s %s %s",
246             iface, lifetime, servers);
247  }
248  
notifyRouteChange(NetlinkEvent::Action action,const char * route,const char * gateway,const char * iface)249  void NetlinkHandler::notifyRouteChange(NetlinkEvent::Action action, const char *route,
250                                         const char *gateway, const char *iface) {
251      notify(ResponseCode::RouteChange,
252             "Route %s %s%s%s%s%s",
253             (action == NetlinkEvent::Action::kRouteUpdated) ? kUpdated : kRemoved,
254             route,
255             (gateway && *gateway) ? " via " : "",
256             gateway,
257             (iface && *iface) ? " dev " : "",
258             iface);
259  }
260  
notifyStrictCleartext(const char * uid,const char * hex)261  void NetlinkHandler::notifyStrictCleartext(const char* uid, const char* hex) {
262      notify(ResponseCode::StrictCleartext, "%s %s", uid, hex);
263  }
264  
265  }  // namespace net
266  }  // namespace android
267