rebind.c 2.8 KB

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