Cache uids

This commit is contained in:
M66B 2017-11-05 08:08:20 +01:00
parent 927c53b8bb
commit 928eab71a6
2 changed files with 141 additions and 71 deletions

View File

@ -328,53 +328,85 @@ jint get_uid(const int version, const int protocol,
const void *daddr, const uint16_t dport) {
jint uid = -1;
char source[INET6_ADDRSTRLEN + 1];
char dest[INET6_ADDRSTRLEN + 1];
inet_ntop(version == 4 ? AF_INET : AF_INET6, saddr, source, sizeof(source));
inet_ntop(version == 4 ? AF_INET : AF_INET6, daddr, dest, sizeof(dest));
log_android(ANDROID_LOG_INFO, "get uid v%d p%d %u > %s/%u",
version, protocol, sport, dest, dport);
struct timeval time;
gettimeofday(&time, NULL);
long now = (time.tv_sec * 1000) + (time.tv_usec / 1000);
// Check IPv6 table first
if (version == 4) {
int8_t saddr128[16];
memset(saddr128, 0, 10);
saddr128[10] = (uint8_t) 0xFF;
saddr128[11] = (uint8_t) 0xFF;
memcpy(saddr128 + 12, saddr, 4);
int8_t daddr128[16];
memset(daddr128, 0, 10);
daddr128[10] = (uint8_t) 0xFF;
daddr128[11] = (uint8_t) 0xFF;
memcpy(daddr128 + 12, daddr, 4);
uid = get_uid_sub(6, protocol, saddr, sport, daddr128, dport);
uid = get_uid_sub(6, protocol, saddr128, sport, daddr128, dport, source, dest, now);
log_android(ANDROID_LOG_DEBUG, "uid v%d p%d %s/%u > %s/%u => %d as inet6",
version, protocol, source, sport, dest, dport, uid);
}
if (uid < 0)
uid = get_uid_sub(version, protocol, saddr, sport, daddr, dport);
if (uid == -1) {
uid = get_uid_sub(version, protocol, saddr, sport, daddr, dport, source, dest, now);
log_android(ANDROID_LOG_DEBUG, "uid v%d p%d %s/%u > %s/%u => %d fallback",
version, protocol, source, sport, dest, dport, uid);
}
if (uid < 0)
log_android(ANDROID_LOG_ERROR, "uid v%d p%d %u > %s/%u not found",
version, protocol, sport, dest, dport);
if (uid == -1)
log_android(ANDROID_LOG_WARN, "uid v%d p%d %s/%u > %s/%u => not found",
version, protocol, source, sport, dest, dport);
else if (uid >= 0)
log_android(ANDROID_LOG_INFO, "uid v%d p%d %s/%u > %s/%u => %d",
version, protocol, source, sport, dest, dport, uid);
return uid;
}
int uid_cache_size = 0;
struct uid_cache_entry *uid_cache = NULL;
jint get_uid_sub(const int version, const int protocol,
const void *saddr, const uint16_t sport,
const void *daddr, const uint16_t dport) {
char line[250];
char hex[16 * 2 + 1];
int fields;
uint8_t _daddr4[4];
uint8_t _daddr6[16];
int _sport;
int _dport;
jint uid = -1;
#ifdef PROFILE_UID
float mselapsed;
struct timeval start, end;
gettimeofday(&start, NULL);
#endif
const void *daddr, const uint16_t dport,
const char *source, const char *dest,
long now) {
// NETLINK is not available on Android due to SELinux policies :-(
// http://stackoverflow.com/questions/27148536/netlink-implementation-for-the-android-ndk
// https://android.googlesource.com/platform/system/sepolicy/+/master/private/app.te (netlink_tcpdiag_socket)
static uint8_t zero[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Check cache
for (int i = 0; i < uid_cache_size; i++)
if (now - uid_cache[i].time <= UID_MAX_AGE &&
uid_cache[i].version == version &&
uid_cache[i].protocol == protocol &&
uid_cache[i].sport == sport &&
(uid_cache[i].dport == dport || uid_cache[i].dport == 0) &&
(memcmp(uid_cache[i].saddr, saddr, version == 4 ? 4 : 16) == 0 ||
memcmp(uid_cache[i].saddr, zero, version == 4 ? 4 : 16) == 0) &&
(memcmp(uid_cache[i].daddr, daddr, version == 4 ? 4 : 16) == 0 ||
memcmp(uid_cache[i].daddr, zero, version == 4 ? 4 : 16) == 0)) {
log_android(ANDROID_LOG_INFO, "uid v%d p%d %s/%u > %s/%u => %d (from cache)",
version, protocol, source, sport, dest, dport, uid_cache[i].uid);
if (protocol == IPPROTO_UDP)
return -2;
else
return uid_cache[i].uid;
}
// Get proc file name
char *fn = NULL;
if (protocol == IPPROTO_ICMP && version == 4)
@ -386,68 +418,92 @@ jint get_uid_sub(const int version, const int protocol,
else if (protocol == IPPROTO_UDP)
fn = (version == 4 ? "/proc/net/udp" : "/proc/net/udp6");
else
return uid;
return -1;
// Open proc file
FILE *fd = fopen(fn, "r");
if (fd == NULL) {
log_android(ANDROID_LOG_ERROR, "fopen %s error %d: %s", fn, errno, strerror(errno));
return uid;
return -2;
}
jint uid = -1;
char line[250];
int fields;
char shex[16 * 2 + 1];
uint8_t _saddr[16];
int _sport;
char dhex[16 * 2 + 1];
uint8_t _daddr[16];
int _dport;
jint _uid;
// Scan proc file
jint u;
int i = 0;
int l = 0;
*line = 0;
int c = 0;
int ws = (version == 4 ? 1 : 4);
const char *fmt = (version == 4
? "%*d: %8s:%X %8s:%X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld"
: "%*d: %32s:%X %32s:%X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld");
while (fgets(line, sizeof(line), fd) != NULL) {
if (i++) {
*hex = 0;
_sport = -1;
_dport = -1;
u = -1;
if (version == 4)
fields = sscanf(
line,
"%*d: %*X:%X %8s:%X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld",
&_sport, hex, &_dport, &u);
else
fields = sscanf(
line,
"%*d: %*X:%X %32s:%X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld",
&_sport, hex, &_dport, &u);
if (!l++)
continue;
if (fields == 4 && (version == 4 ? strlen(hex) == 8 : strlen(hex) == 32)) {
if (_sport > 0 && u >= 0) {
hex2bytes(hex, version == 4 ? _daddr4 : _daddr6);
if (version == 4)
((uint32_t *) _daddr4)[0] = htonl(((uint32_t *) _daddr4)[0]);
else
for (int w = 0; w < 4; w++)
((uint32_t *) _daddr6)[w] = htonl(((uint32_t *) _daddr6)[w]);
fields = sscanf(line, fmt, shex, &_sport, dhex, &_dport, &_uid);
if (fields == 5 && strlen(shex) == ws * 8 && strlen(dhex) == ws * 8) {
hex2bytes(shex, _saddr);
hex2bytes(dhex, _daddr);
if (_sport == sport) {
uid = u;
if (_dport == dport &&
memcmp(version == 4 ? _daddr4 : _daddr6, daddr,
version == 4 ? 4 : 16) == 0)
break;
}
}
} else
log_android(ANDROID_LOG_ERROR, "Invalid field #%d: %s", fields, line);
for (int w = 0; w < ws; w++)
((uint32_t *) _saddr)[w] = htonl(((uint32_t *) _saddr)[w]);
for (int w = 0; w < ws; w++)
((uint32_t *) _daddr)[w] = htonl(((uint32_t *) _daddr)[w]);
if (_sport == sport &&
(_dport == dport || _dport == 0) &&
(memcmp(_saddr, saddr, (size_t) (ws * 4)) == 0 ||
memcmp(_saddr, zero, (size_t) (ws * 4)) == 0) &&
(memcmp(_daddr, daddr, (size_t) (ws * 4)) == 0 ||
memcmp(_daddr, zero, (size_t) (ws * 4)) == 0))
uid = _uid;
for (; c < uid_cache_size; c++)
if (now - uid_cache[c].time > UID_MAX_AGE)
break;
if (c >= uid_cache_size) {
if (uid_cache_size == 0)
uid_cache = malloc(sizeof(struct uid_cache_entry));
else
uid_cache = realloc(uid_cache,
sizeof(struct uid_cache_entry) *
(uid_cache_size + 1));
c = uid_cache_size;
uid_cache_size++;
}
uid_cache[c].version = (uint8_t) version;
uid_cache[c].protocol = (uint8_t) protocol;
memcpy(uid_cache[c].saddr, _saddr, (size_t) (ws * 4));
uid_cache[c].sport = (uint16_t) _sport;
memcpy(uid_cache[c].daddr, daddr, (size_t) (ws * 4));
uid_cache[c].dport = (uint16_t) _dport;
uid_cache[c].uid = _uid;
uid_cache[c].time = now;
} else {
log_android(ANDROID_LOG_ERROR, "Invalid field #%d: %s", fields, line);
return -2;
}
}
if (fclose(fd))
log_android(ANDROID_LOG_ERROR, "fclose %s error %d: %s", fn, errno, strerror(errno));
#ifdef PROFILE_UID
gettimeofday(&end, NULL);
mselapsed = (end.tv_sec - start.tv_sec) * 1000.0 +
(end.tv_usec - start.tv_usec) / 1000.0;
if (mselapsed > PROFILE_UID)
log_android(ANDROID_LOG_WARN, "get uid ip %f", mselapsed);
#endif
return uid;
}

View File

@ -34,7 +34,6 @@
#define TAG "NetGuard.JNI"
// #define PROFILE_UID 5
// #define PROFILE_JNI 5
#define EPOLL_TIMEOUT 3600 // seconds
@ -61,6 +60,8 @@
#define SESSION_MAX 512 // number
#define SESSION_LIMIT 30 // percent
#define UID_MAX_AGE 30000 // milliseconds
#define SOCKS5_NONE 1
#define SOCKS5_HELLO 2
#define SOCKS5_AUTH 3
@ -189,6 +190,17 @@ struct ng_session {
struct ng_session *next;
};
struct uid_cache_entry {
uint8_t version;
uint8_t protocol;
uint8_t saddr[16];
uint16_t sport;
uint8_t daddr[16];
uint16_t dport;
jint uid;
long time;
};
// IPv6
struct ip6_hdr_pseudo {
@ -461,7 +473,9 @@ jint get_uid(const int version, const int protocol,
jint get_uid_sub(const int version, const int protocol,
const void *saddr, const uint16_t sport,
const void *daddr, const uint16_t dport);
const void *daddr, const uint16_t dport,
const char *source, const char *dest,
long now);
int protect_socket(const struct arguments *args, int socket);