2017-01-02 3 views
3

sshuttle claims что он решает много discussed problem от TCP-over-TCP meltdown.Как избавиться от проклятия TCP-over-TCP?

sshuttle собирает TCP-поток локально, мультиплексирует его по-разному в течение сеанса ssh и дизассемблирует его обратно в пакеты на другом конце. Поэтому он никогда не заканчивает работу с TCP-over-TCP. Это просто передача данных по TCP, что безопасно.

Но с точки зрения программы, он поддерживает подключение TCP к целевому серверу со всем, что происходит с ним (читайте экспоненциальный таймаут), который является слоистым о другом сеансе TCP, так как SSH делает еще не просто работа на udp. Это очень похоже на TCP-over-TCP.

Что это за трюк здесь? Действительно ли проблема решена sshuttle?

Я пробовал читать source code, но пока не нашел ответа.

Что еще более важно, как именно они это делают? Если кто-то хочет переопределить его в barebones, где нужно искать вдохновение?

ответ

1

sshuttle клиента устанавливает правила брандмауэра (Iptables в Linux, поэтому sshuttle клиенту нужен корневая привилегия) для перенаправления определенных исходящих TCP соединений в локальный порт (12300 по умолчанию) вы можете увидеть этот процесс При запуске 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 

и удалить IPtables физ правил при sshuttle выходов,

>> 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 подбирают и уплотненные через соединение SSH т o сервер sshuttle, затем снова отключите мультиплексирование. Функция onaccept_tcpin в client.py сделать мультиплексор:

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.

Я видел ту же стратегию (я имею в виду настройку правил брандмауэра) в redsocks, которая направлена ​​на перенаправление любого TCP-соединения на SOCKS или HTTPS-прокси.

2

Как говорится в заявлении, это не 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 не существует.

Есть четыре очевидных способов, вы могли бы сделать это:

  1. индуцируют приложение, чтобы сделать соединение TCP к IP-адрес уже присвоен системе.
  2. Назначьте системе IP-адрес, к которому приложение пытается подключиться.
  3. NAT исходящее TCP-соединение с процессом, запущенным в локальной системе. (jfly answer намекает, что это то, что они делают)
  4. Сделать OS маршрутизирующим TCP-пакеты для вас и прервать его с помощью реализации TCP в пользовательском пространстве.
+0

Это отличное объяснение! Но как именно они это делают? – sanmai

+1

Какую часть вы не понимаете? На моей диаграмме должно быть ясно, что каждое приложение имеет полностью локальное TCP-соединение с одним концом ссылки потока байтов. –

+0

Как они «завершают» первое соединение, чтобы ядро ​​перестало заботиться об этом? См. Обновленный вопрос – sanmai

Смежные вопросы