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