Native experiment: route DNS traffic into dnscrypt-proxy

Setup:

- download dnscrypt-proxy compiled for Android from https://dnscrypt.org/
- copy the following files to /system/xbin using recovery:

-rwxr-xr-x root     root       224320 2016-02-03 14:44 dnscrypt-proxy
-rwxr-xr-x root     root       130432 2016-02-03 14:40 hostip
-rwxr-xr-x root     root       268196 2016-02-03 14:40 libsodium.so

- make these files executable (chmod 755)
- copy dnscrypt-resolvers.csv to /sdcard//Download/dnscrypt/
- run this script from the shell:

export LD_LIBRARY_PATH="/system/xbin"
dnscrypt-proxy -a127.0.0.1:5353 --loglevel=7 --resolver-name="dnscrypt.org-fr" --resolvers-list=/sdcard//Download/dnscrypt/dnscrypt-resolvers.csv

- make sure you set an IPv4 DNS server in NetGuard
- note that Android caches DNS responses for 10 minutes
- profit!

Refs #272
This commit is contained in:
M66B 2016-02-03 15:38:45 +01:00
parent 2834f1e555
commit 0d61d804d8
4 changed files with 42 additions and 24 deletions

View File

@ -35,7 +35,7 @@
void logPacket(eu.faircode.netguard.Packet);
void dnsResolved(eu.faircode.netguard.ResourceRecord);
boolean isDomainBlocked(java.lang.String);
boolean isAddressAllowed(eu.faircode.netguard.Packet);
int isAddressAllowed(eu.faircode.netguard.Packet);
}
#Support library

View File

