If you have multiple IPs assigned on your Linux pc then there is a chance that you want to use different IPs for some applications than default one. Updating IP routes every time isn’t a good idea and you may mess up.
get bindhack.c
wget 'https://gist.githubusercontent.com/akhilin/f6660a2f93f64545ff8fcc0d6b23e42a/raw/7bf3f066b74a4b9e3d3768a8affee26da6a3ada6/bindhack.c' -P /tmp/
compile it
gcc -fPIC -static -shared -o /tmp/bindhack.so /tmp/bindhack.c -lc -ldl
Copy it to library folder
cp /tmp/bindhack.so /usr/lib/ && chmod +x /usr/lib/bindhack.so
Optional (ignore if you have it already )
echo 'nameserver 8.8.8.8' >> /etc/resolv.conf
using bindhack
BIND_ADDR=<source ip> LD_PRELOAD=/usr/lib/bindhack.so <command here>
Example
you can add below function in your .bashrc to spin it at any time
1 2 3 4 5 6 7 8 9 10 11 |
bindhack() { # Author: Akhil Jalagam [ $# -lt 2 ] && echo "missing arguments: $0 [bind ip] [command with quotes]" wget 'https://gist.githubusercontent.com/akhilin/f6660a2f93f64545ff8fcc0d6b23e42a/raw/7bf3f066b74a4b9e3d3768a8affee26da6a3ada6/bindhack.c' -P /tmp/ gcc -fPIC -static -shared -o /tmp/bindhack.so /tmp/bindhack.c -lc -ldl [ -f /usr/lib/bindhack.so ] || `type -P cp` /tmp/bindhack.so /usr/lib/ && chmod +x /usr/lib/bindhack.so [ -f /etc/resolv.conf ] && `type -P cp` /etc/resolv.conf /etc/resolv.conf.bak && echo 'nameserver 8.8.8.8' >> /etc/resolv.conf [ $# -eq 2 ] && BIND_ADDR=$1 LD_PRELOAD=/usr/lib/bindhack.so $2 echo '' `type -P cp` /etc/resolv.conf.bak /etc/resolv.conf } |
take a look at bindhack.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <string.h> #include <dlfcn.h> #include <arpa/inet.h> /* This is the address you want to force everything to use. It can be overriden at runtime by specifying the BIND_SRC environment variable. */ #define SRC_ADDR "192.168.0.1" /* LIBC_NAME should be the name of the library that contains the real bind() and connect() library calls. On Linux this is libc, but on other OS's such as Solaris this would be the socket library */ #define LIBC_NAME "libc.so.6" #define YES 1 #define NO 0 int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen) { struct sockaddr_in src_addr; void *libc; int (*bind_ptr)(int, void *, int); int ret; int passthru; char *bind_src; #ifdef DEBUG fprintf(stderr, "bind() override called for addr: %s\n", SRC_ADDR); #endif libc = dlopen(LIBC_NAME, RTLD_LAZY); if (!libc) { fprintf(stderr, "Unable to open libc!\n"); exit(-1); } *(void **) (&bind_ptr) = dlsym(libc, "bind"); if (!bind_ptr) { fprintf(stderr, "Unable to locate bind function in lib\n"); exit(-1); } passthru = YES; /* By default, we just call regular bind() */ if (my_addr==NULL) { /* If we get a NULL it's because we're being called from the connect() hack */ passthru = NO; #ifdef DEBUG fprintf(stderr, "bind() Received NULL address.\n"); #endif } else { if (my_addr->sa_family == AF_INET) { struct sockaddr_in myaddr_in; /* If this is an INET socket, then we spring to action! */ passthru = NO; memcpy(&myaddr_in, my_addr, addrlen); src_addr.sin_port = myaddr_in.sin_port; } else { passthru = YES; } } if (!passthru) { #ifdef DEBUG fprintf(stderr, "Proceeding with bind hack\n"); #endif src_addr.sin_family = AF_INET; bind_src=getenv("BIND_SRC"); /* If the environment variable BIND_SRC is set, then use that as the source IP to bind instead of the hard-coded SRC_ADDR one. */ if (bind_src) { ret = inet_pton(AF_INET, bind_src, &src_addr.sin_addr); if (ret<=0) { /* If the above failed, then try the built in address. */ inet_pton(AF_INET, SRC_ADDR, &src_addr.sin_addr); } } else { inet_pton(AF_INET, SRC_ADDR, &src_addr.sin_addr); } /* Call real bind function */ ret = (int)(*bind_ptr)(sockfd, (void *)&src_addr, sizeof(src_addr)); } else { #ifdef DEBUG fprintf(stderr, "Calling real bind unmolested\n"); #endif /* Call real bind function */ ret = (int)(*bind_ptr)(sockfd, (void *)my_addr, addrlen); } #ifdef DEBUG fprintf(stderr, "The real bind function returned: %d\n", ret); #endif /* Clean up */ dlclose(libc); return ret; } /* Sometimes (alot of times) programs don't bother to call bind() if they're just making an outgoing connection. To take care of these cases, we need to call bind when they call connect instead. And of course, then call connect as well... */ int connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) { int (*connect_ptr)(int, void *, int); void *libc; int ret; #ifdef DEBUG fprintf(stderr, "connect() override called for addr: %s\n", SRC_ADDR); #endif /* Before we call connect, let's call bind() and make sure we're using our preferred source address. */ ret = bind(sockfd, NULL, 0); /* Our fake bind doesn't really need those params */ libc = dlopen(LIBC_NAME, RTLD_LAZY); if (!libc) { fprintf(stderr, "Unable to open libc!\n"); exit(-1); } *(void **) (&connect_ptr) = dlsym(libc, "connect"); if (!connect_ptr) { fprintf(stderr, "Unable to locate connect function in lib\n"); exit(-1); } /* Call real connect function */ ret = (int)(*connect_ptr)(sockfd, (void *)serv_addr, addrlen); /* Clean up */ dlclose(libc); return ret; } |