/* * rebind: Intercept bind calls and bind to a different port * Copyright 2010 Joel Martin * Licensed under LGPL version 3 (see docs/LICENSE.LGPL-3) * * Overload (LD_PRELOAD) bind system call. If REBIND_PORT_OLD and * REBIND_PORT_NEW environment variables are set then bind on the new * port (of localhost) instead of the old port. * * This allows a bridge/proxy (such as websockify) to run on the old port and * translate traffic to/from the new port. * * Usage: * LD_PRELOAD=./rebind.so \ * REBIND_PORT_OLD=23 \ * REBIND_PORT_NEW=2023 \ * program */ //#define DO_DEBUG 1 #include #include #define __USE_GNU 1 // Pull in RTLD_NEXT #include #include #include #if defined(DO_DEBUG) #define DEBUG(...) \ fprintf(stderr, "rebind: "); \ fprintf(stderr, __VA_ARGS__); #else #define DEBUG(...) #endif int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { static void * (*func)(); int do_move = 0; struct sockaddr_in * addr_in = (struct sockaddr_in *)addr; struct sockaddr_in addr_tmp; socklen_t addrlen_tmp; char * PORT_OLD, * PORT_NEW, * end1, * end2; int ret, oldport, newport, askport = htons(addr_in->sin_port); uint32_t askaddr = htons(addr_in->sin_addr.s_addr); if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "bind"); DEBUG(">> bind(%d, _, %d), askaddr %d, askport %d\n", sockfd, addrlen, askaddr, askport); /* Determine if we should move this socket */ if (addr_in->sin_family == AF_INET) { // TODO: support IPv6 PORT_OLD = getenv("REBIND_OLD_PORT"); PORT_NEW = getenv("REBIND_NEW_PORT"); if (PORT_OLD && (*PORT_OLD != '\0') && PORT_NEW && (*PORT_NEW != '\0')) { oldport = strtol(PORT_OLD, &end1, 10); newport = strtol(PORT_NEW, &end2, 10); if (oldport && (*end1 == '\0') && newport && (*end2 == '\0') && (oldport == askport)) { do_move = 1; } } } if (! do_move) { /* Just pass everything right through to the real bind */ ret = (long) func(sockfd, addr, addrlen); DEBUG("<< bind(%d, _, %d) ret %d\n", sockfd, addrlen, ret); return ret; } DEBUG("binding fd %d on localhost:%d instead of 0x%x:%d\n", sockfd, newport, ntohl(addr_in->sin_addr.s_addr), oldport); /* Use a temporary location for the new address information */ addrlen_tmp = sizeof(addr_tmp); memcpy(&addr_tmp, addr, addrlen_tmp); /* Bind to other port on the loopback instead */ addr_tmp.sin_addr.s_addr = htonl(INADDR_LOOPBACK); addr_tmp.sin_port = htons(newport); ret = (long) func(sockfd, &addr_tmp, addrlen_tmp); DEBUG("<< bind(%d, _, %d) ret %d\n", sockfd, addrlen, ret); return ret; }