5af5b2
#define _GNU_SOURCE
5af5b2
#include <sys/socket.h>
5af5b2
#include <dlfcn.h>
5af5b2
#include <errno.h>
5af5b2
#include <stdlib.h>
5af5b2
#include <string.h>
5af5b2
#include <netinet/in.h>
5af5b2
5af5b2
static int
5af5b2
port_is_okay(unsigned short port)
5af5b2
{
5af5b2
	char *p, *q;
5af5b2
	long l;
5af5b2
5af5b2
	p = getenv("NOPORT");
5af5b2
	while ((p != NULL) && (*p != '\0')) {
5af5b2
		l = strtol(p, &q, 10);
5af5b2
		if ((q == NULL) || (q == p)) {
5af5b2
			break;
5af5b2
		}
5af5b2
		if ((*q == '\0') || (*q == ',')) {
5af5b2
			if (port == l) {
5af5b2
				errno = ECONNREFUSED;
5af5b2
				return -1;
5af5b2
			}
5af5b2
		}
5af5b2
		p = q;
5af5b2
		p += strspn(p, ",");
5af5b2
	}
5af5b2
	return 0;
5af5b2
}
5af5b2
5af5b2
int
5af5b2
connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
5af5b2
{
5af5b2
	unsigned short port;
5af5b2
	static int (*next_connect)(int, const struct sockaddr *, socklen_t);
5af5b2
5af5b2
	if (next_connect == NULL) {
5af5b2
		next_connect = dlsym(RTLD_NEXT, "connect");
5af5b2
		if (next_connect == NULL) {
5af5b2
			errno = ENOSYS;
5af5b2
			return -1;
5af5b2
		}
5af5b2
	}
5af5b2
5af5b2
	if (getenv("NOPORT") == NULL) {
5af5b2
		return next_connect(sockfd, addr, addrlen);
5af5b2
	}
5af5b2
5af5b2
	switch (addr->sa_family) {
5af5b2
	case AF_INET:
5af5b2
		port = ntohs(((struct sockaddr_in *)addr)->sin_port);
5af5b2
		if (port_is_okay(port) != 0) {
5af5b2
			return -1;
5af5b2
		}
5af5b2
		break;
5af5b2
	case AF_INET6:
5af5b2
		port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
5af5b2
		if (port_is_okay(port) != 0) {
5af5b2
			return -1;
5af5b2
		}
5af5b2
		break;
5af5b2
	default:
5af5b2
		break;
5af5b2
	}
5af5b2
	return next_connect(sockfd, addr, addrlen);
5af5b2
}
5af5b2
5af5b2
ssize_t
5af5b2
sendto(int sockfd, const void *buf, size_t len, int flags,
5af5b2
       const struct sockaddr *dest_addr, socklen_t addrlen)
5af5b2
{
5af5b2
	unsigned short port;
5af5b2
	static int (*next_sendto)(int, const void *, size_t, int,
5af5b2
				  const struct sockaddr *, socklen_t);
5af5b2
5af5b2
	if (next_sendto == NULL) {
5af5b2
		next_sendto = dlsym(RTLD_NEXT, "sendto");
5af5b2
		if (next_sendto == NULL) {
5af5b2
			errno = ENOSYS;
5af5b2
			return -1;
5af5b2
		}
5af5b2
	}
5af5b2
5af5b2
	if (getenv("NOPORT") == NULL) {
5af5b2
		return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
5af5b2
	}
5af5b2
7d335d
	if (dest_addr != NULL) {
7d335d
		switch (dest_addr->sa_family) {
7d335d
		case AF_INET:
7d335d
			port = ((struct sockaddr_in *)dest_addr)->sin_port;
7d335d
			port = ntohs(port);
7d335d
			if (port_is_okay(port) != 0) {
7d335d
				return -1;
7d335d
			}
7d335d
			break;
7d335d
		case AF_INET6:
7d335d
			port = ((struct sockaddr_in6 *)dest_addr)->sin6_port;
7d335d
			port = ntohs(port);
7d335d
			if (port_is_okay(port) != 0) {
7d335d
				return -1;
7d335d
			}
7d335d
			break;
7d335d
		default:
7d335d
			break;
5af5b2
		}
5af5b2
	}
5af5b2
	return next_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
5af5b2
}