| 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. */ |
| memset(&hints, 0, 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 is too small! */ |
| struct sockaddr_storage 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); |