NetlinkEvent.cpp revision 80f63d4b2c45bd609cbda78bcd016baf0138a5d3
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#include <stdlib.h> 17#include <string.h> 18 19#define LOG_TAG "NetlinkEvent" 20#include <cutils/log.h> 21 22#include <sysutils/NetlinkEvent.h> 23 24#include <sys/types.h> 25#include <sys/socket.h> 26#include <netinet/in.h> 27#include <netinet/icmp6.h> 28#include <arpa/inet.h> 29#include <net/if.h> 30 31#include <linux/if.h> 32#include <linux/netfilter/nfnetlink.h> 33#include <linux/netfilter_ipv4/ipt_ULOG.h> 34/* From kernel's net/netfilter/xt_quota2.c */ 35const int QLOG_NL_EVENT = 112; 36 37#include <linux/netlink.h> 38#include <linux/rtnetlink.h> 39 40const int NetlinkEvent::NlActionUnknown = 0; 41const int NetlinkEvent::NlActionAdd = 1; 42const int NetlinkEvent::NlActionRemove = 2; 43const int NetlinkEvent::NlActionChange = 3; 44const int NetlinkEvent::NlActionLinkUp = 4; 45const int NetlinkEvent::NlActionLinkDown = 5; 46const int NetlinkEvent::NlActionAddressUpdated = 6; 47const int NetlinkEvent::NlActionAddressRemoved = 7; 48const int NetlinkEvent::NlActionRdnss = 8; 49 50NetlinkEvent::NetlinkEvent() { 51 mAction = NlActionUnknown; 52 memset(mParams, 0, sizeof(mParams)); 53 mPath = NULL; 54 mSubsystem = NULL; 55} 56 57NetlinkEvent::~NetlinkEvent() { 58 int i; 59 if (mPath) 60 free(mPath); 61 if (mSubsystem) 62 free(mSubsystem); 63 for (i = 0; i < NL_PARAMS_MAX; i++) { 64 if (!mParams[i]) 65 break; 66 free(mParams[i]); 67 } 68} 69 70void NetlinkEvent::dump() { 71 int i; 72 73 for (i = 0; i < NL_PARAMS_MAX; i++) { 74 if (!mParams[i]) 75 break; 76 SLOGD("NL param '%s'\n", mParams[i]); 77 } 78} 79 80/* 81 * Parse a RTM_NEWADDR or RTM_DELADDR message. 82 */ 83bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, 84 int rtasize) { 85 struct rtattr *rta; 86 struct ifa_cacheinfo *cacheinfo = NULL; 87 char addrstr[INET6_ADDRSTRLEN] = ""; 88 89 // Sanity check. 90 if (type != RTM_NEWADDR && type != RTM_DELADDR) { 91 SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type); 92 return false; 93 } 94 95 // For log messages. 96 const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR"; 97 98 for (rta = IFA_RTA(ifaddr); RTA_OK(rta, rtasize); 99 rta = RTA_NEXT(rta, rtasize)) { 100 if (rta->rta_type == IFA_ADDRESS) { 101 // Only look at the first address, because we only support notifying 102 // one change at a time. 103 if (*addrstr != '\0') { 104 SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype); 105 continue; 106 } 107 108 // Convert the IP address to a string. 109 if (ifaddr->ifa_family == AF_INET) { 110 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta); 111 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) { 112 SLOGE("Short IPv4 address (%zu bytes) in %s", 113 RTA_PAYLOAD(rta), msgtype); 114 continue; 115 } 116 inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr)); 117 } else if (ifaddr->ifa_family == AF_INET6) { 118 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta); 119 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) { 120 SLOGE("Short IPv6 address (%zu bytes) in %s", 121 RTA_PAYLOAD(rta), msgtype); 122 continue; 123 } 124 inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr)); 125 } else { 126 SLOGE("Unknown address family %d\n", ifaddr->ifa_family); 127 continue; 128 } 129 130 // Find the interface name. 131 char ifname[IFNAMSIZ + 1]; 132 if (!if_indextoname(ifaddr->ifa_index, ifname)) { 133 SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype); 134 return false; 135 } 136 137 // Fill in interface information. 138 mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated : 139 NlActionAddressRemoved; 140 mSubsystem = strdup("net"); 141 asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, 142 ifaddr->ifa_prefixlen); 143 asprintf(&mParams[1], "INTERFACE=%s", ifname); 144 asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags); 145 asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope); 146 } else if (rta->rta_type == IFA_CACHEINFO) { 147 // Address lifetime information. 148 if (cacheinfo) { 149 // We only support one address. 150 SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype); 151 continue; 152 } 153 154 if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) { 155 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s", 156 RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype); 157 continue; 158 } 159 160 cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta); 161 asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered); 162 asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid); 163 asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp); 164 asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp); 165 } 166 } 167 168 if (addrstr[0] == '\0') { 169 SLOGE("No IFA_ADDRESS in %s\n", msgtype); 170 return false; 171 } 172 173 return true; 174} 175 176/* 177 * Parse a RTM_NEWNDUSEROPT message. 178 */ 179bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) { 180 // Check the length is valid. 181 if (msg->nduseropt_opts_len > len) { 182 SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n", 183 msg->nduseropt_opts_len, len); 184 return false; 185 } 186 len = msg->nduseropt_opts_len; 187 188 // Check address family and packet type. 189 if (msg->nduseropt_family != AF_INET6) { 190 SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n", 191 msg->nduseropt_family); 192 return false; 193 } 194 195 if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT || 196 msg->nduseropt_icmp_code != 0) { 197 SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n", 198 msg->nduseropt_icmp_type, msg->nduseropt_icmp_code); 199 return false; 200 } 201 202 // Find the interface name. 203 char ifname[IFNAMSIZ + 1]; 204 if (!if_indextoname(msg->nduseropt_ifindex, ifname)) { 205 SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n", 206 msg->nduseropt_ifindex); 207 return false; 208 } 209 210 // The kernel sends a separate netlink message for each ND option in the RA. 211 // So only parse the first ND option in the message. 212 struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1); 213 214 // The length is in multiples of 8 octets. 215 uint16_t optlen = opthdr->nd_opt_len; 216 if (optlen * 8 > len) { 217 SLOGE("Invalid option length %d > %d for ND option %d\n", 218 optlen * 8, len, opthdr->nd_opt_type); 219 return false; 220 } 221 222 if (opthdr->nd_opt_type == ND_OPT_RDNSS) { 223 // DNS Servers (RFC 6106). 224 // Each address takes up 2*8 octets, and the header takes up 8 octets. 225 // So for a valid option with one or more addresses, optlen must be 226 // odd and greater than 1. 227 if ((optlen < 3) || !(optlen & 0x1)) { 228 SLOGE("Invalid optlen %d for RDNSS option\n", optlen); 229 return false; 230 } 231 int numaddrs = (optlen - 1) / 2; 232 233 // Find the lifetime. 234 struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr; 235 uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime); 236 237 // Construct "SERVERS=<comma-separated string of DNS addresses>". 238 // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the 239 // the last address are followed by ','; the last is followed by '\0'. 240 static const char kServerTag[] = "SERVERS="; 241 static const int kTagLength = sizeof(kServerTag) - 1; 242 int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1); 243 char *buf = (char *) malloc(bufsize); 244 if (!buf) { 245 SLOGE("RDNSS option: out of memory\n"); 246 return false; 247 } 248 strcpy(buf, kServerTag); 249 int pos = kTagLength; 250 251 struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1); 252 for (int i = 0; i < numaddrs; i++) { 253 if (i > 0) { 254 buf[pos++] = ','; 255 } 256 inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos); 257 pos += strlen(buf + pos); 258 } 259 buf[pos] = '\0'; 260 261 mAction = NlActionRdnss; 262 mSubsystem = strdup("net"); 263 asprintf(&mParams[0], "INTERFACE=%s", ifname); 264 asprintf(&mParams[1], "LIFETIME=%u", lifetime); 265 mParams[2] = buf; 266 } else { 267 SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type); 268 return false; 269 } 270 271 return true; 272} 273 274/* 275 * Parse a binary message from a NETLINK_ROUTE netlink socket. 276 */ 277bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { 278 const struct nlmsghdr *nh; 279 280 for (nh = (struct nlmsghdr *) buffer; 281 NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); 282 nh = NLMSG_NEXT(nh, size)) { 283 284 if (nh->nlmsg_type == RTM_NEWLINK) { 285 int len = nh->nlmsg_len - sizeof(*nh); 286 struct ifinfomsg *ifi; 287 288 if (sizeof(*ifi) > (size_t) len) { 289 SLOGE("Got a short RTM_NEWLINK message\n"); 290 continue; 291 } 292 293 ifi = (ifinfomsg *)NLMSG_DATA(nh); 294 if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) { 295 continue; 296 } 297 298 struct rtattr *rta = (struct rtattr *) 299 ((char *) ifi + NLMSG_ALIGN(sizeof(*ifi))); 300 len = NLMSG_PAYLOAD(nh, sizeof(*ifi)); 301 302 while(RTA_OK(rta, len)) { 303 switch(rta->rta_type) { 304 case IFLA_IFNAME: 305 char buffer[16 + IFNAMSIZ]; 306 snprintf(buffer, sizeof(buffer), "INTERFACE=%s", 307 (char *) RTA_DATA(rta)); 308 mParams[0] = strdup(buffer); 309 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? 310 NlActionLinkUp : NlActionLinkDown; 311 mSubsystem = strdup("net"); 312 break; 313 } 314 315 rta = RTA_NEXT(rta, len); 316 } 317 318 } else if (nh->nlmsg_type == QLOG_NL_EVENT) { 319 char *devname; 320 ulog_packet_msg_t *pm; 321 size_t len = nh->nlmsg_len - sizeof(*nh); 322 if (sizeof(*pm) > len) { 323 SLOGE("Got a short QLOG message\n"); 324 continue; 325 } 326 pm = (ulog_packet_msg_t *)NLMSG_DATA(nh); 327 devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name; 328 asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix); 329 asprintf(&mParams[1], "INTERFACE=%s", devname); 330 mSubsystem = strdup("qlog"); 331 mAction = NlActionChange; 332 333 } else if (nh->nlmsg_type == RTM_NEWADDR || 334 nh->nlmsg_type == RTM_DELADDR) { 335 int len = nh->nlmsg_len - sizeof(*nh); 336 struct ifaddrmsg *ifa; 337 338 if (sizeof(*ifa) > (size_t) len) { 339 SLOGE("Got a short RTM_xxxADDR message\n"); 340 continue; 341 } 342 343 ifa = (ifaddrmsg *)NLMSG_DATA(nh); 344 size_t rtasize = IFA_PAYLOAD(nh); 345 if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) { 346 continue; 347 } 348 349 } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) { 350 int len = nh->nlmsg_len - sizeof(*nh); 351 struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh); 352 353 if (sizeof(*ndmsg) > (size_t) len) { 354 SLOGE("Got a short RTM_NEWNDUSEROPT message\n"); 355 continue; 356 } 357 358 size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg)); 359 if (!parseNdUserOptMessage(ndmsg, optsize)) { 360 continue; 361 } 362 363 364 } else { 365 SLOGD("Unexpected netlink message. type=0x%x\n", 366 nh->nlmsg_type); 367 } 368 } 369 370 return true; 371} 372 373/* If the string between 'str' and 'end' begins with 'prefixlen' characters 374 * from the 'prefix' array, then return 'str + prefixlen', otherwise return 375 * NULL. 376 */ 377static const char* 378has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen) 379{ 380 if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen)) 381 return str + prefixlen; 382 else 383 return NULL; 384} 385 386/* Same as strlen(x) for constant string literals ONLY */ 387#define CONST_STRLEN(x) (sizeof(x)-1) 388 389/* Convenience macro to call has_prefix with a constant string literal */ 390#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix)) 391 392 393/* 394 * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT 395 * netlink socket. 396 */ 397bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { 398 const char *s = buffer; 399 const char *end; 400 int param_idx = 0; 401 int first = 1; 402 403 if (size == 0) 404 return false; 405 406 /* Ensure the buffer is zero-terminated, the code below depends on this */ 407 buffer[size-1] = '\0'; 408 409 end = s + size; 410 while (s < end) { 411 if (first) { 412 const char *p; 413 /* buffer is 0-terminated, no need to check p < end */ 414 for (p = s; *p != '@'; p++) { 415 if (!*p) { /* no '@', should not happen */ 416 return false; 417 } 418 } 419 mPath = strdup(p+1); 420 first = 0; 421 } else { 422 const char* a; 423 if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { 424 if (!strcmp(a, "add")) 425 mAction = NlActionAdd; 426 else if (!strcmp(a, "remove")) 427 mAction = NlActionRemove; 428 else if (!strcmp(a, "change")) 429 mAction = NlActionChange; 430 } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { 431 mSeq = atoi(a); 432 } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { 433 mSubsystem = strdup(a); 434 } else if (param_idx < NL_PARAMS_MAX) { 435 mParams[param_idx++] = strdup(s); 436 } 437 } 438 s += strlen(s) + 1; 439 } 440 return true; 441} 442 443bool NetlinkEvent::decode(char *buffer, int size, int format) { 444 if (format == NetlinkListener::NETLINK_FORMAT_BINARY) { 445 return parseBinaryNetlinkMessage(buffer, size); 446 } else { 447 return parseAsciiNetlinkMessage(buffer, size); 448 } 449} 450 451const char *NetlinkEvent::findParam(const char *paramName) { 452 size_t len = strlen(paramName); 453 for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) { 454 const char *ptr = mParams[i] + len; 455 if (!strncmp(mParams[i], paramName, len) && *ptr == '=') 456 return ++ptr; 457 } 458 459 SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); 460 return NULL; 461} 462