On 12/09/2015 09:35, Hiroki Sato wrote:
Ken Moore <k...@pcbsd.org> wrote
in <5668369f.9020...@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.
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
Quick Followup with additional debugging:
The errors appear to explicitly involve the sockaddr[_in6] to string
conversion routine:
I looked at how ifconfig does this same thing (lines 209-214 in
af_inet6.c) and adjusted my routine to match and I still get the same
errors:
[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);
if(s<0){ return "Error creating socket"; }
int err = ioctl(s, SIOCGIFADDR, &ifr);
if(err<0){ return (QString("Error with ioctl:
")+QString::number(err)); }
struct sockaddr_in6 *in = (struct sockaddr_in6 *)(&ifr.ifr_addr);
char straddr[INET6_ADDRSTRLEN];
err = getnameinfo((struct sockaddr *)in, in->sin6_len, straddr,
sizeof(straddr),NULL, 0, NI_NUMERICHOST);
if(err){
qDebug() << "getnameinfo error:" << gai_strerror(err);
//Fall back on ntop instead
inet_ntop(AF_INET6, &in->sin6_addr, straddr, sizeof(straddr));
}
return QString(straddr);
}
[/code]
This returns:
getnameinfo error: ai_family not supported
::6a00:0:0:0
Which obviously does not match what ifconfig returns as the ipv6 address
for the device.
Any other ideas?
--
~~ Ken Moore ~~
PC-BSD/iXsystems
_______________________________________________
freebsd-net@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/freebsd-net
To unsubscribe, send any mail to "freebsd-net-unsubscr...@freebsd.org"