Pergunta

Eu preciso descobrir o externo IP do computador em que um aplicativo C# está sendo executado.

No aplicativo eu tenho uma conexão (via comunicação remota .NET) com um servidor.Existe uma boa maneira de obter o endereço do cliente no lado do servidor?

(Editei a pergunta, para ficar um pouco mais claro.Peço desculpas a todas as pessoas gentis que fizeram o possível para responder à pergunta, quando talvez eu tenha sido um pouco vago demais)

Solução:
Encontrei uma maneira que funcionou muito bem para mim.Ao implementar um IServerChannelSinkProvider e um IServerChannelSink personalizados onde tenho acesso a CommonTransportKeys.IPAddress, é fácil adicionar o IP do cliente no CallContext.

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, 
    IMessage requestmessage, ITransportHeaders requestHeaders, 
    System.IO.Stream requestStream, out IMessage responseMessage, 
    out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
{
    try
    {
        // Get the IP address and add it to the call context.
        IPAddress ipAddr = (IPAddress)requestHeaders[CommonTransportKeys.IPAddress];
        CallContext.SetData("ClientIP", ipAddr);
    }
    catch (Exception)
    {
    }

    sinkStack.Push(this, null);
    ServerProcessing srvProc = _NextSink.ProcessMessage(sinkStack, requestmessage, requestHeaders,
        requestStream, out responseMessage, out responseHeaders, out responseStream);

    return srvProc;
}

E mais tarde (quando recebo uma solicitação de um cliente) é só pegar o IP do CallContext assim.

public string GetClientIP()
{
    // Get the client IP from the call context.
    object data = CallContext.GetData("ClientIP");

    // If the data is null or not a string, then return an empty string.
    if (data == null || !(data is IPAddress))
        return string.Empty;

    // Return the data as a string.
    return ((IPAddress)data).ToString();
}

Agora posso enviar o IP de volta ao cliente.

Foi útil?

Solução 5

Encontrei uma maneira que funcionou muito bem para mim.Ao implementar um IServerChannelSinkProvider e um IServerChannelSink personalizados onde tenho acesso a CommonTransportKeys.IPAddress, é fácil adicionar o IP do cliente no CallContext.

public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, 
    IMessage requestmessage, ITransportHeaders requestHeaders, 
    System.IO.Stream requestStream, out IMessage responseMessage, 
    out ITransportHeaders responseHeaders, out System.IO.Stream responseStream)
{
    try
    {
        // Get the IP address and add it to the call context.
        IPAddress ipAddr = (IPAddress)requestHeaders[CommonTransportKeys.IPAddress];
        CallContext.SetData("ClientIP", ipAddr);
    }
    catch (Exception)
    {
    }

    sinkStack.Push(this, null);
    ServerProcessing srvProc = _NextSink.ProcessMessage(sinkStack, requestmessage, requestHeaders,
        requestStream, out responseMessage, out responseHeaders, out responseStream);

    return srvProc;
}

E mais tarde (quando recebo uma solicitação de um cliente) é só pegar o IP do CallContext assim.

public string GetClientIP()
{
    // Get the client IP from the call context.
    object data = CallContext.GetData("ClientIP");

    // If the data is null or not a string, then return an empty string.
    if (data == null || !(data is IPAddress))
        return string.Empty;

    // Return the data as a string.
    return ((IPAddress)data).ToString();
}

Agora posso enviar o IP de volta ao cliente.

Outras dicas

Esta é uma daquelas questões em que é preciso olhar mais profundamente e talvez repensar o problema original;neste caso, "Por que você precisa de um endereço IP externo?"

O problema é que o computador pode não ter um endereço IP externo.Por exemplo, meu laptop possui um endereço IP interno (192.168.x.y) atribuído pelo roteador.O próprio roteador possui um endereço IP interno, mas seu endereço IP “externo” também é interno.Ele é usado apenas para se comunicar com o modem DSL, que na verdade possui o endereço IP externo voltado para a Internet.

Então, a verdadeira pergunta se torna: "Como faço para obter o endereço IP voltado para a Internet de um dispositivo de 2 lúpulos?" E a resposta é geralmente, você não;pelo menos não sem usar um serviço como whatismyip.com que você já descartou, ou fazer um hack realmente massivo envolvendo codificar a senha do modem DSL em seu aplicativo e consultar o modem DSL e raspar a tela da página de administração (e que Deus o ajude se o modem for substituído).

