SOCKADDR(3SOCKET) Sockets Library Functions SOCKADDR(3SOCKET)

sockaddr, sockaddr_dl, sockaddr_in, sockaddr_in6, sockaddr_ll, sockaddr_storage, sockaddr_un
Socket Address Structures

#include <sys/socket.h>

struct sockaddr sock;


#include <sys/socket.h>
#include <net/if_dl.h>

struct sockaddr_dl dl_sock;


#include <sys/socket.h>
#include <netinet/in.h>

struct sockaddr_in in_sock;


#include <sys/socket.h>
#include <netinet/in.h>

struct sockaddr_in6 in6_sock;


#include <sys/socket.h>

struct sockaddr_ll ll_sock;


#include <sys/socket.h>

struct sockaddr_storage storage_sock;


#include <sys/un.h>

struct sockaddr_un un_sock;

The sockaddr family of structures are designed to represent network addresses for different networking protocols. The structure struct sockaddr is a generic structure that is used across calls to various socket library routines (libsocket(3LIB)) such as accept(3SOCKET) and bind(3SOCKET). Applications do not use the struct sockaddr directly, but instead cast the appropriate networking family specific sockaddr structure to a struct sockaddr *.

Every structure in the sockaddr family begins with a member of the same type, the sa_family_t, though the different structures all have different names for the member. For example, the structure struct sockaddr has the following members defined:

sa_family_t	sa_family	/* address family */
char		sa_data[]	/* socket address (variable-length data) */

The member sa_family corresponds to the socket family that's actually in use. The following table describes the mapping between the address family and the corresponding socket structure that's used. Note that both the generic struct sockaddr and the struct sockaddr_storage are not included, because these are both generic structures. More on the struct sockaddr_storage can be found in the next section.

Socket Structure Address Family
struct sockaddr_dl AF_LINK
struct sockaddr_in AF_INET
struct sockaddr_in6 AF_INET6
struct sockaddr_ll AF_PACKET
struct sockaddr_un AF_UNIX

The sockaddr_storage structure is a sockaddr that is not associated with an address family. Instead, it is large enough to hold the contents of any of the other sockaddr structures. It can be used to embed sufficient storage for a sockaddr of any type within a larger structure.

The structure only has a single member defined. While there are other members that are used to pad out the size of the struct sockaddr_storage, they are not defined and must not be consumed. The only valid member is:

sa_family_t	ss_family	/* address family */

For example, struct sockaddr_storage is useful when running a service that accepts traffic over both IPv4 and IPv6 where it is common to use a single socket for both address families. In that case, rather than guessing whether a struct sockaddr_in or a struct sockaddr_in6 is more appropriate, one can simply use a struct sockaddr_storage and cast to the appropriate family-specific structure type based on the value of the member ss_family.

The sockaddr_in is the socket type which is used for for the Internet Protocol version four (IPv4). It has the following members defined:
sa_family_t	sin_family	/* address family */
in_port_t	sin_port	/* IP port */
struct in_addr	sin_addr	/* IP address */

The member sin_family must always have the value AF_INET for IPv4. The members sin_port and sin_addr describe the IP address and IP port to use. In the case of a call to connect(3SOCKET) these represent the remote IP address and port to which the connection is being made. In the case of bind(3SOCKET) these represent the IP address and port on the local host to which the socket is to be bound. In the case of accept(3SOCKET) these represent the remote IP address and port of the machine whose connection was accepted.

The member sin_port is always stored in Network Byte Order. On many systems, this differs from the native host byte order. Applications should read from the member with the function ntohs(3C) and write to the member with the function htons(3C). The member sin_addr is the four byte IPv4 address. It is also stored in network byte order. The common way to write out the address is to use the function inet_pton(3C) which converts between a human readable IP address such as "10.1.2.3" and the corresponding representation.

Example 1 shows how to prepare an IPv4 socket and deal with network byte-order. See inet(4P) and ip(4P) for more information on IPv4, socket options, etc.

