You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android端基于NSFW JS实现图片拦截的自建VPN问题求助

问题分析与解决方案

一、加载超时的核心原因

你当前的handleTraffic方法只是将VPN接口读取到的数据原封不动写回,完全没有实现网络数据的转发逻辑。VPN的本质是作为网络中间层,需要把设备发往VPN接口的IP数据包解析后,转发到真实的外部网络,再把外部网络的响应封装成IP包返回给设备,否则设备的请求永远无法到达目标服务器,必然超时。

修复转发逻辑的关键步骤

  1. 解析IP数据包:VPN接口接收的是完整的IP数据包,需要先解析出IP头部信息(协议类型、源/目的IP、端口等)。
  2. 建立外部Socket连接:根据解析出的目的IP和端口,创建Socket连接到目标服务器。
  3. 双向数据转发:开启两个线程,分别负责将VPN接口的数据转发到外部Socket,以及将外部Socket的响应转发回VPN接口。

修正后的handleTraffic核心逻辑示例:

private fun handleTraffic() {
    val vpnFileDescriptor = mInterface!!.fileDescriptor
    val vpnInputStream = FileInputStream(vpnFileDescriptor)
    val vpnOutputStream = FileOutputStream(vpnFileDescriptor)
    val buffer = ByteArray(1500) // 对应之前设置的MTU值

    while (true) {
        val bytesRead = vpnInputStream.read(buffer)
        if (bytesRead <= 0) continue

        // 解析IP数据包头部
        val ipHeader = IpHeader(buffer, 0, bytesRead)
        if (!ipHeader.isValid()) continue

        // 根据协议类型处理TCP/UDP包
        when (ipHeader.protocol) {
            IpHeader.PROTOCOL_TCP -> handleTcpPacket(ipHeader, buffer, bytesRead, vpnOutputStream)
            IpHeader.PROTOCOL_UDP -> handleUdpPacket(ipHeader, buffer, bytesRead, vpnOutputStream)
        }
    }
}

// 简易IP头部解析类(需自行实现完整的IP/TCP/UDP头部解析逻辑)
class IpHeader(private val data: ByteArray, private val offset: Int, private val length: Int) {
    val protocol: Byte get() = data[offset + 9]
    val sourceIp: String get() = "${data[offset+10]&0xFF}.${data[offset+11]&0xFF}.${data[offset+12]&0xFF}.${data[offset+13]&0xFF}"
    val destinationIp: String get() = "${data[offset+14]&0xFF}.${data[offset+15]&0xFF}.${data[offset+16]&0xFF}.${data[offset+17]&0xFF}"
    
    fun isValid(): Boolean = length >= 20 // IP头部至少20字节
    companion object {
        const val PROTOCOL_TCP: Byte = 6
        const val PROTOCOL_UDP: Byte = 17
    }
}

二、NSFW图片拦截的实现思路

图片拦截需要在HTTP/HTTPS层面识别图片资源,再调用NSFW JS进行检测,核心步骤如下:

1. 重组TCP流,解析HTTP请求/响应

HTTP数据通过TCP分段传输,需先将多个TCP分段重组为完整的HTTP请求或响应:

  • 对TCP数据包按序列号排序、补全缺失分段,还原完整HTTP数据流。
  • 识别请求路径的图片后缀(.jpg/.png/.webp/.gif等),或响应头的Content-Type是否为image/*。

2. Android中集成NSFW JS

NSFW JS是JavaScript库,Android上可通过两种方式运行:

  • WebView方式:创建隐藏WebView,加载assets目录下的NSFW JS脚本,将图片Base64数据传入WebView调用检测方法。
  • V8引擎方式:集成Chrome V8引擎,直接运行NSFW JS脚本处理图片字节数据。

示例WebView调用NSFW JS的核心代码:

// 初始化WebView加载NSFW脚本
private fun initNsfwDetector(webView: WebView) {
    webView.settings.javaScriptEnabled = true
    webView.loadUrl("file:///android_asset/nsfw.js") // 将nsfw.js放入assets目录
}

// 检测图片是否为NSFW内容
private fun detectNsfwImage(imageBytes: ByteArray, callback: (Boolean) -> Unit) {
    val base64Image = Base64.encodeToString(imageBytes, Base64.DEFAULT)
    webView.evaluateJavascript(
        "detectNsfw('data:image/jpeg;base64,$base64Image')",
        ValueCallback { result ->
            val isNsfw = result.toBoolean()
            callback(isNsfw)
        }
    )
}

3. 拦截NSFW图片的处理逻辑

  • 请求阶段拦截:识别到图片请求后,先获取图片数据进行NSFW检测,若为违规内容则返回403 Forbidden响应,终止请求。
  • 响应阶段拦截:若响应为图片资源,检测后发现违规则替换为预先准备的安全图片(如空白占位图),再返回给设备。

三、额外注意事项

  • 权限配置:AndroidManifest.xml中需添加android.permission.INTERNET、android.permission.BIND_VPN_SERVICE等必要权限。
  • HTTPS解密:若要拦截HTTPS图片,需生成并安装自定义CA证书,实现中间人解密HTTPS流量。
  • 性能优化:NSFW检测为耗时操作,需在后台线程处理,避免阻塞VPN转发逻辑。

内容的提问来源于stack exchange,提问作者Newbee

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 07:07:42