Get external IP address over remoting in C#

Muszę sprawdzić zewnętrzny adres IP komputera, na którym działa aplikacja C#.

W aplikacji mam połączenie (przez. Net remoting) z serwerem. Czy jest dobry sposób na uzyskanie adresu klienta po stronie serwera?

(zredagowałem pytanie, żeby było bardziej jasne. Przepraszam wszystkich miłych ludzi, którzy starali się odpowiedzieć na pytanie, Kiedy być może byłem trochę zbyt niejasny)

Rozwiązanie:
I znalazłem sposób, który zadziałał dla mnie. Implementując własne IServerChannelSinkProvider i IServerChannelSink, gdzie mam dostęp do CommonTransportKeys.IPAddress, łatwo jest dodać IP klienta na 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;
}

A później (kiedy dostaję żądanie od klienta) po prostu pobierz IP z CallContext w ten sposób.

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

Mogę teraz wysłać IP z powrotem do klienta.

Author: Patrik Svensson, 2008-09-16

12 answers

Jest to jedno z tych pytań, gdzie trzeba spojrzeć głębiej i może przemyśleć oryginalny problem; w tym przypadku, " Dlaczego potrzebujesz zewnętrznego adresu IP?"

Problem polega na tym, że komputer może nie mieć zewnętrznego adresu IP. Na przykład mój laptop ma wewnętrzny adres IP (192.168.X. y) przypisane przez router. Sam router ma wewnętrzny adres IP, ale jego "zewnętrzny" adres IP jest również wewnętrzny. Służy tylko do komunikacji z modemem DSL, który w rzeczywistości ma zewnętrzny adres IP skierowany do Internetu.

Więc prawdziwe pytanie staje się: "jak uzyskać adres IP w Internecie urządzenia 2 hops away?"I odpowiedź jest ogólnie, nie masz; przynajmniej nie bez korzystania z usługi, takiej jak whatismyip.com że już odrzucone, lub robi naprawdę ogromny hack obejmujące hardcoding hasło modemu DSL do aplikacji i zapytaniem modemu DSL i scraping ekranu strony administratora (i Boże dopomóż, jeśli modem jest kiedykolwiek zastąpiony).

EDIT: teraz zastosuj to do refakturowanego pytania " Jak uzyskać adres IP mojego klienta z komponentu serwera. NET?"Jak whatismyip.com, najlepsze, co serwer będzie w stanie zrobić, to podać adres IP urządzenia skierowanego do Internetu, który jest mało prawdopodobne, aby był faktycznym adresem IP komputera z uruchomioną aplikacją. Wracając do mojego laptopa, gdyby moje IP internetowe było 75.75.75.75, A IP LAN było 192.168.0.112, serwer byłby w stanie zobaczyć tylko 75.75.75.75 adres IP. To dotrze do mojego modemu DSL. Jeśli serwer chciał zrobić oddzielne połączenie z powrotem do mojego laptopa, chciałbym najpierw skonfigurować modem DSL i wszelkie routery inbetween to i mój laptop do rozpoznawania połączeń przychodzących z serwera i trasy je odpowiednio. Jest kilka sposobów, aby to zrobić, ale jest to poza zakresem tego tematu.

Jeśli rzeczywiście próbujesz nawiązać połączenie z serwera z powrotem do klienta, przemyśl swój projekt ponieważ zagłębiasz się w Terytorium WTF (a przynajmniej utrudniasz wdrożenie aplikacji).

 19
Author: Nathan Strong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-16 19:18:13

Dns.GetHostEntry(Dns.GetHostName()); zwróci tablicę adresów IP. Pierwszym z nich powinien być zewnętrzny adres IP, reszta to te za NAT.

Więc:

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

EDIT:

Istnieją doniesienia, że to nie działa dla niektórych ludzi. Dla mnie tak, ale być może w zależności od konfiguracji sieci może nie działać.

 6
Author: FlySwat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:14:50

Lepiej po prostu użyć http://www.whatismyip.com/automation/n09230945.asp wysyła adres IP tylko dla automatycznego wyszukiwania.

Jeśli chcesz coś, co nie polega na kimś innym umieść własną stronę http://www.unkwndesign.com/ip.php to tylko szybki skrypt:

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

