Run it in a container
Using podman (or possibly rootless Docker) you could run your code inside a container in which you have set up an alias. E.g., I have the following code that calls gethostbyname:
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int argc, char **argv) {
for (int i = 1; i < argc; i++) {
struct hostent *entry = gethostbyname(argv[i]);
for (int j = 0; entry->h_addr_list[j] != NULL; j++) {
printf("%s: %s\n", entry->h_name,
inet_ntoa(*(struct in_addr *)entry->h_addr_list[j]));
}
}
return 0;
}
If I compile this into the command lookuphost and then run ./lookuphost google.com, I get:
$ ./lookuphost google.com
google.com: 142.251.32.110
If I want google.com to resolve to 1.2.3.4, I can do something like this:
$ podman run -it --rm \
--add-host google.com:1.2.3.4 \
-v $PWD:$PWD -w $PWD fedora:37 \
./lookuphost google.com
google.com: 1.2.3.4
Use function interposition
You can use function interposition to wrap the gethostbyname call with your own code. For example, if I put the following in gethostbyname.c:
#define _GNU_SOURCE
#include <arpa/inet.h>
#include <dlfcn.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
struct hostent *gethostbyname(const char *name) {
static struct hostent *(*real_gethostbyname)(const char *) = NULL;
if (!real_gethostbyname) {
real_gethostbyname = dlsym(RTLD_NEXT, "gethostbyname");
}
struct hostent *entry = real_gethostbyname(name);
if (strcmp(name, "google.com") == 0) {
struct in_addr inp;
inet_aton("1.2.3.4", &inp);
entry->h_addr_list[0] = (char *)&inp;
}
return entry;
}
And then build that into a shared library:
gcc -c -fPIC gethostbyname.c
gcc -shared -ldl -fPIC gethostbyname.o -o gethostbyname.so
I can LD_PRELOAD that and run lookuphost and get the expected answer:
$ LD_PRELOAD=./gethostbyname.so ./lookuphost google.com
google.com: 1.2.3.4