Android ***Service - 如何转发截获的互联网流量?

Posted

技术标签:

【中文标题】Android ***Service - 如何转发截获的互联网流量?【英文标题】:Android ***Service - How to forward intercepted internet traffic ? 【发布时间】:2014-02-19 08:44:06 【问题描述】:

我已关注此link 并使用 ***Service 创建了 *** 接口。在将转发路由添加为“0.0.0.0”时,所有互联网流量都将转发到 *** 接口。我可以读取数据包、访问协议、目标 ip 和端口。

现在我正在尝试通过 tcp 套接字将数据包转发到其目的地。但是套接字连接失败,连接超时。

exception: java.net.ConnectException: failed to connect to /74.125.227.114 (port 443): connect failed: ETIMEDOUT (Connection timed out)

注意:当我尝试使用相同 ip 和端口但没有 *** 的套接字连接时,它会连接。无法弄清楚我哪里出错了?

粘贴以下代码:

public class ***ServiceEx extends ***Service implements Handler.Callback, Runnable 
    private static final String TAG = "***ServiceEx";

    private Handler mHandler;
    private Thread mThread;

    private ParcelFileDescriptor mInterface;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        // The handler is only used to show messages.
        if (mHandler == null) 
            mHandler = new Handler(this);
        

        // Stop the previous session by interrupting the thread.
        if (mThread != null) 
            mThread.interrupt();
        

        // Start a new session by creating a new thread.
        mThread = new Thread(this, "Test***Thread");
        mThread.start();
        return START_STICKY;
    

    @Override
    public void onDestroy() 
        if (mThread != null) 
            mThread.interrupt();
        
    

    @Override
    public boolean handleMessage(Message message) 
        if (message != null) 
            Toast.makeText(this, message.what, Toast.LENGTH_SHORT).show();
        
        return true;
    

    @Override
    public synchronized void run() 
        Log.i(TAG,"running ***Service");
        try 
            run***Connection();
         catch (Exception e) 
            e.printStackTrace();
            //Log.e(TAG, "Got " + e.toString());
         finally 
            try 
                mInterface.close();
             catch (Exception e) 
                // ignore
            
            mInterface = null;

            mHandler.sendEmptyMessage(R.string.disconnected);
            Log.i(TAG, "Exiting");
        
    


    private void run***Connection() 

        configure();

        FileInputStream in = new FileInputStream(mInterface.getFileDescriptor());
        FileOutputStream out = new FileOutputStream(mInterface.getFileDescriptor());

        // Allocate the buffer for a single packet.
        ByteBuffer packet = ByteBuffer.allocate(32767);

        Socket tcpSocket = new Socket();

        boolean ok = true;

        // We keep forwarding packets till something goes wrong.
        while (ok) 
            // Assume that we did not make any progress in this iteration.
            try 
                // Read the outgoing packet from the input stream.
                int length = in.read(packet.array());
                if (length > 0) 

                    Log.i(TAG,"packet received");
                    packet.limit(length);

                    String serverIP = getDestinationIP(packet);
                    int port = getDestinationPort(packet, getHeaderLength(packet));

                    Log.d(TAG, "destination IP: " + serverIP + " port: " + port);

                    InetAddress serverAddr = InetAddress.getByName(serverIP);
                    SocketAddress socketadd= new InetSocketAddress(serverAddr, port);

                    tcpSocket.connect(socketadd);  *****// this fails******

                    OutputStream outBuffer = tcpSocket.getOutputStream();
                    outBuffer.write(packet.array());
                    outBuffer.flush();
                    outBuffer.close();
                    packet.clear();
                    ok = false;
                

                if (tcpSocket.isConnected()) 
                    InputStream inBuffer = tcpSocket.getInputStream();
                    byte[] bufferOutput = new byte[32767];
                    inBuffer.read(bufferOutput);
                    if (bufferOutput.length > 0) 
                        String recPacketString = new String(bufferOutput,0,bufferOutput.length,"UTF-8");
                        Log.d(TAG , "recPacketString : " + recPacketString);
                        out.write(bufferOutput);
                    

                    inBuffer.close();
                
             catch (IOException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
                Log.e(TAG,"exception: " + e.toString());
                ok = false;
            

        
    


    private void configure() 
        // If the old interface has exactly the same parameters, use it!
        if (mInterface != null) 
            Log.i(TAG, "Using the previous interface");
            return;
        

        // Configure a builder while parsing the parameters.
        Builder builder = new Builder();
        builder.setMtu(1500);
        builder.addAddress(getLocalIpAddress(), 24);
        builder.addRoute("0.0.0.0", 0);  // to intercept packets
        try 
            mInterface.close();
         catch (Exception e) 
            // ignore
        

        mInterface = builder.establish();
    

【问题讨论】:

现在我知道为什么我不能通过套接字转发数据包了。在添加带有 ip address(0.0.0.0) 的 *** 路由表条目时会导致此问题。为了确认我只添加了特定地址,并且可以看到所有其他地址“除了”路由表中添加的地址的套接字连接是成功的。但是要拦截所有流量,我找不到比将路由表条目添加为 (0.0.0.0) 更好的方法。有人知道吗? 我不完全确定它是否会在您想要进行双向通信时起作用。您的 TUN 接口也在发送第 3 层数据包,而您的套接字是 L4,因此您将数据传送到 tun 接口的方式可能无法正常工作,除非您制作自己的 TCP+IP 数据包 能否添加方法 getDestinationIP、getDestinationPort、getHeaderLength 的定义。我想了解 IP 数据包的工作原理。谢谢。 @shashank:你终于能解决这个问题了吗?另外请添加用于提取目标ip和端口的代码。 你能添加你的方法的定义吗? 【参考方案1】:

我认为您需要保护套接字不被***Service.protect(Socket) 重新路由,如下所述:How to use *** in android?

【讨论】:

【参考方案2】:

从 FileInputStream 读取的数据包含 IPHeader 和 TCP/UDP Header,然后将它们放入套接字中,这将在其上添加另一个 IPHeader 和 TCP/UDP Header。所以服务器端会得到包含IPHeader和TCP/UDP Header的数据,但它认为数据是应用程序数据。所以你无法连接服务器。

【讨论】:

以上是关于Android ***Service - 如何转发截获的互联网流量?的主要内容,如果未能解决你的问题,请参考以下文章

保护 ***Service 中的套接字

将 Zuul、Hystrix(和 Feign)与 Spring Cloud HATEOAS 一起使用时如何转发标头?

如何让android的service一直在后台运行

如何让android的service一直在后台运行

Android如何启用Service,如何停用Service。

Android service如何获取Activity传入的值