diff options
| author | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2023-03-11 18:24:13 +0100 | 
|---|---|---|
| committer | Jörg Frings-Fürst <debian@jff-webhosting.net> | 2023-03-11 18:24:13 +0100 | 
| commit | 980784c1917f19bfd2e9b11faca76d14e8589daa (patch) | |
| tree | c9b3988642585cd50af5ec1ffad75331886c0aa4 /src | |
| parent | bfef0924f58eab930bdd826ac0132786abc32220 (diff) | |
New upstream version 4.12upstream/4.12
Diffstat (limited to 'src')
| -rw-r--r-- | src/Makefile.am | 2 | ||||
| -rw-r--r-- | src/Makefile.in | 2 | ||||
| -rw-r--r-- | src/io.c | 19 | ||||
| -rw-r--r-- | src/libHX.map | 8 | ||||
| -rw-r--r-- | src/rand.c | 2 | ||||
| -rw-r--r-- | src/socket.c | 252 | ||||
| -rw-r--r-- | src/tc-list.c | 8 | ||||
| -rw-r--r-- | src/tc-socket.c | 44 | 
8 files changed, 323 insertions, 14 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 921e6b7..f7ff4f6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,7 +13,7 @@ libHX_la_SOURCES = deque.c dl.c format.c io.c map.c \                     mc.c misc.c opt.c proc.c \                     rand.c socket.c string.c time.c  libHX_la_LIBADD  = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS} -libHX_la_LDFLAGS = -no-undefined -version-info 36:0:4 +libHX_la_LDFLAGS = -no-undefined -version-info 37:0:5  if WITH_GNU_LD  libHX_la_LDFLAGS += -Wl,--version-script=${srcdir}/libHX.map  endif diff --git a/src/Makefile.in b/src/Makefile.in index 8257e20..43f7444 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -780,7 +780,7 @@ libHX_la_SOURCES = deque.c dl.c format.c io.c map.c mc.c misc.c opt.c \  	proc.c rand.c socket.c string.c time.c $(am__append_3)  libHX_la_LIBADD = ${libdl_LIBS} -lm ${libpthread_LIBS} ${librt_LIBS} \  	$(am__append_4) -libHX_la_LDFLAGS = -no-undefined -version-info 36:0:4 $(am__append_2) +libHX_la_LDFLAGS = -no-undefined -version-info 37:0:5 $(am__append_2)  EXTRA_libHX_la_DEPENDENCIES = libHX.map  libHX_rtcheck_la_SOURCES = rtcheck.c  libHX_rtcheck_la_LIBADD = ${libdl_LIBS} @@ -11,6 +11,7 @@  #	include "config.h"  #endif  #include <sys/stat.h> +#include <assert.h>  #include <errno.h>  #include <fcntl.h>  #include <limits.h> @@ -594,39 +595,37 @@ EXPORT_SYMBOL int HX_rrmdir(const char *dir)  EXPORT_SYMBOL ssize_t HXio_fullread(int fd, void *vbuf, size_t size)  {  	char *buf = vbuf; -	size_t done = 0;  	if (size > SSIZE_MAX)  		size = SSIZE_MAX; -	while (done < size) { -		ssize_t ret = read(fd, buf, size - done); +	while (size > 0) { +		ssize_t ret = read(fd, buf, size);  		if (ret < 0)  			return ret;  		else if (ret == 0)  			break; -		done += ret;  		buf += ret; +		size -= ret;  	} -	return done; +	return buf - static_cast(char *, vbuf);  }  EXPORT_SYMBOL ssize_t HXio_fullwrite(int fd, const void *vbuf, size_t size)  {  	const char *buf = vbuf; -	size_t done = 0;  	if (size > SSIZE_MAX)  		size = SSIZE_MAX; -	while (done < size) { -		ssize_t ret = write(fd, buf, size - done); +	while (size > 0) { +		ssize_t ret = write(fd, buf, size);  		if (ret < 0)  			return ret;  		else if (ret == 0)  			break; -		done += ret;  		buf += ret; +		size -= ret;  	} -	return done; +	return buf - static_cast(const char *, vbuf);  }  #if __linux__ diff --git a/src/libHX.map b/src/libHX.map index c4cef55..33415fa 100644 --- a/src/libHX.map +++ b/src/libHX.map @@ -159,3 +159,11 @@ global:  	HX_ipaddr_is_local;  	HX_sockaddr_is_local;  } LIBHX_4.3; + +LIBHX_4.11 { +global: +	HX_addrport_split; +	HX_inet_connect; +	HX_inet_listen; +	HX_local_listen; +} LIBHX_4.9; @@ -27,7 +27,7 @@  static unsigned int HXrand_obtain_seed(void)  { -	unsigned int s; +	unsigned long s;  #if defined(HAVE_CLOCK_GETTIME)  	struct timespec tv; diff --git a/src/socket.c b/src/socket.c index ced884a..9b5d78a 100644 --- a/src/socket.c +++ b/src/socket.c @@ -17,10 +17,12 @@  #ifdef _WIN32  #	include <ws2tcpip.h>  #else +#	include <fcntl.h>  #	include <netdb.h>  #	include <unistd.h>  #	include <netinet/in.h>  #	include <sys/socket.h> +#	include <sys/stat.h>  #endif  #ifdef HAVE_SYS_UN_H  #	include <sys/un.h> @@ -46,6 +48,256 @@  #	define AI_V4MAPPED 0  #endif +/** + * Return the pointer to the singular colon character, any other input + * yields nullptr. + */ +static inline const char *has_exactly_one_colon(const char *s) +{ +	s = strchr(s, ':'); +	if (s == nullptr) +		return nullptr; +	return strchr(s + 1, ':') == nullptr ? s : nullptr; +} + +/** + * @spec:	"[" HOST-ANY "]" [ ":" PORT ] + * 		HOST-NAME [ ":" PORT ] + * 		HOST-IPV4 [ ":" PORT ] + * 		HOST-IPV6 + * @host:	buffer for placing the extracted hostname + * 		(can overlap @spec) + * @hsize:	buffer size for @host + * @port:	storage space for extracted port number + * 		(can be nullptr) + * + * Returns <0 (error code) if unparsable or if the output buffer is too small. + * Success if on >=0. + */ +int HX_addrport_split(const char *spec, char *host, +    size_t hbufsz, uint16_t *pport) +{ +	if (*spec == '[') { +		/* We also happen to allow IPv4 addrs and hostnames in [] */ +		++spec; +		const char *end = strchr(spec, ']'); +		if (end == nullptr) +			return -EINVAL; +		unsigned long hlen = end - spec; +		if (hlen >= hbufsz) +			return -E2BIG; +		if (*++end == '\0') +			return 1; +		if (*end++ != ':') +			return -EINVAL; +		char *nend = nullptr; +		uint16_t port = strtoul(end, &nend, 10); +		if (nend == nullptr || *nend != '\0') +			return -EINVAL; +		memmove(host, spec, hlen); +		host[hlen] = '\0'; +		if (pport == nullptr) +			return 2; +		*pport = port; +		return 2; +	} +	const char *onecolon = has_exactly_one_colon(spec); +	if (onecolon != nullptr) { +		unsigned long hlen = onecolon - spec; +		if (hlen >= hbufsz) +			return -E2BIG; +		char *nend = nullptr; +		uint16_t port = strtoul(onecolon + 1, &nend, 10); +		if (nend == nullptr || *nend != '\0') +			return -EINVAL; +		memmove(host, spec, hlen); +		host[hlen] = '\0'; +		if (pport == nullptr) +			return 2; +		*pport = port; +		return 2; +	} +	size_t hlen = strlen(spec); +	if (hlen >= SIZE_MAX || ++hlen >= hbufsz) +		return -E2BIG; +	memmove(host, spec, hlen); +	return 1; +} + +static int HX_inet_lookup(const char *host, uint16_t port, unsigned int xflags, +    struct addrinfo **res) +{ +	struct addrinfo hints = {}; +#if defined(AI_V4MAPPED) +	hints.ai_flags    = AI_V4MAPPED | xflags; +#else +	hints.ai_flags    = xflags; +#endif +	hints.ai_family   = AF_INET6; +	hints.ai_socktype = SOCK_STREAM; + +	char portbuf[HXSIZEOF_Z32]; +	snprintf(portbuf, sizeof(portbuf), "%hu", port); +	return getaddrinfo(host, port == 0 ? nullptr : portbuf, &hints, res); +} + +int HX_inet_connect(const char *host, uint16_t port, unsigned int oflags) +{ +	struct addrinfo *aires = nullptr; +	int ret = HX_inet_lookup(host, port, AI_ADDRCONFIG, &aires); +	int saved_errno = 0; +	for (const struct addrinfo *r = aires; r != nullptr; r = r->ai_next) { +		int fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); +		if (fd < 0) { +			if (saved_errno == 0) +				saved_errno = errno; +			continue; +		} +#ifdef O_NONBLOCK +		if (oflags & O_NONBLOCK) { +			int flags = fcntl(fd, F_GETFL, 0); +			if (flags < 0) +				flags = 0; +			flags |= O_NONBLOCK; +			if (fcntl(fd, F_SETFL, flags) != 0) { +				saved_errno = errno; +				close(fd); +				continue; +			} +		} +#endif +		ret = connect(fd, r->ai_addr, r->ai_addrlen); +		if (ret == 0) { +			freeaddrinfo(aires); +			return fd; +		} +#ifdef O_NONBLOCK +		if ((errno == EWOULDBLOCK || errno == EINPROGRESS) && +		    (oflags & O_NONBLOCK)) { +			freeaddrinfo(aires); +			return fd; +		} +#endif +		saved_errno = errno; +		close(fd); +	} +	if (aires == nullptr && saved_errno == 0) +		saved_errno = EHOSTUNREACH; +	if (aires != nullptr) +		freeaddrinfo(aires); +	return -(errno = saved_errno); +} + +static int HX_gai_listen(const struct addrinfo *r) +{ +	int fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol); +	if (fd < 0) +		return -2; +	static const int y = 1; +	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, STUPIDWIN(&y), sizeof(y)) < 0) +		/* warn setsockopt: %s, strerror(errno)) */ ; +	int ret = bind(fd, r->ai_addr, r->ai_addrlen); +	if (ret != 0) { +		int se = errno; +		close(fd); +		errno = se; +		return -1; +	} +	ret = listen(fd, SOMAXCONN); +	if (ret != 0) { +		int se = errno; +		close(fd); +		errno = se; +		return -2; +	} +	return fd; +} + +int HX_inet_listen(const char *host, uint16_t port) +{ +	struct addrinfo *aires = nullptr; +	int ret = HX_inet_lookup(host, port, AI_PASSIVE, &aires); +	if (ret != 0) +		; +	int saved_errno = EHOSTUNREACH; +	bool use_env = getenv("HX_LISTEN_TOP_FD") != nullptr || getenv("LISTEN_FDS") != nullptr; +	for (const struct addrinfo *r = aires; r != nullptr; r = r->ai_next) { +		if (use_env) { +			int fd = HX_socket_from_env(r, nullptr); +			if (fd >= 0) { +				freeaddrinfo(aires); +				return fd; +			} +		} +		int fd = HX_gai_listen(r); +		if (fd >= 0) { +			freeaddrinfo(aires); +			return fd; +		} +		saved_errno = errno; +		if (fd == -2) +			continue; +		break; +	} +	if (aires != nullptr) +		freeaddrinfo(aires); +	return -(errno = saved_errno); +} + +int HX_local_listen(const char *path) +{ +#ifdef HAVE_SYS_UN_H +	struct sockaddr_un u; +	if (strlen(path) >= sizeof(u.sun_path)) +		return -EINVAL; +	u.sun_family = AF_LOCAL; +	strcpy(u.sun_path, path); +	struct addrinfo r = {}; +	r.ai_flags = AI_PASSIVE; +	r.ai_family = AF_LOCAL; +	r.ai_socktype = SOCK_STREAM; +	r.ai_addrlen = sizeof(u) - sizeof(u.sun_path) + strlen(u.sun_path) + 1; +	r.ai_addr = reinterpret_cast(struct sockaddr *, &u); +	bool use_env = getenv("HX_LISTEN_TOP_FD") != nullptr || getenv("LISTEN_FDS") != nullptr; +	if (use_env) { +		int fd = HX_socket_from_env(&r, nullptr); +		if (fd >= 0) +			return fd; +	} +	int ret = HX_gai_listen(&r); +	if (ret >= 0) +		return ret; /* fd */ +	if (ret == -2 || errno != EADDRINUSE) +		return -errno; + +	struct stat sb; +	ret = stat(path, &sb); +	if (ret < 0) +		return -errno; +	if (!S_ISSOCK(sb.st_mode)) +		return -ENOTSOCK; + +	int testfd = socket(AF_LOCAL, SOCK_STREAM, 0); +	if (testfd < 0) +		return -errno; +	ret = connect(testfd, r.ai_addr, r.ai_addrlen); +	close(testfd); +	if (ret == 0) +		return -EADDRINUSE; + +	/* There will be a TOCTOU report, but what can you do... */ +	ret = unlink(path); +	if (ret < 0 && errno != ENOENT) +		return -errno; +	ret = HX_gai_listen(&r); +	if (ret >= 0) +		return ret; /* fd */ +	return -errno; +#else +	return -EPROTONOSUPPORT; +#endif +} +  static int try_sk_from_env(int fd, const struct addrinfo *ai, const char *intf)  {  	int value = 0; diff --git a/src/tc-list.c b/src/tc-list.c index e0087e3..2fd6380 100644 --- a/src/tc-list.c +++ b/src/tc-list.c @@ -69,8 +69,14 @@ static void l_dump(bool pop)  	while ((obj = (pop ?  	    HXclist_pop(&strings_ct, struct text_object, list) :  	    HXclist_shift(&strings_ct, struct text_object, list) -	    )) != NULL) +	    )) != NULL) {  		printf("%s item %u (\"%s\")\n", msg[pop], ++i, obj->id); +#ifdef __cplusplus +		delete obj; +#else +		free(obj); +#endif +	}  	printf("Remaining elements: %u\n", strings_ct.items);  } diff --git a/src/tc-socket.c b/src/tc-socket.c index 9c73d24..9904ba8 100644 --- a/src/tc-socket.c +++ b/src/tc-socket.c @@ -7,6 +7,7 @@  #include <libHX/socket.h>  #ifndef _WIN32  #	include <netdb.h> +#	include <unistd.h>  #endif  #ifndef AI_V4MAPPED  #	define AI_V4MAPPED 0 @@ -19,6 +20,15 @@ int main(void)  		"127.0.0.1", "127.0.0.2", "1.1.1.1", "255.255.255.255",  	};  	for (size_t i = 0; i < ARRAY_SIZE(addrs); ++i) { +		char host[32] = {}; +		uint16_t port = 0; + +		int ret = HX_addrport_split(addrs[i], host, sizeof(host), &port); +		if (ret >= 0) +			printf("Parse \"%s\" -> [%s]:%hu\n", addrs[i], host, port); +		else +			return EXIT_FAILURE; +  		printf("%-16s\t", addrs[i]);  		int lcl = HX_ipaddr_is_local(addrs[i], AI_V4MAPPED);  		if (lcl < 0) { @@ -27,5 +37,39 @@ int main(void)  		}  		printf("%d\n", lcl);  	} + +	char host[32] = {}; +	uint16_t port = 0; +	int ret = HX_addrport_split("[fe80::1]:80", host, sizeof(host), &port); +	if (ret < 0 || port != 80) +		return EXIT_FAILURE; +	port = 443; +	ret = HX_addrport_split("::80", host, sizeof(host), &port); +	if (ret < 0 || port != 443) +		return EXIT_FAILURE; +	ret = HX_addrport_split(":::80", host, sizeof(host), &port); +	if (ret < 0 || port != 443) +		return EXIT_FAILURE; +	ret = HX_addrport_split("0.0.0.0", host, sizeof(host), &port); +	if (ret < 0 || port != 443) +		return EXIT_FAILURE; +	ret = HX_addrport_split("0.0.0.0:80", host, sizeof(host), &port); +	if (ret < 0 || port != 80) +		return EXIT_FAILURE; + +	int fd = HX_inet_connect("::1", 80, 0); +	if (fd >= 0) { +		printf("Connected to [::1]:80\n"); +		close(fd); +	} else { +		fprintf(stderr, "HX_inet_connect [::1]:80: %s\n", strerror(-fd)); +	} +	fd = HX_inet_connect("::", 80, 0); +	if (fd >= 0) { +		printf("Connected to [::]:80\n"); +		close(fd); +	} else { +		fprintf(stderr, "HX_inet_connect [::]:80: %s\n", strerror(-fd)); +	}  	return EXIT_SUCCESS;  }  | 
