如何在没有 root 访问权限的情况下使用 gethostbyname 为主机名添加别名?

如何在没有 root 访问权限的情况下使用 gethostbyname 为主机名添加别名?

我正在运行一个程序(在其源代码中):

gethostbyname("whatever");

我希望它使用本地计算机的地址。我无法更改来源。如果我是 root,那就很容易了 - 我只需在 /etc/hosts 中为这个名称起别名即可。但是——作为一个我能做些什么吗?非主机用户对我的gethostbyname()通话有同样的效果吗?

/etc/nsswitch.conf有:

hosts:      files nis dns myhostname

以防万一。

答案1

在容器中运行它

使用播客(或者可能是无根 Docker),您可以在已设置别名的容器内运行代码。例如,我有以下调用的代码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;
}

如果我将其编译到命令中lookuphost然后运行./lookuphost google.com,我会得到:

$ ./lookuphost google.com
google.com: 142.251.32.110

如果我想google.com解决1.2.3.4,我可以这样做:

$ 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

使用函数插入

您可以使用函数插入gethostbyname用您自己的代码包装调用。例如,如果我将以下内容放入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;
}

然后将其构建到共享库中:

gcc -c -fPIC gethostbyname.c
gcc -shared -ldl -fPIC gethostbyname.o -o gethostbyname.so

我可以LD_PRELOAD运行lookuphost并得到预期的答案:

$ LD_PRELOAD=./gethostbyname.so ./lookuphost google.com
google.com: 1.2.3.4

答案2

  • 使用nss_包装器预加载库。它与 @larsks 的建议类似,但工作级别稍低(并提供 passwd 和主机的模拟)。 Samba 将其用于其测试套件。

    export LD_PRELOAD=libnss_wrapper.so
    export NSS_WRAPPER_HOSTS=/path/to/your/hosts
    
  • glibc习惯于为此有一个特定的功能 - 您可以通过创建一个“主机别名”文件$HOSTALIASES,其中包含对列表alias real.hostname.tld(即附加的间接级别,不是指向 IP 地址)。

    $ export HOSTALIASES=~/.hosts
    $ cat > $HOSTALIASES <<!
    whatever   real.example.net
    !
    

    但是,我相信有计划删除此功能,并且它似乎不再适用于我的系统,至少不适用于getent hosts.如果您正在运行带有较旧 Glibc 的发行版,这可能仍然有效。

相关内容