blob: 909df86476dbe56c94375a7cd1e2ceb10d7dc911 [file] [log] [blame]
San Mehat168415b2009-05-06 11:14:21 -07001/*
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>
San Mehat3d407292009-05-07 08:49:30 -070017#include <string.h>
San Mehat168415b2009-05-06 11:14:21 -070018
19#define LOG_TAG "NetlinkEvent"
20#include <cutils/log.h>
21
22#include <sysutils/NetlinkEvent.h>
23
Mike J. Chenec16b9d2011-06-23 14:55:28 -070024#include <sys/types.h>
25#include <sys/socket.h>
Lorenzo Colitti381f70f2013-08-02 05:58:37 +090026#include <netinet/in.h>
Lorenzo Colittic7eec832013-08-12 17:03:32 +090027#include <netinet/icmp6.h>
Lorenzo Colitti381f70f2013-08-02 05:58:37 +090028#include <arpa/inet.h>
29#include <net/if.h>
30
Mike J. Chenec16b9d2011-06-23 14:55:28 -070031#include <linux/if.h>
Lorenzo Colitti9b342932014-06-19 13:16:04 +090032#include <linux/if_addr.h>
33#include <linux/if_link.h>
JP Abgralle6f80142011-07-14 16:46:32 -070034#include <linux/netfilter/nfnetlink.h>
Jeff Sharkey9a20e672014-10-30 14:51:59 -070035#include <linux/netfilter/nfnetlink_log.h>
JP Abgralle6f80142011-07-14 16:46:32 -070036#include <linux/netfilter_ipv4/ipt_ULOG.h>
Jeff Sharkey9a20e672014-10-30 14:51:59 -070037
JP Abgralle6f80142011-07-14 16:46:32 -070038/* From kernel's net/netfilter/xt_quota2.c */
Jeff Sharkey9a20e672014-10-30 14:51:59 -070039const int LOCAL_QLOG_NL_EVENT = 112;
40const int LOCAL_NFLOG_PACKET = NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET;
JP Abgralle6f80142011-07-14 16:46:32 -070041
42#include <linux/netlink.h>
43#include <linux/rtnetlink.h>
Mike J. Chenec16b9d2011-06-23 14:55:28 -070044
Jeff Sharkey9a20e672014-10-30 14:51:59 -070045#include <netlink/attr.h>
46#include <netlink/genl/genl.h>
47#include <netlink/handlers.h>
48#include <netlink/msg.h>
49
San Mehat168415b2009-05-06 11:14:21 -070050const int NetlinkEvent::NlActionUnknown = 0;
51const int NetlinkEvent::NlActionAdd = 1;
52const int NetlinkEvent::NlActionRemove = 2;
53const int NetlinkEvent::NlActionChange = 3;
Mike J. Chenec16b9d2011-06-23 14:55:28 -070054const int NetlinkEvent::NlActionLinkUp = 4;
55const int NetlinkEvent::NlActionLinkDown = 5;
Lorenzo Colitti526b8382013-09-03 00:25:14 +090056const int NetlinkEvent::NlActionAddressUpdated = 6;
57const int NetlinkEvent::NlActionAddressRemoved = 7;
Lorenzo Colittic7eec832013-08-12 17:03:32 +090058const int NetlinkEvent::NlActionRdnss = 8;
Lorenzo Colittid7ff7ea2014-06-11 17:37:12 +090059const int NetlinkEvent::NlActionRouteUpdated = 9;
60const int NetlinkEvent::NlActionRouteRemoved = 10;
San Mehat168415b2009-05-06 11:14:21 -070061
62NetlinkEvent::NetlinkEvent() {
63 mAction = NlActionUnknown;
San Mehatebfe3db2009-10-10 17:35:13 -070064 memset(mParams, 0, sizeof(mParams));
65 mPath = NULL;
66 mSubsystem = NULL;
San Mehat168415b2009-05-06 11:14:21 -070067}
68
69NetlinkEvent::~NetlinkEvent() {
70 int i;
71 if (mPath)
72 free(mPath);
73 if (mSubsystem)
74 free(mSubsystem);
75 for (i = 0; i < NL_PARAMS_MAX; i++) {
76 if (!mParams[i])
77 break;
78 free(mParams[i]);
79 }
80}
81
San Mehatd6744132009-12-24 07:17:09 -080082void NetlinkEvent::dump() {
83 int i;
84
85 for (i = 0; i < NL_PARAMS_MAX; i++) {
86 if (!mParams[i])
87 break;
San Mehat7e8529a2010-03-25 09:31:42 -070088 SLOGD("NL param '%s'\n", mParams[i]);
San Mehatd6744132009-12-24 07:17:09 -080089 }
90}
91
Mike J. Chenec16b9d2011-06-23 14:55:28 -070092/*
Lorenzo Colitti9b342932014-06-19 13:16:04 +090093 * Returns the message name for a message in the NETLINK_ROUTE family, or NULL
94 * if parsing that message is not supported.
95 */
96static const char *rtMessageName(int type) {
97#define NL_EVENT_RTM_NAME(rtm) case rtm: return #rtm;
98 switch (type) {
99 NL_EVENT_RTM_NAME(RTM_NEWLINK);
100 NL_EVENT_RTM_NAME(RTM_DELLINK);
101 NL_EVENT_RTM_NAME(RTM_NEWADDR);
102 NL_EVENT_RTM_NAME(RTM_DELADDR);
103 NL_EVENT_RTM_NAME(RTM_NEWROUTE);
104 NL_EVENT_RTM_NAME(RTM_DELROUTE);
105 NL_EVENT_RTM_NAME(RTM_NEWNDUSEROPT);
Jeff Sharkey9a20e672014-10-30 14:51:59 -0700106 NL_EVENT_RTM_NAME(LOCAL_QLOG_NL_EVENT);
107 NL_EVENT_RTM_NAME(LOCAL_NFLOG_PACKET);
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900108 default:
109 return NULL;
110 }
111#undef NL_EVENT_RTM_NAME
112}
113
114/*
115 * Checks that a binary NETLINK_ROUTE message is long enough for a payload of
116 * size bytes.
117 */
118static bool checkRtNetlinkLength(const struct nlmsghdr *nh, size_t size) {
119 if (nh->nlmsg_len < NLMSG_LENGTH(size)) {
120 SLOGE("Got a short %s message\n", rtMessageName(nh->nlmsg_type));
121 return false;
122 }
123 return true;
124}
125
126/*
127 * Utility function to log errors.
128 */
129static bool maybeLogDuplicateAttribute(bool isDup,
130 const char *attributeName,
131 const char *messageName) {
132 if (isDup) {
133 SLOGE("Multiple %s attributes in %s, ignoring\n", attributeName, messageName);
134 return true;
135 }
136 return false;
137}
138
139/*
140 * Parse a RTM_NEWLINK message.
141 */
142bool NetlinkEvent::parseIfInfoMessage(const struct nlmsghdr *nh) {
143 struct ifinfomsg *ifi = (struct ifinfomsg *) NLMSG_DATA(nh);
144 if (!checkRtNetlinkLength(nh, sizeof(*ifi)))
145 return false;
146
147 if ((ifi->ifi_flags & IFF_LOOPBACK) != 0) {
148 return false;
149 }
150
151 int len = IFLA_PAYLOAD(nh);
152 struct rtattr *rta;
153 for (rta = IFLA_RTA(ifi); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
154 switch(rta->rta_type) {
155 case IFLA_IFNAME:
156 asprintf(&mParams[0], "INTERFACE=%s", (char *) RTA_DATA(rta));
157 mAction = (ifi->ifi_flags & IFF_LOWER_UP) ? NlActionLinkUp :
158 NlActionLinkDown;
159 mSubsystem = strdup("net");
160 return true;
161 }
162 }
163
164 return false;
165}
166
167/*
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900168 * Parse a RTM_NEWADDR or RTM_DELADDR message.
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900169 */
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900170bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) {
171 struct ifaddrmsg *ifaddr = (struct ifaddrmsg *) NLMSG_DATA(nh);
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900172 struct ifa_cacheinfo *cacheinfo = NULL;
173 char addrstr[INET6_ADDRSTRLEN] = "";
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900174 char ifname[IFNAMSIZ];
175
176 if (!checkRtNetlinkLength(nh, sizeof(*ifaddr)))
177 return false;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900178
179 // Sanity check.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900180 int type = nh->nlmsg_type;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900181 if (type != RTM_NEWADDR && type != RTM_DELADDR) {
182 SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type);
183 return false;
184 }
185
186 // For log messages.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900187 const char *msgtype = rtMessageName(type);
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900188
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900189 struct rtattr *rta;
190 int len = IFA_PAYLOAD(nh);
191 for (rta = IFA_RTA(ifaddr); RTA_OK(rta, len); rta = RTA_NEXT(rta, len)) {
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900192 if (rta->rta_type == IFA_ADDRESS) {
193 // Only look at the first address, because we only support notifying
194 // one change at a time.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900195 if (maybeLogDuplicateAttribute(*addrstr != '\0', "IFA_ADDRESS", msgtype))
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900196 continue;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900197
198 // Convert the IP address to a string.
199 if (ifaddr->ifa_family == AF_INET) {
200 struct in_addr *addr4 = (struct in_addr *) RTA_DATA(rta);
201 if (RTA_PAYLOAD(rta) < sizeof(*addr4)) {
Mark Salyzyn80f63d42014-05-01 07:47:04 -0700202 SLOGE("Short IPv4 address (%zu bytes) in %s",
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900203 RTA_PAYLOAD(rta), msgtype);
204 continue;
205 }
206 inet_ntop(AF_INET, addr4, addrstr, sizeof(addrstr));
207 } else if (ifaddr->ifa_family == AF_INET6) {
208 struct in6_addr *addr6 = (struct in6_addr *) RTA_DATA(rta);
209 if (RTA_PAYLOAD(rta) < sizeof(*addr6)) {
Mark Salyzyn80f63d42014-05-01 07:47:04 -0700210 SLOGE("Short IPv6 address (%zu bytes) in %s",
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900211 RTA_PAYLOAD(rta), msgtype);
212 continue;
213 }
214 inet_ntop(AF_INET6, addr6, addrstr, sizeof(addrstr));
215 } else {
216 SLOGE("Unknown address family %d\n", ifaddr->ifa_family);
217 continue;
218 }
219
220 // Find the interface name.
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900221 if (!if_indextoname(ifaddr->ifa_index, ifname)) {
222 SLOGE("Unknown ifindex %d in %s", ifaddr->ifa_index, msgtype);
223 return false;
224 }
225
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900226 } else if (rta->rta_type == IFA_CACHEINFO) {
227 // Address lifetime information.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900228 if (maybeLogDuplicateAttribute(cacheinfo, "IFA_CACHEINFO", msgtype))
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900229 continue;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900230
231 if (RTA_PAYLOAD(rta) < sizeof(*cacheinfo)) {
Mark Salyzyn80f63d42014-05-01 07:47:04 -0700232 SLOGE("Short IFA_CACHEINFO (%zu vs. %zu bytes) in %s",
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900233 RTA_PAYLOAD(rta), sizeof(cacheinfo), msgtype);
234 continue;
235 }
236
237 cacheinfo = (struct ifa_cacheinfo *) RTA_DATA(rta);
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900238 }
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900239 }
240
241 if (addrstr[0] == '\0') {
242 SLOGE("No IFA_ADDRESS in %s\n", msgtype);
243 return false;
244 }
245
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900246 // Fill in netlink event information.
247 mAction = (type == RTM_NEWADDR) ? NlActionAddressUpdated :
248 NlActionAddressRemoved;
249 mSubsystem = strdup("net");
250 asprintf(&mParams[0], "ADDRESS=%s/%d", addrstr,
251 ifaddr->ifa_prefixlen);
252 asprintf(&mParams[1], "INTERFACE=%s", ifname);
253 asprintf(&mParams[2], "FLAGS=%u", ifaddr->ifa_flags);
254 asprintf(&mParams[3], "SCOPE=%u", ifaddr->ifa_scope);
255
256 if (cacheinfo) {
257 asprintf(&mParams[4], "PREFERRED=%u", cacheinfo->ifa_prefered);
258 asprintf(&mParams[5], "VALID=%u", cacheinfo->ifa_valid);
259 asprintf(&mParams[6], "CSTAMP=%u", cacheinfo->cstamp);
260 asprintf(&mParams[7], "TSTAMP=%u", cacheinfo->tstamp);
261 }
262
263 return true;
264}
265
266/*
267 * Parse a QLOG_NL_EVENT message.
268 */
269bool NetlinkEvent::parseUlogPacketMessage(const struct nlmsghdr *nh) {
270 const char *devname;
271 ulog_packet_msg_t *pm = (ulog_packet_msg_t *) NLMSG_DATA(nh);
272 if (!checkRtNetlinkLength(nh, sizeof(*pm)))
273 return false;
274
275 devname = pm->indev_name[0] ? pm->indev_name : pm->outdev_name;
276 asprintf(&mParams[0], "ALERT_NAME=%s", pm->prefix);
277 asprintf(&mParams[1], "INTERFACE=%s", devname);
278 mSubsystem = strdup("qlog");
279 mAction = NlActionChange;
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900280 return true;
281}
282
283/*
Jeff Sharkey9a20e672014-10-30 14:51:59 -0700284 * Parse a LOCAL_NFLOG_PACKET message.
285 */
286bool NetlinkEvent::parseNfPacketMessage(struct nlmsghdr *nh) {
287 int uid = -1;
288 int len = 0;
289 char* raw = NULL;
290
291 struct nlattr *uid_attr = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_UID);
292 if (uid_attr) {
293 uid = ntohl(nla_get_u32(uid_attr));
294 }
295
296 struct nlattr *payload = nlmsg_find_attr(nh, sizeof(struct genlmsghdr), NFULA_PAYLOAD);
297 if (payload) {
298 /* First 256 bytes is plenty */
299 len = nla_len(payload);
300 if (len > 256) len = 256;
301 raw = (char*) nla_data(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 = NlActionChange;
315 return true;
316}
317
318/*
Lorenzo Colittid7ff7ea2014-06-11 17:37:12 +0900319 * Parse a RTM_NEWROUTE or RTM_DELROUTE message.
320 */
321bool 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) ? NlActionRouteUpdated :
401 NlActionRouteRemoved;
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/*
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900411 * Parse a RTM_NEWNDUSEROPT message.
412 */
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900413bool 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
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900418 // Check the length is valid.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900419 int len = NLMSG_PAYLOAD(nh, sizeof(*msg));
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900420 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.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900442 char ifname[IFNAMSIZ];
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900443 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 int numaddrs = (optlen - 1) / 2;
471
472 // Find the lifetime.
473 struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
474 uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
475
476 // Construct "SERVERS=<comma-separated string of DNS addresses>".
477 // Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
478 // the last address are followed by ','; the last is followed by '\0'.
479 static const char kServerTag[] = "SERVERS=";
480 static const int kTagLength = sizeof(kServerTag) - 1;
481 int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
482 char *buf = (char *) malloc(bufsize);
483 if (!buf) {
484 SLOGE("RDNSS option: out of memory\n");
485 return false;
486 }
487 strcpy(buf, kServerTag);
488 int pos = kTagLength;
489
490 struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
491 for (int i = 0; i < numaddrs; i++) {
492 if (i > 0) {
493 buf[pos++] = ',';
494 }
495 inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
496 pos += strlen(buf + pos);
497 }
498 buf[pos] = '\0';
499
500 mAction = NlActionRdnss;
501 mSubsystem = strdup("net");
502 asprintf(&mParams[0], "INTERFACE=%s", ifname);
503 asprintf(&mParams[1], "LIFETIME=%u", lifetime);
504 mParams[2] = buf;
505 } else {
506 SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
507 return false;
508 }
509
510 return true;
511}
512
513/*
514 * Parse a binary message from a NETLINK_ROUTE netlink socket.
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900515 *
516 * Note that this function can only parse one message, because the message's
517 * content has to be stored in the class's member variables (mAction,
518 * mSubsystem, etc.). Invalid or unrecognized messages are skipped, but if
519 * there are multiple valid messages in the buffer, only the first one will be
520 * returned.
521 *
522 * TODO: consider only ever looking at the first message.
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700523 */
524bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
Jeff Sharkey9a20e672014-10-30 14:51:59 -0700525 struct nlmsghdr *nh;
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700526
Lorenzo Colitti96834562013-08-17 03:40:31 +0900527 for (nh = (struct nlmsghdr *) buffer;
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900528 NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
Lorenzo Colitti96834562013-08-17 03:40:31 +0900529 nh = NLMSG_NEXT(nh, size)) {
JP Abgralle6f80142011-07-14 16:46:32 -0700530
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900531 if (!rtMessageName(nh->nlmsg_type)) {
532 SLOGD("Unexpected netlink message type %d\n", nh->nlmsg_type);
533 continue;
534 }
535
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700536 if (nh->nlmsg_type == RTM_NEWLINK) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900537 if (parseIfInfoMessage(nh))
538 return true;
JP Abgralle6f80142011-07-14 16:46:32 -0700539
Jeff Sharkey9a20e672014-10-30 14:51:59 -0700540 } else if (nh->nlmsg_type == LOCAL_QLOG_NL_EVENT) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900541 if (parseUlogPacketMessage(nh))
542 return true;
JP Abgralle6f80142011-07-14 16:46:32 -0700543
Lorenzo Colitti381f70f2013-08-02 05:58:37 +0900544 } else if (nh->nlmsg_type == RTM_NEWADDR ||
545 nh->nlmsg_type == RTM_DELADDR) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900546 if (parseIfAddrMessage(nh))
547 return true;
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900548
Lorenzo Colittid7ff7ea2014-06-11 17:37:12 +0900549 } else if (nh->nlmsg_type == RTM_NEWROUTE ||
550 nh->nlmsg_type == RTM_DELROUTE) {
551 if (parseRtMessage(nh))
552 return true;
553
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900554 } else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900555 if (parseNdUserOptMessage(nh))
556 return true;
Lorenzo Colittic7eec832013-08-12 17:03:32 +0900557
Jeff Sharkey9a20e672014-10-30 14:51:59 -0700558 } else if (nh->nlmsg_type == LOCAL_NFLOG_PACKET) {
559 if (parseNfPacketMessage(nh))
560 return true;
561
JP Abgralle6f80142011-07-14 16:46:32 -0700562 }
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700563 }
564
Lorenzo Colitti9b342932014-06-19 13:16:04 +0900565 return false;
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700566}
567
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100568/* If the string between 'str' and 'end' begins with 'prefixlen' characters
569 * from the 'prefix' array, then return 'str + prefixlen', otherwise return
570 * NULL.
571 */
572static const char*
573has_prefix(const char* str, const char* end, const char* prefix, size_t prefixlen)
574{
575 if ((end-str) >= (ptrdiff_t)prefixlen && !memcmp(str, prefix, prefixlen))
576 return str + prefixlen;
577 else
578 return NULL;
579}
580
581/* Same as strlen(x) for constant string literals ONLY */
582#define CONST_STRLEN(x) (sizeof(x)-1)
583
584/* Convenience macro to call has_prefix with a constant string literal */
585#define HAS_CONST_PREFIX(str,end,prefix) has_prefix((str),(end),prefix,CONST_STRLEN(prefix))
586
587
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700588/*
589 * Parse an ASCII-formatted message from a NETLINK_KOBJECT_UEVENT
590 * netlink socket.
591 */
592bool NetlinkEvent::parseAsciiNetlinkMessage(char *buffer, int size) {
Mike J. Chen17260b12011-06-23 15:00:30 -0700593 const char *s = buffer;
594 const char *end;
San Mehat168415b2009-05-06 11:14:21 -0700595 int param_idx = 0;
San Mehat168415b2009-05-06 11:14:21 -0700596 int first = 1;
597
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100598 if (size == 0)
599 return false;
600
601 /* Ensure the buffer is zero-terminated, the code below depends on this */
602 buffer[size-1] = '\0';
603
San Mehat168415b2009-05-06 11:14:21 -0700604 end = s + size;
605 while (s < end) {
606 if (first) {
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100607 const char *p;
608 /* buffer is 0-terminated, no need to check p < end */
609 for (p = s; *p != '@'; p++) {
610 if (!*p) { /* no '@', should not happen */
611 return false;
612 }
613 }
614 mPath = strdup(p+1);
San Mehat168415b2009-05-06 11:14:21 -0700615 first = 0;
616 } else {
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100617 const char* a;
618 if ((a = HAS_CONST_PREFIX(s, end, "ACTION=")) != NULL) {
San Mehat168415b2009-05-06 11:14:21 -0700619 if (!strcmp(a, "add"))
620 mAction = NlActionAdd;
621 else if (!strcmp(a, "remove"))
622 mAction = NlActionRemove;
623 else if (!strcmp(a, "change"))
624 mAction = NlActionChange;
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100625 } else if ((a = HAS_CONST_PREFIX(s, end, "SEQNUM=")) != NULL) {
626 mSeq = atoi(a);
627 } else if ((a = HAS_CONST_PREFIX(s, end, "SUBSYSTEM=")) != NULL) {
628 mSubsystem = strdup(a);
629 } else if (param_idx < NL_PARAMS_MAX) {
San Mehat168415b2009-05-06 11:14:21 -0700630 mParams[param_idx++] = strdup(s);
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100631 }
San Mehat168415b2009-05-06 11:14:21 -0700632 }
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100633 s += strlen(s) + 1;
San Mehat168415b2009-05-06 11:14:21 -0700634 }
635 return true;
636}
637
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700638bool NetlinkEvent::decode(char *buffer, int size, int format) {
Jeff Sharkey9a20e672014-10-30 14:51:59 -0700639 if (format == NetlinkListener::NETLINK_FORMAT_BINARY
640 || format == NetlinkListener::NETLINK_FORMAT_BINARY_UNICAST) {
Mike J. Chen17260b12011-06-23 15:00:30 -0700641 return parseBinaryNetlinkMessage(buffer, size);
642 } else {
643 return parseAsciiNetlinkMessage(buffer, size);
644 }
Mike J. Chenec16b9d2011-06-23 14:55:28 -0700645}
646
San Mehat168415b2009-05-06 11:14:21 -0700647const char *NetlinkEvent::findParam(const char *paramName) {
Chih-Wei Huang80ec37a2010-07-14 14:00:41 +0800648 size_t len = strlen(paramName);
David 'Digit' Turner3311eea2011-01-17 01:59:22 +0100649 for (int i = 0; i < NL_PARAMS_MAX && mParams[i] != NULL; ++i) {
Chih-Wei Huang80ec37a2010-07-14 14:00:41 +0800650 const char *ptr = mParams[i] + len;
651 if (!strncmp(mParams[i], paramName, len) && *ptr == '=')
652 return ++ptr;
San Mehat168415b2009-05-06 11:14:21 -0700653 }
654
San Mehat7e8529a2010-03-25 09:31:42 -0700655 SLOGE("NetlinkEvent::FindParam(): Parameter '%s' not found", paramName);
San Mehat168415b2009-05-06 11:14:21 -0700656 return NULL;
657}