8

sshuttle は、 TCP-over-TCP メルトダウンという多くの議論された問題を解決すると主張しています。

sshuttle は、TCP ストリームをローカルで組み立て、ssh セッションでステートフルに多重化し、反対側で逆アセンブルしてパケットに戻します。したがって、TCP-over-TCP を実行することは決してありません。これは、安全な単なるデータオーバー TCP です。

しかし、プログラムの観点からは、ターゲット サーバーへの TCP 接続を、それに付随するすべて (読み取り指数タイムアウト) で維持します。SSH はまだudp. これは、TCP-over-TCP によく似ています。

ここでのトリックは何ですか?問題は本当に sshuttle によって解決されますか?

ソースコードを読んでみましたが、今のところ答えが見つかりません。

さらに重要なことは、彼らはどのようにそれを行うのでしょうか? ベアボーンでそれを再実装したい場合、どこからインスピレーションを探すべきですか?

4

2 に答える 2

3

sshuttlesshuttleクライアントは、特定の送信 TCP 接続をローカル ポート (デフォルトでは 12300) にリダイレクトするようにファイアウォール ルール (Linux では iptables、そのためクライアントに root 権限が必要です) を設定します。sshuttle の起動時にこのプロセスを確認できます。

firewall manager: starting transproxy.
>> iptables -t nat -N sshuttle-12300
>> iptables -t nat -F sshuttle-12300
>> iptables -t nat -I OUTPUT 1 -j sshuttle-12300
>> iptables -t nat -I PREROUTING 1 -j sshuttle-12300
>> iptables -t nat -A sshuttle-12300 -j RETURN --dest 127.0.0.0/8 -p tcp
>> iptables -t nat -A sshuttle-12300 -j REDIRECT --dest 0.0.0.0/0 -p tcp --to-ports 12300 -m ttl ! --ttl 42

そして、sshuttle の終了時に iptables nat ルールを削除します。

>> iptables -t nat -D OUTPUT -j sshuttle-12300
>> iptables -t nat -D PREROUTING -j sshuttle-12300
>> iptables -t nat -F sshuttle-12300
>> iptables -t nat -X sshuttle-12300

TCP コンテンツが取得され、sshuttleサーバーへの ssh 接続を介して多重化された後、再び接続に逆多重化されます。client.pyの関数onaccept_tcpinは、muxを実行します。

def onaccept_tcp(listener, method, mux, handlers):
    global _extra_fd
    try:
        sock, srcip = listener.accept()
    except socket.error as e:
        if e.args[0] in [errno.EMFILE, errno.ENFILE]:
            debug1('Rejected incoming connection: too many open files!\n')
            # free up an fd so we can eat the connection
            os.close(_extra_fd)
            try:
                sock, srcip = listener.accept()
                sock.close()
            finally:
                _extra_fd = os.open('/dev/null', os.O_RDONLY)
            return
        else:
            raise

    dstip = method.get_tcp_dstip(sock)
    debug1('Accept TCP: %s:%r -> %s:%r.\n' % (srcip[0], srcip[1],
                                              dstip[0], dstip[1]))
    if dstip[1] == sock.getsockname()[1] and islocal(dstip[0], sock.family):
        debug1("-- ignored: that's my address!\n")
        sock.close()
        return
    chan = mux.next_channel()
    if not chan:
        log('warning: too many open channels.  Discarded connection.\n')
        sock.close()
        return
    mux.send(chan, ssnet.CMD_TCP_CONNECT, b'%d,%s,%d' %
             (sock.family, dstip[0].encode("ASCII"), dstip[1]))
    outwrap = MuxWrapper(mux, chan)
    handlers.append(Proxy(SockWrapper(sock, sock), outwrap))
    expire_connections(time.time(), mux)

ssnet.pyでデータがどのようにパックされているかを確認できます。

TCP接続をSOCKSまたはHTTPSプロキシにリダイレクトすることを目的としたredsocksで同じ戦略(ファイアウォールルールの設定を意味します)を見てきました。

于 2017-01-02T17:13:38.390 に答える
3

声明にあるように、これはTCP-over-TCP ではありません。

これは TCP-over-TCP です。

First application   
  First end of outer TCP connection  
  First end of inner TCP connection  
   Datagram/packet link  
  Send end of inner TCP connection  
  Second end of outer TCP connection  
Second application  

外側の TCP 接続が内側の TCP 接続を介してどのように伝送されるかに注目してください。

これは彼らがしていることです:

First application   
 First end of outer TCP connection  
  Outer end of First TCP connection  
  Inner end of First TCP connection  
    Byte stream link  
  Inner end of Second TCP connection  
  Outer end of Second TCP connection  
Second application 

内部 TCP 接続を介して転送される外部 TCP 接続がないことに注意してください。TCP-over-TCP はありません。

あなたがそれを行うことができる4つの明白な方法があります:

  1. システムにすでに割り当てられている IP アドレスへの TCP 接続を確立するようにアプリケーションを誘導します。
  2. アプリケーションが接続しようとする IP アドレスをシステムに割り当てます。
  3. ローカル システムで実行されているプロセスへのアウトバウンド TCP 接続を NAT します。( jfly answerは、これが彼らの仕事であることを示唆しています)
  4. OSにTCPパケットをルーティングさせ、ユーザー空間でのTCPの実装で終了させます。
于 2017-01-02T12:55:29.137 に答える