嵌入式 ARM 平台 busybox
可以 ping ip
,但是不能 ping domain name
本篇主要涉及
- gcc v4.9
- libnss 动态链接库
- busybox 动态与静态编译
- busybox 动态编译下使用域名解析
- busybox 静态编译下使用域名解析
环境
- Linux v4.9.22
- Busybox v1.27.2
- Gcc v4.9
现象
ping IP
可以正常工作, ping domain name
时报错如下
# ping www.baidu.com
ping: bad address 'www.baidu.com'
# nslookup www.baidu.com
Server: 192.168.110.1
Address 1: 192.168.110.1
nslookup: can't resolve 'www.baidu.com'
确认环境设置
需要确认路由表及 nameserver
,如下:
# route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.110.1 0.0.0.0 UG 0 0 0 eth0
192.168.110.0 * 255.255.254.0 U 0 0 0 eth0
# cat /etc/resolv.conf
nameserver 192.168.110.1
nameserver 114.114.114.114
nameserver 202.101.172.35
相同的配置在使用 uclibc
编译的开发板上工作正常
添加默认路由表命令如下
route add default gw 192.168.110.1 dev eth0
相关信息
- Busybox ping IP works, but hostname nslookup fails with “bad address”
- ping: bad address ‘www.baidu.com’
- FS#41769 - [busybox] DNS lookups don’t work
- Name resolution in busybox
- libc6 version 2.19 breaks NSS loading for static binaries
- Linux 文件系统域名解析实现
- arm 开发板无法使用 dns 解析问题
包括 busybox
下文档 busybox_footer.pod
下解释
LIBC NSS
GNU Libc (glibc) uses the Name Service Switch (NSS) to configure the behavior
of the C library for the local environment, and to configure how it reads
system data, such as passwords and group information. This is implemented
using an /etc/nsswitch.conf configuration file, and using one or more of the
/lib/libnss_* libraries. BusyBox tries to avoid using any libc calls that make
use of NSS. Some applets however, such as login and su, will use libc functions
that require NSS.
If you enable CONFIG_USE_BB_PWD_GRP, BusyBox will use internal functions to
directly access the /etc/passwd, /etc/group, and /etc/shadow files without
using NSS. This may allow you to run your system without the need for
installing any of the NSS configuration files and libraries.
When used with glibc, the BusyBox ‘networking’ applets will similarly require
that you install at least some of the glibc NSS stuff (in particular,
/etc/nsswitch.conf, /lib/libnss_dns, /lib/libnss_files, and /lib/libresolv*).
Shameless Plug: As an alternative, one could use a C library such as uClibc. In
addition to making your system significantly smaller, uClibc does not require the
use of any NSS support files or libraries.
从以上可以获知:
libnss
设计就是动态库,不建议静态编译。要静态编译,请先重新编译glibc
,把–enable-libnss-static
放上glibc
需要libnss
库支持,编译工具链中直接包含了相关的文件,是动态库✔ ~/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib > ll libnss_dns* libnss_dns-2.19-2014.08-1-git.so libnss_dns.so.2 -> libnss_dns-2.19-2014.08-1-git.so ✔ ~/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib > ll libnss_files* libnss_files-2.19-2014.08-1-git.so libnss_files.so.2 -> libnss_files-2.19-2014.08-1-git.so ✔ ~/gcc-linaro-4.9.4-2017.01-i686_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib > ll libresolv* libresolv-2.19-2014.08-1-git.so libresolv.so.2 -> libresolv-2.19-2014.08-1-git.so
busybox
需要动态编译来完成对libnss
的使用
NSS(Name Service Switch 与 nsswitch.conf
NSS(Name Service Switch)
是 类 unix 操作系统
中的一种工具,它为通用配置数据库和名称解析机制提供了各种来源。这些源文件包括本地操作系统文件(例如 /etc/passwd
、 /etc/group
和 /etc/hosts
)、 域名系统 (DNS)
、 网络信息服务 (NIS)
和 LDAP
nsswitch.conf(name service switch configuration,名称服务切换配置)
文件位于 /etc
目录下,由它规定通过哪些途径以及按照什么顺序以及通过这些途径来查找特定类型的信息,还可以指定某个方法奏效或失效时系统将采取什么动作
本篇文章中涉及到 DNS 解析顺序
解决方案
动态编译
busybox
使用动态编译,然后将 libnss
相关文件拷贝到 rootfs/lib
下,并配置文件 /etc/hosts, /etc/resolv.conf, /etc/nsswitch.conf
静态编译
参考文章:nslookup 在静态编译的 busybox 上如何正常解析域名
使用 getaddrinfo
进行域名解析。这个函数是 libnss
里的一个 API
(可以在 glibc
源码中查看 nss
目录)。解决办法是绕过它,自己实现域名解析
搜索 busybox
源文件
busybox-1.27.2 > grep "getaddrinfo" * -Rn
libbb/inet_common.c:160: s = getaddrinfo(name, NULL, &req, &ai);
libbb/inet_common.c:162: bb_error_msg("getaddrinfo: %s: %d", name, s);
libbb/xconnect.c:5: * Connect to host at port using address resolution from getaddrinfo
libbb/xconnect.c:247: /* Next two if blocks allow to skip getaddrinfo()
libbb/xconnect.c:249: * getaddrinfo() initializes DNS resolution machinery,
libbb/xconnect.c:285: rc = getaddrinfo(host, NULL, &hint, &result);
networking/nslookup.c:90: rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result);
networking/nslookup.c:200: /* getaddrinfo and friends are free to request a resolver
networking/nslookup.c:202: * after getaddrinfo (in server_print). This reportedly helps
inet_common.c
、 xconnect.c
以及 nslookup.c
这三个文件中的 getaddrinfo
使用 getaddrinfo.h 覆盖解决此问题