|
| 1 | +#define _GNU_SOURCE |
| 2 | +#include <dlfcn.h> |
| 3 | +#include <sys/types.h> |
| 4 | +#include <sys/socket.h> |
| 5 | +#include <errno.h> |
| 6 | +#include <stdbool.h> |
| 7 | +#include <pthread.h> |
| 8 | +#include <stdio.h> |
| 9 | +#include <netinet/in.h> |
| 10 | +#include <arpa/inet.h> |
| 11 | + |
| 12 | +static int (*real_connect)(int, const struct sockaddr *, socklen_t) = NULL; |
| 13 | +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; |
| 14 | +static int connect_count = 0; |
| 15 | + |
| 16 | +static void init_real_connect(void) { |
| 17 | + if (!real_connect) { |
| 18 | + real_connect = dlsym(RTLD_NEXT, "connect"); |
| 19 | + } |
| 20 | +} |
| 21 | + |
| 22 | +int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { |
| 23 | + init_real_connect(); |
| 24 | + |
| 25 | + pthread_mutex_lock(&lock); |
| 26 | + connect_count++; |
| 27 | + int n = connect_count; |
| 28 | + pthread_mutex_unlock(&lock); |
| 29 | + |
| 30 | + // Optional: log destination for debugging |
| 31 | + if (addr && addrlen >= sizeof(struct sockaddr_in) && addr->sa_family == AF_INET) { |
| 32 | + const struct sockaddr_in *sa = (const struct sockaddr_in *)addr; |
| 33 | + char ip[INET_ADDRSTRLEN]; |
| 34 | + inet_ntop(AF_INET, &sa->sin_addr, ip, sizeof(ip)); |
| 35 | + fprintf(stderr, "[blockfirst] #%d connect to %s:%d\n", |
| 36 | + n, ip, ntohs(sa->sin_port)); |
| 37 | + } |
| 38 | + |
| 39 | + // Block *only* the first connect() call for this process |
| 40 | + if (n == 1) { |
| 41 | + errno = ECONNREFUSED; |
| 42 | + fprintf(stderr, "[blockfirst] blocking first connect()\n"); |
| 43 | + return -1; |
| 44 | + } |
| 45 | + |
| 46 | + // All later calls: behave normally |
| 47 | + return real_connect(sockfd, addr, addrlen); |
| 48 | +} |
0 commit comments