diff options
| author | Treehugger Robot <treehugger-gerrit@google.com> | 2017-02-15 06:05:48 +0000 |
|---|---|---|
| committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-02-15 06:05:49 +0000 |
| commit | 4142d02b27793c9effb18ceb4c028e3ccaff7ebf (patch) | |
| tree | 0952fcd2e0e1ec060903bc72b60207c5387148db /server/RouteController.cpp | |
| parent | 1e1253aaaf196a76cfdd0bc5e94e6ad2ca4e7b25 (diff) | |
| parent | 220ca739ad863fcd40c9ca107f6e0f68f7a45d14 (diff) | |
Merge changes Ib327e8a3,I195dd388,I4875ac7f,I8479a8c2,Ia6fcde63, ...
* changes:
Don't complain when deleting non-existent tethering rules.
Don't call NetlinkCallbacks with nullptr on NLMSG_DONE.
Use netlink code to flush rules.
Add a generic netlink dump function and use it in SockDiag.
Move the netlink command code to a new NetlinkCommands file.
Put most of netd into the android::net namespace.
Diffstat (limited to 'server/RouteController.cpp')
| -rw-r--r-- | server/RouteController.cpp | 153 |
1 files changed, 74 insertions, 79 deletions
diff --git a/server/RouteController.cpp b/server/RouteController.cpp index a50dab32..87b0043c 100644 --- a/server/RouteController.cpp +++ b/server/RouteController.cpp @@ -27,9 +27,10 @@ #include <map> +#include "DummyNetwork.h" #include "Fwmark.h" +#include "NetlinkCommands.h" #include "UidRanges.h" -#include "DummyNetwork.h" #include "android-base/file.h" #define LOG_TAG "Netd" @@ -41,6 +42,9 @@ using android::base::WriteStringToFile; using android::net::UidRange; +namespace android { +namespace net { + namespace { // BEGIN CONSTANTS -------------------------------------------------------------------------------- @@ -90,8 +94,7 @@ struct fib_rule_uid_range { const uint16_t NETLINK_REQUEST_FLAGS = NLM_F_REQUEST | NLM_F_ACK; const uint16_t NETLINK_CREATE_REQUEST_FLAGS = NETLINK_REQUEST_FLAGS | NLM_F_CREATE | NLM_F_EXCL; - -const sockaddr_nl NETLINK_ADDRESS = {AF_NETLINK, 0, 0, 0}; +const uint16_t NETLINK_DUMP_FLAGS = NLM_F_REQUEST | NLM_F_DUMP; const uint8_t AF_FAMILIES[] = {AF_INET, AF_INET6}; @@ -196,70 +199,6 @@ void updateTableNamesFile() { } } -// Sends a netlink request and possibly expects an ack. -// |iov| is an array of struct iovec that contains the netlink message payload. -// The netlink header is generated by this function based on |action| and |flags|. -// Returns -errno if there was an error or if the kernel reported an error. - -// Disable optimizations in ASan build. -// ASan reports an out-of-bounds 32-bit(!) access in the first loop of the -// function (over iov[]). -#ifdef __clang__ -#if __has_feature(address_sanitizer) -__attribute__((optnone)) -#endif -#endif -WARN_UNUSED_RESULT int sendNetlinkRequest(uint16_t action, uint16_t flags, iovec* iov, int iovlen) { - nlmsghdr nlmsg = { - .nlmsg_type = action, - .nlmsg_flags = flags, - }; - iov[0].iov_base = &nlmsg; - iov[0].iov_len = sizeof(nlmsg); - for (int i = 0; i < iovlen; ++i) { - nlmsg.nlmsg_len += iov[i].iov_len; - } - - int sock = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE); - if (sock == -1) { - return -errno; - } - - int ret = 0; - struct { - nlmsghdr msg; - nlmsgerr err; - } response; - - - if (connect(sock, reinterpret_cast<const sockaddr*>(&NETLINK_ADDRESS), - sizeof(NETLINK_ADDRESS)) == -1 || writev(sock, iov, iovlen) == -1) { - ret = -errno; - ALOGE("netlink socket connect/writev failed (%s)", strerror(-ret)); - close(sock); - return ret; - } - - if (flags & NLM_F_ACK) { - ret = recv(sock, &response, sizeof(response), 0); - if (ret == sizeof(response)) { - ret = response.err.error; // Netlink errors are negative errno. - } else if (ret == -1) { - ret = -errno; - ALOGE("netlink recv failed (%s)", strerror(-ret)); - } else { - ALOGE("bad netlink response message size (%d != %zu)", ret, sizeof(response)); - ret = -EBADMSG; - } - } - - if (sock != -1) { - close(sock); - } - - return ret; -} - // Returns 0 on success or negative errno on failure. int padInterfaceName(const char* input, char* name, size_t* length, uint16_t* padding) { if (!input) { @@ -373,8 +312,12 @@ WARN_UNUSED_RESULT int modifyIpRule(uint16_t action, uint32_t priority, uint8_t for (size_t i = 0; i < ARRAY_SIZE(AF_FAMILIES); ++i) { rule.family = AF_FAMILIES[i]; if (int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov))) { - ALOGE("Error %s %s rule: %s", actionName(action), familyName(rule.family), - strerror(-ret)); + if (!(action == RTM_DELRULE && ret == -ENOENT && priority == RULE_PRIORITY_TETHERING)) { + // Don't log when deleting a tethering rule that's not there. This matches the + // behaviour of clearTetheringRules, which ignores ENOENT in this case. + ALOGE("Error %s %s rule: %s", actionName(action), familyName(rule.family), + strerror(-ret)); + } return ret; } } @@ -899,21 +842,70 @@ WARN_UNUSED_RESULT int modifyTetheredNetwork(uint16_t action, const char* inputI inputInterface, OIF_NONE, INVALID_UID, INVALID_UID); } +uint32_t getRulePriority(const nlmsghdr *nlh) { + uint32_t rta_len = RTM_PAYLOAD(nlh); + rtmsg *msg = reinterpret_cast<rtmsg *>(NLMSG_DATA(nlh)); + rtattr *rta = reinterpret_cast<rtattr *> RTM_RTA(msg); + for (; RTA_OK(rta, rta_len); rta = RTA_NEXT(rta, rta_len)) { + if (rta->rta_type == FRA_PRIORITY) { + return *(static_cast<uint32_t *>(RTA_DATA(rta))); + } + } + return 0; +} + // Returns 0 on success or negative errno on failure. WARN_UNUSED_RESULT int flushRules() { - for (size_t i = 0; i < ARRAY_SIZE(IP_VERSIONS); ++i) { - const char* argv[] = { - IP_PATH, - IP_VERSIONS[i], - "rule", - "flush", + int readSock = openRtNetlinkSocket(); + if (readSock < 0) { + return readSock; + } + + int writeSock = openRtNetlinkSocket(); + if (writeSock < 0) { + close(readSock); + return writeSock; + } + + NetlinkDumpCallback callback = [writeSock] (nlmsghdr *nlh) { + // Don't touch rules at priority 0 because by default they are used for local input. + if (getRulePriority(nlh) == 0) return; + + nlh->nlmsg_type = RTM_DELRULE; + nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; + if (write(writeSock, nlh, nlh->nlmsg_len) == -1) { + ALOGE("Error writing flush request: %s", strerror(errno)); + return; + } + + int ret = recvNetlinkAck(writeSock); + if (ret != 0 && ret != -ENOENT) { + ALOGW("Flushing rules: %s", strerror(-ret)); + } + }; + + int ret = 0; + for (const int family : { AF_INET, AF_INET6 }) { + // struct fib_rule_hdr and struct rtmsg are functionally identical. + rtmsg rule = { + .rtm_family = static_cast<uint8_t>(family), + }; + iovec iov[] = { + { NULL, 0 }, + { &rule, sizeof(rule) }, }; - if (android_fork_execvp(ARRAY_SIZE(argv), const_cast<char**>(argv), NULL, false, false)) { - ALOGE("failed to flush rules"); - return -EREMOTEIO; + uint16_t action = RTM_GETRULE; + uint16_t flags = NETLINK_DUMP_FLAGS; + + if ((ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), callback)) != 0) { + break; } } - return 0; + + close(readSock); + close(writeSock); + + return ret; } // Adds or removes an IPv4 or IPv6 route to the specified table and, if it's a directly-connected @@ -1164,3 +1156,6 @@ int RouteController::removeVirtualNetworkFallthrough(unsigned vpnNetId, Permission permission) { return modifyVpnFallthroughRule(RTM_DELRULE, vpnNetId, physicalInterface, permission); } + +} // namespace net +} // namespace android |
