Date: Wed, 9 Dec 2015 11:14:10 -0500 From: Ken Moore <ken@pcbsd.org> To: Hiroki Sato <hrs@FreeBSD.org> Cc: freebsd-net@freebsd.org Subject: Re: IPv6 Address as text (C) Message-ID: <56685352.60206@pcbsd.org> In-Reply-To: <20151209.233515.1592617248580059512.hrs@allbsd.org> References: <5668369F.9020309@pcbsd.org> <20151209.233515.1592617248580059512.hrs@allbsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On 12/09/2015 09:35, Hiroki Sato wrote: > Ken Moore <ken@pcbsd.org> wrote > in <5668369F.9020309@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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?56685352.60206>