diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2013-11-20 02:21:29 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2013-11-20 02:21:30 +0000 |
commit | 8c099bc206094dd229f4468b85c23b8639fb05ea (patch) | |
tree | b6a9975fad93b8fdc56a8c082ee9f6e1a75931b2 | |
parent | 3fa14a53e70cd55df031646fe3735a6fde37deb8 (diff) | |
parent | 381f70f52a282e6da780e4b686aaa9c230be2cdc (diff) | |
download | system_core-8c099bc206094dd229f4468b85c23b8639fb05ea.zip system_core-8c099bc206094dd229f4468b85c23b8639fb05ea.tar.gz system_core-8c099bc206094dd229f4468b85c23b8639fb05ea.tar.bz2 |
Merge "Parse IP address changes in NetlinkEvent."
-rw-r--r-- | include/sysutils/NetlinkEvent.h | 1 | ||||
-rw-r--r-- | libsysutils/src/NetlinkEvent.cpp | 117 |
2 files changed, 117 insertions, 1 deletions
diff --git a/include/sysutils/NetlinkEvent.h b/include/sysutils/NetlinkEvent.h index 25a56f7..2a734cb 100644 --- a/include/sysutils/NetlinkEvent.h +++ b/include/sysutils/NetlinkEvent.h @@ -47,6 +47,7 @@ public: void dump(); protected: + bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize); bool parseBinaryNetlinkMessage(char *buffer, int size); bool parseAsciiNetlinkMessage(char *buffer, int size); }; diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 4beebb7..b6da72f 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -23,6 +23,10 @@ #include <sys/types.h> #include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <net/if.h> + #include <linux/if.h> #include <linux/netfilter/nfnetlink.h> #include <linux/netfilter_ipv4/ipt_ULOG.h> @@ -70,6 +74,102 @@ void NetlinkEvent::dump() { } /* + * Decode a RTM_NEWADDR or RTM_DELADDR message. + */ +bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, + int rtasize) { + struct rtattr *rta = IFA_RTA(ifaddr); + struct ifa_cacheinfo *cacheinfo = NULL; + char addrstr[INET6_ADDRSTRLEN] = ""; + + // Sanity check. + if (type != RTM_NEWADDR && type != RTM_DELADDR) { + SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type); + return false; + } + + // For log messages. + const char *msgtype = (type == RTM_NEWADDR) ? "RTM_NEWADDR" : "RTM_DELADDR"; + + while(RTA_OK(rta, rtasize)) { + if (rta->rta_type == IFA_ADDRESS) { + // Only look at the first address, because we only support notifying + // one change at a time. + if (*addrstr != '\0') { + SLOGE("Multiple IFA_ADDRESSes in %s, ignoring\n", msgtype); + continue; + } + + // Convert the IP address to a string. + if (ifaddr->ifa_family == AF_INET) { + struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta); + if (RTA_PAYLOAD(rta) < sizeof(*addr4)) { + SLOGE("Short IPv4 address (%d bytes) in %s", + RTA_PAYLOAD(rta), msgtype); + continue; + } + inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr)); + } else if (ifaddr->ifa_family == AF_INET6) { + struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta); + if (RTA_PAYLOAD(rta) < sizeof(*addr6)) { + SLOGE("Short IPv6 address (%d bytes) in %s", + RTA_PAYLOAD(rta), msgtype); + continue; + } + inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr)); + } else { + SLOGE("Unknown address family %d\n", ifaddr->ifa_family); + continue; + } + + // Find the interface name. + char ifname[IFNAMSIZ + 1]; + if (!if_indextoname(ifaddr->ifa_index, ifname)) { + SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype); + return false; + } + + // Fill in interface information. + mAction = (type == RTM_NEWADDR) ? NlActionAdd : NlActionRemove; + mSubsystem = strdup("address"); + asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr, + ifaddr->ifa_prefixlen); + asprintf(&mParams[1], "IFACE=%s", ifname); + asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags); + asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope); + } else if (rta->rta_type == IFA_CACHEINFO) { + // Address lifetime information. + if (cacheinfo) { + // We only support one address. + SLOGE("Multiple IFA_CACHEINFOs in %s, ignoring\n", msgtype); + continue; + } + + if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) { + SLOGE("Short IFA_CACHEINFO (%d vs. %d bytes) in %s", + RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype); + continue; + } + + cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta); + asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered); + asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid); + asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp); + asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp); + } + + rta = RTA_NEXT(rta, rtasize); + } + + if (addrstr[0] == '\0') { + SLOGE("No IFA_ADDRESS in %s\n", msgtype); + return false; + } + + return true; +} + +/* * Parse an binary message from a NETLINK_ROUTE netlink socket. */ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { @@ -105,7 +205,7 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { mParams[0] = strdup(buffer); mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp : NlActionLinkDown; - mSubsystem = strdup("net"); + mSubsystem = strdup("interface"); break; } @@ -127,6 +227,21 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) { mSubsystem = strdup("qlog"); mAction = NlActionChange; + } else if (nh->nlmsg_type == RTM_NEWADDR || + nh->nlmsg_type == RTM_DELADDR) { + int len = nh->nlmsg_len - sizeof(*nh); + struct ifaddrmsg *ifa; + + if (sizeof(*ifa) > (size_t) len) { + SLOGE("Got a short RTM_xxxADDR message\n"); + continue; + } + + ifa = (ifaddrmsg *)NLMSG_DATA(nh); + size_t rtasize = IFA_PAYLOAD(nh); + if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) { + continue; + } } else { SLOGD("Unexpected netlink message. type=0x%x\n", nh->nlmsg_type); } |