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 34 static const char *kUpdated = "updated"; 35 static const char *kRemoved = "removed"; 36 37 namespace android { 38 namespace net { 39 40 NetlinkHandler::NetlinkHandler(NetlinkManager *nm, int listenerSocket, 41 int format) : 42 NetlinkListener(listenerSocket, format) { 43 mNm = nm; 44 } 45 46 NetlinkHandler::~NetlinkHandler() { 47 } 48 49 int NetlinkHandler::start() { 50 return this->startListener(); 51 } 52 53 int NetlinkHandler::stop() { 54 return this->stopListener(); 55 } 56 57 void NetlinkHandler::onEvent(NetlinkEvent *evt) { 58 const char *subsys = evt->getSubsystem(); 59 if (!subsys) { 60 ALOGW("No subsystem found in netlink event"); 61 return; 62 } 63 64 if (!strcmp(subsys, "net")) { 65 NetlinkEvent::Action action = evt->getAction(); 66 const char *iface = evt->findParam("INTERFACE"); 67 68 if (action == NetlinkEvent::Action::kAdd) { 69 notifyInterfaceAdded(iface); 70 } else if (action == NetlinkEvent::Action::kRemove) { 71 notifyInterfaceRemoved(iface); 72 } else if (action == NetlinkEvent::Action::kChange) { 73 evt->dump(); 74 notifyInterfaceChanged("nana", true); 75 } else if (action == NetlinkEvent::Action::kLinkUp) { 76 notifyInterfaceLinkChanged(iface, true); 77 } else if (action == NetlinkEvent::Action::kLinkDown) { 78 notifyInterfaceLinkChanged(iface, false); 79 } else if (action == NetlinkEvent::Action::kAddressUpdated || 80 action == NetlinkEvent::Action::kAddressRemoved) { 81 const char *address = evt->findParam("ADDRESS"); 82 const char *flags = evt->findParam("FLAGS"); 83 const char *scope = evt->findParam("SCOPE"); 84 if (action == NetlinkEvent::Action::kAddressRemoved && iface && address) { 85 // Note: if this interface was deleted, iface is "" and we don't notify. 86 SockDiag sd; 87 if (sd.open()) { 88 char addrstr[INET6_ADDRSTRLEN]; 89 strncpy(addrstr, address, sizeof(addrstr)); 90 char *slash = strchr(addrstr, '/'); 91 if (slash) { 92 *slash = '\0'; 93 } 94 95 int ret = sd.destroySockets(addrstr); 96 if (ret < 0) { 97 ALOGE("Error destroying sockets: %s", strerror(ret)); 98 } 99 } else { 100 ALOGE("Error opening NETLINK_SOCK_DIAG socket: %s", strerror(errno)); 101 } 102 } 103 if (iface && iface[0] && address && flags && scope) { 104 notifyAddressChanged(action, address, iface, flags, scope); 105 } 106 } else if (action == NetlinkEvent::Action::kRdnss) { 107 const char *lifetime = evt->findParam("LIFETIME"); 108 const char *servers = evt->findParam("SERVERS"); 109 if (lifetime && servers) { 110 notifyInterfaceDnsServers(iface, lifetime, servers); 111 } 112 } else if (action == NetlinkEvent::Action::kRouteUpdated || 113 action == NetlinkEvent::Action::kRouteRemoved) { 114 const char *route = evt->findParam("ROUTE"); 115 const char *gateway = evt->findParam("GATEWAY"); 116 const char *iface = evt->findParam("INTERFACE"); 117 if (route && (gateway || iface)) { 118 notifyRouteChange(action, route, gateway, iface); 119 } 120 } 121 122 } else if (!strcmp(subsys, "qlog") || !strcmp(subsys, "xt_quota2")) { 123 const char *alertName = evt->findParam("ALERT_NAME"); 124 const char *iface = evt->findParam("INTERFACE"); 125 notifyQuotaLimitReached(alertName, iface); 126 127 } else if (!strcmp(subsys, "strict")) { 128 const char *uid = evt->findParam("UID"); 129 const char *hex = evt->findParam("HEX"); 130 notifyStrictCleartext(uid, hex); 131 132 } else if (!strcmp(subsys, "xt_idletimer")) { 133 const char *label = evt->findParam("INTERFACE"); 134 const char *state = evt->findParam("STATE"); 135 const char *timestamp = evt->findParam("TIME_NS"); 136 const char *uid = evt->findParam("UID"); 137 if (state) 138 notifyInterfaceClassActivity(label, !strcmp("active", state), 139 timestamp, uid); 140 141 #if !LOG_NDEBUG 142 } else if (strcmp(subsys, "platform") && strcmp(subsys, "backlight")) { 143 /* It is not a VSYNC or a backlight event */ 144 ALOGV("unexpected event from subsystem %s", subsys); 145 #endif 146 } 147 } 148 149 void NetlinkHandler::notify(int code, const char *format, ...) { 150 char *msg; 151 va_list args; 152 va_start(args, format); 153 if (vasprintf(&msg, format, args) >= 0) { 154 mNm->getBroadcaster()->sendBroadcast(code, msg, false); 155 free(msg); 156 } else { 157 SLOGE("Failed to send notification: vasprintf: %s", strerror(errno)); 158 } 159 va_end(args); 160 } 161 162 void NetlinkHandler::notifyInterfaceAdded(const char *name) { 163 notify(ResponseCode::InterfaceChange, "Iface added %s", name); 164 } 165 166 void NetlinkHandler::notifyInterfaceRemoved(const char *name) { 167 notify(ResponseCode::InterfaceChange, "Iface removed %s", name); 168 } 169 170 void NetlinkHandler::notifyInterfaceChanged(const char *name, bool isUp) { 171 notify(ResponseCode::InterfaceChange, 172 "Iface changed %s %s", name, (isUp ? "up" : "down")); 173 } 174 175 void NetlinkHandler::notifyInterfaceLinkChanged(const char *name, bool isUp) { 176 notify(ResponseCode::InterfaceChange, 177 "Iface linkstate %s %s", name, (isUp ? "up" : "down")); 178 } 179 180 void NetlinkHandler::notifyQuotaLimitReached(const char *name, const char *iface) { 181 notify(ResponseCode::BandwidthControl, "limit alert %s %s", name, iface); 182 } 183 184 void NetlinkHandler::notifyInterfaceClassActivity(const char *name, 185 bool isActive, 186 const char *timestamp, 187 const char *uid) { 188 if (timestamp == NULL) 189 notify(ResponseCode::InterfaceClassActivity, 190 "IfaceClass %s %s", isActive ? "active" : "idle", name); 191 else if (uid != NULL && isActive) 192 notify(ResponseCode::InterfaceClassActivity, 193 "IfaceClass active %s %s %s", name, timestamp, uid); 194 else 195 notify(ResponseCode::InterfaceClassActivity, 196 "IfaceClass %s %s %s", isActive ? "active" : "idle", name, timestamp); 197 } 198 199 void NetlinkHandler::notifyAddressChanged(NetlinkEvent::Action action, const char *addr, 200 const char *iface, const char *flags, 201 const char *scope) { 202 notify(ResponseCode::InterfaceAddressChange, 203 "Address %s %s %s %s %s", 204 (action == NetlinkEvent::Action::kAddressUpdated) ? kUpdated : kRemoved, 205 addr, iface, flags, scope); 206 } 207 208 void NetlinkHandler::notifyInterfaceDnsServers(const char *iface, 209 const char *lifetime, 210 const char *servers) { 211 notify(ResponseCode::InterfaceDnsInfo, "DnsInfo servers %s %s %s", 212 iface, lifetime, servers); 213 } 214 215 void NetlinkHandler::notifyRouteChange(NetlinkEvent::Action action, const char *route, 216 const char *gateway, const char *iface) { 217 notify(ResponseCode::RouteChange, 218 "Route %s %s%s%s%s%s", 219 (action == NetlinkEvent::Action::kRouteUpdated) ? kUpdated : kRemoved, 220 route, 221 (gateway && *gateway) ? " via " : "", 222 gateway, 223 (iface && *iface) ? " dev " : "", 224 iface); 225 } 226 227 void NetlinkHandler::notifyStrictCleartext(const char* uid, const char* hex) { 228 notify(ResponseCode::StrictCleartext, "%s %s", uid, hex); 229 } 230 231 } // namespace net 232 } // namespace android 233