В каких версиях Windows (если есть) SO_EXCLUSIVEADDRUSE может предотвратить повторное связывание порта с остаточными соединениями?

Рассмотрим следующую ситуацию в Windows:

  1. сокет прослушивания 1 имеет установленную опцию SO_EXCLUSIVEADDRUSE и привязывается к порту
  2. прослушивать сокет 1 получает входящее соединение, которое он принимает для создания подключенного сокета
  3. сокет прослушивания 1 закрыт, но подключенный сокет остается открытым (в некотором смысле, возможно, ESTABLISHED или TIME_WAIT)
  4. Для сокета прослушивания 2 задана опция SO_EXCLUSIVEADDRUSE, и он пытается подключиться к тому же порту, что и первый прослушивающий сокет. Успешно?

В сети нет тонны информации об этом, но большинство из них согласны с тем, что на последнем этапе bind всегда будет вызывать ошибку, потому что SO_EXCLUSIVEADDRUSE предотвращает прослушивание сокета 2 и подключенного сокета, совместно использующего порт. Это важно, потому что SO_EXCLUSIVEADDRUSE обеспечивает некоторые нетривиальные преимущества безопасности, но если это нарушает повторную привязку порта, трудно решить, использовать это или нет.

текущие документы MSDN ясно, что, по крайней мере, в некоторых случаях затяжное соединение может привести к сбою второго bind, хотя они нечетко говорят о том, что именно считается "активным соединением":

И наоборот, сокет с установленным SO_EXCLUSIVEADDRUSE не обязательно может быть повторно использован сразу после закрытия сокета. Например, если прослушивающий сокет с установленным SO_EXCLUSIVEADDRUSE принимает соединение и затем закрывается, другой сокет (также с SO_EXCLUSIVEADDRUSE) не может привязаться к тому же порту, что и первый сокет, до тех пор, пока исходное соединение не станет неактивным.

libuv явно предпочитает не использовать SO_EXCLUSIVEADDRUSE - несмотря на преимущества безопасности - потому что они говорят, что это мешает TIME_WAIT обработке.

И этот microsoft.com Сообщение в блоге от 2005 года содержит некоторые дополнительные сведения, утверждая, что подключенный сокет может предотвратить SO_EXCLUSIVEADDRUSE повторное связывание по крайней мере в некоторых случаях (но не TIME_WAIT):

Хотя опция SO_EXCLUSIVEADDRUSE чрезвычайно полезна, есть важное предостережение. Если по крайней мере одно соединение, которое возникло или было принято на порте, привязанном к монопольному доступу, активно, то все привязки к этому порту завершатся ошибкой. В этом случае «соединение» определяется как сокет, который явно подключен к одноранговому узлу через connect, WSAConnect или ConnectEx с установленным эксклюзивным флагом или соединение, возвращаемое из прослушивающего сокета (например, от accept, WSAAccept или AcceptEx ), для которого установлена ​​эксклюзивная опция (на прослушивающем сокете). Активный порт для TCP определяется как в состояниях ESTABLISHED, FIN_WAIT, FIN_WAIT_2 или LAST_ACK.

Поэтому я написал небольшой скрипт, чтобы попробовать на себе:

https://gist.github.com/njsmith/8770bed5bbf2154940e8e3e7762e4ac3

и действительно, когда я запускаю его в Windows 10, я получаю:

rebind with existing listening socket: failed
    details: OSError(10048, 'Only one usage of each socket address (protocol/network address/port) is normally permitted', None, 10048, None)
rebind with live connected sockets: succeeded
rebind with TIME_WAIT socket: succeeded

Итак, мой предварительный вывод заключается в том, что MSDN и все остальные ошибаются: пока исходный прослушивающий сокет закрыт, SO_EXCLUSIVEADDRUSE действительно позволяет повторно привязать порт, с которым связаны оставшиеся подключенные сокеты, будь то состояние ESTABLISHED или TIME_WAIT или что-то еще. Этого все хотят, и это здорово. Предположительно, в 2005 году это было не так, но где-то между тем и сейчас они это исправили.

Вопросы:

  • Верна ли моя интерпретация этих результатов?
  • Есть ли еще один случай, когда мне не хватает предыдущего соединения, когда предыдущее соединение могло привести к сбою SO_EXCLUSIVEADDRUSE bind, а обычное bind - сбою? (Я ожидал, что если СОЗДАННЫЕ сокеты не вызывают проблемы, значит, ничего не происходит, но я могу что-то упустить.)
  • Самое главное: когда они внесли изменения? Например, я тестировал Windows 10, но если бы мой код по какой-то причине нуждался в ориентировании на Windows Vista, сработало бы это или нет? Или это всегда так работало, а документация всегда была неправильной?

person Nathaniel J. Smith    schedule 10.08.2017    source источник


Ответы (1)


В каких версиях Windows (если таковые имеются) SO_EXCLUSIVEADDRUSE предотвращает повторное связывание порта, имеющего затяжные соединения TIME_WAIT?

Никто.

Верна ли моя интерпретация этих результатов?

Нет. Ваши результаты показывают, что сокет ESTABLISHED не блокирует повторную привязку. Они также показывают, что сокет TIME_WAIT тоже этого не делает, но об этом уже сказано во всех ваших цитатах. Согласно процитированной вами документации, TIME_WAIT никогда не предотвращает повторное связывание порта. Только «активный порт», как определено в документации (ESTABLISHED, FIN_WAIT, FIN_WAIT_2 или LAST_ACK), должен делать это, и ваш сценарий показывает, что это не так или больше не так.

Сообщение, в котором вы утверждаете, что с ним не согласны, вообще не противоречит.

person user207421    schedule 11.08.2017
comment
Ах, хороший момент - я неправильно прочитал список состояний TCP в сообщении в блоге (который я нашел всего за несколько минут до публикации ...). MSDN, к сожалению, не определяет активное соединение, и все остальные, кажется, интерпретировали это расплывчатое предупреждение как относящееся к TIME_WAIT, так что меня охватила толпа. Я отредактирую вопрос, чтобы удалить явный аспект TIME_WAIT, чтобы он оставался значимым. - person Nathaniel J. Smith; 11.08.2017