Support parsing netlink route messages.

Bug: 9180552
Change-Id: I4a36d869ac692647fb226d0912285bdf2ffcb1fa
This commit is contained in:
Lorenzo Colitti 2014-06-11 17:37:12 +09:00
parent 9b34293566
commit d7ff7ea652
2 changed files with 102 additions and 0 deletions

View file

@ -37,6 +37,8 @@ public:
const static int NlActionAddressUpdated;
const static int NlActionAddressRemoved;
const static int NlActionRdnss;
const static int NlActionRouteUpdated;
const static int NlActionRouteRemoved;
NetlinkEvent();
virtual ~NetlinkEvent();
@ -55,6 +57,7 @@ public:
bool parseIfInfoMessage(const struct nlmsghdr *nh);
bool parseIfAddrMessage(const struct nlmsghdr *nh);
bool parseUlogPacketMessage(const struct nlmsghdr *nh);
bool parseRtMessage(const struct nlmsghdr *nh);
bool parseNdUserOptMessage(const struct nlmsghdr *nh);
};

View file

@ -48,6 +48,8 @@ const int NetlinkEvent::NlActionLinkDown = 5;
const int NetlinkEvent::NlActionAddressUpdated = 6;
const int NetlinkEvent::NlActionAddressRemoved = 7;
const int NetlinkEvent::NlActionRdnss = 8;
const int NetlinkEvent::NlActionRouteUpdated = 9;
const int NetlinkEvent::NlActionRouteRemoved = 10;
NetlinkEvent::NetlinkEvent() {
mAction = NlActionUnknown;
@ -269,6 +271,98 @@ bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
return true;
}
/*
* Parse a RTM_NEWROUTE or RTM_DELROUTE message.
*/
bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) {
uint8_t type = nh->nlmsg_type;
const char *msgname = rtMessageName(type);
// Sanity check.
if (type != RTM_NEWROUTE && type != RTM_DELROUTE) {
SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname);
return false;
}
struct rtmsg *rtm = (struct rtmsg *) NLMSG_DATA(nh);
if (!checkRtNetlinkLength(nh, sizeof(*rtm)))
return false;
if (// Ignore static routes we've set up ourselves.
(rtm->rtm_protocol != RTPROT_KERNEL &&
rtm->rtm_protocol != RTPROT_RA) ||
// We're only interested in global unicast routes.
(rtm->rtm_scope != RT_SCOPE_UNIVERSE) ||
(rtm->rtm_type != RTN_UNICAST) ||
// We don't support source routing.
(rtm->rtm_src_len != 0) ||
// Cloned routes aren't real routes.
(rtm->rtm_flags & RTM_F_CLONED)) {
return false;
}
int family = rtm->rtm_family;
int prefixLength = rtm->rtm_dst_len;
// Currently we only support: destination, (one) next hop, ifindex.
char dst[INET6_ADDRSTRLEN] = "";
char gw[INET6_ADDRSTRLEN] = "";
char dev[IFNAMSIZ] = "";
size_t len = RTM_PAYLOAD(nh);
struct rtattr *rta;
for (rta = RTM_RTA(rtm); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
switch (rta->rta_type) {
case RTA_DST:
if (maybeLogDuplicateAttribute(*dst, "RTA_DST", msgname))
continue;
if (!inet_ntop(family, RTA_DATA(rta), dst, sizeof(dst)))
return false;
continue;
case RTA_GATEWAY:
if (maybeLogDuplicateAttribute(*gw, "RTA_GATEWAY", msgname))
continue;
if (!inet_ntop(family, RTA_DATA(rta), gw, sizeof(gw)))
return false;
continue;
case RTA_OIF:
if (maybeLogDuplicateAttribute(*dev, "RTA_OIF", msgname))
continue;
if (!if_indextoname(* (int *) RTA_DATA(rta), dev))
return false;
default:
continue;
}
}
// If there's no RTA_DST attribute, then:
// - If the prefix length is zero, it's the default route.
// - If the prefix length is nonzero, there's something we don't understand.
// Ignore the event.
if (!*dst && !prefixLength) {
if (family == AF_INET) {
strncpy(dst, "0.0.0.0", sizeof(dst));
} else if (family == AF_INET6) {
strncpy(dst, "::", sizeof(dst));
}
}
// A useful route must have a destination and at least either a gateway or
// an interface.
if (!*dst || (!*gw && !*dev))
return false;
// Fill in netlink event information.
mAction = (type == RTM_NEWROUTE) ? NlActionRouteUpdated :
NlActionRouteRemoved;
mSubsystem = strdup("net");
asprintf(&mParams[0], "ROUTE=%s/%d", dst, prefixLength);
asprintf(&mParams[1], "GATEWAY=%s", (*gw) ? gw : "");
asprintf(&mParams[2], "INTERFACE=%s", (*dev) ? dev : "");
return true;
}
/*
* Parse a RTM_NEWNDUSEROPT message.
*/
@ -408,6 +502,11 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
if (parseIfAddrMessage(nh))
return true;
} else if (nh->nlmsg_type == RTM_NEWROUTE ||
nh->nlmsg_type == RTM_DELROUTE) {
if (parseRtMessage(nh))
return true;
} else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
if (parseNdUserOptMessage(nh))
return true;