]>
Commit | Line | Data |
---|---|---|
f2538f33 JM |
1 | /* |
2 | * rebind: Intercept bind calls and bind to a different port | |
3 | * Copyright 2010 Joel Martin | |
1d728ace | 4 | * Licensed under MPL-2.0 (see docs/LICENSE.MPL-2.0) |
f2538f33 JM |
5 | * |
6 | * Overload (LD_PRELOAD) bind system call. If REBIND_PORT_OLD and | |
7 | * REBIND_PORT_NEW environment variables are set then bind on the new | |
8 | * port (of localhost) instead of the old port. | |
9 | * | |
7c1cd937 JM |
10 | * This allows a bridge/proxy (such as websockify) to run on the old port and |
11 | * translate traffic to/from the new port. | |
f2538f33 JM |
12 | * |
13 | * Usage: | |
14 | * LD_PRELOAD=./rebind.so \ | |
15 | * REBIND_PORT_OLD=23 \ | |
16 | * REBIND_PORT_NEW=2023 \ | |
17 | * program | |
18 | */ | |
19 | ||
20 | //#define DO_DEBUG 1 | |
21 | ||
22 | #include <stdio.h> | |
23 | #include <stdlib.h> | |
24 | ||
25 | #define __USE_GNU 1 // Pull in RTLD_NEXT | |
26 | #include <dlfcn.h> | |
27 | ||
28 | #include <string.h> | |
29 | #include <netinet/in.h> | |
30 | ||
31 | ||
32 | #if defined(DO_DEBUG) | |
33 | #define DEBUG(...) \ | |
34 | fprintf(stderr, "wswrapper: "); \ | |
35 | fprintf(stderr, __VA_ARGS__); | |
36 | #else | |
37 | #define DEBUG(...) | |
38 | #endif | |
39 | ||
40 | ||
41 | int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) | |
42 | { | |
43 | static void * (*func)(); | |
44 | int do_move = 0; | |
45 | struct sockaddr_in * addr_in = (struct sockaddr_in *)addr; | |
46 | struct sockaddr_in addr_tmp; | |
47 | socklen_t addrlen_tmp; | |
48 | char * PORT_OLD, * PORT_NEW, * end1, * end2; | |
49 | int ret, oldport, newport, askport = htons(addr_in->sin_port); | |
50 | uint32_t askaddr = htons(addr_in->sin_addr.s_addr); | |
51 | if (!func) func = (void *(*)()) dlsym(RTLD_NEXT, "bind"); | |
52 | ||
53 | DEBUG(">> bind(%d, _, %d), askaddr %d, askport %d\n", | |
54 | sockfd, addrlen, askaddr, askport); | |
55 | ||
56 | /* Determine if we should move this socket */ | |
57 | if (addr_in->sin_family == AF_INET) { | |
58 | // TODO: support IPv6 | |
59 | PORT_OLD = getenv("REBIND_OLD_PORT"); | |
60 | PORT_NEW = getenv("REBIND_NEW_PORT"); | |
61 | if (PORT_OLD && (*PORT_OLD != '\0') && | |
62 | PORT_NEW && (*PORT_NEW != '\0')) { | |
63 | oldport = strtol(PORT_OLD, &end1, 10); | |
64 | newport = strtol(PORT_NEW, &end2, 10); | |
65 | if (oldport && (*end1 == '\0') && | |
66 | newport && (*end2 == '\0') && | |
67 | (oldport == askport)) { | |
68 | do_move = 1; | |
69 | } | |
70 | } | |
71 | } | |
72 | ||
73 | if (! do_move) { | |
74 | /* Just pass everything right through to the real bind */ | |
75 | ret = (int) func(sockfd, addr, addrlen); | |
76 | DEBUG("<< bind(%d, _, %d) ret %d\n", sockfd, addrlen, ret); | |
77 | return ret; | |
78 | } | |
79 | ||
80 | DEBUG("binding fd %d on localhost:%d instead of 0x%x:%d\n", | |
81 | sockfd, newport, ntohl(addr_in->sin_addr.s_addr), oldport); | |
82 | ||
83 | /* Use a temporary location for the new address information */ | |
84 | addrlen_tmp = sizeof(addr_tmp); | |
85 | memcpy(&addr_tmp, addr, addrlen_tmp); | |
86 | ||
87 | /* Bind to other port on the loopback instead */ | |
88 | addr_tmp.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | |
89 | addr_tmp.sin_port = htons(newport); | |
90 | ret = (int) func(sockfd, &addr_tmp, addrlen_tmp); | |
91 | ||
92 | DEBUG("<< bind(%d, _, %d) ret %d\n", sockfd, addrlen, ret); | |
93 | return ret; | |
94 | } |