Проверьте, находится ли IP в локальной сети (за брандмауэрами и маршрутизаторами)

Я просматривал Интернет около 5 часов и не смог найти решение своей проблемы:

Моя компания разрабатывает образовательную игру и я пишу для нее автоапдейтер с помощью Monotorrent. Игра будет использоваться в школах, но, поскольку в большинстве школ очень слабое подключение к Интернету, в сети должен быть только один компьютер, который загружается с https-сидера, а остальные должны загружаться с одного компьютера, который загружается с https-сидера.

Так что я получаю кучу IP-адресов от трекера, и мне нужно отфильтровать только те, которые находятся в локальной сети.

Конечно, школы иногда довольно строги с брандмауэрами, и между некоторыми компьютерами в школе будет множество маршрутизаторов и коммутаторов.

Я уже пробовал большинство решений, таких как

 NetworkInterface[] interfaces = NetworkInterface.GetAllNetworkInterfaces();

    foreach (NetworkInterface iface in interfaces)
    {
        IPInterfaceProperties properties = iface.GetIPProperties();

        foreach (UnicastIPAddressInformation address in properties.UnicastAddresses)
        {
            Console.WriteLine(
                "{0} (Mask: {1})",
                address.Address,
                address.IPv4Mask
                );
        }
    }

Или аналогичные методы только доставляют информацию о маршрутизаторе/коммутаторе/что-то еще.

Короче говоря, я хочу проверить, доступен ли данный IP-адрес через локальную сеть.

Я был бы очень признателен за любую помощь, потому что эта функция осталась последней :)


person Squirrel    schedule 29.08.2011    source источник
comment
все ли компьютеры, на которых установлена ​​игра, подключаются к вашему интернет-серверу?   -  person Yahia    schedule 29.08.2011
comment
Существует ограниченное количество IP-адресов, разрешенных для внутреннего использования, в частных подсетях. Разве этого недостаточно для идентификации? Очень редко можно использовать общедоступные IP-адреса, а затем закрывать их брандмауэром, потому что вы не хотите тратить IPv4-адреса впустую. IPv6 — это совсем другое дело.   -  person jishi    schedule 29.08.2011
comment
@jishi вы предполагаете, что сети в школах настроены в соответствии с рекомендациями. Хотя частные диапазоны рекомендуются, ничто не мешает вам использовать общедоступные.   -  person Jonathan Dickinson    schedule 29.08.2011
comment
@ Yahia все подключаются к одному и тому же трекеру да, но только один из них подключается к html-раздатчику, так что все остальные загружаются с этого компьютера (таким образом я экономлю пропускную способность, потому что игра загружается только одним компьютером и распределяется по локальной сети )   -  person Squirrel    schedule 30.08.2011
comment
@Jonathan Dickinson Ну, если они использовали общедоступные IP-адреса и для NAT, то у них, вероятно, есть более серьезные проблемы, чем у нескольких клиентов, которые генерируют немного большую пропускную способность ...   -  person jishi    schedule 30.08.2011
comment
@jishi определенно, но ваше приложение все равно должно стараться вести себя предсказуемо.   -  person Jonathan Dickinson    schedule 30.08.2011
comment
@Jonathan Dickinson Конечно, хорошо, если приложение может учитывать неправильные конфигурации, но я бы не назвал это необходимостью. Однако есть другие жизнеспособные и более надежные решения, я просто хотел дать простое решение, если оно может быть подвержено сбоям.   -  person jishi    schedule 30.08.2011
comment
@jishi - конечно, это будет работать в процентиле 99%, и это действительно просто (просто проверьте, равен ли первый байт 10 или 192).   -  person Jonathan Dickinson    schedule 30.08.2011
comment
ну, пока в офисе он работает отлично, к сожалению, я думаю, что смогу протестировать его только в ближайшие выходные, но я сразу же опубликую свои результаты, еще раз спасибо всем вам (особенно Джонатану Дикинсону)   -  person Squirrel    schedule 30.08.2011


Ответы (3)


Вы можете воспользоваться TTL. При TTL, равном 1, пакет не сможет попасть в Интернет:

private static bool IsLanIP(IPAddress address)
{
    var ping = new Ping();
    var rep = ping.Send(address, 100, new byte[] { 1 }, new PingOptions()
    {
        DontFragment = true,
        Ttl = 1
    });
    return rep.Status != IPStatus.TtlExpired && rep.Status != IPStatus.TimedOut && rep.Status != IPStatus.TimeExceeded;
}

Однако помните, что по какой-то причине она называется маской IPv4 — вы можете использовать ее как таковую (так что вот ваше алгоритмическое решение):

