当前位置:首页 > 技术与方案 > Linux及应用

网络地址处理 (3)

(2012-09-26 17:25:16)

9.1.3.2主机名获取

apr_sockaddr_info_get函数用以完成从主机名到网络地址的转换,而APR中提供的apr_getnameinfo则可以实现从网络地址到主机名的转换,该函数定义如下:

APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, apr_sockaddr_t *sa, apr_int32_t flags);

参数sa指定需要转换的网络地址,转换后的主机名由hostname返回。fags是标志位,用以控制内部的转换过程。

{

#if defined(HAVE_GETNAMEINFO)

int rc;

#if defined(NI_MAXHOST)

char tmphostname[NI_MAXHOST];

#else

char tmphostname[256];

#endif

 

SET_H_ERRNO(0);

 

#if APR_HAVE_IPV6

if (sockaddr->family == AF_INET6 &&

IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) {

struct sockaddr_in tmpsa;

tmpsa.sin_family = AF_INET;

tmpsa.sin_addr.s_addr = ((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];

#ifdef SIN6_LEN

tmpsa.sin_len = sizeof(tmpsa);

#endif

rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),

tmphostname, sizeof(tmphostname), NULL, 0,

flags != 0 ? flags : NI_NAMEREQD);

}

else

#endif

#endif

rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,

tmphostname, sizeof(tmphostname), NULL, 0,

flags != 0 ? flags : NI_NAMEREQD);

在函数的内部实现从地址到主机名称的解析是由函数getnameinfo完成的,该函数是getaddrinfo的互补函数,它以一个套接口地址为参数,返回描述其中的主机的一个字符串和描述其中的服务的另一个字符串。另外该函数以协议无关的方式提供这些信息,调用者必须关心存放在套接口地址结构中的协议地址的类型,这些由函数自行处理。

需要转换的地址到底是IPv4还是IPv6,这由地址结构中的family参数决定。尽管理想中的做法是将apr_getnameinfo()中的参数直接传递给getnameinfo()函数,但是在一些平台上还是会出现一些问题。

MacOS X Panther has a lousy getnameinfo() implementation that doesn't fill the buffer when no DNS entry is found for a host and a numerical result wasn't explicitely asked. As a result, Pure-FTPd didn't even start on Panther (saying "bad IP address") . We now check for EAI_NONAME if available and we retry with NI_NUMERICHOST if this is what getnameinfo() returns. Thanks to Yann Bizeul for his valuable help on this issue. Will research it more and see if I can come up with a patch (I am NOT good at C!)

在一些操作系统中,比如老版本的Mac OS X,如果Ipv6地址是由Ipv4地址映射的结果,那么该地址在传递给getnameinfo函数的时候将会产生错误,这是系统本身实现的BUG。因此对于这种情况,解决的方法就是将这种Ipv6地址重新转换为Ipv4地址。Ipv6地址是否是由Ipv4地址进行映射而成,通过宏IN6_IS_ADDR_V4MAPPED可以实现检测。IPV4到IPV6地址的映射可以用下图描述:

Ipv4地址通过在其十六进制前面添加前导零的方式映射为IPV6地址。反之如果一个IPV6地址是由IPV4地址映射而成,则只要剔除前面的前导零即可,剔除后的地址通常为((apr_uint32_t *)sockaddr->ipaddr_ptr)[3];一旦获取了实际的IPV4地址,则可以将其传递给getnameinfo函数。

对于其余的IP地址,包括普通的Ipv4地址,非Ipv4映射的Ipv6地址,由于不存在BUG,因此可以直接调用getnameinfo。

getnameinfo函数原型如下:

Int getnameinfo(const struct sockaddr* sockaddr, socklen_t addrlen,

char *host, socklen_t hostlen,

char *serv, socklen_t servlen, int flag);

函数的前面几个参数都非常容易理解,只有最后一个参数flag,它用于控制getnameinfo的操作,它允许的值如下面所列:

NI_DGRAM

当知道处理的是数据报套接口的时候,调用者应该设置NI_DGRAM标志,因为在套接口地址结构中给出的仅仅是IP地址和端口号,getnameinfo无法就此确定所用协议是TCP还是UDP。比如端口514,在TCP端口上提供rsh服务,而在UDP端口上则提供syslog服务。

NI_NOFQDN

该标志导致返回的主机名称被截去第一个点号之后的内容。比如假设套接口结构中的IP地址为912.168.42.2,那么不设置该标志返回的主机名为aix.unpbook.com,那么如果设置了该标志后返回的主机名则为aix。

NI_NUMERICHOST,NI_NUMERICSERV,NI_NUMERICSCOPE

该标志通知getnameinfo不要调用DNS,而是以数值表达格式作为字符串返回IP地址;类似的,NI_NUMERICSERV标志指定以十进制数格式作为字符串返回端口号,以代替查找服务名;NI_NUMERICSCOPE则指定以数值格式作为字符串返回范围标识,以代替其名字

NI_NAMEREQD

该标志通知getnameinfo函数如果无法适用DNS反向解析出主机名,则直接返回一个错误。需要把客户的IP地址映射成主机名的那些服务器可以使用该特性。

如果flag没有指定,即为零,那么NI_NAMEREQD将是Apache中默认的标志项,如果不设置该标志,那么在反向解析失败的时候getnameinfo将返回一个数值地址字符串,显然这并不是Apache所需要的结果。

if (rc != 0) {

*hostname = NULL;

#ifndef WIN32

if (rc == EAI_SYSTEM) {

if (h_errno) { /* for broken implementations which set h_errno */

return h_errno + APR_OS_START_SYSERR;

}

else { /* "normal" case */

return errno + APR_OS_START_SYSERR;

}

}

else

#endif

{

#if defined(NEGATIVE_EAI)

if (rc < 0) rc = -rc;w

#endif

return rc + APR_OS_START_EAIERR; /* return the EAI_ error */

}

}

*hostname = sockaddr->hostname = apr_pstrdup(sockaddr->pool, tmphostname);

return APR_SUCCESS;

上面的代码是对getnameinfo发生错误时候的处理(rc==0意味着成功,否则意味着转换失败)。此时将需要返回的主机名称设置为NULL。当getnameinfo发生错误的时候通常会返回EAI_XXXX的错误码,在所有这些错误码中比较特殊的就是EAI_SYSTEM,它意味着同时在errno变量中有系统错误返回,而其余的EAI_XXXX错误并不会设置errno变量。

更多
关闭窗口 打印 
网站首页    -    联系我们    -   收藏本站    -    网站地图                                                               客户服务热线:0571-85023000
本网站所有网页信息已申请知识产权和著作权保护,版权归四海光纤公司所有,未经授权禁止任何人复制或镜像,违者必究。
公司主营:杭州光纤光缆视频会议系统,是专业的通信网络工程、视频会议系统建设专家

中华人民共和国备案号:浙ICP备10018243号