Skip to content

Instantly share code, notes, and snippets.

@stbuehler
Forked from markusfisch/README.md
Last active July 22, 2024 00:35
Show Gist options
  • Save stbuehler/95d40dcf8f68e89fce7e05b545a9131d to your computer and use it in GitHub Desktop.
Save stbuehler/95d40dcf8f68e89fce7e05b545a9131d to your computer and use it in GitHub Desktop.
Force any binary to use a specific network interface in Linux

setnif

Force any binary to use a specific network interface.

Build: $ make

Use: LD_PRELOAD=$(pwd)/setnif.so NIF=eth1 program args...

Linux only.

all: setnif.so
.PHONY: all
setnif.so: setnif.c
gcc -O2 -o $@ -fpic -shared $< -ldl -D_GNU_SOURCE
clean:
rm -f setnif.so
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define CONST_STR_LEN(s) (s), (sizeof(s) - 1)
static int (*std_socket)(int, int, int);
static const char *nif;
static int nif_len;
static void __attribute__ ((constructor)) setnif_init(void) {
const char *err;
std_socket = dlsym(RTLD_NEXT, "socket");
nif = getenv("NIF");
nif_len = strlen(nif);
}
static int set_nif(int fd) {
if (NULL == nif) return fd;
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, nif, strlen(nif)) < 0) {
int e = errno;
close(fd);
errno = e;
return -1;
}
return fd;
}
int socket(int domain, int type, int protocol) {
int fd;
if (NULL == std_socket) {
errno = ENOSYS;
return -1;
}
fd = std_socket(domain, type, protocol);
if (fd < 0) return fd;
switch (domain) {
case AF_INET:
case AF_INET6:
return set_nif(fd);
default:
return fd;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment