![如何在没有 root 访问权限的情况下使用 gethostbyname 为主机名添加别名?](https://linux22.com/image/219241/%E5%A6%82%E4%BD%95%E5%9C%A8%E6%B2%A1%E6%9C%89%20root%20%E8%AE%BF%E9%97%AE%E6%9D%83%E9%99%90%E7%9A%84%E6%83%85%E5%86%B5%E4%B8%8B%E4%BD%BF%E7%94%A8%20gethostbyname%20%E4%B8%BA%E4%B8%BB%E6%9C%BA%E5%90%8D%E6%B7%BB%E5%8A%A0%E5%88%AB%E5%90%8D%EF%BC%9F.png)
我正在运行一个程序(在其源代码中):
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 的发行版,这可能仍然有效。