add forcebindiface.c
[hband-ld-preload-libs.git] / src / forcebindiface.c
blobaecb38b736fcea9ee90c11db13e8b18335428089
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/socket.h>
4 #include <netinet/in.h>
5 #include <dlfcn.h>
6 #include <net/if.h>
7 #include <string.h>
8 #include <errno.h>
10 //Credits go to https://catonmat.net/simple-ld-preload-tutorial and https://catonmat.net/simple-ld-preload-tutorial-part-two
11 //And of course to https://unix.stackexchange.com/a/648721/334883
13 //compile with gcc -nostartfiles -fpic -shared bindInterface.c -o bindInterface.so -ldl -D_GNU_SOURCE
14 //Use with BIND_INTERFACE=<network interface> LD_PRELOAD=./bindInterface.so <your program> like curl ifconfig.me
16 int socket(int family, int type, int protocol)
18 //printf("MySocket\n"); //"LD_PRELOAD=./bind.so wget -O- ifconfig.me 2> /dev/null" prints two times "MySocket". First is for DNS-Lookup.
19 //If your first nameserver is not reachable via bound interface,
20 //then it will try the next nameserver until it succeeds or stops with name resolution error.
21 //This is why it could take significantly longer than curl --interface wlan0 ifconfig.me
22 char *bind_addr_env;
23 struct ifreq interface;
24 int *(*original_socket)(int, int, int);
25 original_socket = dlsym(RTLD_NEXT,"socket");
26 int fd = (int)(*original_socket)(family,type,protocol);
27 bind_addr_env = getenv("BIND_INTERFACE");
28 int errorCode;
29 if ( bind_addr_env!= NULL && strlen(bind_addr_env) > 0)
31 //printf(bind_addr_env);
32 strcpy(interface.ifr_name,bind_addr_env);
33 errorCode = setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &interface, sizeof(interface));
34 if ( errorCode < 0)
36 perror("setsockopt");
37 errno = EINVAL;
38 return -1;
41 else
43 //printf("Warning: Programm with LD_PRELOAD started, but BIND_INTERFACE environment variable not set\n");
44 fprintf(stderr,"Warning: Programm started with LD_PRELOAD, but BIND_INTERFACE environment variable not set\n");
47 return fd;