How to get the external IP address in C++?

2019-06-07 14:03发布

How would I go about finding the external IP of a user in C++? I need a method that would work for any system, not just mine. Additionally, the system could be behind a router, thus NAT would come into play making it harder to retrieve the external IP.

Ideally, I'd like to do this without using any 3rd party service like whatsmyip. However, I'm not sure if this is possible. If I don't use a 3rd party service, I'd have to go through the router and if ping is disabled I'm guessing this might not be possible (I could be wrong, not too sure).

If I were to use a 3rd party service like whatsmyip, how might I go about this? Is there a web service that they expose? I've seen this link: http://automation.whatismyip.com/n09230945.asp but it doesn't seem to be working. Would it be possible to fetch the external IP by using some HTTP methods and retrieve it, or would I effectively need to scrape the page to get the IP from it?

I'm limited to using Windows API's to accomplish this (no 3rd party API's)

4条回答
姐就是有狂的资本
2楼-- · 2019-06-07 14:23

You can use a library like curl or curlpp to get the content of http://myexternalip.com/raw . Its response is only your external ip, you can read and use it.

查看更多
贪生不怕死
3楼-- · 2019-06-07 14:28

enter image description here

Here is the winsock way. It simply extracts the IP address embedded in the HTML code that the server sent.

This code uses http://api.ipify.org/ .

Below are two different codes. One for VS2012-2015 that uses strcpy_s( ) and one for Visual C++ 6.0 that uses strcpy( ) , because VS2012-2015 throws an error message prompting you to use strcpy_s( ) instead of strcpy( ).

Visual Studio 2012-2015 code.

#include "stdafx.h"
#include <string.h>
#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <locale>
#include <sstream>
using namespace std;
#pragma comment(lib,"ws2_32.lib")


string website_HTML;
locale local;
void get_Website(string url);
char lineBuffer[200][80] = { ' ' };
char buffer[10000];
char ip_address[16];
int i = 0, bufLen = 0, j = 0, lineCount = 0;
int lineIndex = 0, posIndex = 0;

//****************************************************

int main(void){
    cout << "\n\n\n";
    get_Website("api.ipify.org");
    for (size_t i = 0; i<website_HTML.length(); ++i) website_HTML[i] = tolower(website_HTML[i], local);

    istringstream ss(website_HTML);
    string stoken;

    while (getline(ss, stoken, '\n')) {

        //cout <<"-->"<< stoken.c_str() << '\n';

        strcpy_s(lineBuffer[lineIndex], stoken.c_str());
        int dot = 0;
        for (int ii = 0; ii< strlen(lineBuffer[lineIndex]); ii++){

            if (lineBuffer[lineIndex][ii] == '.') dot++;
            if (dot >= 3){
                dot = 0;
                strcpy_s(ip_address, lineBuffer[lineIndex]);
            }
        }

        lineIndex++;
    }
    cout << "Your IP Address is  " << ip_address << " \n\n";


    cout << "\nPress ANY key to close.\n\n";
    cin.ignore(); cin.get();

    return 0;
}

//****************************************************

void get_Website(string url){
    WSADATA wsaData;
    SOCKET Socket;
    SOCKADDR_IN SockAddr;
    int lineCount = 0;
    int rowCount = 0;
    struct hostent *host;
    string get_http;


    get_http = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n";

    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0){
        cout << "WSAStartup failed.\n";
        system("pause");
        //return 1;
    }

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    host = gethostbyname(url.c_str());

    SockAddr.sin_port = htons(80);
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

    if (connect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr)) != 0){
        cout << "Could not connect";
        system("pause");
        //return 1;
    }
    send(Socket, get_http.c_str(), strlen(get_http.c_str()), 0);

    int nDataLength;
    while ((nDataLength = recv(Socket, buffer, 10000, 0)) > 0){
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){

            website_HTML += buffer[i];
            i += 1;
        }
    }

    closesocket(Socket);
    WSACleanup();

}

