名字与地址转换

概述

我们通常使用主机名而不是数值地址来访问主机,主机名可以是简单的名字,也可以是全限定域名。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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值