diff --git a/docs/ipv4_ipv6.txt b/docs/ipv4_ipv6.txt new file mode 100644 index 000000000..5a63aa776 --- /dev/null +++ b/docs/ipv4_ipv6.txt @@ -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);