Jedynym minusem jest to, że pobierze tylko zewnętrzny adres IP interfejsu, który został użyty do utworzenia żądania.

 5
Author: UnkwnTech,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:15:40

Odpowiedź Jonathana Hollanda jest zasadniczo poprawna, ale warto dodać, że wywołania API za Dns.GetHostByName są dość czasochłonne i to jest dobry pomysł, aby buforować wyniki tak, że kod musi być wywołany tylko raz.

 4
Author: Yes - that Jake.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:13:42

Znalazłem sposób, który działał świetnie dla mnie. Implementując własne IServerChannelSinkProvider i IServerChannelSink, gdzie mam dostęp do CommonTransportKeys.IPAddress, łatwo jest dodać IP klienta na 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;
}

A później (kiedy dostaję żądanie od klienta) po prostu pobierz IP z CallContext w ten sposób.

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

Mogę teraz wysłać IP z powrotem do klienta.

 4
Author: Patrik Svensson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-08-23 20:53:17

Głównym problemem jest to, że publiczny adres IP niekoniecznie jest skorelowany z lokalnym komputerem, na którym działa aplikacja. Jest on tłumaczony z sieci wewnętrznej przez firewall. Aby naprawdę uzyskać publiczny adres IP bez przesłuchiwania sieci lokalnej, należy złożyć wniosek na stronę internetową i zwrócić wynik. Jeśli nie chcesz korzystać z publicznie dostępnego WhatIsMyIP.com wpisz stronę, którą możesz łatwo utworzyć i samodzielnie hostować - najlepiej jako serwis internetowy, dzięki czemu możesz zrobić prosty połączenie zgodne z soap z poziomu aplikacji. Niekoniecznie zrobiłbyś zrzut ekranu tak samo jak post zza kulis i przeczytał odpowiedź.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:22:44

Jeśli chcesz tylko adres IP przypisany do adaptera, możesz użyć WMI i klasy Win32_NetworkAdapterConfiguration.

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

 2
Author: TimK,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:10:31

Rozwiązanie Patrika działa dla mnie!

Dokonałem jednej ważnej zmiany. W wiadomości proces ustawiam CallContext używając tego kodu:

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

To umieszcza adres ip w prawidłowym CallContext, dzięki czemu można go później pobrać za pomocą GetClientIP().

 2
Author: Justin Tanner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-29 20:59:14

Cóż, zakładając, że masz System.Net.Sockets.TcpClient podłączony do swojego klienta, możesz (na serwerze) użyć client.Client.RemoteEndPoint. To da ci System.Net.EndPoint wskazanie na klienta, który powinien zawierać instancję podklasy System.Net.IPEndPoint, chociaż nie jestem pewien warunków do tego. Po castingu do tego możesz sprawdzić, czy jest to właściwość Address, aby uzyskać adres klienta.

W skrócie, mamy

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);
}
Powodzenia.
 1
Author: configurator,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 22:34:57

Uważam, że teoretycznie nie jesteś w stanie zrobić czegoś takiego będąc za routerem (np. używając nieprawidłowych zakresów ip) bez korzystania z zewnętrznej "pomocy".

 0
Author: Eduardo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:18:23

Możesz w zasadzie przeanalizować zwróconą stronę, wykonując WebRequest http://whatismyipaddress.com

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

 -2
Author: Matt Michielsen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:24:15

Najbardziej wiarygodnym sposobem jest sprawdzenie strony takiej jak http://checkip.dyndns.org / lub podobne, ponieważ dopóki nie wejdziesz na zewnątrz swojej sieci, nie znajdziesz swojego zewnętrznego IP. Jednak twarde kodowanie takiego adresu URL prosi o ewentualną awarię. Możesz chcieć wykonać tę kontrolę tylko wtedy, gdy bieżący adres IP wygląda jak prywatny adres RFC1918 (192.168.x.x jest najbardziej znanym z nich.

Jeśli tego nie zrobisz, możesz wdrożyć własną, podobną usługę zewnętrzny do Firewalla, więc przynajmniej będziesz wiedział, czy jest zepsuty.

 -3
Author: Alex M,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 20:13:28