@ -1084,12 +1084,12 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
}
// Called from native code
private boolean isAddressAllowed(Packet packet) {
private int isAddressAllowed(Packet packet) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// Allow name resolving
if (packet.uid == Process.myUid())
return true;
return -1;
packet.allowed = false;
if (packet.protocol == 6 /* TCP */ || packet.protocol == 17 /* UDP */
@ -1123,7 +1123,7 @@ public class SinkholeService extends VpnService implements SharedPreferences.OnS
if (prefs.getBoolean("log", false) || prefs.getBoolean("log_app", false))
logPacket(packet);
return packet.allowed;
return packet.allowed ? -1 : 0;
}
private BroadcastReceiver interactiveStateReceiver = new BroadcastReceiver() {

View File

@ -875,7 +875,7 @@ void check_icmp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds
0, (uint8_t *) &pseudo, sizeof(struct ip6_hdr_pseudo));
}
icmp->icmp_cksum = 0;
icmp->icmp_cksum = ~calc_checksum(csum, buffer, bytes);
icmp->icmp_cksum = ~calc_checksum(csum, buffer, (size_t) bytes);
// Forward to tun
if (write_icmp(args, cur, buffer, (size_t) bytes) < 0)
@ -913,7 +913,7 @@ void check_udp_sockets(const struct arguments *args, fd_set *rfds, fd_set *wfds,
if (FD_ISSET(cur->socket, rfds)) {
cur->time = time(NULL);
uint16_t blen = cur->version == 4 ? UDP4_MAXMSG : UDP6_MAXMSG;
uint16_t blen = (uint16_t) (cur->version == 4 ? UDP4_MAXMSG : UDP6_MAXMSG);
uint8_t *buffer = malloc(blen);
ssize_t bytes = recv(cur->socket, buffer, blen, 0);
if (bytes < 0) {
@ -1413,14 +1413,14 @@ void handle_ip(const struct arguments *args, const uint8_t *pkt, const size_t le
#endif
// Check if allowed
jboolean allowed = 0;
int32_t allowed = 0;
if (protocol == IPPROTO_UDP && dport == 53)
allowed = 1; // allow DNS
allowed = 5353; // allow DNS
else if (protocol == IPPROTO_UDP && has_udp_session(args, pkt, payload)) {
allowed = 1;
allowed = -1;
log_android(ANDROID_LOG_INFO, "UDP existing session allowed");
} else if (protocol == IPPROTO_TCP && !syn)
allowed = 1; // assume session
allowed = -1; // assume session
else {
jobject objPacket = create_packet(
args, version, protocol, flags, source, sport, dest, dport, "", uid, 0);
@ -1432,7 +1432,7 @@ void handle_ip(const struct arguments *args, const uint8_t *pkt, const size_t le
if (protocol == IPPROTO_ICMP || protocol == IPPROTO_ICMPV6)
handle_icmp(args, pkt, length, payload, uid);
else if (protocol == IPPROTO_UDP)
handle_udp(args, pkt, length, payload, uid);
handle_udp(args, pkt, length, payload, uid, allowed);
else if (protocol == IPPROTO_TCP)
handle_tcp(args, pkt, length, payload, uid);
}
@ -1536,7 +1536,7 @@ jboolean handle_icmp(const struct arguments *args,
csum = calc_checksum(0, (uint8_t *) &pseudo, sizeof(struct ip6_hdr_pseudo));
}
icmp->icmp_cksum = 0;
icmp->icmp_cksum = ~calc_checksum(csum, icmp, icmplen);
icmp->icmp_cksum = ~calc_checksum(csum, (uint8_t *) icmp, icmplen);
log_android(ANDROID_LOG_INFO,
"ICMP forward from tun %s to %s type %d code %d id %x seq %d data %d",
@ -1594,7 +1594,7 @@ int has_udp_session(const struct arguments *args, const uint8_t *pkt, const uint
jboolean handle_udp(const struct arguments *args,
const uint8_t *pkt, size_t length, const uint8_t *payload,
int uid) {
int uid, int32_t lport) {
// Get headers
const uint8_t version = (*pkt) >> 4;
const struct iphdr *ip4 = (struct iphdr *) pkt;
@ -1629,8 +1629,8 @@ jboolean handle_udp(const struct arguments *args,
// Create new session if needed
if (cur == NULL) {
log_android(ANDROID_LOG_INFO, "UDP new session from %s/%u to %s/%u",
source, ntohs(udphdr->source), dest, ntohs(udphdr->dest));
log_android(ANDROID_LOG_INFO, "UDP new session from %s/%u to %s/%u lport %d",
source, ntohs(udphdr->source), dest, ntohs(udphdr->dest), lport);
// Register session
struct udp_session *u = malloc(sizeof(struct udp_session));
@ -1652,6 +1652,7 @@ jboolean handle_udp(const struct arguments *args,
u->next = NULL;
// Open UDP socket
u->lport = lport;
u->socket = open_udp_socket(args, u);
if (u->socket < 0) {
free(u);
@ -1710,12 +1711,26 @@ jboolean handle_udp(const struct arguments *args,
struct sockaddr_in6 server6;
if (version == 4) {
server4.sin_family = AF_INET;
server4.sin_addr.s_addr = (__be32) ip4->daddr;
server4.sin_port = udphdr->dest;
if (cur->lport < 0 || cur->uid == 2000) {
server4.sin_addr.s_addr = (__be32) ip4->daddr;
server4.sin_port = udphdr->dest;
}
else {
inet_pton(AF_INET, "127.0.0.1", &server4.sin_addr.s_addr);
server4.sin_port = htons(cur->lport);
log_android(ANDROID_LOG_WARN, "Redirecting to local IP4 port %d", cur->lport);
}
} else {
server6.sin6_family = AF_INET6;
memcpy(&server6.sin6_addr, &ip6->ip6_dst, 16);
server6.sin6_port = udphdr->dest;
if (cur->lport < 0 || cur->uid == 2000) {
memcpy(&server6.sin6_addr, &ip6->ip6_dst, 16);
server6.sin6_port = udphdr->dest;
}
else {
inet_pton(AF_INET6, "::1", &ip6->ip6_dst);
server4.sin_port = htons(cur->lport);
log_android(ANDROID_LOG_WARN, "Redirecting to local IP6 port %d", cur->lport);
}
}
if (sendto(cur->socket, data, (socklen_t) datalen, MSG_NOSIGNAL,
@ -3175,7 +3190,7 @@ jboolean is_domain_blocked(const struct arguments *args, const char *name) {
static jmethodID midIsAddressAllowed = NULL;
jboolean is_address_allowed(const struct arguments *args, jobject jpacket) {
jint is_address_allowed(const struct arguments *args, jobject jpacket) {
#ifdef PROFILE_JNI
float mselapsed;
struct timeval start, end;
@ -3184,11 +3199,11 @@ jboolean is_address_allowed(const struct arguments *args, jobject jpacket) {
jclass clsService = (*args->env)->GetObjectClass(args->env, args->instance);
const char *signature = "(Leu/faircode/netguard/Packet;)Z";
const char *signature = "(Leu/faircode/netguard/Packet;)I";
if (midIsAddressAllowed == NULL)
midIsAddressAllowed = jniGetMethodID(args->env, clsService, "isAddressAllowed", signature);
jboolean jallowed = (*args->env)->CallBooleanMethod(
jint jallowed = (*args->env)->CallIntMethod(
args->env, args->instance, midIsAddressAllowed, jpacket);
jniCheckException(args->env);

View File

@ -78,6 +78,7 @@ struct udp_session {
__be16 dest; // network notation
uint8_t stop;
int32_t lport; // host notation
jint socket;
struct udp_session *next;
@ -270,7 +271,7 @@ int has_udp_session(const struct arguments *args, const uint8_t *pkt, const uint
jboolean handle_udp(const struct arguments *args,
const uint8_t *pkt, size_t length,
const uint8_t *payload,
int uid);
int uid, int32_t lport);
int get_dns_query(const struct arguments *args, const struct udp_session *u,
const uint8_t *data, const size_t datalen,
@ -290,6 +291,8 @@ jboolean handle_tcp(const struct arguments *args,
const uint8_t *payload,
int uid);
int open_icmp_socket(const struct arguments *args, const struct icmp_session *cur);
int open_udp_socket(const struct arguments *args, const struct udp_session *cur);
int open_tcp_socket(const struct arguments *args, const struct tcp_session *cur);
@ -353,7 +356,7 @@ void dns_resolved(const struct arguments *args,
jboolean is_domain_blocked(const struct arguments *args, const char *name);
jboolean is_address_allowed(const struct arguments *args, jobject objPacket);
jint is_address_allowed(const struct arguments *args, jobject objPacket);
jobject create_packet(const struct arguments *args,
jint version,