10

I am using getifaddrs() and inet_ntop() to get the ip addresses on the system. When the system is set to IPv6 the address returned is in the shortened version (using :: for zeros). Is there any way to expand that address to a full one?

This is the code I am using:

struct ifaddrs *myaddrs, *ifa;
void *in_addr;
char buf[64];

if(getifaddrs(&myaddrs) != 0)
{
    perror("getifaddrs");
    exit(1);
}

for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next)
{
    if (ifa->ifa_addr == NULL)
        continue;
    if (!(ifa->ifa_flags & IFF_UP))
        continue;

    switch (ifa->ifa_addr->sa_family)
    {
        case AF_INET:
        {
            struct sockaddr_in *s4 = (struct sockaddr_in *)ifa->ifa_addr;
            in_addr = &s4->sin_addr;
            break;
        }

        case AF_INET6:
        {
            struct sockaddr_in6 *s6 = (struct sockaddr_in6 *)ifa->ifa_addr;
            in_addr = &s6->sin6_addr;
            break;
        }

        default:
            continue;
    }

    if (!inet_ntop(ifa->ifa_addr->sa_family, in_addr, buf, sizeof(buf)))
    {
        printf("%s: inet_ntop failed!\n", ifa->ifa_name);
    }
    else
    {
        printf("IP address: %s\n", buf);
    }
}

freeifaddrs(myaddrs);

Code is greatly appreciated.

EDIT:
Since this is apparently very hard to comprehend I will give you an example:

If I get abcd:12::3 I need to expand it to abcd:0012:0000:0000:0000:0000:0000:0003
The reason? because it's part of the requirements. Simple as that.

Jessica
  • 2,005
  • 4
  • 28
  • 44
  • 1
    the shortened version is a valid ipv6 adress - so why would you want to expand it? – Femaref Sep 16 '10 at 14:04
  • because I need to store it in full in our database. that is the requirement. – Jessica Sep 16 '10 at 14:05
  • 1
    @Jessica: You are storing it as a 128-bit integer, correct? Because storing it as a textual representation is slightly pointless - there are IPv6 addresses that can be represented in many ways, precisely because of the `::` shortened syntax. – Piskvor left the building Sep 16 '10 at 14:10
  • @Piskvor thank you for the explanation. However, I am still in need to expand the address. regardless how I store it and what I do with it. – Jessica Sep 16 '10 at 14:11
  • @Jessica: (I think that the way you store it does matter - two BIGINTs vs a CHAR, but anyway) Could you convert it to the integer and then bit-shift it out, and convert to hex? That way, you should get the unabridged version. Also, check this out: http://stackoverflow.com/q/1120371/19746 – Piskvor left the building Sep 16 '10 at 14:17
  • 3
    Ok, i'll make it easier for you. I need to store it in a string. char*, char[] or whatever. I just need to store the address. that's all, what's so hard to understand? I asked a very specific question. I don't care about SQL databases. – Jessica Sep 16 '10 at 14:18
  • @Jessica: Easier for *me*?!? The linked question has a function to do this, you just need to port it into `c`. – Piskvor left the building Sep 16 '10 at 14:20
  • What I meant, it's I'll make it easier for you to understand since I don't know whether you understood the question. I'll make it even easier (and I'll edit the question title as well so everyone understand) I need to print to stdout the IPv6 fully expanded. thank you. – Jessica Sep 16 '10 at 14:23
  • @Jessica: Oh, ok, now I get it :) You did mention storing it in the database, that's probably what confused me. Anyway, I meant this answer - it doesn't have anything to do with a database, and the functions mentioned there seem to be exactly what you're asking for: http://stackoverflow.com/questions/1120371/how-to-convert-ipv6-from-binary-for-storage-in-mysql/1271123#1271123 – Piskvor left the building Sep 16 '10 at 14:25
  • thank you. I looked at the code and i really don't understand what it is doing. what function is doing what? Beside python is a no go for me. thanks anyway. – Jessica Sep 16 '10 at 14:27
  • 3
    Your requirments are wrong. See RFC 5952 "A Recommendation for IPv6 Address Text Representation" – bortzmeyer Sep 18 '10 at 17:04
  • 1
    @bortzmeyer: No. Recommendations which do not meet requirements are wrong. If sort order (database!) is important, RFC 5952 is a complete mess. – Tino Jan 05 '13 at 15:02
  • If you sort IP addresses in a database, you don't compare them as text. – bortzmeyer Jan 07 '13 at 21:15
  • I need to query a DNS blacklist, and it requires expanding the IPv6 address. Thanks for the question, Jessica! – sep332 Dec 02 '13 at 20:41

