【发布时间】:2018-04-20 23:15:17
【问题描述】:
所以我的情况是,我正在代理 Android 设备上的所有用户 DNS 请求,并使用本地数据库解析它们或将它们转发到某个上游 DNS 服务器。最近我对基于 TLS 的 DNS 产生了更大的兴趣,我尝试在 rfc 之后实现它。
由于所有这些都是在移动设备上完成的,我不想为每个代理请求(总计约 6.7 kB)建立新的 TLS 连接,因为用户可能正在使用移动连接。
长话短说,RFC 声明如下:
[...] 这份文件 规定 TLS 的成功协商表明 双方保持空闲 DNS 连接打开的意愿, 独立于 TCP 上的 DNS 超时或其他建议 没有 TLS
我使用以下代码发送测试请求并评估结果(为了便于阅读而进行了删减)。:
private void tlsTest(){
Socket s = establishConnection("1.1.1.1"); //Cloudflare in this example, reproducible for Quad9 as well
DataInputStream in; //Created from the Socket
DataOutputStream out; //Created from the Socket
for (int i = 0; i < 20; i++) {
byte[] data = dnsRequestTypeA("google.com");
data = new DatagramPacket(data, 0, data.length, destination, 853).getData();
out.writeShort(data.length);
out.write(data);
out.flush();
int times = 0;
while((message = readDNSMessage(in)) == null && ++times <= 10){
Thread.sleep(200);
}
System.out.println("Response: " + message);
Thread.sleep(2500);
}
}
private DNSMessage readDNSMessage(DataInputStream in) throws IOException {
byte[] lengthBytes = new byte[2];
if(in.read(lengthBytes) < 0)return null;
// Each DNS answer is preceded with an unsigned short giving the length of the packet
int length = (lengthBytes[0]&0xFF) + ((lengthBytes[1] &0xFF) << 8);
byte[] data = new byte[length];
in.read(data);
return new DNSMessage(data);
}
@NonNull
private Socket establishConnection(String host) throws IOException {
Socket socket = getSocketFactory().createSocket(host, 853);
socket.setKeepAlive(true);
return socket;
}
这里的问题是,当短时间内没有请求(大约 1-2 秒我的测试)。
有没有人有这方面的经验?我做错了什么(也许它与 Android 用于 TLS 的 OpenSSL 实现有关)?显然,每隔一秒左右向服务器发送一次虚假请求是可行的,但这是一个非常棘手的解决方法。
【问题讨论】:
-
你不能对已经被对端关闭的连接做任何事情。
-
是的,我知道,我最初问是否有人有同样的经历,或者我是否做错了什么。但后来我了解到 dns-over-tls 服务器不符合关于 tls 会话保持活动状态的 RFC,并且在一次查询后简单地结束它。