Trying to get NAT's external IPAddress with INATExternalIPAddressCallback in C#

久未见 提交于 2019-12-06 07:55:29

问题


How do I get the external IP Address of a NAT using the windows library? I am trying to find any information on INATExternalIPAddressCallback, but have only found one example in C++ using unavailable interfaces to C#. Any guidance would be much appreciated.

-Karl


回答1:


Sorry, that I don't answer with an existing API from Windows that uses the UPNP service, but it migh help you

You could also use a STUN-server on the internet, there are many open ones, every VOIP provider has one. http://en.wikipedia.org/wiki/STUN http://tools.ietf.org/html/rfc3489

e.g. open an UDP-socket, connect to stun.gmx.net on port 3478 and send a paket like this:

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);
        }
    }

}

}

The IP-address returned by ParseResponse should be your ip adress like the outside world sees it.

Note that will not be able to get your external ip without either the help of an internet server or directly via upnp from your server




回答2:


On CodeProject the following article by harold aptroot describes what you want to do:

NAT traversal with UPnP in C#, without any libraries. http://www.codeproject.com/KB/IP/upnpnattraversal.aspx

Off course this only works if your router supports UPnP.

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

The INATExternalIPAddressCallback interface is implemented by the NAT application with UPnP technology. It provides a method that the system calls if the external IP address of the NAT computer changes.

Are you trying to get the external IP address once or do you want to be notified if it changes. You do not need to implement the callback for INATExternalIPAddressCallback if you just want to get the current external IP address




回答3:


The system behind the NAT does not know it's "real" IP. In fact, as far as the OS is concerned, it has an IP like any other. It simply routes out to the defined gateway and doesn't have to worry about the details. The fact that the IP configured isn't a broadcast address (10.whatever, 192.168.whatever) does not matter to the OS.

The ONLY way of getting your external IP is to query some external system. It might be your UPnP router (which could, in thoery, return yet another non-broadcast address) or it might be some external server on the internet (this "STUN" thing, for example).

If it were me, I'd just host my own service on my website. You can just throw up a simple php script on most any PHP-capable website:

<?php echo $REMOTE_ADDR; >

This will kick back the IP address of the client. Next you've got to write the client code to grab the results of that script (fairly easy in C#).



来源:https://stackoverflow.com/questions/799557/trying-to-get-nats-external-ipaddress-with-inatexternalipaddresscallback-in-c-s

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!