Visual C++ 6.0 code

    #include <string.h>
    #include <winsock2.h>
    #include <windows.h>
    #include <iostream>
    #include <vector>
    #include <locale>
    #include <sstream>
    using namespace std;
    #pragma comment(lib,"ws2_32.lib")


    string website_HTML;
    locale local;
    void get_Website(string url );
    char lineBuffer[200][80] ={' '};
    char buffer[10000];
    char ip_address[16];
    int i = 0, bufLen=0, j=0,lineCount=0;
    int lineIndex=0, posIndex=0;

     //****************************************************

    int main( void ){
        cout << "\n\n\n";
        get_Website("api.ipify.org" );
        for (size_t i=0; i<website_HTML.length(); ++i) website_HTML[i]= tolower(website_HTML[i],local);

        istringstream ss(website_HTML);
        string stoken;

        while(getline(ss, stoken, '\n')) {

                  strcpy(lineBuffer[lineIndex],stoken.c_str());
                  int dot=0;
                  for (int ii=0; ii< strlen( lineBuffer[lineIndex] ); ii++ ){

                      if (lineBuffer[lineIndex][ii] == '.') dot++;
                      if (dot>=3){
                          dot=0;
                          strcpy(ip_address,lineBuffer[lineIndex]);
                      }
                  }
                  lineIndex++;
         }
        cout<<"Your IP Address is  "<< ip_address<<" \n\n"; 

       cout<<"\nPress ANY key to close.\n\n";
       cin.ignore(); cin.get(); 


     return 0;
}

 //****************************************************

void get_Website(string url ){
    WSADATA wsaData;
    SOCKET Socket;
    SOCKADDR_IN SockAddr;
    int lineCount=0;
    int rowCount=0;
    struct hostent *host;
    string get_http;


    get_http = "GET / HTTP/1.1\r\nHost: " + url + "\r\nConnection: close\r\n\r\n";

    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0){
        cout << "WSAStartup failed.\n";
        system("pause");
        //return 1;
    }

    Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    host = gethostbyname(url.c_str());

    SockAddr.sin_port=htons(80);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);

    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
        cout << "Could not connect";
        system("pause");
        //return 1;
    }
    send(Socket,get_http.c_str(), strlen(get_http.c_str()),0 );

    int nDataLength;
    while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){        
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r'){

            website_HTML+=buffer[i];
            i += 1;
        }               
    }

    closesocket(Socket);
    WSACleanup();

}
查看更多
SAY GOODBYE
4楼-- · 2019-06-07 14:36

This has nothing to do with C++ or any language in particular.
Furthermore, knowing the address of your router won't do you much good, you will know it's NAT address, not it's external address, and it is also possible your router is not the last router on the way out to the internet.
You must use an external entity - usually a webservice of some sort that will report the IP address of the router that contacted it.
Here is a sample question of someone asking how to get the client IP address in PHP.

查看更多
Root(大扎)
5楼-- · 2019-06-07 14:38

In theory, you can use the Windows uPnP API to do this. You'd start by using the UPnPDeviceFinder to enumerate Internet Gateway Devices. Then you get an IUPnPRemoteEndpointInfo for the gateway (well, there's usually only one, anyway) and invoke its GetStringValue, passing a string containing "RemoteAddress" to get its remote address (which I think means its external address, though I'll admit I'm not entirely certain). Oh, and since this is COM, that has to be a system string, not a normal string.

Getting the IP from an external provider is a lot easier. Without using any 3rd party libraries, code for it looks like this:

#include <windows.h>
#include <wininet.h>
#include <string>
#include <iostream>

std::string real_ip() { 

    HINTERNET net = InternetOpen("IP retriever",
        INTERNET_OPEN_TYPE_PRECONFIG,
        NULL,
        NULL,
        0);

    HINTERNET conn = InternetOpenUrl(net, 
                                     "http://myexternalip.com/raw", 
                                      NULL, 
                                      0, 
                                      INTERNET_FLAG_RELOAD, 
                                      0);

    char buffer[4096];
    DWORD read;

    InternetReadFile(conn, buffer, sizeof(buffer)/sizeof(buffer[0]), &read);
    InternetCloseHandle(net);    

    return std::string(buffer, read);
}

int main() {
    std::cout << real_ip() << "\n";
}

compiled with:

cl ip_addr.cpp wininet.lib

Note: if your machine is configured to use IPv6, this can (and will) retrieve your IPv6 address).

查看更多
登录 后发表回答