123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371 |
- #include <sys/socket.h>
- #include <sys/un.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <assert.h>
- #include <stdlib.h>
- #include <string.h>
- #include "asprintf.h"
- #include "sock.h"
- #include "warnp.h"
- #include "sock_internal.h"
- #include "sock_util.h"
- #ifdef POSIXFAIL_INET_ADDRSTRLEN
- #define INET_ADDRSTRLEN 16
- #endif
- #ifdef POSIXFAIL_INET6_ADDRSTRLEN
- #define INET6_ADDRSTRLEN 46
- #endif
- /**
- * sock_addr_cmp(sa1, sa2):
- * Return non-zero iff the socket addresses ${sa1} and ${sa2} are different.
- */
- int
- sock_addr_cmp(const struct sock_addr * sa1, const struct sock_addr * sa2)
- {
- /* Family, socket type, and name length must match. */
- if ((sa1->ai_family != sa2->ai_family) ||
- (sa1->ai_socktype != sa2->ai_socktype) ||
- (sa1->namelen != sa2->namelen))
- return (1);
- /* The required length of the sockaddr must match. */
- if (memcmp(sa1->name, sa2->name, sa1->namelen) != 0)
- return (1);
- /* Everything matched. */
- return (0);
- }
- /**
- * sock_addr_dup(sa):
- * Duplicate the provided socket address.
- */
- struct sock_addr *
- sock_addr_dup(const struct sock_addr * sa)
- {
- struct sock_addr * sa2;
- /* Allocate a struct sock_addr and copy fields. */
- if ((sa2 = malloc(sizeof(struct sock_addr))) == NULL)
- goto err0;
- sa2->ai_family = sa->ai_family;
- sa2->ai_socktype = sa->ai_socktype;
- sa2->namelen = sa->namelen;
- /* Allocate and copy the sockaddr. */
- if ((sa2->name = malloc(sa2->namelen)) == NULL)
- goto err1;
- memcpy(sa2->name, sa->name, sa2->namelen);
- /* Success! */
- return (sa2);
- err1:
- free(sa2);
- err0:
- /* Failure! */
- return (NULL);
- }
- /**
- * sock_addr_duplist(sas):
- * Duplicate the provided list of socket addresses.
- */
- struct sock_addr **
- sock_addr_duplist(struct sock_addr * const * sas)
- {
- struct sock_addr ** sas2;
- size_t i;
- /* Count socket addresses. */
- for (i = 0; sas[i] != NULL; i++)
- continue;
- /* Allocate the list to hold addresses plus a NULL terminator. */
- if ((sas2 = malloc((i + 1) * sizeof(struct sock_addr *))) == NULL)
- goto err0;
- /* Duplicate addresses and NULL-terminate. */
- for (i = 0; sas[i] != NULL; i++) {
- if ((sas2[i] = sock_addr_dup(sas[i])) == NULL)
- goto err1;
- }
- sas2[i] = NULL;
- /* Success! */
- return (sas2);
- err1:
- /*
- * Regardless of how many addresses we managed to duplicate before
- * failing and being sent here, we have a valid socket address list,
- * since the erroring sock_addr_dup call NULL-terminated it for us;
- * so we can free it and its constituent addresses easily.
- */
- sock_addr_freelist(sas2);
- err0:
- /* Failure! */
- return (NULL);
- }
- /**
- * sock_addr_serialize(sa, buf, buflen):
- * Allocate a buffer and serialize the socket address ${sa} into it. Return
- * the buffer via ${buf} and its length via ${buflen}. The serialization is
- * machine and operating system dependent.
- */
- int
- sock_addr_serialize(const struct sock_addr * sa,
- uint8_t ** buf, size_t * buflen)
- {
- uint8_t * p;
- /* Compute buffer length and allocate buffer. */
- *buflen = 2 * sizeof(int) + sizeof(socklen_t) + sa->namelen;
- if ((p = *buf = malloc(*buflen)) == NULL)
- goto err0;
- /* Copy in data. */
- memcpy(p, &sa->ai_family, sizeof(int));
- p += sizeof(int);
- memcpy(p, &sa->ai_socktype, sizeof(int));
- p += sizeof(int);
- memcpy(p, &sa->namelen, sizeof(socklen_t));
- p += sizeof(socklen_t);
- memcpy(p, sa->name, sa->namelen);
- /* Success! */
- return (0);
- err0:
- /* Failure! */
- return (-1);
- }
- /**
- * sock_addr_deserialize(buf, buflen):
- * Deserialize the ${buflen}-byte serialized socket address from ${buf}.
- */
- struct sock_addr *
- sock_addr_deserialize(const uint8_t * buf, size_t buflen)
- {
- struct sock_addr * sa;
- /* Sanity check. */
- if (buflen < 2 * sizeof(int) + sizeof(socklen_t))
- goto err0;
- /* Allocate a structure and copy in fields. */
- if ((sa = malloc(sizeof(struct sock_addr))) == NULL)
- goto err0;
- memcpy(&sa->ai_family, buf, sizeof(int));
- buf += sizeof(int);
- memcpy(&sa->ai_socktype, buf, sizeof(int));
- buf += sizeof(int);
- memcpy(&sa->namelen, buf, sizeof(socklen_t));
- buf += sizeof(socklen_t);
- /* Allocate and copy the sockaddr. */
- if (buflen != 2 * sizeof(int) + sizeof(socklen_t) + sa->namelen)
- goto err1;
- if ((sa->name = malloc(sa->namelen)) == NULL)
- goto err1;
- memcpy(sa->name, buf, sa->namelen);
- /* Success! */
- return (sa);
- err1:
- free(sa);
- err0:
- /* Failure! */
- return (NULL);
- }
- /* Prettyprint an IPv4 address. */
- static char *
- prettyprint_ipv4(struct sockaddr * name, size_t namelen)
- {
- struct sockaddr_in sa_in;
- char addr[INET_ADDRSTRLEN];
- char * s;
- /* Check name length. */
- if (namelen != sizeof(struct sockaddr_in))
- return (NULL);
- /* Copy into buffer for alignment. */
- memcpy(&sa_in, name, namelen);
- /* Convert IP address to string. */
- if (inet_ntop(AF_INET, &sa_in.sin_addr, addr, sizeof(addr)) == NULL)
- return (NULL);
- /* Construct address string. */
- if (asprintf(&s, "[%s]:%d", addr, ntohs(sa_in.sin_port)) == -1)
- return (NULL);
- /* Success! */
- return (s);
- }
- /* Prettyprint an IPv6 address. */
- static char *
- prettyprint_ipv6(struct sockaddr * name, size_t namelen)
- {
- struct sockaddr_in6 sa_in6;
- char addr[INET6_ADDRSTRLEN];
- char * s;
- /* Check name length. */
- if (namelen != sizeof(struct sockaddr_in6))
- return (NULL);
- /* Copy into buffer for alignment. */
- memcpy(&sa_in6, name, namelen);
- /* Convert IPv6 address to string. */
- if (inet_ntop(AF_INET6, &sa_in6.sin6_addr, addr, sizeof(addr)) == NULL)
- return (NULL);
- /* Construct address string. */
- if (asprintf(&s, "[%s]:%d", addr, ntohs(sa_in6.sin6_port)) == -1)
- return (NULL);
- /* Success! */
- return (s);
- }
- /* Prettyprint a UNIX address. */
- static char *
- prettyprint_unix(struct sockaddr_un * name)
- {
- /* Just strdup the path. */
- return (strdup(name->sun_path));
- }
- /**
- * sock_addr_prettyprint(sa):
- * Allocate and return a string in one of the forms
- * /path/to/unix/socket
- * [ip.v4.ad.dr]:port
- * [ipv6:add::ress]:port
- * representing the provided socket address.
- */
- char *
- sock_addr_prettyprint(const struct sock_addr * sa)
- {
- /* Handle different types of addresses differently. */
- switch (sa->ai_family) {
- case AF_INET:
- return (prettyprint_ipv4(sa->name, sa->namelen));
- case AF_INET6:
- return (prettyprint_ipv6(sa->name, sa->namelen));
- case AF_UNIX:
- return (prettyprint_unix((struct sockaddr_un *)(sa->name)));
- default:
- return (strdup("Unknown address"));
- }
- }
- /**
- * sock_addr_ensure_port(addr):
- * Allocate a new string to serve as the address for sock_resolve().
- * If ${addr} contains a port number or is the address of a Unix domain
- * socket, duplicate that string; if not, add a port number of ":0".
- */
- char *
- sock_addr_ensure_port(const char * addr)
- {
- char * bind_addr;
- char * cr;
- /* Sanity check. */
- assert(addr != NULL);
- /* Where is the right-most colon in $addr? */
- cr = strrchr(addr, ':');
- /* Figure out what type of address $addr is. */
- if (cr == addr) {
- /*
- * If the right-most colon is the first char, it's not a valid
- * address, but we'll strdup it anyway.
- */
- bind_addr = strdup(addr);
- } else if (addr[0] == '/') {
- /* It's a Unix domain socket and doesn't need a port number. */
- bind_addr = strdup(addr);
- } else if (addr[0] != '[') {
- /* It's a hostname... */
- if (cr == NULL) {
- /* ... without any port number, so we add ":0". */
- if (asprintf(&bind_addr, "%s:0", addr) == -1)
- goto err0;
- } else {
- /* ... which already has a port number. */
- bind_addr = strdup(addr);
- }
- } else {
- /* addr[0] == '[', so it's an address... */
- if ((cr == NULL) || (cr[-1] != ']')) {
- /* ... without a port number, so we add ":0". */
- if (asprintf(&bind_addr, "%s:0", addr) == -1)
- goto err0;
- } else {
- /* ... which already has a port number. */
- bind_addr = strdup(addr);
- }
- }
- /* Success! */
- return (bind_addr);
- err0:
- /* Failure! */
- return (NULL);
- }
- /**
- * sock_addr_validate(addr):
- * Check that ${addr} is syntactically valid, but do not perform any address
- * resolution.
- */
- int
- sock_addr_validate(const char * addr)
- {
- /* Sanity check. */
- assert(addr != NULL);
- /* Check for an empty address. */
- if (strlen(addr) == 0) {
- warn0("Empty socket address.");
- goto err0;
- }
- /* If this isn't a UNIX socket address, check for a missing hostname. */
- if ((addr[0] != '/') && (addr[0] == ':')) {
- warn0("No host in \"%s\"", addr);
- goto err0;
- }
- /* Success! */
- return (0);
- err0:
- /* Failure! */
- return (-1);
- }
|