due99 2025-10-20 16:02 采纳率: 0%
浏览 10

关于#android#的问题,请各位专家解答!

Android开发中 想做DNS拦截 并将希望访问我们指定的IP网址 但是现在遇到的问题是希望绑定53端口拦截所有53 端口的数据包 但是现在无法绑定

private void startDnsHijackServer() {
    try {
        // 尝试绑定到53端口(需要root或系统权限)
        dnsSocket = new DatagramSocket(PORT_DNS);
        WifiLog.i(TAG, "DNS劫持服务器启动在端口 " + PORT_DNS);
        byte[] buffer = new byte[512];

        while (isRunning && !dnsSocket.isClosed()) {
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
            dnsSocket.receive(packet);

            // 在新线程中处理每个DNS请求
            new Thread(new DnsHandler(packet)).start();
        }
    } catch (Exception e) {
        WifiLog.e(TAG, "DNS服务器启动失败: " + e.getMessage());

        // 备选方案:使用非特权端口,然后通过iptables重定向
        startFallbackDnsServer();
    }
}

}

但是日志打印2025-10-20 15:51:07.456 28208-28208 SdkWifi com.yealink.devicesdk I DnsHijackService:DnsHijacker is created
2025-10-20 15:51:07.457 28208-28208 SdkWifi com.yealink.devicesdk I DnsHijackService:DNS劫持服务已启动
2025-10-20 15:51:07.460 28208-28241 SdkWifi com.yealink.devicesdk E DnsHijackService:DNS服务器启动失败: bind failed: EACCES (Permission denied)
2025-10-20 15:51:07.460 28208-28241 SdkWifi com.yealink.devicesdk I DnsHijackService:备选DNS服务器启动在端口 5353
2025-10-20 15:51:07.466 28208-28241 SdkWifi com.yealink.devicesdk E DnsHijackService:iptables重定向失败: Cannot run program "su": error=13, Permission denied

  • 写回答