The sockaddr_in6 structure is the sockaddr for the Internet Protocol version six (IPv6). Unlike the struct sockaddr_in, the struct sockaddr_in6 has additional members beyond those shown here which are required to be initialized to zero through a function such as bzero(3C) or memset(3C). If the entire struct sockaddr_in6 is not zeroed before use, applications will experience undefined behavior. The struct sockaddr_in6 has the following public members:
sa_family_t	sin6_family	/* address family */
in_port_t	sin6_port	/* IPv6 port */
struct in6_addr	sin6_addr	/* IPv6 address */
uint32_t	sin6_flowinfo;	/* traffic class and flow info */
uint32_t	sin6_scope_id;	/* interface scope */

The member sin6_family must always have the value AF_INET6. The members sin6_port and sin6_addr are the IPv6 equivalents of the struct sockaddr_in sin_port and sin_addr. Like their IPv4 counterparts, both of these members must be in network byte order. The member sin6_port describes the IPv6 port and should be manipulated with the functions ntohs(3C) and htons(3C). The member sin6_addr describes the 16-byte IPv6 address. In addition to the function inet_pton(3C), the header file <netinet/in.h> defines many macros for manipulating and testing IPv6 addresses.

The member sin6_flowinfo contains the traffic class and flow label associated with the IPv6 header. The member sin6_scope_id may contain an identifier which varies based on the scope of the address in sin6_addr. Applications do not need to initialize sin6_scope_id; it will be populated by the operating system as a result of various library calls.

Example 2 shows how to prepare an IPv6 socket. For more information on IPv6, please see inet6(4P) and ip6(4P).

The sockaddr_un structure specifies the address of a socket used to communicate between processes running on a single system, commonly known as a UNIX domain socket. Sockets of this type are identified by a path in the file system. The struct sockaddr_un has the following members:
sa_family_t	sun_family	/* address family */
char		sun_path[108]	/* path name */

The member sun_family must always have the value AF_UNIX. The member sun_path is populated with a NUL terminated array of characters that specify a file system path. The maximum length of any such path, including the NUL terminator, is 108 bytes.

The sockaddr_dl structure is used to describe a layer 2 link-level address. This is used as part of various socket ioctls, such as those for arp(4P). The structure has the following members:
ushort_t	sdl_family;	/* address family */
ushort_t	sdl_index;	/* if != 0, system interface index */
uchar_t		sdl_type;	/* interface type */
uchar_t		sdl_nlen;	/* interface name length */
uchar_t		sdl_alen;	/* link level address length */
uchar_t		sdl_slen;	/* link layer selector length */
char		sdl_data[244];	/* contains both if name and ll address

The member sdl_family must always have the value AF_LINK. When the member sdl_index is non-zero this refers to the interface identifier that corresponds to the struct sockaddr_dl. This identifier is the same identifier that's shown by tools like ifconfig(8) and used in the SIOC* set of socket ioctls. The member sdl_type refers to the media that is used for the socket. The most common case is that the medium for the interface is Ethernet which has the value IFT_ETHER. The full set of types is derived from RFC1573 and recorded in the file <net/if_types.h>. The member sdl_slen describes the length of a selector, if it exists, for the specified medium. This is used in protocols such as Trill.

The sdl_data, sdl_nlen and sdl_alen members together describe a character string containing the interface name and the link-layer network address. The name starts at the beginning of sdl_data, i.e. at sdl_data[0]. The name of the interface occupies the next sdl_nlen bytes and is not NUL terminated. The link-layer network address begins immediately after the interface name, and is sdl_alen bytes long. The macro LLADDR(struct sockaddr_dl *) returns the start of the link-layer network address. The interpretation of the link-layer address depends on the value of sdl_type. For example, if the type is IFT_ETHER then the address is expressed as a 6-byte MAC address.

The sockaddr_ll is used as part of a socket type which is responsible for packet capture: AF_PACKET sockets. It is generally designed for use with Ethernet networks. The members of the struct sockaddr_ll are:
uint16_t        sll_family;	/* address family */
uint16_t        sll_protocol;	/* link layer protocol */
int32_t         sll_ifindex;	/* interface index */
uint16_t        sll_hatype;	/* ARP hardware type */
uint8_t         sll_pkttype;	/* packet type */
uint8_t         sll_halen;	/* hardware address length */
uint8_t         sll_addr[8];	/* hardware type */

