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

Android VpnService在API 33以下实现路由排除的方案咨询

API 32及以下实现DNS流量绕过VPN代理

核心背景

你的需求是让DNS查询绕过仅支持TCP的VPN代理,其余流量全部走代理。在API 33+可以用excludeRoute快速实现,但API 32及以下无此方法,无需手动枚举大量路由段,可通过以下优雅方案解决。

优雅实现方案

方案:自动生成互补路由段

通过代码自动计算出除DNS服务器IP外的所有IPv4路由段,替代手动编写大量addRoute条目。核心思路是拆分0.0.0.0/0默认路由,排除目标DNS的IP段,将剩余路由添加到VPN配置中。

实现代码

首先定义一个路由工具类,用于计算互补路由段:

import android.net.IpPrefix;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class IpPrefixUtils {
    public static List<IpPrefix> getComplementaryPrefixes(List<IpPrefix> excludePrefixes) {
        List<IpPrefix> result = new ArrayList<>();
        Queue<IpPrefix> queue = new LinkedList<>();
        
        try {
            queue.add(new IpPrefix(InetAddress.getByName("0.0.0.0"), 0));
        } catch (UnknownHostException e) {
            e.printStackTrace();
            return result;
        }

        for (IpPrefix exclude : excludePrefixes) {
            Queue<IpPrefix> tempQueue = new LinkedList<>();
            while (!queue.isEmpty()) {
                IpPrefix current = queue.poll();
                if (!current.contains(exclude)) {
                    tempQueue.add(current);
                } else if (current.equals(exclude)) {
                    continue;
                } else {
                    List<IpPrefix> children = splitPrefix(current);
                    for (IpPrefix child : children) {
                        if (child.contains(exclude)) {
                            queue.add(child);
                        } else {
                            tempQueue.add(child);
                        }
                    }
                }
            }
            queue = tempQueue;
        }
        result.addAll(queue);
        return result;
    }

    private static List<IpPrefix> splitPrefix(IpPrefix prefix) {
        List<IpPrefix> children = new ArrayList<>(2);
        int prefixLength = prefix.getPrefixLength();
        if (prefixLength >= 32) {
            return children;
        }

        byte[] addrBytes = prefix.getAddress().getAddress();
        int bitPos = prefixLength / 8;
        int bitOffset = 7 - (prefixLength % 8);

        // 生成第一个子前缀IP
        byte[] firstChildBytes = Arrays.copyOf(addrBytes, 4);
        firstChildBytes[bitPos] &= ~(1 << bitOffset);
        // 生成第二个子前缀IP
        byte[] secondChildBytes = Arrays.copyOf(firstChildBytes, 4);
        secondChildBytes[bitPos] |= (1 << bitOffset);

        try {
            children.add(new IpPrefix(InetAddress.getByAddress(firstChildBytes), prefixLength + 1));
            children.add(new IpPrefix(InetAddress.getByAddress(secondChildBytes), prefixLength + 1));
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
        return children;
    }
}

然后在VPN配置中使用该工具类:

import android.net.IpPrefix;
import android.os.ParcelFileDescriptor;
import android.net.VpnService;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;

// 初始化VPN Builder
VpnService.Builder builder = new VpnService.Builder()
        .setMtu(1500)
        .addAddress("26.26.26.1", 24);

// 目标DNS服务器IP
String dnsIp = "8.8.8.8";
builder.addDnsServer(dnsIp);

try {
    // 生成要排除的DNS前缀
    IpPrefix dnsPrefix = new IpPrefix(InetAddress.getByName(dnsIp), 32);
    // 获取互补路由段(所有非DNS的IPv4路由)
    List<IpPrefix> includeRoutes = IpPrefixUtils.getComplementaryPrefixes(Collections.singletonList(dnsPrefix));
    
    // 添加所有互补路由到VPN
    for (IpPrefix route : includeRoutes) {
        builder.addRoute(route.getAddress(), route.getPrefixLength());
    }
} catch (UnknownHostException e) {
    e.printStackTrace();
}

// 建立VPN连接
ParcelFileDescriptor vpnInterface = builder.establish();

关键说明

  • 该工具类会自动拆分0.0.0.0/0为不包含目标DNS IP的路由段,无需手动编写大量路由条目。
  • 支持多个DNS服务器:只需将所有DNS的IpPrefix加入excludePrefixes列表即可。
  • 可扩展支持IPv6:只需在工具类中添加IPv6地址的拆分逻辑。
  • 路由数量可控:排除单个IPv4时,仅会生成约10个左右的路由段,性能影响可忽略。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 12:22:03