所以我的情况是我在Android设备上代理所有用户的DNS请求,并使用本地数据库解析它们或将它们转发到某个上游DNS服务器。由于最近对TLS的DNS有了更大的兴趣,我尝试在rfc之后实现它。
由于所有这些都是在移动设备上完成的,我不希望为每个代理请求建立新的TLS连接(总计大约6.7 kB),因为用户可能在移动设备上。
长话短说,rfc陈述如下:
[...]这份文件 规定TLS的成功谈判表明了 双方愿意保持闲置的DNS连接开放, 独立于DNS over TCP的超时或其他建议 没有TLS
我使用以下代码发送测试请求并评估结果(为了便于阅读而修剪)。:
B
这里的问题是,当没有短时间请求时,服务器似乎关闭连接(在尝试发送请求[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实现有关)?显然,只是通过虚拟请求每隔一秒左右向服务器发送垃圾邮件就可以了,但这将是一个非常糟糕的解决方法。
答案 0 :(得分:0)
经过一段时间的调试后,我找不到任何直接的解决方案。在编写本文时,我没有使用像Wireshark这样的工具来确定任何错误的实现,但现在采用了不同的处理方法;
我只是尽可能长时间地保持套接字处于活动状态(如果发送数据包失败,则在抛出异常之前最多重试5次)。此外,我缓存了所有查询,但由于这会严重影响性能/资源使用,我再次放弃它。