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 #define LOG_TAG "NetlinkEvent" 18 19 #include <arpa/inet.h> 20 #include <limits.h> 21 #include <linux/genetlink.h> 22 #include <linux/if.h> 23 #include <linux/if_addr.h> 24 #include <linux/if_link.h> 25 #include <linux/netfilter/nfnetlink.h> 26 #include <linux/netfilter/nfnetlink_log.h> 27 #include <linux/netfilter_ipv4/ipt_ULOG.h> 28 #include <linux/netlink.h> 29 #include <linux/rtnetlink.h> 30 #include <net/if.h> 31 #include <netinet/icmp6.h> 32 #include <netinet/in.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <sys/socket.h> 36 #include <sys/types.h> 37 38 /* From kernel's net/netfilter/xt_quota2.c */ 39 const int LOCAL_QLOG_NL_EVENT = 112; 40 const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET; 41 42 #include <log/log.h> 43 #include <sysutils/NetlinkEvent.h> 44 45 NetlinkEvent::NetlinkEvent() { 46 mAction = Action::kUnknown; 47 memset(mParams, 0, sizeof(mParams)); 48 mPath = NULL; 49 mSubsystem = NULL; 50 } 51 52 NetlinkEvent::~NetlinkEvent() { 53 int i; 54 if (mPath) 55 free(mPath); 56 if (mSubsystem) 57 free(mSubsystem); 58 for (i = 0; i < NL_PARAMS_MAX; i++) { 59 if (!mParams[i]) 60 break; 61 free(mParams[i]); 62 } 63 } 64 65 void NetlinkEvent::dump() { 66 int i; 67 68 for (i = 0; i < NL_PARAMS_MAX; i++) { 69 if (!mParams[i]) 70 break; 71 SLOGD("NL param '%s'\n", mParams[i]); 72 } 73 } 74 75 /* 76 * Returns the message name for a message in the NETLINK_ROUTE family, or NULL 77 * if parsing that message is not supported. 78 */ 79 static const char *rtMessageName(int type) { 80 #define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm; 81 switch (type) { 82 NL_EVENT_RTM_NAME(RTM_NEWLINK); 83 NL_EVENT_RTM_NAME(RTM_DELLINK); 84 NL_EVENT_RTM_NAME(RTM_NEWADDR); 85 NL_EVENT_RTM_NAME(RTM_DELADDR); 86 NL_EVENT_RTM_NAME(RTM_NEWROUTE); 87 NL_EVENT_RTM_NAME(RTM_DELROUTE); 88 NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT); 89 NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT); 90 NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET); 91 default: 92 return NULL; 93 } 94 #undef NL_EVENT_RTM_NAME 95 } 96 97 /* 98 * Checks that a binary NETLINK_ROUTE message is long enough for a payload of 99 * size bytes. 100 */ 101 static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) { 102 if (nh->nlmsg_len < NLMSG_LENGTH(size)) { 103 SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type)); 104 return false; 105 } 106 return true; 107 } 108 109 /* 110 * Utility function to log errors. 111 */ 112 static bool maybeLogDuplicateAttribute(bool isDup, 113 const char *attributeName, 114 const char *messageName) { 115 if (isDup) { 116 SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName); 117 return true; 118 } 119 return false; 120 } 121 122 /* 123 * Parse a RTM_NEWLINK message. 124 */ 125 bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) { 126 struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh); 127 if (!checkRtNetlinkLength(nh, sizeof(*ifi))) 128 return false; 129 130 if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) { 131 return false; 132 } 133 134 int len = IFLA_PAYLOAD(nh); 135 struct rtattr *rta; 136 for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { 137 switch(rta->rta_type) { 138 case IFLA_IFNAME: 139 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta)); 140 // We can get the interface change information from sysfs update 141 // already. But in case we missed those message when devices start. 142 // We do a update again when received a kLinkUp event. To make 143 // the message consistent, use IFINDEX here as well since sysfs 144 // uses IFINDEX. 145 asprintf(&mParams[1], "IFINDEX=%d", ifi->ifi_index); 146 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? Action::kLinkUp : 147 Action::kLinkDown; 148 mSubsystem = strdup("net"); 149 return true; 150 } 151 } 152 153 return false; 154 } 155 156 /* 157 * Parse a RTM_NEWADDR or RTM_DELADDR message. 158 */ 159 bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) { 160 struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh); 161 struct ifa_cacheinfo *cacheinfo = NULL; 162 char addrstr[INET6_ADDRSTRLEN] = ""; 163 char ifname[IFNAMSIZ] = ""; 164 165 if (!checkRtNetlinkLength(nh, sizeof(*ifaddr))) 166 return false; 167 168 // Sanity check. 169 int type = nh->nlmsg_type; 170 if (type != RTM_NEWADDR && type != RTM_DELADDR) { 171 SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type); 172 return false; 173 } 174 175 // For log messages. 176 const char *msgtype = rtMessageName(type); 177 178 struct rtattr *rta; 179 int len = IFA_PAYLOAD(nh); 180 for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { 181 if (rta->rta_type == IFA_ADDRESS) { 182 // Only look at the first address, because we only support notifying 183 // one change at a time. 184 if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype)) 185 continue; 186 187 // Convert the IP address to a string. 188 if (ifaddr->ifa_family == AF_INET) { 189 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta); 190 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) { 191 SLOGE("Short IPv4 address (%zu bytes) in %s", 192 RTA_PAYLOAD(rta), msgtype); 193 continue; 194 } 195 inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr)); 196 } else if (ifaddr->ifa_family == AF_INET6) { 197 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta); 198 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) { 199 SLOGE("Short IPv6 address (%zu bytes) in %s", 200 RTA_PAYLOAD(rta), msgtype); 201 continue; 202 } 203 inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr)); 204 } else { 205 SLOGE("Unknown address family %d\n", ifaddr->ifa_family); 206 continue; 207 } 208 209 // Find the interface name. 210 if (!if_indextoname(ifaddr->ifa_index, ifname)) { 211 SLOGD("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype); 212 } 213 214 } else if (rta->rta_type == IFA_CACHEINFO) { 215 // Address lifetime information. 216 if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype)) 217 continue; 218 219 if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) { 220 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s", 221 RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype); 222 continue; 223 } 224 225 cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta); 226 } 227 } 228 229 if (addrstr[0] == '\0') { 230 SLOGE("No IFA_ADDRESS in %s\n", msgtype); 231 return false; 232 } 233 234 // Fill in netlink event information. 235 mAction = (type == RTM_NEWADDR) ? Action::kAddressUpdated : 236 Action::kAddressRemoved; 237 mSubsystem = strdup("net"); 238 asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, ifaddr->ifa_prefixlen); 239 asprintf(&mParams[1], "INTERFACE=%s", ifname); 240 asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags); 241 asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope); 242 asprintf(&mParams[4], "IFINDEX=%u", ifaddr->ifa_index); 243 244 if (cacheinfo) { 245 asprintf(&mParams[5], "PREFERRED=%u", cacheinfo->ifa_prefered); 246 asprintf(&mParams[6], "VALID=%u", cacheinfo->ifa_valid); 247 asprintf(&mParams[7], "CSTAMP=%u", cacheinfo->cstamp); 248 asprintf(&mParams[8], "TSTAMP=%u", cacheinfo->tstamp); 249 } 250 251 return true; 252 } 253 254 /* 255 * Parse a QLOG_NL_EVENT message. 256 */ 257 bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) { 258 const char *devname; 259 ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh); 260 if (!checkRtNetlinkLength(nh, sizeof(*pm))) 261 return false; 262 263 devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name; 264 asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix); 265 asprintf(&mParams[1], "INTERFACE=%s", devname); 266 mSubsystem = strdup("qlog"); 267 mAction = Action::kChange; 268 return true; 269 } 270 271 static size_t nlAttrLen(const nlattr* nla) { 272 return nla->nla_len - NLA_HDRLEN; 273 } 274 275 static const uint8_t* nlAttrData(const nlattr* nla) { 276 return reinterpret_cast<const uint8_t*>(nla) + NLA_HDRLEN; 277 } 278 279 static uint32_t nlAttrU32(const nlattr* nla) { 280 return *reinterpret_cast<const uint32_t*>(nlAttrData(nla)); 281 } 282 283 /* 284 * Parse a LOCAL_NFLOG_PACKET message. 285 */ 286 bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) { 287 int uid = -1; 288 int len = 0; 289 char* raw = NULL; 290 291 struct nlattr* uid_attr = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_UID); 292 if (uid_attr) { 293 uid = ntohl(nlAttrU32(uid_attr)); 294 } 295 296 struct nlattr* payload = findNlAttr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD); 297 if (payload) { 298 /* First 256 bytes is plenty */ 299 len = nlAttrLen(payload); 300 if (len > 256) len = 256; 301 raw = (char*)nlAttrData(payload); 302 } 303 304 char* hex = (char*) calloc(1, 5 + (len * 2)); 305 strcpy(hex, "HEX="); 306 for (int i = 0; i < len; i++) { 307 hex[4 + (i * 2)] = "0123456789abcdef"[(raw[i] >> 4) & 0xf]; 308 hex[5 + (i * 2)] = "0123456789abcdef"[raw[i] & 0xf]; 309 } 310 311 asprintf(&mParams[0], "UID=%d", uid); 312 mParams[1] = hex; 313 mSubsystem = strdup("strict"); 314 mAction = Action::kChange; 315 return true; 316 } 317 318 /* 319 * Parse a RTM_NEWROUTE or RTM_DELROUTE message. 320 */ 321 bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) { 322 uint8_t type = nh->nlmsg_type; 323 const char *msgname = rtMessageName(type); 324 325 // Sanity check. 326 if (type != RTM_NEWROUTE && type != RTM_DELROUTE) { 327 SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname); 328 return false; 329 } 330 331 struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh); 332 if (!checkRtNetlinkLength(nh, sizeof(*rtm))) 333 return false; 334 335 if (// Ignore static routes we've set up ourselves. 336 (rtm->rtm_protocol != RTPROT_KERNEL && 337 rtm->rtm_protocol != RTPROT_RA) || 338 // We're only interested in global unicast routes. 339 (rtm->rtm_scope != RT_SCOPE_UNIVERSE) || 340 (rtm->rtm_type != RTN_UNICAST) || 341 // We don't support source routing. 342 (rtm->rtm_src_len != 0) || 343 // Cloned routes aren't real routes. 344 (rtm->rtm_flags & RTM_F_CLONED)) { 345 return false; 346 } 347 348 int family = rtm->rtm_family; 349 int prefixLength = rtm->rtm_dst_len; 350 351 // Currently we only support: destination, (one) next hop, ifindex. 352 char dst[INET6_ADDRSTRLEN] = ""; 353 char gw[INET6_ADDRSTRLEN] = ""; 354 char dev[IFNAMSIZ] = ""; 355 356 size_t len = RTM_PAYLOAD(nh); 357 struct rtattr *rta; 358 for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) { 359 switch (rta->rta_type) { 360 case RTA_DST: 361 if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname)) 362 continue; 363 if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst))) 364 return false; 365 continue; 366 case RTA_GATEWAY: 367 if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname)) 368 continue; 369 if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw))) 370 return false; 371 continue; 372 case RTA_OIF: 373 if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname)) 374 continue; 375 if (!if_indextoname(* (int *) RTA_DATA(rta), dev)) 376 return false; 377 default: 378 continue; 379 } 380 } 381 382 // If there's no RTA_DST attribute, then: 383 // - If the prefix length is zero, it's the default route. 384 // - If the prefix length is nonzero, there's something we don't understand. 385 // Ignore the event. 386 if (!*dst && !prefixLength) { 387 if (family == AF_INET) { 388 strncpy(dst, "0.0.0.0", sizeof(dst)); 389 } else if (family == AF_INET6) { 390 strncpy(dst, "::", sizeof(dst)); 391 } 392 } 393 394 // A useful route must have a destination and at least either a gateway or 395 // an interface. 396 if (!*dst || (!*gw && !*dev)) 397 return false; 398 399 // Fill in netlink event information. 400 mAction = (type == RTM_NEWROUTE) ? Action::kRouteUpdated : 401 Action::kRouteRemoved; 402 mSubsystem = strdup("net"); 403 asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength); 404 asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : ""); 405 asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : ""); 406 407 return true; 408 } 409 410 /* 411 * Parse a RTM_NEWNDUSEROPT message. 412 */ 413 bool NetlinkEvent::parseNdUserOptMessage(const struct nlmsghdr *nh) { 414 struct nduseroptmsg *msg = (struct nduseroptmsg *) NLMSG_DATA(nh); 415 if (!checkRtNetlinkLength(nh, sizeof(*msg))) 416 return false; 417 418 // Check the length is valid. 419 int len = NLMSG_PAYLOAD(nh, sizeof(*msg)); 420 if (msg->nduseropt_opts_len > len) { 421 SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n", 422 msg->nduseropt_opts_len, len); 423 return false; 424 } 425 len = msg->nduseropt_opts_len; 426 427 // Check address family and packet type. 428 if (msg->nduseropt_family != AF_INET6) { 429 SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n", 430 msg->nduseropt_family); 431 return false; 432 } 433 434 if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT || 435 msg->nduseropt_icmp_code != 0) { 436 SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n", 437 msg->nduseropt_icmp_type, msg->nduseropt_icmp_code); 438 return false; 439 } 440 441 // Find the interface name. 442 char ifname[IFNAMSIZ]; 443 if (!if_indextoname(msg->nduseropt_ifindex, ifname)) { 444 SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n", 445 msg->nduseropt_ifindex); 446 return false; 447 } 448 449 // The kernel sends a separate netlink message for each ND option in the RA. 450 // So only parse the first ND option in the message. 451 struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1); 452 453 // The length is in multiples of 8 octets. 454 uint16_t optlen = opthdr->nd_opt_len; 455 if (optlen * 8 > len) { 456 SLOGE("Invalid option length %d > %d for ND option %d\n", 457 optlen * 8, len, opthdr->nd_opt_type); 458 return false; 459 } 460 461 if (opthdr->nd_opt_type == ND_OPT_RDNSS) { 462 // DNS Servers (RFC 6106). 463 // Each address takes up 2*8 octets, and the header takes up 8 octets. 464 // So for a valid option with one or more addresses, optlen must be 465 // odd and greater than 1. 466 if ((optlen < 3) || !(optlen & 0x1)) { 467 SLOGE("Invalid optlen %d for RDNSS option\n", optlen); 468 return false; 469 } 470 const int numaddrs = (optlen - 1) / 2; 471 472 // Find the lifetime. 473 struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr; 474 const uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime); 475 476 // Construct "SERVERS=<comma-separated string of DNS addresses>". 477 static const char kServerTag[] = "SERVERS="; 478 static const size_t kTagLength = strlen(kServerTag); 479 // Reserve sufficient space for an IPv6 link-local address: all but the 480 // last address are followed by ','; the last is followed by '\0'. 481 static const size_t kMaxSingleAddressLength = 482 INET6_ADDRSTRLEN + strlen("%") + IFNAMSIZ + strlen(","); 483 const size_t bufsize = kTagLength + numaddrs * kMaxSingleAddressLength; 484 char *buf = (char *) malloc(bufsize); 485 if (!buf) { 486 SLOGE("RDNSS option: out of memory\n"); 487 return false; 488 } 489 strcpy(buf, kServerTag); 490 size_t pos = kTagLength; 491 492 struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1); 493 for (int i = 0; i < numaddrs; i++) { 494 if (i > 0) { 495 buf[pos++] = ','; 496 } 497 inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos); 498 pos += strlen(buf + pos); 499 if (IN6_IS_ADDR_LINKLOCAL(addrs + i)) { 500 buf[pos++] = '%'; 501 pos += strlcpy(buf + pos, ifname, bufsize - pos); 502 } 503 } 504 buf[pos] = '\0'; 505 506 mAction = Action::kRdnss; 507 mSubsystem = strdup("net"); 508 asprintf(&mParams[0], "INTERFACE=%s", ifname); 509 asprintf(&mParams[1], "LIFETIME=%u", lifetime); 510 mParams[2] = buf; 511 } else if (opthdr->nd_opt_type == ND_OPT_DNSSL) { 512 // TODO: support DNSSL. 513 } else { 514 SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type); 515 return false; 516 } 517 518 return true; 519 } 520 521 /* 522 * Parse a binary message from a NETLINK_ROUTE netlink socket. 523 * 524 * Note that this function can only parse one message, because the message's 525 * content has to be stored in the class's member variables (mAction, 526 * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if 527 * there are multiple valid messages in the buffer, only the first one will be 528 * returned. 529 * 530 * TODO: consider only ever looking at the first message. 531 */ 532 bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { 533 struct nlmsghdr *nh; 534 535 for (nh = (struct nlmsghdr *) buffer; 536 NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE); 537 nh = NLMSG_NEXT(nh, size)) { 538 539 if (!rtMessageName(nh->nlmsg_type)) { 540 SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type); 541 continue; 542 } 543 544 if (nh->nlmsg_type == RTM_NEWLINK) { 545 if (parseIfInfoMessage(nh)) 546 return true; 547 548 } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) { 549 if (parseUlogPacketMessage(nh)) 550 return true; 551 552 } else if (nh->nlmsg_type == RTM_NEWADDR || 553 nh->nlmsg_type == RTM_DELADDR) { 554 if (parseIfAddrMessage(nh)) 555 return true; 556 557 } else if (nh->nlmsg_type == RTM_NEWROUTE || 558 nh->nlmsg_type == RTM_DELROUTE) { 559 if (parseRtMessage(nh)) 560 return true; 561 562 } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) { 563 if (parseNdUserOptMessage(nh)) 564 return true; 565 566 } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) { 567 if (parseNfPacketMessage(nh)) 568 return true; 569 570 } 571 } 572 573 return false; 574 } 575 576 /* If the string between 'str' and 'end' begins with 'prefixlen' characters 577 * from the 'prefix' array, then return 'str + prefixlen', otherwise return 578 * NULL. 579 */ 580 static const char* 581 has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen) 582 { 583 if ((end - str) >= (ptrdiff_t)prefixlen && 584 (prefixlen == 0 || !memcmp(str, prefix, prefixlen))) { 585 return str + prefixlen; 586 } else { 587 return NULL; 588 } 589 } 590 591 /* Same as strlen(x) for constant string literals ONLY */ 592 #define CONST_STRLEN(x) (sizeof(x)-1) 593 594 /* Convenience macro to call has_prefix with a constant string literal */ 595 #define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix)) 596 597 598 /* 599 * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT 600 * netlink socket. 601 */ 602 bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) { 603 const char *s = buffer; 604 const char *end; 605 int param_idx = 0; 606 int first = 1; 607 608 if (size == 0) 609 return false; 610 611 /* Ensure the buffer is zero-terminated, the code below depends on this */ 612 buffer[size-1] = '\0'; 613 614 end = s + size; 615 while (s < end) { 616 if (first) { 617 const char *p; 618 /* buffer is 0-terminated, no need to check p < end */ 619 for (p = s; *p != '@'; p++) { 620 if (!*p) { /* no '@', should not happen */ 621 return false; 622 } 623 } 624 mPath = strdup(p+1); 625 first = 0; 626 } else { 627 const char* a; 628 if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) { 629 if (!strcmp(a, "add")) 630 mAction = Action::kAdd; 631 else if (!strcmp(a, "remove")) 632 mAction = Action::kRemove; 633 else if (!strcmp(a, "change")) 634 mAction = Action::kChange; 635 } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) { 636 mSeq = atoi(a); 637 } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) { 638 mSubsystem = strdup(a); 639 } else if (param_idx < NL_PARAMS_MAX) { 640 mParams[param_idx++] = strdup(s); 641 } 642 } 643 s += strlen(s) + 1; 644 } 645 return true; 646 } 647 648 bool NetlinkEvent::decode(char *buffer, int size, int format) { 649 if (format == NetlinkListener::NETLINK_FORMAT_BINARY 650 || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) { 651 return parseBinaryNetlinkMessage(buffer, size); 652 } else { 653 return parseAsciiNetlinkMessage(buffer, size); 654 } 655 } 656 657 const char *NetlinkEvent::findParam(const char *paramName) { 658 size_t len = strlen(paramName); 659 for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) { 660 const char *ptr = mParams[i] + len; 661 if (!strncmp(mParams[i], paramName, len) && *ptr == '=') 662 return ++ptr; 663 } 664 665 SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName); 666 return NULL; 667 } 668 669 nlattr* NetlinkEvent::findNlAttr(const nlmsghdr* nh, size_t hdrlen, uint16_t attr) { 670 if (nh == nullptr || NLMSG_HDRLEN + NLMSG_ALIGN(hdrlen) > SSIZE_MAX) { 671 return nullptr; 672 } 673 674 // Skip header, padding, and family header. 675 const ssize_t NLA_START = NLMSG_HDRLEN + NLMSG_ALIGN(hdrlen); 676 ssize_t left = nh->nlmsg_len - NLA_START; 677 uint8_t* hdr = ((uint8_t*)nh) + NLA_START; 678 679 while (left >= NLA_HDRLEN) { 680 nlattr* nla = (nlattr*)hdr; 681 if (nla->nla_type == attr) { 682 return nla; 683 } 684 685 hdr += NLA_ALIGN(nla->nla_len); 686 left -= NLA_ALIGN(nla->nla_len); 687 } 688 689 return nullptr; 690 } 691