问题
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