Ken Chen a4a35a92ea Add tagSocket/untagSocket NDK APIs
Provide native APIs to tag the various sockets used for network
transfer, which helps apps tracking down data usage inside their app.

We've had equivalent Java APIs since API level 14.
https://developer.android.com/reference/android/net/TrafficStats.html#tagSocket(java.net.Socket)
https://developer.android.com/reference/android/net/TrafficStats.html#untagSocket(java.net.Socket)

Given that these Java APIs are implemented in native side, providing
NDK APIs directly will be easier for native users to use it.

Bug: 29761778
Bug: 202086915
Test: Tests in change Ic6554d9b98cef9b41b7eae06315d284c574c0a45
Change-Id: I802ce62f82199ce087bf8feb03afb26de1ce526e
2022-01-12 23:21:17 +08:00

176 lines
4.5 KiB
C

/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <android/multinetwork.h>
#include <errno.h>
#include <NetdClient.h> // the functions that communicate with netd
#include <resolv_netid.h> // android_getaddrinfofornet()
#include <stdlib.h>
#include <sys/limits.h>
// This value MUST be kept in sync with the corresponding value in
// the android.net.Network#getNetworkHandle() implementation.
static const uint32_t kHandleMagic = 0xcafed00d;
static const uint32_t kHandleMagicSize = 32;
static int getnetidfromhandle(net_handle_t handle, unsigned *netid) {
static const uint32_t k32BitMask = 0xffffffff;
// Check for minimum acceptable version of the API in the low bits.
if (handle != NETWORK_UNSPECIFIED &&
(handle & k32BitMask) != kHandleMagic) {
return 0;
}
if (netid != NULL) {
*netid = ((handle >> (CHAR_BIT * sizeof(k32BitMask))) & k32BitMask);
}
return 1;
}
static net_handle_t gethandlefromnetid(unsigned netid) {
if (netid == NETID_UNSET) {
return NETWORK_UNSPECIFIED;
}
return (((net_handle_t) netid) << kHandleMagicSize) | kHandleMagic;
}
int android_setsocknetwork(net_handle_t network, int fd) {
unsigned netid;
if (!getnetidfromhandle(network, &netid)) {
errno = EINVAL;
return -1;
}
int rval = setNetworkForSocket(netid, fd);
if (rval < 0) {
errno = -rval;
rval = -1;
}
return rval;
}
int android_setprocnetwork(net_handle_t network) {
unsigned netid;
if (!getnetidfromhandle(network, &netid)) {
errno = EINVAL;
return -1;
}
int rval = setNetworkForProcess(netid);
if (rval < 0) {
errno = -rval;
rval = -1;
}
return rval;
}
int android_getprocnetwork(net_handle_t *network) {
if (network == NULL) {
errno = EINVAL;
return -1;
}
unsigned netid = getNetworkForProcess();
*network = gethandlefromnetid(netid);
return 0;
}
int android_setprocdns(net_handle_t network) {
unsigned netid;
if (!getnetidfromhandle(network, &netid)) {
errno = EINVAL;
return -1;
}
int rval = setNetworkForResolv(netid);
if (rval < 0) {
errno = -rval;
rval = -1;
}
return rval;
}
int android_getprocdns(net_handle_t *network) {
if (network == NULL) {
errno = EINVAL;
return -1;
}
unsigned netid;
int rval = getNetworkForDns(&netid);
if (rval < 0) {
errno = -rval;
return -1;
}
*network = gethandlefromnetid(netid);
return 0;
}
int android_getaddrinfofornetwork(net_handle_t network,
const char *node, const char *service,
const struct addrinfo *hints, struct addrinfo **res) {
unsigned netid;
if (!getnetidfromhandle(network, &netid)) {
errno = EINVAL;
return EAI_SYSTEM;
}
return android_getaddrinfofornet(node, service, hints, netid, 0, res);
}
int android_res_nquery(net_handle_t network, const char *dname,
int ns_class, int ns_type, enum ResNsendFlags flags) {
unsigned netid;
if (!getnetidfromhandle(network, &netid)) {
return -ENONET;
}
return resNetworkQuery(netid, dname, ns_class, ns_type, flags);
}
int android_res_nresult(int fd, int *rcode, uint8_t *answer, size_t anslen) {
return resNetworkResult(fd, rcode, answer, anslen);
}
int android_res_nsend(net_handle_t network, const uint8_t *msg, size_t msglen,
enum ResNsendFlags flags) {
unsigned netid;
if (!getnetidfromhandle(network, &netid)) {
return -ENONET;
}
return resNetworkSend(netid, msg, msglen, flags);
}
void android_res_cancel(int nsend_fd) {
resNetworkCancel(nsend_fd);
}
int android_tag_socket_with_uid(int sockfd, int tag, uid_t uid) {
return tagSocket(sockfd, tag, uid);
}
int android_tag_socket(int sockfd, int tag) {
return tagSocket(sockfd, tag, -1);
}
int android_untag_socket(int sockfd) {
return untagSocket(sockfd);
}