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