add ipv6 developer doc
authorDenis Vlasenko <vda.linux@googlemail.com>
Thu, 26 Oct 2006 17:21:13 +0000 (17:21 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Thu, 26 Oct 2006 17:21:13 +0000 (17:21 -0000)
docs/ipv4_ipv6.txt [new file with mode: 0644]

diff --git a/docs/ipv4_ipv6.txt b/docs/ipv4_ipv6.txt
new file mode 100644 (file)
index 0000000..5a63aa7
--- /dev/null
@@ -0,0 +1,222 @@
+We need better network address conv helpers.
+This is what our applets want:
+
+          sockaddr -> hostname
+udhcp:    hostname -> ipv4 addr
+nslookup: hostname -> list of names - done
+tftp:     host,port -> sockaddr
+nc:       host,port -> sockaddr
+inetd: ?
+traceroute: ?, hostname -> ipv4 addr
+arping    hostname -> ipv4 addr
+ping6     hostname -> ipv6 addr
+ifconfig  hostname -> ipv4 addr (FIXME error check?)
+ipcalc    ipv4 addr -> hostname
+syslogd   hostname -> sockaddr
+inet_common.c: buggy. hostname -> ipv4 addr
+mount     hostname -> sockaddr_in
+
+==================
+HOWTO get rid of inet_ntoa/aton:
+
+foo.sin_addr.s_addr = inet_addr(cp);
+-
+inet_pton(AF_INET, cp, &foo.sin_addr);
+
+inet_aton(cp, &foo.sin_addr);
+-
+inet_pton(AF_INET, cp, &foo.sin_addr);
+
+ptr = inet_ntoa(foo.sin_addr);
+-
+char str[INET_ADDRSTRLEN];
+ptr = inet_ntop(AF_INET, &foo.sin_addr, str, sizeof(str));
+
+===================
+
+       struct addrinfo {
+           int     ai_flags;
+           int     ai_family;
+           int     ai_socktype;
+           int     ai_protocol;
+           size_t  ai_addrlen;
+           struct sockaddr *ai_addr;
+           char   *ai_canonname;
+           struct addrinfo *ai_next;
+       };
+       int getaddrinfo(const char *node, const char *service,
+                       const struct addrinfo *hints,
+                       struct addrinfo **res);
+
+       void freeaddrinfo(struct addrinfo *res);
+
+       const char *gai_strerror(int errcode);
+
+       The members ai_family, ai_socktype, and ai_protocol have the same  meaning
+       as  the corresponding parameters in the socket(2) system call.  The getad-
+       drinfo(3) function returns socket addresses in either IPv4 or IPv6 address
+       family, (ai_family will be set to either AF_INET or AF_INET6).
+
+       The  hints  parameter specifies the preferred socket type, or protocol.  A
+       NULL hints specifies that any network address or protocol  is  acceptable.
+       If  this  parameter  is  not NULL it points to an addrinfo structure whose
+       ai_family, ai_socktype, and  ai_protocol  members  specify  the  preferred
+       socket type.  AF_UNSPEC in ai_family specifies any protocol family (either
+       IPv4 or IPv6, for example).  0 in  ai_socktype  or  ai_protocol  specifies
+       that any socket type or protocol is acceptable as well.  The ai_flags mem-
+       ber specifies additional options, defined below.  Multiple flags are spec-
+       ified  by  logically  OR-ing  them together.  All the other members in the
+       hints parameter must contain either 0, or a null pointer.
+
+       The node or service parameter, but not both, may be NULL.  node  specifies
+       either  a  numerical network address (dotted-decimal format for IPv4, hex-
+       adecimal format for IPv6) or a network hostname, whose  network  addresses
+       are looked up and resolved.  If hints.ai_flags contains the AI_NUMERICHOST
+       flag then the node parameter must be a  numerical  network  address.   The
+       AI_NUMERICHOST  flag  suppresses  any  potentially  lengthy  network  host
+       address lookups.
+
+       The getaddrinfo(3) function creates a linked list of addrinfo  structures,
+       one  for  each  network address subject to any restrictions imposed by the
+       hints parameter.  The ai_canonname field of the first  of  these  addrinfo
+       structures  is  set  to  point  to  the  official  name  of  the  host, if
+       hints.ai_flags includes the AI_CANONNAME  flag.   ai_family,  ai_socktype,
+       and  ai_protocol specify the socket creation parameters.  A pointer to the
+       socket address is placed in the ai_addr member,  and  the  length  of  the
+       socket address, in bytes, is placed in the ai_addrlen member.
+
+       If  node is NULL, the network address in each socket structure is initial-
+       ized according to the AI_PASSIVE flag, which  is  set  in  hints.ai_flags.
+       The  network  address in each socket structure will be left unspecified if
+       AI_PASSIVE flag is set.  This is used by server applications, which intend
+       to  accept client connections on any network address.  The network address
+       will be set to the loopback interface address if the  AI_PASSIVE  flag  is
+       not  set.  This is used by client applications, which intend to connect to
+       a server running on the same network host.
+
+       If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4 addresses are
+       returned  in the list pointed to by result only if the local system has at
+       least has at least one IPv4 address configured,  and  IPv6  addresses  are
+       only  returned  if  the local system has at least one IPv6 address config-
+       ured.
+
+       If hint.ai_flags specifies the AI_V4MAPPED flag, and  hints.ai_family  was
+       specified as AF_INET6, and no matching IPv6 addresses could be found, then
+       return IPv4-mapped IPv6 addresses in the list pointed to  by  result.   If
+       both  AI_V4MAPPED and AI_ALL are specified in hints.ai_family, then return
+       both IPv6 and IPv4-mapped IPv6 addresses in the list pointed to by result.
+       AI_ALL is ignored if AI_V4MAPPED is not also specified.
+
+       service  sets the port number in the network address of each socket struc-
+       ture.  If service is NULL the port number will be left uninitialized.   If
+       AI_NUMERICSERV  is  specified  in  hints.ai_flags and service is not NULL,
+       then service must point to a string  containing  a  numeric  port  number.
+       This  flag  is used to inhibit the invocation of a name resolution service
+       in cases where it is known not to be required.
+
+
+==============
+
+       int getnameinfo(const struct sockaddr *sa, socklen_t salen,
+                       char *host, size_t hostlen,
+                       char *serv, size_t servlen, int flags);
+
+       The  getnameinfo(3)  function is defined for protocol-independent
+       address-to-nodename translation.  It combines the functionality
+       of gethostbyaddr(3) and getservbyport(3) and is the inverse of
+       getaddrinfo(3).  The sa argument is a pointer to a generic socket address
+       structure (of type sockaddr_in or  sockaddr_in6)  of  size  salen  that
+       holds  the  input IP address and port number.  The arguments host and
+       serv are pointers to buffers (of size hostlen and servlen respectively)
+       to hold the return values.
+
+       The caller can specify that no hostname (or no service name) is required
+       by providing a NULL host (or serv) argument or a zero hostlen (or servlen)
+       parameter. However, at least one of hostname or service name must be requested.
+
+       The flags argument modifies the behaviour of getnameinfo(3) as follows:
+
+       NI_NOFQDN
+              If set, return only the hostname part of the FQDN for local hosts.
+
+       NI_NUMERICHOST
+              If set, then the numeric form of the hostname is returned.
+              (When not set, this will still happen in case the node's name
+              cannot be looked up.)
+
+       NI_NAMEREQD
+              If set, then a error is returned if the hostname cannot be looked up.
+
+       NI_NUMERICSERV
+              If set, then the service address is returned in numeric form,
+              for example by its port number.
+
+       NI_DGRAM
+              If  set, then the service is datagram (UDP) based rather than stream
+              (TCP) based. This is required for the few ports (512-514) that have different
+              services for UDP and TCP.
+
+=================
+
+Modified IPv6-aware C code:
+
+    struct addrinfo *res, *aip;
+    struct addrinfo hints;
+    int sock = -1;
+    int error;
+
+    /* Get host address. Any type of address will do. */
+    bzero(&hints, sizeof(hints));
+    hints.ai_flags = AI_ALL|AI_ADDRCONFIG;
+    hints.ai_socktype = SOCK_STREAM;
+
+    error = getaddrinfo(hostname, servicename, &hints, &res);
+    if (error != 0) {
+       (void) fprintf(stderr,
+          "getaddrinfo: %s for host %s service %s\n",
+          gai_strerror(error), hostname, servicename);
+       return (-1);
+    }
+    /* Try all returned addresses until one works */
+    for (aip = res; aip != NULL; aip = aip->ai_next) {
+       /*
+       * Open socket. The address type depends on what
+       * getaddrinfo() gave us.
+       */
+       sock = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
+       if (sock == -1) {
+          perror("socket");
+          freeaddrinfo(res);
+          return (-1);
+       }
+
+       /* Connect to the host. */
+       if (connect(sock, aip->ai_addr, aip->ai_addrlen) == -1) {
+          perror("connect");
+          (void) close(sock);
+          sock = -1;
+          continue;
+       }
+       break;
+    }
+    freeaddrinfo(res);
+
+Note that for new applications, if you write address-family-agnostic data structures,
+there is no need for porting.
+
+However, when it comes to server-side programming in C/C++, there is an additional wrinkle.
+Namely, depending on whether your application is written for a dual-stack platform, such
+as Solaris or Linux, or a single-stack platform, such as Windows, you would need to
+structure the code differently.
+
+Here's the corresponding server C code for a dual-stack platform:
+
+    int ServSock, csock;
+    struct sockaddr addr, from;
+    ...
+    ServSock = socket(AF_INET6, SOCK_STREAM, PF_INET6);
+    bind(ServSock, &addr, sizeof(addr));
+    do {
+       csock = accept(ServSocket, &from, sizeof(from));
+       doClientStuff(csock);
+    } while (!finished);