#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <dlfcn.h>

static int lookup(struct in_addr *dest, const char *name)
{
	struct addrinfo *res, *ptr;
	int ret;
	if (getaddrinfo(name, NULL, NULL, &res)) {
		return ENETDOWN;
	}
	for (ptr = res; ptr; ptr = ptr->ai_next) {
		if (ptr->ai_addr->sa_family == AF_INET) {
			*dest = ((struct sockaddr_in *)(ptr->ai_addr))->sin_addr;
			ret = 0;
			goto done;
		}
	}
done:
	freeaddrinfo(res);
	return ret;
}

int connect(int sockfd, const struct sockaddr *serv_addr,
            socklen_t addrlen)
{
	static int (*real_connect)(int, const struct sockaddr *, socklen_t)
            = NULL;
	static struct in_addr scripts_ip = {0},
	                      scripts_cert_ip = {0},
	                      scripts_vhosts_ip = {0},
	                      scripts_test_ip = {0};

	if (!real_connect) {
		real_connect = dlsym(RTLD_NEXT, "connect");
	}
	if (!real_connect) {
		errno = ELIBACC;
		return -1;
	}

	if (serv_addr->sa_family == AF_INET) {
		struct sockaddr_in new_addr;
		memcpy(&new_addr, serv_addr, sizeof(new_addr));
		if (new_addr.sin_port == htons(80) ||
		    new_addr.sin_port == htons(443) ||
		    new_addr.sin_port == htons(444)) {
			if (!scripts_ip.s_addr) {
				errno = lookup(&scripts_test_ip, "scripts-test.mit.edu");
				if (errno) return -1;
				errno = lookup(&scripts_vhosts_ip, "scripts-vhosts.mit.edu");
				if (errno) return -1;
				errno = lookup(&scripts_cert_ip, "scripts-cert.mit.edu");
				if (errno) return -1;
				errno = lookup(&scripts_ip, "scripts.mit.edu");
				if (errno) return -1;
			}
			if (new_addr.sin_addr.s_addr == scripts_ip.s_addr ||
			    new_addr.sin_addr.s_addr == scripts_vhosts_ip.s_addr ||
			    new_addr.sin_addr.s_addr == scripts_cert_ip.s_addr) {
				new_addr.sin_addr = scripts_test_ip;
				return real_connect(sockfd, (struct sockaddr *)&new_addr, sizeof(new_addr));
			}
		}
	}
	return real_connect(sockfd, serv_addr, addrlen);
}