3 Answers3

12
void ipv6_to_str_unexpanded(char *str, const struct in6_addr *addr) {
   sprintf(str, "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
                 (int)addr->s6_addr[0], (int)addr->s6_addr[1],
                 (int)addr->s6_addr[2], (int)addr->s6_addr[3],
                 (int)addr->s6_addr[4], (int)addr->s6_addr[5],
                 (int)addr->s6_addr[6], (int)addr->s6_addr[7],
                 (int)addr->s6_addr[8], (int)addr->s6_addr[9],
                 (int)addr->s6_addr[10], (int)addr->s6_addr[11],
                 (int)addr->s6_addr[12], (int)addr->s6_addr[13],
                 (int)addr->s6_addr[14], (int)addr->s6_addr[15]);
}
pevik
  • 4,523
  • 3
  • 33
  • 44
nategoose
  • 12,054
  • 27
  • 42
0
            #include<stdio.h>
            #include <netinet/in.h>
            #include <arpa/inet.h>

            struct in6_addrr
            {
                unsigned char addr[16];
            };

            void ipv6_expander(const struct in6_addr * addr)
            {
                char str[40];
                sprintf(str,"%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x",
                (int)addr->s6_addr[0], (int)addr->s6_addr[1],
                (int)addr->s6_addr[2], (int)addr->s6_addr[3],
                (int)addr->s6_addr[4], (int)addr->s6_addr[5],
                (int)addr->s6_addr[6], (int)addr->s6_addr[7],
                (int)addr->s6_addr[8], (int)addr->s6_addr[9],
                (int)addr->s6_addr[10], (int)addr->s6_addr[11],
                (int)addr->s6_addr[12], (int)addr->s6_addr[13],
                (int)addr->s6_addr[14], (int)addr->s6_addr[15]);
                 printf("\nExpanded ipv6 Addr %s\n",str);
            }

            int main(int argc,char *argv[])
            {
                struct in6_addrr ipv6;
                printf("\nGiven IPv6 Addr %s\n",argv[1]);
                if(inet_pton(AF_INET6,argv[1],&ipv6.addr))
                {
                    ipv6_expander(&ipv6.addr);
                }
                else
                {
                    printf("\n error\n");
                }
                return;
            }
Arun Raj
  • 85
  • 1
  • 7
0

You can use inet_ntop:

Convert IPv4 and IPv6 addresses from binary to text form

Example from https://man7.org/linux/man-pages/man3/inet_pton.3.html:

    #include <arpa/inet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    int main(int argc, char *argv[])
    {
        unsigned char buf[sizeof(struct in6_addr)];
        int domain, s;
        char str[INET6_ADDRSTRLEN];

        if (argc != 3) {
            fprintf(stderr, "Usage: %s {i4|i6|<num>} string\n", argv[0]);
            exit(EXIT_FAILURE);
        }

        domain = (strcmp(argv[1], "i4") == 0) ? AF_INET :
                 (strcmp(argv[1], "i6") == 0) ? AF_INET6 : atoi(argv[1]);

        s = inet_pton(domain, argv[2], buf);
        if (s <= 0) {
            if (s == 0)
                fprintf(stderr, "Not in presentation format");
            else
                perror("inet_pton");
            exit(EXIT_FAILURE);
        }

        if (inet_ntop(domain, buf, str, INET6_ADDRSTRLEN) == NULL) {
            perror("inet_ntop");
            exit(EXIT_FAILURE);
        }

        printf("%s\n", str);

        exit(EXIT_SUCCESS);
    }
parsley72
  • 8,449
  • 8
  • 65
  • 98