如何使用Windows库获取NAT的外部IP地址?我试图在INATExternalIPAddressCallback上找到任何信息,但只在C ++中找到一个使用C#的不可用接口的例子。任何指导都将非常感谢。
-Karl
答案 0 :(得分:2)
很抱歉,我不回答Windows中使用UPNP服务的现有API,但它很有帮助
您也可以在互联网上使用STUN服务器,有许多开放服务器,每个VOIP提供商都有一个。 http://en.wikipedia.org/wiki/STUN http://tools.ietf.org/html/rfc3489
e.g。打开一个UDP套接字,在端口3478上连接到stun.gmx.net并发送一个像这样的paket:
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);
}
}
}
}
ParseResponse返回的IP地址应该是外界看到的IP地址。
请注意,如果没有互联网服务器的帮助或直接通过服务器upnp,将无法获取外部IP
答案 1 :(得分:1)
在CodeProject上,harold aptroot的以下文章描述了你想要做的事情:
在C#中使用UPnP进行NAT遍历,没有任何库。 http://www.codeproject.com/KB/IP/upnpnattraversal.aspx
当然,这只适用于路由器支持UPnP的情况。
来自MSDN的- http://msdn.microsoft.com/en-us/library/aa365074(VS.85).aspx:
INATExternalIPAddressCallback接口由NAT应用程序使用UPnP技术实现。它提供了一种方法,如果NAT计算机的外部IP地址更改,系统将调用该方法。
您是尝试获取外部IP地址一次还是希望在更改时收到通知?如果您只想获取当前的外部IP地址,则无需为INATExternalIPAddressCallback实现回调
答案 2 :(得分:1)
NAT背后的系统并不知道它是“真正的”IP。实际上,就操作系统而言,它具有与任何其他IP一样的IP。它只是路由到定义的网关,而不必担心细节。配置的IP不是广播地址(10.whatever,192.168.whatever)这一事实对操作系统无关紧要。
获取外部IP的唯一方法是查询某些外部系统。它可能是你的UPnP路由器(它可以在理论上返回另一个非广播地址),或者它可能是互联网上的一些外部服务器(例如,这是“STUN”的东西)。
如果是我,我只是在我的网站上托管自己的服务。你可以在任何支持PHP的网站上抛出一个简单的PHP脚本:
<?php echo $REMOTE_ADDR; >
这将重新启动客户端的IP地址。接下来,您必须编写客户端代码以获取该脚本的结果(在C#中相当容易)。