EDITAR:Agora, para aplicar isso na pergunta refatória: "Como obtenho o endereço IP do meu cliente de um componente .NET do servidor?" Como Whatismyip.com, o melhor que o servidor poderá fazer é fornecer o endereço IP do seu dispositivo voltado para a Internet, o que é improvável que seja o endereço IP real do computador executando o aplicativo.Voltando ao meu laptop, se meu IP voltado para a Internet fosse 75.75.75.75 e o IP da LAN fosse 192.168.0.112, o servidor só conseguiria ver o endereço IP 75.75.75.75.Isso levará até o meu modem DSL.Se o seu servidor quisesse fazer uma conexão separada com meu laptop, primeiro eu precisaria configurar o modem DSL e quaisquer roteadores entre ele e meu laptop para reconhecer as conexões de entrada do seu servidor e roteá-las adequadamente.Existem algumas maneiras de fazer isso, mas estão fora do escopo deste tópico.

Se você está de fato tentando fazer uma conexão do servidor de volta para o cliente, repense seu design porque você está se aprofundando no território WTF (ou pelo menos, tornando seu aplicativo muito mais difícil de implantar).

Dns.GetHostEntry(Dns.GetHostName());retornará uma matriz de endereços IP.O primeiro deverá ser o IP externo, os demais serão os que estão atrás do NAT.

Então:

IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
string externalIP = IPHost.AddressList[0].ToString();

EDITAR:

Há relatos de que isso não funciona para algumas pessoas.Para mim funciona, mas talvez dependendo da configuração da sua rede, pode não funcionar.

Melhor apenas usar http://www.whatismyip.com/automation/n09230945.asp ele gera apenas o IP apenas para pesquisas automatizadas.

Se você quer algo que não dependa de outra pessoa, crie sua própria página http://www.unkwndesign.com/ip.php é apenas um script rápido:

<?php
echo 'Your Public IP is: ' . $_SERVER['REMOTE_ADDR'];
?>

A única desvantagem aqui é que ele recuperará apenas o IP externo da interface que foi usada para criar a solicitação.

A resposta de Jonathan Holland está fundamentalmente correta, mas vale a pena acrescentar que as chamadas de API por trás de Dns.GetHostByName consomem bastante tempo e é uma boa ideia armazenar em cache os resultados para que o código só precise ser chamado uma vez.

O principal problema é que o endereço IP público não está necessariamente correlacionado ao computador local que executa o aplicativo.Ele é transferido da rede interna por meio de um firewall.Obter verdadeiramente o IP público sem interrogar a rede local é fazer uma solicitação a uma página da internet e retornar o resultado.Se você não quiser usar um site do tipo WhatIsMyIP.com disponível publicamente, você pode facilmente criar um e hospedá-lo você mesmo - de preferência como um serviço da web para que você possa fazer uma chamada simples e compatível com Soap a partir de seu aplicativo.Você não necessariamente faria uma captura de tela, mas sim uma postagem dos bastidores e leria a resposta.

Se você quiser apenas o IP vinculado ao adaptador, poderá usar o WMI e a classe Win32_NetworkAdapterConfiguration.

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

A solução de Patrik funciona para mim!

Eu fiz um mudança importante.Na mensagem do processo eu configurei o CallContext usando este código:

// try to set the call context
LogicalCallContext lcc = (LogicalCallContext)requestMessage.Properties["__CallContext"];
if (lcc != null)
{
    lcc.SetData("ClientIP", ipAddr);
}

Isso coloca o endereço IP no CallContext correto, para que possa ser recuperado posteriormente comGetClientIP().

Bem, supondo que você tenha um System.Net.Sockets.TcpClient conectado ao seu cliente, você pode (no servidor) usar client.Client.RemoteEndPoint.Isto lhe dará um System.Net.EndPoint apontando para o cliente;que deve contém uma instância do System.Net.IPEndPoint subclasse, embora não tenha certeza sobre as condições para isso.Depois de transmitir isso, você pode verificar se está Address propriedade para obter o endereço do cliente.

Em suma, temos

using (System.Net.Sockets.TcpClient client = whatever) {
    System.Net.EndPoint ep = client.Client.RemoteEndPoint;
    System.Net.IPEndPoint ip = (System.Net.IPEndPoint)ep;
    DoSomethingWith(ip.Address);
}

Boa sorte.

Acredito que, teoricamente, você não conseguirá fazer isso enquanto estiver atrás de um roteador (por exemplo,usando intervalos de IP inválidos) sem usar uma "ajuda" externa.

Basicamente, você pode analisar a página retornada fazendo um WebRequest de http://whatismyipaddress.com

http://www.dreamincode.net/forums/showtopic24692.htm

A maneira mais confiável de fazer isso é verificar um site como http://checkip.dyndns.org/ ou similar, porque até que você realmente acesse sua rede, você não conseguirá encontrar seu IP externo.No entanto, codificar tal URL está solicitando uma eventual falha.Você pode querer realizar esta verificação apenas se o IP atual se parecer com um RFC1918 endereço privado (192.168.x.x sendo o mais familiar deles.

Caso contrário, você poderá implementar seu próprio serviço semelhante, externo ao firewall, para pelo menos saber se ele está quebrado.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top