1条回答 默认 最新

  • 宝码香车 优质创作者: JavaScript技术领域 2025-10-20 18:39
    关注

    让【宝码香车】来帮您解答,本回答参考DeepSeek编写,并整理提供。

    如果答案让您满意,请采纳、点赞、关注,非常感谢!
    .
    每日一句正能量,让它带给您好心情:每一次坚持,都是对自己的肯定。
    .

    Android DNS拦截端口绑定问题解决方案

    从日志可以看出,您遇到了两个关键问题:

    问题分析

    1. 绑定53端口失败Permission denied 错误
    2. iptables重定向失败:缺少root权限

    解决方案

    方案1:使用非特权端口 + iptables重定向(需要root权限)

    private static final int PORT_DNS = 53;
    private static final int PORT_FALLBACK = 5353;
    
    
    private void startDnsHijackServer() {
        try {
            dnsSocket = new DatagramSocket(PORT_DNS);
            WifiLog.i(TAG, "DNS劫持服务器启动在端口 " + PORT_DNS);
            startDnsListening();
        } catch (Exception e) {
            WifiLog.e(TAG, "DNS服务器启动失败: " + e.getMessage());
            startFallbackDnsServer();
        }
    }
    
    
    private void startFallbackDnsServer() {
        try {
            dnsSocket = new DatagramSocket(PORT_FALLBACK);
            WifiLog.i(TAG, "备选DNS服务器启动在端口 " + PORT_FALLBACK);
            
            // 尝试设置iptables重定向
            if (setupIptablesRedirect()) {
                WifiLog.i(TAG, "iptables重定向设置成功");
            } else {
                WifiLog.w(TAG, "iptables重定向设置失败,将使用本地DNS服务");
            }
            
            startDnsListening();
        } catch (Exception e) {
            WifiLog.e(TAG, "备选DNS服务器启动失败: " + e.getMessage());
        }
    }
    
    
    private boolean setupIptablesRedirect() {
        try {
            // 方法1:使用su命令(需要root)
            String[] commands = {
                "iptables -t nat -A OUTPUT -p udp --dport 53 -j REDIRECT --to-port " + PORT_FALLBACK,
                "iptables -t nat -A OUTPUT -p tcp --dport 53 -j REDIRECT --to-port " + PORT_FALLBACK
            };
            
            Process process = Runtime.getRuntime().exec("su");
            DataOutputStream os = new DataOutputStream(process.getOutputStream());
            
            for (String command : commands) {
                os.writeBytes(command + "\n");
            }
            os.writeBytes("exit\n");
            os.flush();
            
            return process.waitFor() == 0;
        } catch (Exception e) {
            WifiLog.e(TAG, "iptables重定向失败: " + e.getMessage());
            return false;
        }
    }
    
    
    private void startDnsListening() {
        byte[] buffer = new byte[512];
        while (isRunning && !dnsSocket.isClosed()) {
            try {
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                dnsSocket.receive(packet);
                new Thread(new DnsHandler(packet)).start();
            } catch (Exception e) {
                if (isRunning) {
                    WifiLog.e(TAG, "DNS接收错误: " + e.getMessage());
                }
            }
        }
    }
    

    方案2:VPN方式(无需root权限,推荐)

    public class DnsVpnService extends VpnService {
        private static final String TAG = "DnsVpnService";
        private ParcelFileDescriptor vpnInterface;
        
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            Builder builder = new Builder();
            builder.setMtu(1500);
            builder.addAddress("10.8.0.2", 32);
            builder.addRoute("0.0.0.0", 0);
            builder.setSession("DNSInterceptor");
            
            try {
                vpnInterface = builder.establish();
                
                // 启动DNS处理线程
                new Thread(new DnsInterceptor()).start();
                
            } catch (Exception e) {
                WifiLog.e(TAG, "VPN建立失败: " + e.getMessage());
            }
            
            return START_STICKY;
        }
        
        private class DnsInterceptor implements Runnable {
            @Override
            public void run() {
                try {
                    FileInputStream in = new FileInputStream(vpnInterface.getFileDescriptor());
                    
                    while (true) {
                        // 在这里拦截和处理DNS请求
                        // 可以使用本地DNS服务器或者自定义DNS解析逻辑
                    }
                    
                } catch (Exception e) {
                    WifiLog.e(TAG, "DNS拦截器错误: " + e.getMessage());
                }
            }
        }
        
        @Override
        public void onDestroy() {
            if (vpnInterface != null) {
                try {
                    vpnInterface.close();
                } catch (Exception e) {
                    WifiLog.e(TAG, "关闭VPN接口错误: " + e.getMessage());
                }
            }
            super.onDestroy();
        }
    }
    

    方案3:使用本地DNS解析器

    public class LocalDnsResolver {
        private static final String TAG = "LocalDnsResolver";
        private static final int DNS_PORT = 5353;
        private DatagramSocket dnsSocket;
        
        public void start() {
            try {
                dnsSocket = new DatagramSocket(DNS_PORT);
                WifiLog.i(TAG, "本地DNS解析器启动在端口 " + DNS_PORT);
                
                ExecutorService executor = Executors.newFixedThreadPool(10);
                byte[] buffer = new byte[512];
                
                while (!dnsSocket.isClosed()) {
                    DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
                    dnsSocket.receive(packet);
                    executor.execute(new DnsQueryHandler(packet));
                }
                
            } catch (Exception e) {
                WifiLog.e(TAG, "本地DNS解析器错误: " + e.getMessage());
            }
        }
        
        private class DnsQueryHandler implements Runnable {
            private final DatagramPacket originalPacket;
            
            public DnsQueryHandler(DatagramPacket packet) {
                this.originalPacket = packet;
            }
            
            @Override
            public void run() {
                try {
                    // 解析DNS查询
                    DNSMessage query = new DNSMessage(originalPacket.getData());
                    
                    // 自定义DNS解析逻辑
                    DNSMessage response = resolveDnsQuery(query);
                    
                    // 发送响应
                    byte[] responseData = response.toArray();
                    DatagramPacket responsePacket = new DatagramPacket(
                        responseData, responseData.length,
                        originalPacket.getAddress(), originalPacket.getPort()
                    );
                    dnsSocket.send(responsePacket);
                    
                } catch (Exception e) {
                    WifiLog.e(TAG, "DNS查询处理错误: " + e.getMessage());
                }
            }
            
            private DNSMessage resolveDnsQuery(DNSMessage query) {
                // 实现自定义DNS解析逻辑
                // 可以返回指定的IP地址
                return createCustomDnsResponse(query);
            }
        }
    }
    

    权限配置

    AndroidManifest.xml 中添加:

    <!-- VPN方式需要的权限 -->
    <uses-permission android:name="android.permission.BIND_VPN_SERVICE" />
    
    
    <service
        android:name=".DnsVpnService"
        android:permission="android.permission.BIND_VPN_SERVICE">
        <intent-filter>
            <action android:name="android.net.VpnService" />
        </intent-filter>
    </service>
    
    
    <!-- 网络权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    

    建议

    1. 推荐使用VPN方案,因为它不需要root权限,兼容性更好
    2. 如果必须使用53端口,考虑将应用做成系统应用
    3. 在非root设备上,使用非特权端口配合DNS重定向配置

    希望这些方案能帮助您解决问题!

    评论

报告相同问题?

问题事件

  • 创建了问题 10月20日