am cbc32e9f: Merge "Support parsing RDNSS ND options from netlink."
* commit 'cbc32e9f7e95d9c35ec5d855a13fd9346e9f55bf': Support parsing RDNSS ND options from netlink.
This commit is contained in:
commit
85fddd867b
2 changed files with 124 additions and 5 deletions
|
|
@ -36,6 +36,7 @@ public:
|
||||||
const static int NlActionLinkUp;
|
const static int NlActionLinkUp;
|
||||||
const static int NlActionAddressUpdated;
|
const static int NlActionAddressUpdated;
|
||||||
const static int NlActionAddressRemoved;
|
const static int NlActionAddressRemoved;
|
||||||
|
const static int NlActionRdnss;
|
||||||
|
|
||||||
NetlinkEvent();
|
NetlinkEvent();
|
||||||
virtual ~NetlinkEvent();
|
virtual ~NetlinkEvent();
|
||||||
|
|
@ -49,9 +50,10 @@ public:
|
||||||
void dump();
|
void dump();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
|
|
||||||
bool parseBinaryNetlinkMessage(char *buffer, int size);
|
bool parseBinaryNetlinkMessage(char *buffer, int size);
|
||||||
bool parseAsciiNetlinkMessage(char *buffer, int size);
|
bool parseAsciiNetlinkMessage(char *buffer, int size);
|
||||||
|
bool parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr, int rtasize);
|
||||||
|
bool parseNdUserOptMessage(struct nduseroptmsg *msg, int optsize);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/in.h>
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
|
|
||||||
|
|
@ -44,6 +45,7 @@ const int NetlinkEvent::NlActionLinkUp = 4;
|
||||||
const int NetlinkEvent::NlActionLinkDown = 5;
|
const int NetlinkEvent::NlActionLinkDown = 5;
|
||||||
const int NetlinkEvent::NlActionAddressUpdated = 6;
|
const int NetlinkEvent::NlActionAddressUpdated = 6;
|
||||||
const int NetlinkEvent::NlActionAddressRemoved = 7;
|
const int NetlinkEvent::NlActionAddressRemoved = 7;
|
||||||
|
const int NetlinkEvent::NlActionRdnss = 8;
|
||||||
|
|
||||||
NetlinkEvent::NetlinkEvent() {
|
NetlinkEvent::NetlinkEvent() {
|
||||||
mAction = NlActionUnknown;
|
mAction = NlActionUnknown;
|
||||||
|
|
@ -76,7 +78,7 @@ void NetlinkEvent::dump() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Decode a RTM_NEWADDR or RTM_DELADDR message.
|
* Parse a RTM_NEWADDR or RTM_DELADDR message.
|
||||||
*/
|
*/
|
||||||
bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
|
bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
|
||||||
int rtasize) {
|
int rtasize) {
|
||||||
|
|
@ -172,13 +174,111 @@ bool NetlinkEvent::parseIfAddrMessage(int type, struct ifaddrmsg *ifaddr,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse an binary message from a NETLINK_ROUTE netlink socket.
|
* Parse a RTM_NEWNDUSEROPT message.
|
||||||
|
*/
|
||||||
|
bool NetlinkEvent::parseNdUserOptMessage(struct nduseroptmsg *msg, int len) {
|
||||||
|
// Check the length is valid.
|
||||||
|
if (msg->nduseropt_opts_len > len) {
|
||||||
|
SLOGE("RTM_NEWNDUSEROPT invalid length %d > %d\n",
|
||||||
|
msg->nduseropt_opts_len, len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
len = msg->nduseropt_opts_len;
|
||||||
|
|
||||||
|
// Check address family and packet type.
|
||||||
|
if (msg->nduseropt_family != AF_INET6) {
|
||||||
|
SLOGE("RTM_NEWNDUSEROPT message for unknown family %d\n",
|
||||||
|
msg->nduseropt_family);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->nduseropt_icmp_type != ND_ROUTER_ADVERT ||
|
||||||
|
msg->nduseropt_icmp_code != 0) {
|
||||||
|
SLOGE("RTM_NEWNDUSEROPT message for unknown ICMPv6 type/code %d/%d\n",
|
||||||
|
msg->nduseropt_icmp_type, msg->nduseropt_icmp_code);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the interface name.
|
||||||
|
char ifname[IFNAMSIZ + 1];
|
||||||
|
if (!if_indextoname(msg->nduseropt_ifindex, ifname)) {
|
||||||
|
SLOGE("RTM_NEWNDUSEROPT on unknown ifindex %d\n",
|
||||||
|
msg->nduseropt_ifindex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The kernel sends a separate netlink message for each ND option in the RA.
|
||||||
|
// So only parse the first ND option in the message.
|
||||||
|
struct nd_opt_hdr *opthdr = (struct nd_opt_hdr *) (msg + 1);
|
||||||
|
|
||||||
|
// The length is in multiples of 8 octets.
|
||||||
|
uint16_t optlen = opthdr->nd_opt_len;
|
||||||
|
if (optlen * 8 > len) {
|
||||||
|
SLOGE("Invalid option length %d > %d for ND option %d\n",
|
||||||
|
optlen * 8, len, opthdr->nd_opt_type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opthdr->nd_opt_type == ND_OPT_RDNSS) {
|
||||||
|
// DNS Servers (RFC 6106).
|
||||||
|
// Each address takes up 2*8 octets, and the header takes up 8 octets.
|
||||||
|
// So for a valid option with one or more addresses, optlen must be
|
||||||
|
// odd and greater than 1.
|
||||||
|
if ((optlen < 3) || !(optlen & 0x1)) {
|
||||||
|
SLOGE("Invalid optlen %d for RDNSS option\n", optlen);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int numaddrs = (optlen - 1) / 2;
|
||||||
|
|
||||||
|
// Find the lifetime.
|
||||||
|
struct nd_opt_rdnss *rndss_opt = (struct nd_opt_rdnss *) opthdr;
|
||||||
|
uint32_t lifetime = ntohl(rndss_opt->nd_opt_rdnss_lifetime);
|
||||||
|
|
||||||
|
// Construct "SERVERS=<comma-separated string of DNS addresses>".
|
||||||
|
// Reserve (INET6_ADDRSTRLEN + 1) chars for each address: all but the
|
||||||
|
// the last address are followed by ','; the last is followed by '\0'.
|
||||||
|
static const char kServerTag[] = "SERVERS=";
|
||||||
|
static const int kTagLength = sizeof(kServerTag) - 1;
|
||||||
|
int bufsize = kTagLength + numaddrs * (INET6_ADDRSTRLEN + 1);
|
||||||
|
char *buf = (char *) malloc(bufsize);
|
||||||
|
if (!buf) {
|
||||||
|
SLOGE("RDNSS option: out of memory\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
strcpy(buf, kServerTag);
|
||||||
|
int pos = kTagLength;
|
||||||
|
|
||||||
|
struct in6_addr *addrs = (struct in6_addr *) (rndss_opt + 1);
|
||||||
|
for (int i = 0; i < numaddrs; i++) {
|
||||||
|
if (i > 0) {
|
||||||
|
buf[pos++] = ',';
|
||||||
|
}
|
||||||
|
inet_ntop(AF_INET6, addrs + i, buf + pos, bufsize - pos);
|
||||||
|
pos += strlen(buf + pos);
|
||||||
|
}
|
||||||
|
buf[pos] = '\0';
|
||||||
|
|
||||||
|
mAction = NlActionRdnss;
|
||||||
|
mSubsystem = strdup("net");
|
||||||
|
asprintf(&mParams[0], "INTERFACE=%s", ifname);
|
||||||
|
asprintf(&mParams[1], "LIFETIME=%u", lifetime);
|
||||||
|
mParams[2] = buf;
|
||||||
|
} else {
|
||||||
|
SLOGD("Unknown ND option type %d\n", opthdr->nd_opt_type);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parse a binary message from a NETLINK_ROUTE netlink socket.
|
||||||
*/
|
*/
|
||||||
bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
|
bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
|
||||||
const struct nlmsghdr *nh;
|
const struct nlmsghdr *nh;
|
||||||
|
|
||||||
for (nh = (struct nlmsghdr *) buffer;
|
for (nh = (struct nlmsghdr *) buffer;
|
||||||
NLMSG_OK(nh, size) && (nh->nlmsg_type != NLMSG_DONE);
|
NLMSG_OK(nh, (unsigned) size) && (nh->nlmsg_type != NLMSG_DONE);
|
||||||
nh = NLMSG_NEXT(nh, size)) {
|
nh = NLMSG_NEXT(nh, size)) {
|
||||||
|
|
||||||
if (nh->nlmsg_type == RTM_NEWLINK) {
|
if (nh->nlmsg_type == RTM_NEWLINK) {
|
||||||
|
|
@ -245,8 +345,25 @@ bool NetlinkEvent::parseBinaryNetlinkMessage(char *buffer, int size) {
|
||||||
if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
|
if (!parseIfAddrMessage(nh->nlmsg_type, ifa, rtasize)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (nh->nlmsg_type == RTM_NEWNDUSEROPT) {
|
||||||
|
int len = nh->nlmsg_len - sizeof(*nh);
|
||||||
|
struct nduseroptmsg *ndmsg = (struct nduseroptmsg *) NLMSG_DATA(nh);
|
||||||
|
|
||||||
|
if (sizeof(*ndmsg) > (size_t) len) {
|
||||||
|
SLOGE("Got a short RTM_NEWNDUSEROPT message\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t optsize = NLMSG_PAYLOAD(nh, sizeof(*ndmsg));
|
||||||
|
if (!parseNdUserOptMessage(ndmsg, optsize)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
SLOGD("Unexpected netlink message. type=0x%x\n", nh->nlmsg_type);
|
SLOGD("Unexpected netlink message. type=0x%x\n",
|
||||||
|
nh->nlmsg_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue