123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- 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);
|