|
|
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 |
}
|