NetGuard/app/src/main/jni/netguard/netguard.c

226 lines
6.6 KiB
C
Raw Normal View History

2016-01-09 11:10:11 +00:00
#include <jni.h>
2016-01-09 20:17:42 +00:00
#include <stdio.h>
2016-01-10 07:14:47 +00:00
#include <time.h>
2016-01-09 15:56:23 +00:00
#include <unistd.h>
2016-01-09 11:10:11 +00:00
#include <android/log.h>
2016-01-09 15:56:23 +00:00
#include <arpa/inet.h>
2016-01-09 11:10:11 +00:00
#include <netinet/ip.h>
#include <netinet/ip6.h>
2016-01-09 15:56:23 +00:00
#include <netinet/udp.h>
#include <netinet/tcp.h>
2016-01-09 11:10:11 +00:00
#define TAG "NetGuard.JNI"
2016-01-09 15:56:23 +00:00
#define MAXPKT 32768
2016-01-09 11:10:11 +00:00
2016-01-09 18:53:28 +00:00
void decode(JNIEnv *env, jobject instance, jbyte *, int);
2016-01-10 11:51:02 +00:00
int getUid(int, int, void *, int);
2016-01-09 20:17:42 +00:00
2016-01-09 11:10:11 +00:00
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_SinkholeService_jni_1init(JNIEnv *env, jobject instance) {
__android_log_print(ANDROID_LOG_INFO, TAG, "Init", 1);
}
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_SinkholeService_jni_1decode(JNIEnv *env, jobject instance,
2016-01-09 18:53:28 +00:00
jbyteArray buffer_, jint length) {
2016-01-09 11:10:11 +00:00
jbyte *buffer = (*env)->GetByteArrayElements(env, buffer_, NULL);
2016-01-09 18:53:28 +00:00
decode(env, instance, buffer, length);
2016-01-09 11:10:11 +00:00
(*env)->ReleaseByteArrayElements(env, buffer_, buffer, 0);
}
2016-01-09 15:56:23 +00:00
JNIEXPORT void JNICALL
Java_eu_faircode_netguard_SinkholeService_jni_1receive(JNIEnv *env, jobject instance, jint fd) {
int len;
2016-01-10 07:14:47 +00:00
jbyte buffer[MAXPKT];
2016-01-09 15:56:23 +00:00
while (1) {
2016-01-10 07:14:47 +00:00
len = read(fd, buffer, sizeof(buffer));
2016-01-09 15:56:23 +00:00
if (len < 0) {
__android_log_print(ANDROID_LOG_WARN, TAG, "Receive error %d", len);
return;
2016-01-09 11:10:11 +00:00
2016-01-09 18:53:28 +00:00
} else if (len > 0)
decode(env, instance, buffer, len);
else
2016-01-09 15:56:23 +00:00
__android_log_print(ANDROID_LOG_WARN, TAG, "Nothing received");
}
}
2016-01-09 18:53:28 +00:00
void decode(JNIEnv *env, jobject instance, jbyte *buffer, int length) {
2016-01-10 07:14:47 +00:00
jbyte protocol;
2016-01-10 11:51:02 +00:00
void *saddr;
void *daddr;
2016-01-09 18:53:28 +00:00
char source[40];
char dest[40];
char flags[10];
int flen = 0;
2016-01-10 07:14:47 +00:00
jbyte *payload;
2016-01-09 18:53:28 +00:00
2016-01-10 07:14:47 +00:00
// Get protocol, addresses & payload
2016-01-09 18:53:28 +00:00
jbyte version = (*buffer) >> 4;
if (version == 4) {
struct iphdr *ip4hdr = buffer;
2016-01-10 07:14:47 +00:00
2016-01-09 18:53:28 +00:00
protocol = ip4hdr->protocol;
2016-01-10 11:51:02 +00:00
saddr = &ip4hdr->saddr;
daddr = &ip4hdr->daddr;
2016-01-09 18:53:28 +00:00
if (ip4hdr->frag_off & IP_MF)
flags[flen++] = '+';
2016-01-09 18:53:28 +00:00
jbyte optlen = 0;
if (ip4hdr->ihl > 5)
optlen = buffer[20];
2016-01-10 07:14:47 +00:00
payload = buffer + (20 + optlen) * sizeof(jbyte);
2016-01-09 18:53:28 +00:00
}
else if (version == 6) {
struct ip6_hdr *ip6hdr = buffer;
2016-01-10 07:14:47 +00:00
2016-01-09 18:53:28 +00:00
protocol = ip6hdr->ip6_nxt;
2016-01-10 11:51:02 +00:00
saddr = &ip6hdr->ip6_src;
daddr = &ip6hdr->ip6_dst;
2016-01-09 18:53:28 +00:00
payload = buffer + 40 * sizeof(jbyte);
}
else {
__android_log_print(ANDROID_LOG_WARN, TAG, "Unknown version %d", version);
2016-01-10 07:14:47 +00:00
return;
2016-01-09 18:53:28 +00:00
}
2016-01-10 07:14:47 +00:00
// Get ports & flags
2016-01-09 18:53:28 +00:00
int sport = -1;
int dport = -1;
if (protocol == IPPROTO_TCP) {
struct tcphdr *tcp = payload;
2016-01-10 07:14:47 +00:00
2016-01-09 18:53:28 +00:00
sport = ntohs(tcp->source);
dport = ntohs(tcp->dest);
2016-01-10 07:14:47 +00:00
2016-01-09 18:53:28 +00:00
if (tcp->syn)
flags[flen++] = 'S';
if (tcp->ack)
flags[flen++] = 'A';
if (tcp->psh)
flags[flen++] = 'P';
if (tcp->fin)
flags[flen++] = 'F';
if (tcp->fin)
flags[flen++] = 'R';
} else if (protocol == IPPROTO_UDP) {
struct udphdr *udp = payload;
2016-01-10 07:14:47 +00:00
2016-01-09 18:53:28 +00:00
sport = ntohs(udp->source);
dport = ntohs(udp->dest);
}
flags[flen] = 0;
2016-01-10 11:51:02 +00:00
inet_ntop(version == 4 ? AF_INET : AF_INET6, saddr, source, sizeof(source));
inet_ntop(version == 4 ? AF_INET : AF_INET6, daddr, dest, sizeof(dest));
// __android_log_print(ANDROID_LOG_INFO, TAG, "Packet v%d %s/%d -> %s/%d proto %d flags %s",
// version, source, sport, dest, dport, protocol, flags);
2016-01-09 18:53:28 +00:00
2016-01-10 07:14:47 +00:00
// Get uid
int uid = -1;
if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP) {
// Sleep 10 ms
struct timespec tim, tim2;
tim.tv_sec = 0;
tim.tv_nsec = 10000000L;
nanosleep(&tim, &tim2);
// Lookup uid
2016-01-10 11:51:02 +00:00
uid = getUid(protocol, version, saddr, sport);
2016-01-10 07:14:47 +00:00
if (uid < 0 && version == 4) {
2016-01-10 11:51:02 +00:00
int8_t saddr128[16];
memset(saddr128, 0, 10);
saddr128[10] = 0xFF;
saddr128[11] = 0xFF;
memcpy(saddr128 + 12, saddr, 4);
uid = getUid(protocol, 6, saddr128, sport);
2016-01-10 07:14:47 +00:00
}
}
// Call back
2016-01-09 18:53:28 +00:00
jclass cls = (*env)->GetObjectClass(env, instance);
jmethodID mid = (*env)->GetMethodID(env, cls, "logPacket",
2016-01-10 07:14:47 +00:00
"(ILjava/lang/String;ILjava/lang/String;IILjava/lang/String;I)V");
2016-01-09 18:53:28 +00:00
if (mid != 0) {
jstring jsource = (*env)->NewStringUTF(env, source);
jstring jdest = (*env)->NewStringUTF(env, dest);
jstring jflags = (*env)->NewStringUTF(env, flags);
(*env)->CallVoidMethod(env, instance, mid,
2016-01-10 07:14:47 +00:00
version, jsource, sport, jdest, dport, protocol, jflags, uid);
(*env)->DeleteLocalRef(env, jsource);
(*env)->DeleteLocalRef(env, jdest);
(*env)->DeleteLocalRef(env, jflags);
2016-01-10 16:10:52 +00:00
jthrowable ex = (*env)->ExceptionOccurred(env);
if (ex) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
(*env)->DeleteLocalRef(env, ex);
}
2016-01-09 18:53:28 +00:00
}
}
2016-01-09 20:17:42 +00:00
2016-01-10 11:51:02 +00:00
int getUid(int protocol, int version, void *saddr, int sport) {
2016-01-10 07:14:47 +00:00
char line[250];
int fields;
int32_t addr32;
int8_t addr128[16];
int port;
int uid = -1;
// Get proc file name
char *fn = NULL;
if (protocol == IPPROTO_TCP)
fn = (version == 4 ? "/proc/net/tcp" : "/proc/net/tcp6");
else if (protocol == IPPROTO_UDP)
fn = (version == 4 ? "/proc/net/udp" : "/proc/net/udp6");
else
return -1;
// Open proc file
FILE *fd = fopen(fn, "r");
if (fd == NULL) {
__android_log_print(ANDROID_LOG_ERROR, TAG, "Error opening %s", fn);
return -1;
}
// Scan proc file
int i = 0;
while (fgets(line, sizeof(line), fd) != NULL) {
if (i++) {
if (version == 4)
fields = sscanf(line,
"%*d: %X:%X %*X:%*X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld ",
&addr32, &port, &uid);
else
fields = sscanf(line,
"%*d: %8X%8X%8X%8X:%X %*X:%*X %*X %*lX:%*lX %*X:%*X %*X %d %*d %*ld ",
addr128, addr128 + 4, addr128 + 8, addr128 + 12, &port, &uid);
if (fields < 3) {
__android_log_print(ANDROID_LOG_ERROR, TAG, "Invalid field #%d: %s", fields, line);
break;
2016-01-09 20:17:42 +00:00
}
2016-01-10 07:14:47 +00:00
2016-01-10 11:51:02 +00:00
if (port == sport) {
if (version == 4) {
if (addr32 == *((int32_t *) saddr))
return uid;
}
else {
if (memcmp(addr128, saddr, (size_t) 16) == 0)
return uid;
}
}
2016-01-09 20:17:42 +00:00
}
}
2016-01-10 07:14:47 +00:00
fclose(fd);
2016-01-10 11:51:02 +00:00
return -1;
2016-01-09 20:17:42 +00:00
}