LinuxQuestions.org
View the Most Wanted LQ Wiki articles.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 12-22-2008, 01:40 AM   #1
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Rep: Reputation: 115Reputation: 115
IPv6 vs IPv4


I am doing some socket programming and have run across something that I can deal with, but it is annoying.

The distro is Mandriva 2008. Basically, I am trying to write some protocol agnostic code, with the goal of handling either ipv6 or ipv4, whichever comes up.

At this point, I am writing some server code that is listening on a port for a connection, and then is connecting, passing some data back and forth, then upon command shutting down. Vanilla stuff.

At this time, I am communicating with this server code via telnet across my LAN from another Mandriva machine. The networking code is based on the libunp.a code that is provided in the book Unix Network Programming Second Edition by Richard Stevens. I am using it because I have a lot of working code that is based on it.

When I set up the listener socket on the server, I do it like this:

Code:
hints.ai_flags = AI_PASSIVE;
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;

	if ( (n = getaddrinfo(host, serv, &hints, &res)) != 0)
		err_quit("tcp_listen error for %s, %s: %s",
				 host, serv, gai_strerror(n));
At a later time, the server accepts a communication from my other machine via telnet based upon this code:

Code:
	        int listenfd=0;
                socklen_t addrlen,namelen;
	        struct sockaddr *cliaddr;
		commandfd = Accept(listenfd, cliaddr, &addrlen);
where Accept is a wrapper subroutine that calls accept.

Immediately after this, I want to get the IP address of the client that has contacted me. So I do this:

Code:
	char s[INET6_ADDRSTRLEN];
	        namelen = INET6_ADDRSTRLEN;
		get_ip_str(cliaddr, &s, namelen);  
 printf("new client: connecting to %s\n", s);
where the subroutine get_ip_str() is defined as:

Code:
char *get_ip_str(const struct sockaddr *sa, char *s, size_t maxlen)
{
    switch(sa->sa_family) {
        case AF_INET:
            inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
                    s, maxlen);
            break;

        case AF_INET6:
            inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
                    s, maxlen);
            break;

        default:
            strncpy(s, "Unknown AF", maxlen);
            return NULL;
    }

    return s;
}
Now, my network is defined using IPv4 and I rather expected to have an IPv4 definition provided for me. But when I execute the program and print out the result of my network address search, this is what I get:
Quote:
new client: connecting to ::ffff:192.168.0.2
You can see that the correct IPv4 address is buried in the IPv6 field, but in fact my socket has been declared as IPv6.

This is not a huge problem; I can always parse the string, but I am wondering what this means, and why I am not getting the proper IPv4 definition when the network is configured that way.

Also, of course, this could cause me some issues actually identifying that I am really on an IPv6 network, if I make the necessary hack to assume this is an IPv4 network regardless of what the socket says.

Does anyone know what I can do to get this to behave properly?

Last edited by jiml8; 12-22-2008 at 01:41 AM.
 
Old 12-22-2008, 03:58 AM   #2
jcookeman
Member
 
Registered: Jul 2003
Location: London, UK
Distribution: FreeBSD, OpenSuse, Ubuntu, RHEL
Posts: 417

Rep: Reputation: 33
IPv4 mapped addresses.

Have a look at this beauty from Exim's host.c

Code:
uschar *
host_ntoa(int type, const void *arg, uschar *buffer, int *portptr)
	

{
uschar *yield;

/* The new world. It is annoying that we have to fish out the address from
different places in the block, depending on what kind of address it is. It
is also a pain that inet_ntop() returns a const uschar *, whereas the IPv4
function inet_ntoa() returns just uschar *, and some picky compilers insist
on warning if one assigns a const uschar * to a uschar *. Hence the casts. */

#if HAVE_IPV6
uschar addr_buffer[46];
if (type < 0)
  {
  int family = ((struct sockaddr *)arg)->sa_family;
  if (family == AF_INET6)
    {
    struct sockaddr_in6 *sk = (struct sockaddr_in6 *)arg;
    yield = (uschar *)inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
      sizeof(addr_buffer));
    if (portptr != NULL) *portptr = ntohs(sk->sin6_port);
    }
  else
    {
    struct sockaddr_in *sk = (struct sockaddr_in *)arg;
    yield = (uschar *)inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
      sizeof(addr_buffer));
    if (portptr != NULL) *portptr = ntohs(sk->sin_port);
    }
  }
else
  {
  yield = (uschar *)inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
  }

/* If the result is a mapped IPv4 address, show it in V4 format. */

if (Ustrncmp(yield, "::ffff:", 7) == 0) yield += 7;

#else  /* HAVE_IPV6 */

/* The old world */

if (type < 0)
  {
  yield = US inet_ntoa(((struct sockaddr_in *)arg)->sin_addr);
  if (portptr != NULL) *portptr = ntohs(((struct sockaddr_in *)arg)->sin_port);
  }
else
  yield = US inet_ntoa(*((struct in_addr *)arg));
#endif

/* If there is no buffer, put the string into some new store. */

if (buffer == NULL) return string_copy(yield);

/* Callers of this function with a non-NULL buffer must ensure that it is
large enough to hold an IPv6 address, namely, at least 46 bytes. That's what
makes this use of strcpy() OK. */

Ustrcpy(buffer, yield);
return buffer;
}
 
Old 12-22-2008, 11:53 AM   #3
jiml8
Senior Member
 
Registered: Sep 2003
Posts: 3,171

Original Poster
Rep: Reputation: 115Reputation: 115
Quote:
IPv4 mapped addresses.
Well, that makes sense, though it is a royal PITA. It should be a lot easier to get the address from a socket.
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
ipv6 and ipv4 Ammad Linux - Networking 1 12-02-2006 04:44 PM
ipv4 to ipv6 anant_wsu Linux - Networking 1 01-03-2006 05:28 PM
block ipv4 and not ipv6 linuxtesting2 Linux - Networking 0 04-29-2004 01:16 PM
IPv6 to IPv4 thomjakub *BSD 1 03-06-2004 02:17 AM
ipv4 vs. ipv6 radix Linux - Security 2 09-17-2003 02:39 PM


All times are GMT -5. The time now is 11:15 PM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration