IPv6 Address as text (C)

Mark Atkinson atkin901 at gmail.com
Wed Dec 9 16:31:48 UTC 2015


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 12/9/15 7:25 AM, Ken Moore wrote:
> On 12/09/2015 09:35, Hiroki Sato wrote:
>> Ken Moore <ken at pcbsd.org> wrote in <5668369F.9020309 at pcbsd.org>:
>> 
>> ke> Note: Please CC me on replies - I am not subscribed to this
>> list. ke> ke> I am having a bit of trouble getting an accurate
>> string representation ke> of the current IPv6 address for a given
>> device using the C system ke> libraries and was wondering of
>> somebody with more experience than me ke> might be able to spot
>> the error... ke> ke> Background: ke> I have been working on a
>> couple simple C/C++/Qt functions to return ke> printable forms of
>> the current ipv4 and ipv6 addresses assigned to a ke> particular
>> device, and while the ipv4 function works fine the ipv6 ke>
>> address is consistently wrong and almost always the same string
>> - ke> making me think it is converting some internal error code
>> to a string ke> ("::XXe2:ffff:ff7f:0" where the "X"s are the only
>> two characters which ke> ever change). ke> ke> The two functions
>> are nearly identical, and I think the error probably ke> comes
>> from needing to use inet_ntop() for the ipv6 address because ke>
>> there is no ipv6-compatible version of the inet_ntoa() function. 
>> ke> Do you have any thoughts or ideas about where the error might
>> be ke> coming from or a better way to read off the ipv6 address
>> as a string? ke> ke> Here are the two functions: ke> Note: "name"
>> is the QString of the device name (wlan0, re0, other...), ke> and
>> is an internal variable for the overall "NetDevice" class ke>
>> [code] ke> //Fetch the IPv4 address and return it as a QString 
>> ke> QString NetDevice::ipAsString(){ ke>    struct ifreq ifr; ke>
>> memset(&ifr, 0, sizeof(struct ifreq)); ke> ke>
>> strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); ke>    int s
>> = socket(PF_INET, SOCK_DGRAM, 0); ke> ke>    ioctl(s,
>> SIOCGIFADDR, &ifr); ke>    struct in_addr in = ((sockaddr_in *)
>> &ifr.ifr_addr)->sin_addr; ke> ke>    return QString(
>> inet_ntoa(in) ); ke> } ke> ke> //Fetch the IPv6 address and
>> return it as a QString ke> QString NetDevice::ipv6AsString(){ ke>
>> struct ifreq ifr; ke>    memset(&ifr, 0, sizeof(struct ifreq)); 
>> ke> ke>    strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); 
>> ke>    int s = socket(PF_INET6, SOCK_DGRAM, 0); ke> ke>
>> ioctl(s, SIOCGIFADDR, &ifr);
>> 
>> Should this be SIOCGIFADDR_IN6 here?  You should check the error 
>> code.
> There does not appear to be any *_IN6 definitions in any of the 
> /usr/include/[sys, net, netinet]/* include files (sys/sockio.h
> appears to hold the defines needed - nothing ipv6 related though).
> 
>> Anyway, you should use getnameinfo() for IPv4 and IPv6 instead
>> of inet_ntop() and inet_ntoa() for this purpose.  It is an
>> address family independent API which accepts struct sockaddr
>> directly like this:
>> 
>> ---- struct sockaddr *sa; /* input */ char hbuf[NI_MAXHOST]; int
>> error;
>> 
>> error = getnameinfo(sa, sa->sa_len, hbuf, sizeof(hbuf), NULL, 0,
>> NI_NUMERICHOST); if (error) { errx(1, "getnameinfo: %s",
>> gai_strerror(error)); /* NOTREACHED */ } printf("host=%s\n",
>> hbuf); ----
>> 
>> See getnameinfo(3) for more details.
>> 
>> -- Hiroki
> 
> So I adjusted the function to use getnameinfo() as you recommended:
> and the reported error is "ai_family not supported".
> 
> [code] QString NetDevice::ipv6AsString(){ struct ifreq ifr; 
> memset(&ifr, 0, sizeof(struct ifreq));
> 
> strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ); int s =
> socket(PF_INET6, SOCK_DGRAM, 0);
> 
> ioctl(s, SIOCGIFADDR, &ifr); sockaddr *in = (&ifr.ifr_addr); char
> straddr[INET6_ADDRSTRLEN];
> 
> int err = getnameinfo(in, in->sa_len, straddr, 
> sizeof(straddr),NULL, 0, NI_NUMERICHOST); if(err){ return
> QString(gai_strerror(err)); } else{ return QString(straddr); } } 
> [/code]
> 
> 

ioctl() is probably not returning what you expect (and you're not
checking for error).   You should probably be using getifaddrs(3).
Interfaces can contain lots of addresses and ipv6 enabled interfaces
will always contain a link-local at least.

You may need to determine the scope of the address as well and if you
only want globally routeable addresses, use that.




-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2

iEYEARECAAYFAlZoV2MACgkQrDN5kXnx8yazdgCgmaZEIa/zhTZ6+R7il3a7DPUO
VY4AnR5lUlK8jbMSofduLYAK7G27aox7
=GtN9
-----END PGP SIGNATURE-----



More information about the freebsd-net mailing list