The member sll_family must be AF_PACKET. The member sll_protocol refers to a link-layer protocol. For example, when capturing Ethernet frames the value of sll_protocol is the Ethertype. This member is written in network byte order and applications should use htons(3C) and ntohs(3C) to read and write the member.

The member sll_ifindex is the interface's index. It is used as an identifier in various ioctls and included in the output of ifconfig(8). When calling bind(3SOCKET) it should be filled in with the index that corresponds to the interface for which packets should be captured on.

The member sll_pkttype describes the type of the packet based on a list of types in the header file <netpacket/packet.h>. These types include: PACKET_OUTGOING, a packet that was leaving the host and has been looped back for packet capture; PACKET_HOST, a packet that was destined for this host; PACKET_BROADCAST, a packet that was broadcast across the link-layer; PACKET_MULTICAST, a packet that was sent to a link-layer multicast address; and PACKET_OTHERHOST, a packet that was captured only because the device in question was in promiscuous mode.

The member sll_hatype contains the hardware type as defined by arp(4P). The list of types can be found in <net/if_arp.h>. The member sll_halen contains the length, in bytes, of the hardware address, while the member sll_addr contains the actual address in network byte order.

Example 1 Preparing an IPv4 sockaddr_in to connect to a remote host

The following example shows how one would open a socket and prepare it to connect to the remote host whose address is the IP address 127.0.0.1 on port 80. This program should be compiled with the C compiler cc and linked against the libraries libsocket and libnsl. If this example was named ip4.c, then the full link line would be cc ip4.c -lsocket -lnsl.

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <strings.h>

int
main(void)
{
	int sock;
	struct sockaddr_in in;

	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		return (1);
	}

	bzero(&in, sizeof (struct sockaddr_in));
	in.sin_family = AF_INET;
	in.sin_port = htons(80);
	if (inet_pton(AF_INET, "127.0.0.1", &in.sin_addr) != 1) {
		perror("inet_pton");
		return (1);
	}

	if (connect(sock, (struct sockaddr *)&in,
	    sizeof (struct sockaddr_in)) != 0) {
		perror("connect");
		return (1);
	}

	/* use socket */

	return (0);
}

Example 2 Preparing an IPv6 sockaddr_in6 to bind to a local address

The following example shows how one would open a socket and prepare it to bind to the local IPv6 address ::1 port on port 12345. This program should be compiled with the C compiler cc and linked against the libraries libsocket and libnsl. If this example was named ip6.c, then the full compiler line would be cc ip6.c -lsocket -lnsl.

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <inttypes.h>
#include <strings.h>

int
main(void)
{
	int sock6;
	struct sockaddr_in6 in6;

	if ((sock6 = socket(AF_INET6, SOCK_STREAM, 0)) < 0) {
		perror("socket");
		return (1);
	}

	bzero(&in6, sizeof (struct sockaddr_in6));
	in6.sin6_family = AF_INET6;
	in6.sin6_port = htons(12345);
	if (inet_pton(AF_INET6, "::1", &in6.sin6_addr) != 1) {
		perror("inet_pton");
		return (1);
	}

	if (bind(sock6, (struct sockaddr *)&in6,
	    sizeof (struct sockaddr_in6)) != 0) {
		perror("bind");
		return (1);
	}

	/* use server socket */

	return (0);
}

socket(3HEAD), un.h(3HEAD), accept(3SOCKET), bind(3SOCKET), connect(3SOCKET), socket(3SOCKET), arp(4P), inet(4P), inet6(4P), ip(4P), ip6(4P)
April 9, 2016 OmniOS