保护 ***Service 中的套接字
Posted
技术标签:
【中文标题】保护 ***Service 中的套接字【英文标题】:Protect a socket in ***Service 【发布时间】:2013-12-01 09:24:54 【问题描述】:我正在探索 android 的 ***Service 的功能。目前,我通过在用户空间中重建 IP 堆栈构建了一个非常基本的请求转发器:我从 ***Service 的输入流中读取 IP 数据包,解析它们,对于我不想转发的连接,我尝试重新创建那些套接字连接在 *** 连接之外。
我了解到这最后一点是由***Service.protect()
促成的,并尝试按如下方式实现它:
Socket socket = new Socket();
***Service.protect(socket);
socket.connect(new InetSocketAddress(
header.getDestinationAddress(), // From my IP datagram header
body.getDestinationPort())); // From the TCP datagram header
不幸的是,这种方法会导致回环到 *** 接口。
虽然上面的代码会简单地阻塞并最终超时,但我通过从单独的线程调用Socket.connect(InetSocketAddress)
来观察环回;连接直接返回到我的 ***Service 的输入流,然后重复该过程。
不用说,这会导致循环。我觉得这是因为在创建套接字时(以及随后调用***Service.protect(Socket)
),我还没有设置目标IP和端口。
情况似乎确实如此,因为在我的 ***Service 实现中覆盖 ***Service.protect(Socket)
和 ***Service.protect(int)
并在这两种情况下调用 supers 都会返回 false。
如何正确保护套接字连接?
【问题讨论】:
【参考方案1】:以下代码有效。
Socket socket = SocketChannel.open().socket();
if ((null != socket) && (null != ***Service))
***Service.protect(socket);
socket.connect(...);
new Socket() 没有有效的文件描述符,因此无法保护。
【讨论】:
建立***接口后也要调用protect方法。 此方法创建一个套接字,当在 Android 8.0 或更高版本上写入该应用程序时会导致应用崩溃。不过,Mai Quoc Hui 下面的回答很可靠。改用那个!【参考方案2】:我发现另一种解决方案是用 C/C++ 写出来。
Java:
public native int createSocket();
public native int connectSocket(int fd);
C++:
// For sockets
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
// For error codes
#include <errno.h>
extern "C"
JNIEXPORT jint JNICALL
Java_com_pixplicity_example_jni_***Interface_createSocket(
JNIEnv * env, jobject thiz)
// Create the socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
int err = errno;
// Return the file descriptor
return sockfd;
JNIEXPORT jint JNICALL
Java_com_pixplicity_example_jni_***Interface_connectSocket(
JNIEnv * env, jobject thiz, jint sockFd)
// Host & port are hard-coded here
char* host = "74.125.136.113"; // google.com
int port = 80;
struct sockaddr_in peerAddr;
int ret;
peerAddr.sin_family = AF_INET;
peerAddr.sin_port = htons(port);
peerAddr.sin_addr.s_addr = inet_addr(host);
// Connect to host
ret = connect((int) sockFd, (struct sockaddr *) &peerAddr,
sizeof(peerAddr));
if (ret != 0)
perror("connect failed");
close(sockFd);
// Return the error code
return ret;
【讨论】:
【参考方案3】:您需要在保护之前绑定您的套接字。这对我有用:
Socket socket = new Socket();
//bind to any address
socket.bind(new InetSocketAddress(0));
***Service.protect(socket);
socket.connect(...);
【讨论】:
【参考方案4】:您可以通过将您的应用程序添加到***Service.builder.addDisallowedApplication("your package name")
来排除您的应用程序套接字(以及流经它的流量)使用 ***
我尝试了这个并在 *** 隧道接口和我的传出 Internet 接口上运行 tcpdump
对其进行了测试。来自我的应用程序的数据包不会在 *** 接口中循环,而是通过手机的前向 Internet 接口发送。
【讨论】:
【参考方案5】:我需要保护OkHttpClient
中的套接字。它会创建无法保护的未连接套接字(意味着service.protect()
返回false
)并且当它们连接时显然为时已晚(例如,当我试图在networkInterceptor
中保护它们时)。经典晦涩的 Android 行为。
无论如何,Mai Quoc Huy 的回答对我来说是正确的,整个代码看起来像这样。
val protectedHttpClient = OkHttpClient.Builder()
.socketFactory(object : SocketFactory()
override fun createSocket(): Socket = Socket().apply
bind(InetSocketAddress(0))
val result = service?.protect(this)
override fun createSocket(host: String?, port: Int) = unsupported()
override fun createSocket(host: String?, port: Int, localHost: InetAddress?, localPort: Int) = unsupported()
override fun createSocket(host: InetAddress?, port: Int) = unsupported()
override fun createSocket(address: InetAddress?, port: Int, localAddress: InetAddress?, localPort: Int) = unsupported()
private fun unsupported(): Nothing = throw UnsupportedOperationException("This factory can only create unconnected sockets for OkHttp")
)
.build()
【讨论】:
以上是关于保护 ***Service 中的套接字的主要内容,如果未能解决你的问题,请参考以下文章