带有 ***Service 的 Android 防火墙。响应已传递,但抛出 SocketTimeoutException
Posted
技术标签:
【中文标题】带有 ***Service 的 Android 防火墙。响应已传递,但抛出 SocketTimeoutException【英文标题】:A firewall for Android with ***Service. Responses are delivered, but a SocketTimeoutException is thrown 【发布时间】:2015-07-15 21:16:45 【问题描述】:我正在使用***Service 为 android 实现一个简单的防火墙。我的应用类似于Toy***Service,但它不会将原始 IP 数据包发送到远程 *** 服务器,该服务器会将它们转发到它们的目的地。
我的实现在这里:https://bitbucket.org/MaksimDmitriev/norootfirewall/src/006f7c33cd1cd4055f372ed3a88664fe2a4be3dd/src/com/norootfw/NoRootFwService.java?at=unix
我可以在本地完成所有这些转发例程吗?这就是我想要实现的。
我初始化了一个 TUN 设备及其文件描述符:
mInterface = new Builder().setSession(getString(R.string.app_name))
.addAddress("10.0.2.1", 24)
.addRoute("0.0.0.0", 1)
.addRoute("128.0.0.0", 1)
.establish();
in = new FileInputStream(mInterface.getFileDescriptor());
out = new FileOutputStream(mInterface.getFileDescriptor());
我将 0.0.0.0/1 和 128.0.0.0/1 分配给 TUN 设备,使其比默认路由 0.0.0.0/0 更可取。我使用了 0.0.0.0/0 并遇到了同样的异常,如下所示。
这是一个示例 UDP 请求。
1).我从 TUN 设备读取了一个 IP 数据包。
05-06 00:46:52.749: D/UDPChecksum(31077): Sent == [69, 0, 0, 36, 0, 0, 64, 0, 64, 17, 108, 91, 10, 0, 2, 1, -64, -88, 1, -59, -53, 1, -50, -87, 0, 16, 89, -114, 85, 68, 80, 95, 68, 65, 84, 65]
请考虑 IPv4 数据包结构here. 例如,第一个数字 69(二进制的 0100 0101)表示 IP 协议的版本为 4(高 4 位)。而低 4 位代表 32 位字中的Internet Header Length (IHL)。
2). 然后创建一个 protected DatagramSocket
并将数据(不带其 IP 和 UDP 标头)发送到我要读取的目标地址从捕获的IP数据包中。
3)。我收到来自远程计算机的响应,并希望将其发送回初始化请求的应用程序。
4).我交换IP包中的源IP地址和目的IP地址和端口号,计算IPv4头校验和和UDP校验和(已经构造了一个IPv4伪头)。
05-06 00:46:52.889: D/UDPChecksum(31077): mIpv4PseudoHeader == [-64, -88, 1, -59, 10, 0, 2, 1, 0, 17, 0, 14]
5). 然后我将计算出的校验和设置为IP包的对应索引,并将IP包写入TUN设备的输出流out
。
05-06 00:46:52.889: D/UDPChecksum(31077): To TUN == [69, 0, 0, 34, 0, 0, 64, 0, 64, 17, 108, 93, -64, -88, 1, -59, 10, 0, 2, 1, -50, -87, -53, 1, 0, 14, -105, -72, 85, 68, 80, 95, 79, 75]
响应到达我的应用程序。 DatagramSocket
在调用其 receive() 方法后被阻塞,填充了我提供的缓冲区。
byte[] responseBuffer = new byte[RESPONSE_SIZE];
try
mDatagramSocket.send(mDatagramPacket);
final DatagramPacket response = new DatagramPacket(responseBuffer, responseBuffer.length);
mDatagramSocket.receive(response);
catch (IOException e)
Log.e("NoRootFwService", "error: " + Arrays.toString(responseBuffer)); // I can see the correct response here.
logException(e);
但是它的socket在超时的时候会抛出异常。
05-05 23:46:58.389: E/CLIENT(20553): java.net.SocketTimeoutException
05-05 23:46:58.389: E/CLIENT(20553): at libcore.io.IoBridge.maybeThrowAfterRecvfrom(IoBridge.java:551)
05-05 23:46:58.389: E/CLIENT(20553): at libcore.io.IoBridge.recvfrom(IoBridge.java:509)
05-05 23:46:58.389: E/CLIENT(20553): at java.net.PlainDatagramSocketImpl.doRecv(PlainDatagramSocketImpl.java:161)
05-05 23:46:58.389: E/CLIENT(20553): at java.net.PlainDatagramSocketImpl.receive(PlainDatagramSocketImpl.java:169)
05-05 23:46:58.389: E/CLIENT(20553): at java.net.DatagramSocket.receive(DatagramSocket.java:250)
05-05 23:46:58.389: E/CLIENT(20553): at socket.client.MainActivity$UdpThread.run(MainActivity.java:195)
05-05 23:46:58.389: E/CLIENT(20553): Caused by: libcore.io.ErrnoException: recvfrom failed: EAGAIN (Try again)
05-05 23:46:58.389: E/CLIENT(20553): at libcore.io.Posix.recvfromBytes(Native Method)
05-05 23:46:58.389: E/CLIENT(20553): at libcore.io.Posix.recvfrom(Posix.java:141)
05-05 23:46:58.389: E/CLIENT(20553): at libcore.io.BlockGuardOs.recvfrom(BlockGuardOs.java:164)
05-05 23:46:58.389: E/CLIENT(20553): at libcore.io.IoBridge.recvfrom(IoBridge.java:506)
05-05 23:46:58.389: E/CLIENT(20553): ... 4 more
没有防火墙,一切正常。 我阅读了这些讨论,但它们没有帮助:
https://***.com/a/17820461/1065835
Android firewall with ***Service
【问题讨论】:
您的防火墙是否有可能将自己作为主 IP 传输,从而导致虚假 IP 日志。 *** 不倾向于以这种方式喜欢来自单个客户端的多个 IP。 @DCdaz,什么是主IP?假IP日志是什么意思? *** 通常不允许多个 IP 来自同一位置,有时防火墙可能会像另一个 IP 一样阻止您与客户端的连接,因为它的使用条款与IP的 @DCdaz,我不明白你。我期望的响应到达我的应用程序,但监听它的套接字仍然被阻塞。好像它需要什么意味着好的,你可以解除阻止 @MaksimDmitriev 你怎么知道在套接字被阻塞时响应是否到达你的应用程序? 'SocketTimeoutException' 不是意味着您没有得到任何响应吗? 【参考方案1】:尝试添加缺少的 SocketTimeoutException 异常处理程序
byte[] responseBuffer = new byte[RESPONSE_SIZE];
try
mDatagramSocket.send(mDatagramPacket);
final DatagramPacket response = new DatagramPacket(responseBuffer, responseBuffer.length);
mDatagramSocket.receive(response);
catch (SocketTimeoutException e)
// ignore
; // continue;
catch (IOException e)
Log.e("NoRootFwService", "error: " + Arrays.toString(responseBuffer)); // I can see the correct response here.
logException(e);
source
【讨论】:
你从我的问题中复制了它。 无论如何,这不是答案。我需要修复我的防火墙而不是客户端进行测试 您的防火墙可能没有问题。请运行混杂的 Wireshark 捕获流量,将其保存为 pcap 文件并将其上传到某处进行分析。这样我们就可以很容易地看到数据包级别发生了什么。 我的防火墙有问题。我做了一件事。我找到了原因 对于未来的读者,请在您有时间的时候告诉我们哪里出了问题以及您是如何发现问题的。顺便说一句,这与积分无关;这只是为了正确地结束你的问题。【参考方案2】:从 recvfrom() 调用文档:
[EAGAIN] 或 [EWOULDBLOCK] 套接字的文件描述符标记为 O_NONBLOCK 并且没有数据等待接收;或 MSG_OOB 已设置且没有带外数据 可用并且套接字的文件描述符标记为 O_NONBLOCK 或者套接字不支持阻塞等待带外数据。
简单解释
如果套接字上没有可用的消息,则接收调用等待 要到达的消息,除非套接字是非阻塞的(参见 fcntl(2)), 在这种情况下,返回值 -1 并且外部变量 errno 设置为 EAGAIN
DatagramSocket 未处于阻塞模式,并且您似乎正在尝试从套接字读取并且没有要读取的数据,您确定您真的在接收数据吗?尝试为每个接收到的数据包清理缓冲区。
【讨论】:
其实这不是它不起作用的原因。我找到了原因。我应该给谁400分? :) 如果我给你一个提示,你很快就会猜到。 那我真的不知道:/但我很想知道答案是什么:) 你应该使用不同的套接字形式发送和接收,【参考方案3】:关键是我使用了错误的 IPv4 伪标头来计算校验和。它既不包含数据包 UDP 标头,也不包含传输的数据。由于我包含了 UDP 标头和数据,因此我没有看到原始问题的异常。
【讨论】:
您的回答不是很清楚,也没有告诉我们您是如何发现错误的。 我知道问题出在哪里,错误的伪标头会产生不正确的 UDP 校验和,信息不匹配且没有地址信息(干得好,真的很难找到),但我无法确定您何时收到错误(我假设当您将响应数据包转发到 tun 时会产生错误)因为堆栈跟踪错误不完整并且您的 bitbucket 代码未更新,无论如何,如果我的回答对您有所帮助,我很高兴。 我在 bitbucket 上阅读了您的代码。看来您还没有实现 TCP,只有 UDP。任何指针?我想了解您的代码背后的原理。我可以阅读任何文章吗?? @sirackh,你是对的。我还没有实现 TCP,但其他人已经实现了。观看此视频(视频为俄语)。你能理解吗? youtube.com/watch?v=pqMqfVlGyWM @MaksimDmitriev 不幸的是我不会说俄语。可能还有其他链接吗?还是文章??以上是关于带有 ***Service 的 Android 防火墙。响应已传递,但抛出 SocketTimeoutException的主要内容,如果未能解决你的问题,请参考以下文章
带有 ***Service 的 Android 防火墙。响应已传递,但抛出 SocketTimeoutException