Implemented DNS over HTTPS (Google JSON)
This commit is contained in:
parent
1a8145971d
commit
fdd28b6b6d
@ -22,7 +22,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
public class HttpsIetfProvider extends HttpsProvider {
|
public class HttpsIetfProvider extends HttpsProvider {
|
||||||
private static final String HTTPS_SUFFIX = "https://";
|
// implemented https://tools.ietf.org/html/draft-ietf-doh-dns-over-https-11
|
||||||
|
|
||||||
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
|
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
|
||||||
.connectTimeout(10, TimeUnit.SECONDS)
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
@ -0,0 +1,139 @@
|
|||||||
|
package org.itxtech.daedalus.provider;
|
||||||
|
|
||||||
|
import android.os.ParcelFileDescriptor;
|
||||||
|
import com.google.gson.JsonArray;
|
||||||
|
import com.google.gson.JsonElement;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.JsonParser;
|
||||||
|
import okhttp3.*;
|
||||||
|
import org.itxtech.daedalus.service.DaedalusVpnService;
|
||||||
|
import org.minidns.dnsmessage.DnsMessage;
|
||||||
|
import org.minidns.dnsname.DnsName;
|
||||||
|
import org.minidns.record.*;
|
||||||
|
import org.pcap4j.packet.IpPacket;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Daedalus Project
|
||||||
|
*
|
||||||
|
* @author iTX Technologies
|
||||||
|
* @link https://itxtech.org
|
||||||
|
* <p>
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*/
|
||||||
|
public class HttpsJsonProvider extends HttpsProvider {
|
||||||
|
/*
|
||||||
|
* Implemented https://developers.cloudflare.com/1.1.1.1/dns-over-https/json-format/
|
||||||
|
* https://developers.google.com/speed/public-dns/docs/dns-over-https
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static final OkHttpClient HTTP_CLIENT = new OkHttpClient.Builder()
|
||||||
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.readTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.writeTimeout(10, TimeUnit.SECONDS)
|
||||||
|
.addInterceptor((chain) -> {
|
||||||
|
Request original = chain.request();
|
||||||
|
|
||||||
|
Request request = original.newBuilder()
|
||||||
|
.header("Accept", "application/dns-json")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return chain.proceed(request);
|
||||||
|
})
|
||||||
|
.build();
|
||||||
|
|
||||||
|
public HttpsJsonProvider(ParcelFileDescriptor descriptor, DaedalusVpnService service) {
|
||||||
|
super(descriptor, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void sendRequestToServer(IpPacket parsedPacket, DnsMessage message, String uri) {
|
||||||
|
whqList.add(new WaitingHttpsRequest(parsedPacket) {
|
||||||
|
@Override
|
||||||
|
public void doRequest() {
|
||||||
|
final byte[] rawRequest = message.toArray();
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(HttpUrl.parse(HTTPS_SUFFIX + uri).newBuilder()
|
||||||
|
.addQueryParameter("name", message.getQuestion().name.toString())
|
||||||
|
.addQueryParameter("type", message.getQuestion().type.name())
|
||||||
|
.build())
|
||||||
|
.get()
|
||||||
|
.build();
|
||||||
|
HTTP_CLIENT.newCall(request).enqueue(new Callback() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call call, IOException e) {
|
||||||
|
result = rawRequest;
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call call, Response response) throws IOException {
|
||||||
|
if (response.isSuccessful()) {
|
||||||
|
JsonObject jsonObject = new JsonParser().parse(response.body().string()).getAsJsonObject();
|
||||||
|
DnsMessage.Builder msg = message.asBuilder()
|
||||||
|
.setRecursionDesired(jsonObject.get("RD").getAsBoolean())
|
||||||
|
.setRecursionAvailable(jsonObject.get("RA").getAsBoolean())
|
||||||
|
.setAuthenticData(jsonObject.get("AD").getAsBoolean())
|
||||||
|
.setCheckingDisabled(jsonObject.get("CD").getAsBoolean());
|
||||||
|
if (jsonObject.has("Answer")) {
|
||||||
|
JsonArray answers = jsonObject.get("Answer").getAsJsonArray();
|
||||||
|
for (JsonElement answer : answers) {
|
||||||
|
JsonObject ans = answer.getAsJsonObject();
|
||||||
|
Record.TYPE type = Record.TYPE.getType(ans.get("type").getAsInt());
|
||||||
|
String data = ans.get("data").getAsString();
|
||||||
|
Data recordData = null;
|
||||||
|
switch (type) {
|
||||||
|
case A:
|
||||||
|
recordData = new A(data);
|
||||||
|
break;
|
||||||
|
case AAAA:
|
||||||
|
recordData = new AAAA(data);
|
||||||
|
break;
|
||||||
|
case CNAME:
|
||||||
|
recordData = new CNAME(data);
|
||||||
|
break;
|
||||||
|
case MX:
|
||||||
|
recordData = new MX(5, data);
|
||||||
|
break;
|
||||||
|
case SOA:
|
||||||
|
String[] sections = data.split(" ");
|
||||||
|
if (sections.length == 7) {
|
||||||
|
recordData = new SOA(sections[0], sections[1],
|
||||||
|
Long.valueOf(sections[2]), Integer.valueOf(sections[3]),
|
||||||
|
Integer.valueOf(sections[4]), Integer.valueOf(sections[5]),
|
||||||
|
Long.valueOf(sections[6]));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DNAME:
|
||||||
|
recordData = new DNAME(data);
|
||||||
|
break;
|
||||||
|
case NS:
|
||||||
|
recordData = new NS(DnsName.from(data));
|
||||||
|
break;
|
||||||
|
case TXT:
|
||||||
|
recordData = new TXT(data.getBytes());
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (recordData != null) {
|
||||||
|
msg.addAnswer(new Record<>(ans.get("name").getAsString(),
|
||||||
|
type, 1,
|
||||||
|
ans.get("TTL").getAsLong(),
|
||||||
|
recordData));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = msg.build().toArray();
|
||||||
|
completed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,8 @@ import java.util.LinkedList;
|
|||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*/
|
*/
|
||||||
abstract public class HttpsProvider extends Provider {
|
abstract public class HttpsProvider extends Provider {
|
||||||
|
protected static final String HTTPS_SUFFIX = "https://";
|
||||||
|
|
||||||
private static final String TAG = "HttpsProvider";
|
private static final String TAG = "HttpsProvider";
|
||||||
|
|
||||||
protected final WhqList whqList = new WhqList();
|
protected final WhqList whqList = new WhqList();
|
||||||
@ -147,7 +149,8 @@ abstract public class HttpsProvider extends Provider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!resolve(parsedPacket, dnsMsg) && uri != null) {
|
if (!resolve(parsedPacket, dnsMsg) && uri != null) {
|
||||||
sendRequestToServer(parsedPacket, dnsMsg, uri);
|
sendRequestToServer(parsedPacket, dnsMsg.asBuilder().setId(0).build(), uri);
|
||||||
|
//SHOULD use a DNS ID of 0 in every DNS request (according to draft-ietf-doh-dns-over-https-11)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,9 +169,6 @@ abstract public class HttpsProvider extends Provider {
|
|||||||
public abstract void doRequest();
|
public abstract void doRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Queue of WaitingOnSocketPacket, bound on time and space.
|
|
||||||
*/
|
|
||||||
public static class WhqList implements Iterable<WaitingHttpsRequest> {
|
public static class WhqList implements Iterable<WaitingHttpsRequest> {
|
||||||
private final LinkedList<WaitingHttpsRequest> list = new LinkedList<>();
|
private final LinkedList<WaitingHttpsRequest> list = new LinkedList<>();
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ public class ProviderPicker {
|
|||||||
case DNS_QUERY_METHOD_HTTPS_IETF:
|
case DNS_QUERY_METHOD_HTTPS_IETF:
|
||||||
return new HttpsIetfProvider(descriptor, service);
|
return new HttpsIetfProvider(descriptor, service);
|
||||||
case DNS_QUERY_METHOD_HTTPS_JSON:
|
case DNS_QUERY_METHOD_HTTPS_JSON:
|
||||||
break;
|
return new HttpsJsonProvider(descriptor, service);
|
||||||
case DNS_QUERY_METHOD_TLS:
|
case DNS_QUERY_METHOD_TLS:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user