简体   繁体   中英

C - Get External IP Address

I need to get my public IP address through C/C++ calls. I know as an alternative I can get from external links like "http://whatismyip.akamai.com"

I wrote a sample to get external IP address. But my program is not returning external IP address. I am getting internal IP address. Am I missing anything here?

If it is not possible through this way, Can I read DNS and get IP address? OR is there any way I can get external IP address programmatically using C API (Not by reaching some website )?

#include <stdio.h>
#include <sys/types.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>

int main (int argc, const char * argv[]) {
    struct ifaddrs * ifAddrStruct=NULL;
    struct ifaddrs * ifa=NULL;
    void * tmpAddrPtr=NULL;

    getifaddrs(&ifAddrStruct);

    for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
        if (!ifa->ifa_addr) {
            continue;
        }
        if (ifa->ifa_addr->sa_family == AF_INET) {

            tmpAddrPtr=&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
            char addressBuffer[INET_ADDRSTRLEN];
            inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
        } else if (ifa->ifa_addr->sa_family == AF_INET6) {

            tmpAddrPtr=&((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
            char addressBuffer[INET6_ADDRSTRLEN];
            inet_ntop(AF_INET6, tmpAddrPtr, addressBuffer, INET6_ADDRSTRLEN);
            printf("%s IP Address %s\n", ifa->ifa_name, addressBuffer);
        }
    }
    if (ifAddrStruct!=NULL) freeifaddrs(ifAddrStruct);
    return 0;
}

NOTE: I do have external IP address, and I can get it when I run curl http://whatismyip.akamai.com

"External IP" is a property of the network; not a property of the computer that is connected to the network. Thus, there is no function that you could call to get such information from the standard library or the operating system, as the system doesn't know the information.

I wrote a sample to get external IP address.

You wrote a program that gets the IP address of network interfaces. If the interface is connected to a public network, then the IP is external. If the interface is connected to a private network, then the IP is internal.


A solution to get the external IP through a private network is to connect to an external service that can see the IP from which the requests comes from. You seem to already know of this.

A more advanced approach that doesn't require external connections is to run similar service on the router system. As pointed out in a comment, UPnP or more specifically, IGD is such service that a router might provide. There is no standard UPnP client provided by C++ standard nor POSIX.

If you're getting an internal IP address then the public IP address is probablty not a property of your computer.

Most computers are behind a router that does network address translation, so they do not have a public IP.

UPNP is one methos where routers can provice public IP addresses to NAT clients. it may be possible for you to use UPNP to get your public IP.

Some IPV6 routers give out IPV6 addresses that your computer can be reached on from the public internet.

Querying an outside source will get you the address that the request appears to come from this may be your public address (or maybe you're behind a proxy or VPN)

Which is best depends on what you want to do with it.

The code you wrote gets the IP addresses of the network interfaces on your local machine. They have nothing to do with your external IP address which if you're behind one or more layers of NAT actually resides on a router with a direct Internet connection.

The way services like the one you mentioned work is because when you make a connection to them they can see what your external IP is and can then send it back to you.

Here's a quick and dirty way to connect to the service you listed to get back the IP:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>

int main(void)
{
    struct addrinfo hints = {0}, *addrs;
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = 0;

    int rval = getaddrinfo("whatismyip.akamai.com", "80", &hints, &addrs);
    if (rval != 0) {
        fprintf(stderr,"getaddrinfo failed: %s\n", gai_strerror(rval));
        return 1;
    }

    int s = socket(addrs->ai_family, addrs->ai_socktype, addrs->ai_protocol);
    if (s == -1) {
        perror("socket failed");
        return 1;
    }
    rval = connect(s, addrs->ai_addr, addrs->ai_addrlen);
    if (rval == -1) {
        perror("connect failed");
        return 1;
    }

    char cmd[] = "GET / HTTP/1.1\nHost: whatismyip.akamai.com\n\n";
    rval = send(s, cmd, strlen(cmd), 0);
    if (rval == -1) {
        perror("send failed");
        return 1;
    }

    char buf[1000] = {0};
    rval = recv(s, buf, sizeof(buf), 0);
    if (rval == -1) {
        perror("recv failed");
        return 1;
    }
    printf("response: %s\n", buf);

    char *start = buf, *end;
    end = strchr(start, '\n');
    if (!strncmp(start, "HTTP/1.1 200 OK", end - start - 1)) {
        while (!(end[1] == '\r' && end[2] == '\n')) {
            start = end + 2;
            end = strchr(start, '\n');
        }
        start = end + 3;
        end = strchr(start, '\n');
        if (end) *end = 0;
        printf("my IP: %s\n", start);
    } else {
        printf("request failed\n");
    }

    close(s);
    freeaddrinfo(addrs);
    return 0;
}

Note that this doesn't implement a complete HTTP client and makes some assumptions about what the response looks like, but is enough to get you started.

The other option is that you can instead use int fd = popen("curl http://whatismyip.akamai.com", "r"); to run curl in a separate process and read its output via a pipe.

#include <stdlib.h>
#include <stdio.h>

int main()
{
    FILE *curl;
    if((curl = popen("curl https://icanhazip.com/", "r")) == NULL){
        eprintf("ERROR: Failed to run curl.\n");
        return 1;
    }

    char* ip = malloc(99);
    if(fgets(ip, 99, curl) != NULL){
        eprintf("ERROR: could not access icanhazip.com (do you have internet connection?)\n");
        return 1;
    }
    
    // at this point, the variable "ip" stores your public IP address
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM