文章目录
概述
我们通常使用主机名而不是数值地址来访问主机,主机名可以是简单的名字,也可以是全限定域名。unix提供了gethostbyname
实现主机名到地址之间的转换,gethostbyaddr
实现地址到主机名之间的转换。
gethostbyname
实现主机名到地址之间的转换,仅支持IPv4,函数原型如下:
#include <netdb.h>
struct hostent *gethostbyname(const char *hostname);
- hostname: 字符串形式的主机名
- return: hostent结构的主机信息
gethostbyname
和其他socket函数不同,出错时它不会修改errno
,而是修改netdb.h
中定义的h_errno
,t通过调用hstrerror(h_errno)
获取错误信息的字符串表示,错误信息如下:
- HOST_NOT_FOUND: 记录未找到
- TRY_AGAIN: 重试
- NO_RECOVERY: DNS服务不可达
- NO_DATA: 记录能找到,但是没有A记录,如只有AAAA记录的域名
gethostbyname流程
/etc/nsswitch.conf
如果在本机/etc/hosts
中加了www.baidu.com,在调用gethostbyname
访问www.baidu的时候,优先从本机hosts
中读取,还是向DNS请求域名呢?
# cat /etc/hosts
3.3.3.3 www.baidu.com testhostalias5 testhostalias6
结论是,如果本机安装了nscd,那么优先从nscd缓存中获取a/aaaa记录,如果没有安装,那么根据/etc/nsswitch.conf的配置,确定优先从哪里获取记录。
/etc/nsswitch.conf中关于hosts的配置如下:
#hosts: files dns myhostname
hosts: dns files myhostname
- files: 本机文件,如hosts对应/etc/hosts,账户密码对应/etc/passwd
- dns: 根据配置/etc/resolv.conf,从DNS服务器上请求
先files后dns验证
# ./a.out www.baidu.com
official hostname: www.baidu.com
alias: testhostalias5
alias: testhostalias6
address: 3.3.3.3
直接从hosts获取结果,hosts中如果没有,立即从DNS服务器上请求。
先dns后files验证
# ./a.out www.baidu.com
official hostname: www.a.shifen.com
alias: www.baidu.com
address: 36.152.44.96
address: 36.152.44.95
直接从DNS服务器请求结果,如果DNS服务器没有结果,超时后从hosts文件获取结果。
gethostname实例
附上unp上的实例:
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <arpa/inet.h>
int
main(int argc, char **argv)
{
char *ptr, **pptr;
char str[INET_ADDRSTRLEN];
struct hostent *hptr;
while (--argc > 0) {
ptr = *++argv;
if ((hptr = gethostbyname(ptr)) == NULL) {
printf("gethostbyname error for host: %s: %s\n", ptr, hstrerror(h_errno));
continue;
}
printf("official hostname: %s\n", hptr->h_name);
for (pptr = hptr->h_aliases; *pptr != NULL; pptr++) {
printf("\talias: %s\n", *pptr);
}
switch (hptr->h_addrtype) {
case AF_INET:
pptr = hptr->h_addr_list;
for ( ; *pptr != NULL; pptr++) {
inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str));
printf("\taddress: %s\n", str);
}
break;
default:
printf("unknow address type");
break;
}
}
return 0;
}
gethostbyaddr
gethostbyaddr
实现根据地址获取主机名,也就是DNS中的ptr记录。函数原型如下:
#include <netdb.h>
struct hostent *gethostbyaddr (const void *addr, socklen_t len, int type);
- addr: struct in_addr类型指针
- len: IPv4长度,4
- type: 协议族,A
- return: struct hostent指针
gethostbyaddr实例
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
int main(int argc, char **argv)
{
char *ptr, **pptr;
char s_addr[256];
struct in_addr addr;
socklen_t len = 4;
struct hostent *hstent;
while(--argc > 0){
argv++;
strncpy(s_addr, *argv, sizeof(s_addr));
inet_aton(s_addr, &addr);
if ((hstent = gethostbyaddr(&addr, len, AF_INET)) == NULL){
printf("gethostaddr %s failed %s\n", s_addr, hstrerror(h_errno));
}
printf("addr : %s --> hostname : %s\n", s_addr, hstent->h_name);
}
return 0;
}