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