@Override
    public void forward(byte[] packet, int len, OutputStream output) {
        IpHeader ipHeader = new IpHeader(packet, 0);
        TcpHeader tcpHeader = new TcpHeader(ipHeader, packet, ipHeader.getHeaderLength());

        // Src IP & Port
        int localIp = ipHeader.getSourceIp();
        short localPort = tcpHeader.getSourcePort();

        // Dest IP & Port
        int remoteIp = ipHeader.getDestinationIp();
        short remotePort = tcpHeader.getDestinationPort();

        // TCP data size
        int tcpDataSize = ipHeader.getDataLength() - tcpHeader.getHeaderLength();

        NetBareLog.v("ip: %s:%d -> %s:%d", NetBareUtils.convertIp(localIp),
                NetBareUtils.convertPort(localPort), NetBareUtils.convertIp(remoteIp),
                NetBareUtils.convertPort(remotePort));
        NetBareLog.v("tcp: %s, size: %d", tcpHeader.toString(), tcpDataSize);

        // Tcp handshakes and proxy forward flow.

        // Client: 10.1.10.1:40988
        // Server: 182.254.116.117:80
        // Proxy Server: 10.1.10.1:38283

        // 10.1.10.1:40988 -> 182.254.116.117:80 SYN
        // Forward: 182.254.116.117:40988 -> 10.1.10.1:38283 SYN

        // 10.1.10.1:38283 -> 182.254.116.117:40988 SYN+ACK
        // Forward: 182.254.116.117:80 -> 10.1.10.1:40988 SYN+ACK

        // 10.1.10.1:40988 -> 182.254.116.117:80 ACK
        // Forward: 182.254.116.117:80 -> 10.1.10.1:38283 ACK

        if (localPort != mProxyServer.getPort()) {
            // Client requests to server
            Session session = mSessionProvider.ensureQuery(Protocol.TCP, localPort, remotePort, remoteIp);
            session.packetIndex++;

            // Forward client request to proxy server.
            ipHeader.setSourceIp(remoteIp);
            ipHeader.setDestinationIp(mProxyServer.getIp());
            tcpHeader.setDestinationPort(mProxyServer.getPort());

            ipHeader.updateChecksum();
            tcpHeader.updateChecksum();

            session.sendDataSize += tcpDataSize;
        } else {
            // Proxy server responses forward client request.
            Session session = mSessionProvider.query(remotePort);
            if (session == null) {
                NetBareLog.w("No session saved with key: " + remotePort);
                return;
            }
            // Forward proxy server response to client.
            ipHeader.setSourceIp(remoteIp);
            ipHeader.setDestinationIp(mProxyServer.getIp());
            tcpHeader.setSourcePort(session.remotePort);

            ipHeader.updateChecksum();
            tcpHeader.updateChecksum();

            session.receiveDataSize += tcpDataSize;
        }

        try {
            output.write(packet, 0, len);
        } catch (IOException e) {
            NetBareLog.e(e.getMessage());
        }
    }
Handshake with local TCP proxy server and then forward packets to it.

@author Megatron King
@since 2018-10-09 01:30
netbare-core/src/main/java/com/github/megatronking/netbare/proxy/TcpProxyServerForwarder.java