private static bool IsLanIP(IPAddress address)
{
    var interfaces = NetworkInterface.GetAllNetworkInterfaces();
    foreach (var iface in interfaces)
    {
        var properties = iface.GetIPProperties();
        foreach (var ifAddr in properties.UnicastAddresses)
        {
            if (ifAddr.IPv4Mask != null && 
                ifAddr.Address.AddressFamily == AddressFamily.InterNetwork &&
                CheckMask(ifAddr.Address, ifAddr.IPv4Mask, address))
                return true;
        }
    }
    return false;
}

private static bool CheckMask(IPAddress address, IPAddress mask, IPAddress target)
{
    if (mask == null)
        return false;

    var ba = address.GetAddressBytes();
    var bm = mask.GetAddressBytes();
    var bb = target.GetAddressBytes();

    if (ba.Length != bm.Length || bm.Length != bb.Length)
        return false;

    for (var i = 0; i < ba.Length; i++)
    {
        int m = bm[i];

        int a = ba[i] & m;
        int b = bb[i] & m;

        if (a != b)
            return false;
    }

    return true;
}
person Jonathan Dickinson    schedule 29.08.2011
comment
второе решение, кажется, работает, большое спасибо, хотя я не уверен в TTL-решении, поправьте меня, если я ошибаюсь (я действительно не уверен), но это не так, что ttl также уменьшается при прохождении через локальный коммутатор или роутер? Потому что если так, то он не попадет за локальные коммутаторы? - person Squirrel; 30.08.2011
comment
@Squirrel, насколько я знаю, уменьшается только при прохождении маршрутизатора (не коммутатора или концентратора); и в локальной сети должен быть только один маршрутизатор. Однако раствор маски с наименьшей вероятностью даст ложные результаты. - person Jonathan Dickinson; 30.08.2011
comment
Простая проверка того, находится ли IP-адрес в той же локальной сети, на самом деле не говорит о том, находитесь ли вы в локальной сети или у вас просто есть интернет-провайдер, который обслуживает вас по IP-адресам. Вы можете быть частью сети /24 или даже /22 с общедоступным IP-адресом, тогда вы не в локальной сети, а в том же провайдере. - person jishi; 30.08.2011
comment
@jishi ваш маршрутизатор будет иметь IP-адрес вашего интернет-провайдера; и я не уверен, можно ли настроить шлюз для «сквозной передачи» напрямую в Интернет - даже в этом случае ваш интернет-провайдер / NS / страна все равно не сможет выделить этот диапазон IP-адресов IANA. Таким образом, вы можете испортить его с одного конца, но не с другого. - person Jonathan Dickinson; 30.08.2011
comment
Проверил в школе, решение с маской IPv4 сработало просто отлично. еще раз большое спасибо - person Squirrel; 05.09.2011
comment
Может ли кто-нибудь предложить решение, которое будет работать, если клиент использует ip4 или ip6? - person Watson; 16.08.2012
comment
@user190084 user190084 технически это должно работать с IPv6, но я не проверял. Вы получаете какие-либо ошибки? Изменить: по крайней мере, если вы удалите обходной путь для проверки, специфичной для IPv4. - person Jonathan Dickinson; 17.08.2012

Обычно можно с уверенностью предположить, что любые IP-адреса, такие как 10.x.x.x (класс A) или 192.x.x.x (класс C), находятся внутри частной локальной сети. Классические IP-адреса

person Arun    schedule 29.08.2011
comment
Предположение - действительно плохой путь. Пользователи - идиоты, они делают все виды сумасшедших вещей. - person Jonathan Dickinson; 29.08.2011
comment
@Jonathan Как пользователь, я оскорблен. Я как разработчик согласен. - person Rotem; 13.01.2014

Одна вещь, которую вы могли бы использовать, - это попытаться общаться между клиентами с помощью многоадресной рассылки. Большинство брандмауэров и маршрутизаторов будут блокировать многоадресный трафик (и определенно интернет-провайдеры), а это означает, что вы не сможете присоединиться к многоадресной группе, если в локальной сети нет другого клиента. Простой коммутатор будет передавать трафик, коммутатор уровня 3 может блокировать его или разрешать в зависимости от конфигурации. В любом случае, если коммутатор уровня 3 заблокирует его, вы, вероятно, все равно находитесь в разных подсетях, поэтому все другие варианты также не сработают.

Одной из технологий, которая приходит на ум, является SSDP ( http://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol ), который, я думаю, вполне послужит вашей цели. Таким образом, вам действительно не нужно выяснять, находитесь ли вы в локальной сети или нет, просто найдите другой узел, который активно загружает, если вы не можете его найти, начните загружать себя.

Поскольку SSDP является стандартом, используемым в uPnP, вы, вероятно, сможете найти достойные реализации, с которыми вы могли бы работать.

person jishi    schedule 30.08.2011