Запретные методы определения интернет-соединения на конкретном интерфейсе - остались? (дотнет)

Обсуждалось ранее:
проверить, доступно ли подключение к Интернету. с C#
Как определить, интерфейс подключен к Интернету (т. е. компьютер находится в сети)
Как лучше всего проверить подключение к Интернету с помощью .NET?
Тестирование для интернета подключение через определенный сетевой адаптер

Задача: Просканировать сетевые интерфейсы на компьютере и на лету проверить доступность интернета. Оказалось раздражающим.

Сначала пройдемся по интерфейсам, используя приведенный ниже псевдокод (переведенный с языка APL). Естественно было бы удобно тестировать подключение к интернету внутри петли, благо интерфейс и так удобен.

pingpong = #.Net.NetworkInformation.Ping.New // An instance of the Ping class

:For i :In #.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces
    (Change the current namespace to i -> everything hereafter happens for "i")

    :If NetworkInterfaceType.(⎕THIS = Ethernet) 
    :OrIf NetworkInterfaceType.(⎕THIS = Wireless80211) // Skip others, like Loopback, AsymmetricDsl, Atm etc

        (Get stuff like GetIPProperties.UnicastAddresses, GetIPProperties.GatewayAddresses, blabla)

        // Check the "OperationalStatus" property (not ok for internet detection)
        dumb = OperationalStatus.(⎕THIS = Up) 
        // Do a blocking call on pingpong to Google's 8.8.8.8 (not ok for internet detection)
        dumb = pingpong.Send (#.Net.IPAddress.New Convert.ToInt64 256⊥⌽8 8 8 8) 1000 (#.Text.Encoding.ASCII.GetBytes 32⍴' ') (#.NetworkInformation.PingOptions.New 128 1) // Ttl, DontFragment

    :End
:End

Проблематика выше:

  • Перечисление OperationalStatus
    Показывает только то, что интерфейс готов, но не то, что он имеет функциональное соединение.

  • pingpong.Send blabla — класс Ping dotnet
    Было бы идеально, но не отправляет через нужный интерфейс "i". Вместо этого Windows использует интерфейс по умолчанию. Таким образом, это не скажет нам, есть ли у интерфейса «i» подключение к Интернету.

Что тогда?

  • System.Runtime.InteropServices.DllImport("Wininet.dll") Справочник по WinINet
    Предоставляет некоторые функции, которых нет в .net, но... Это просто не тот путь, которым нужно идти в 2016 году, имхо.

  • Эхо-запрос ICMP — Учебное пособие по простому Ping
    Закодирован необходимый ICMP пакетная передача. Это должно происходить через необработанный сокет. Проблема: Необработанные сокеты требуют повышенного контроля учетных записей, что неприемлемо. Мы не можем заставить клиентов запускать наше приложение от имени администратора :-).
    Дополнительная проблема: ограничение прыжков. Я хотел использовать значение TTL, равное 4, этого было бы достаточно, чтобы пакет покинул локальную среду. TTL=4 попадает в инфраструктуру интернет-провайдера, где достигает 0 и становится бумерангом. Но поведение, подобное NAT, на различных устройствах и брандмауэрах принимает пакеты только от цели. Т.е. если мы пропингуем 8.8.8.8 с TTL=4, мы получим ответ с промежуточного IP-адреса, который блокируется брандмауэром, так как это не 8.8.8.8. ICMP-запрос работает отлично, если TTL высокий, а ответ приходит от Google, в противном случае мой код имеет тайм-аут. Это не имеет значения, так как UAC с повышенными правами делает это невозможным.

  • UDP ping
    UDP ping работает, отправляя пакет UDP на (надеюсь, неиспользуемый) порт на удаленной конечной точке и желая получить недоступное место назначения ICMP (что говорит нам о том, что кто-то - > у нас есть интернет). Проблема в том, что конечная точка может быть совершенно неинформативной, если мы попадем на используемый порт (и помните, что это должна быть универсальная утилита ping, проверяющая общедоступный, еще не выбранный/ повторно выбранная цель). Мы не можем знать заранее, как ведут себя порты.

  • TCP SYN — пример
    TCP ping работает сделав первые шаги в инициировании TCP-соединения. Один просто подключается к IP-адресу (и порту!), и должен увидеть передачу, например:

    → SYN
    ← SYN,ACK
    → ACK
    → FIN,ACK
    ← FIN,ACK
    → ACK
    , после чего соединение разрывается. Тайм-аут означает, что там никого нет. Я просто нахожу это несколько сомнительным. Если я попытаюсь TCP-подключиться к порту 80 на удаленной конечной точке, как я могу предположить, что он отвечает? Откуда мы знаем, что так будет через 1 год? Просто кажется слабым способом определить интернет-соединение, выполнив целевое соединение TCP. Удаленные конечные точки не корректно принимают TCP-соединения, вместо этого они, как правило, сосредотачиваются на блокировке.

  • Командная строка ping.exe
    Позволяет указать локальный интерфейс с параметром -S. Можно добавить > tempfile.txt к команде, выполнить ее из кода, прочитать и проанализировать tempfile.txt, а затем молча удалить его. Ууууу... это действительно лучший вариант? :-) В основном он делает то, что мы хотим: не требует повышенных прав UAC, позволяет нам установить интерфейс (т.е. локальный IP-адрес), позволяет нам установить ограниченный TTL и даже волшебным образом обходит брандмауэр (как...? ).

Я был бы признателен услышать о лучших идеях для определения подключения к Интернету? Я знаю о запросах Http и поиске Dns - было бы неплохо, если бы было что-то более умное.


person Stormwind    schedule 18.07.2016    source источник