Попытка получить внешний IP-адрес NAT с помощью INATExternalIPAddressCallback в C # - PullRequest
3 голосов
/ 28 апреля 2009

Как мне получить внешний IP-адрес NAT с помощью библиотеки Windows? Я пытаюсь найти любую информацию о INATExternalIPAddressCallback, но нашел только один пример в C ++, используя недоступные интерфейсы для C #. Любое руководство будет высоко ценится.

-Карл

Ответы [ 3 ]

2 голосов
/ 04 мая 2009

Извините, что я не отвечаю с существующим API из Windows, который использует службу UPNP, но это может помочь вам

Вы также можете использовать STUN-сервер в Интернете, есть много открытых, у каждого VOIP-провайдера есть. http://en.wikipedia.org/wiki/STUN http://tools.ietf.org/html/rfc3489

например. откройте UDP-сокет, подключитесь к stun.gmx.net через порт 3478 и отправьте пакет следующим образом:

using System;
using System.Net;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;

namespace xxx
{
class STUNPacket
{
    static RNGCryptoServiceProvider m_rand=new RNGCryptoServiceProvider();

    private byte[] m_requestid=new byte[16];

    public STUNPacket()
    {
        m_rand.GetBytes(m_requestid);
    }

    public byte[] CreateRequest()
    {
        byte[] packet=new byte[0x1c] {
            //Header:
            0x00,0x01,      //Art des STUN-Pakets: 0x0001=Binding Request
            0x00,0x08,      //Länge des Pakets ohne Header
            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,    //Transkations-ID
            //Message-Attribute:
            0x00,0x03,      //Typ: Change-Request
            0x00,0x04,      //Länge: 4 Bytes
            0x00,0x00,0x00,0x00 //Weder IP, noch Port ändern
        };

        for(int i=0;i<16;i++)
            packet[i+4]=m_requestid[i];

        return packet;
    }

    public IPEndPoint ParseResponse(byte[] paket)
    {
        if (paket.Length<20)
            throw new Exception("STUN-Response zu kurz, um einen Header zu haben");
        if (paket[0]!=1||paket[1]!=1)
            throw new Exception("STUN-Reposne hat falschen Typ, muss Binding-Response sein");
        for (int i=0;i<16;i++)
            if (paket[i+4]!=m_requestid[i])
                throw new Exception("STUN-Antwort hat falsche Transkations-ID");
        int size=paket[2]*256+paket[3];
        int pos=20;
        for(;;)
        {
            if (size<4)
                throw new Exception("Verbleibende Nachricht zu kurz für weiteren Attributheader, "+
                    "Mapped-Adress-Attribut nicht gefunden");
            int attrsize=paket[pos+2]*256+paket[pos+3];
            if (pos+4+attrsize>paket.Length)
                throw new Exception("Attributheader hat Länge, die nicht mehr ins Paket passt");
            //Wenn kein Mapped-Adress-Attribut, dann überspringen
            if (paket[pos]!=0||paket[pos+1]!=1)
            {
                pos+=attrsize;
                continue;
            }
            if (attrsize<8)
                throw new Exception("Mapped-Adress-Attribut ist zu kurz");
            if (paket[pos+5]!=1)
                throw new Exception("Adreßfamilie von Mapped-Adress ist nicht IPV4");
            int port=paket[pos+6]*256+paket[pos+7];
            IPAddress adress=new IPAddress(new byte[4] { paket[pos+8],paket[pos+9],paket[pos+10],paket[pos+11] });
            return new IPEndPoint(adress,port);
        }
    }

}

}

IP-адрес, возвращаемый ParseResponse, должен быть вашим IP-адресом так, как его видит внешний мир.

Обратите внимание, что вы не сможете получить ваш внешний ip без помощи интернет-сервера или напрямую через upnp с вашего сервера

1 голос
/ 18 мая 2009

Система за NAT не знает, что это "настоящий" IP. На самом деле, что касается ОС, она имеет IP-адрес, как и любой другой. Он просто направляется к определенному шлюзу и не должен беспокоиться о деталях. Тот факт, что настроенный IP-адрес не является широковещательным адресом (10. что бы ни было, 192.168. Что бы то ни было), не имеет значения для ОС.

ЕДИНСТВЕННЫЙ способ получить ваш внешний IP - это запросить какую-нибудь внешнюю систему. Это может быть ваш маршрутизатор UPnP (который может, в свою очередь, возвратить еще один не широковещательный адрес), или это может быть какой-то внешний сервер в Интернете (например, это «STUN»).

Если бы это был я, я бы просто разместил свой собственный сервис на моем сайте. Вы можете просто запустить простой скрипт php на большинстве PHP-сайтов:

<?php echo $REMOTE_ADDR; >

Это отбросит IP-адрес клиента. Затем вам нужно написать клиентский код, чтобы получить результаты этого сценария (довольно просто в C #).

1 голос
/ 29 апреля 2009

В CodeProject следующая статья Гарольда Аппрута описывает, что вы хотите сделать:

Обход NAT с помощью UPnP в C # без каких-либо библиотек. http://www.codeproject.com/KB/IP/upnpnattraversal.aspx

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

из MSDN - http://msdn.microsoft.com/en-us/library/aa365074(VS.85).aspx:

Интерфейс INATExternalIPAddressCallback реализован приложением NAT с технологией UPnP. Он предоставляет метод, который вызывается системой, если внешний IP-адрес компьютера NAT изменится .

Пытаетесь ли вы один раз получить внешний IP-адрес или хотите получать уведомления об его изменении. Вам не нужно реализовывать обратный вызов для INATExternalIPAddressCallback, если вы просто хотите получить текущий внешний IP-адрес

...